Search code examples
pythonmatplotlibplotglyph

Draw a plot of glyphs in Matplotlib


I was using Matplotlib to plot some scientific visualizations for which heat map plots (as the one below) was sufficient. My code is all written in Python too.

enter image description here

However, now I need to present a more "elaborated" plot, which consists of glyphs. The following image (the second one) shows an example:

enter image description here

In that image, each point of the plot is a glyph that represents a probability of a vector field orientation. This is glyph is draw as a circle with a main direction and a standard deviation from its direction.

I would like to do something similar. My idea was to draw something like a polar histogram at each position and to have a plot comprised by polar charts. However, I don't think that is possible with Matplotlib; at least I don't have any idea how this can be done. As my whole code is written in Python, I was wondering if somehow I can stand with Matplotlib, or if I should study how to do this with OpenGL or another API/libraty.

Thank you.


Solution

  • Perhaps a whole lot of something like this:

    enter image description here

    import matplotlib.pyplot as plt
    import numpy as np
    from matplotlib.collections import PatchCollection
    from matplotlib.patches import Wedge, Circle
    from math import degrees, pi
    
    fig, ax = plt.subplots()
    wedges = []
    circles = []
    
    for x in np.arange(0, 3.3, .3):
        for y in np.arange(0, 3.3, .3):
            theta, phi = np.random.random(2)  # functions of (x,y) in reality
            for v in (0, pi):
                wedges.append(Wedge((x, y),
                                .15,
                                degrees(v - phi - theta/2),
                                degrees(v - phi + theta/2),
                                edgecolor='none'),
                                )
            circles.append(Circle((x, y),
                                 .15,
                                 edgecolor='none'))
    
    
    colors = np.linspace(0, 1, len(circles))  # function of (x,y) in reality
    collection = PatchCollection(circles, cmap=plt.cm.jet, alpha=0.2)
    collection.set_array(np.array(colors))
    collection.set_edgecolor('none')
    ax.add_collection(collection)
    
    #wedgecolors = list(chain.from_iterable(repeat(i,2) for i in colors))
    wedgecolors = np.array([colors, colors]).flatten('F') # no itertools
    collection = PatchCollection(wedges, cmap=plt.cm.jet, alpha=1)
    collection.set_array(np.array(wedgecolors))
    collection.set_edgecolor('none')
    ax.add_collection(collection)
    
    ax.set_xlim(0,3)
    ax.set_ylim(0,3)
    ax.set_aspect('equal')
    plt.show()
    

    (Setting the edgecolor has to be done (redone?) after the collection.set_array call, apparently.)