Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib Rectangle With Color Gradient Fill

I want to draw a rectangle, with a gradient color fill from left to right, at an arbitrary position with arbitrary dimensions in my axes instance (ax1) coordinate system.

enter image description here

My first thought was to create a path patch and somehow set its fill as a color gradient. But according to THIS POST there isn't a way to do that.

Next I tried using a colorbar. I created a second axes instance ax2 using fig.add_axes([left, bottom, width, height]) and added a color bar to that.

ax2 = fig.add_axes([0, 0, width, height/8])
colors = [grad_start_color, grad_end_color]
index  = [0.0, 1.0]
cm = LinearSegmentedColormap.from_list('my_colormap', zip(index, colors))
colorbar.ColorbarBase(ax2, cmap=cm, orientation='horizontal')

But the positional parameters passed to fig.add_axes() are in the coordinate system of fig, and don't match up with the coordinate system of ax1.

How can I do this?

like image 437
dmoench Avatar asked Jul 26 '14 23:07

dmoench


2 Answers

I have been asking myself a similar question and spent some time looking for the answer to find in the end that this can quite easily be done by imshow:

from matplotlib import pyplot

pyplot.imshow([[0.,1.], [0.,1.]], 
  cmap = pyplot.cm.Greens, 
  interpolation = 'bicubic'
)

enter image description here

It is possible to specify a colormap, what interpolation to use and much more. One additional thing, I find very interesting, is the possibility to specify which part of the colormap to use. This is done by means of vmin and vmax:

pyplot.imshow([[64, 192], [64, 192]], 
  cmap = pyplot.cm.Greens, 
  interpolation = 'bicubic', 
  vmin = 0, vmax = 255
)

enter image description here

Inspired by this example


Additional Note:

I chose X = [[0.,1.], [0.,1.]] to make the gradient change from left to right. By setting the array to something like X = [[0.,0.], [1.,1.]], you get a gradient from top to bottom. In general, it is possible to specify the colour for each corner where in X = [[i00, i01],[i10, i11]], i00, i01, i10 and i11 specify colours for the upper-left, upper-right, lower-left and lower-right corners respectively. Increasing the size of X obviously allows to set colours for more specific points.

like image 129
Mr Tsjolder Avatar answered Sep 21 '22 15:09

Mr Tsjolder


did you ever solve this? I wanted the same thing and found the answer using the coordinate mapping from here,

 #Map axis to coordinate system
def maptodatacoords(ax, dat_coord):
    tr1 = ax.transData.transform(dat_coord)
    #create an inverse transversion from display to figure coordinates:
    fig = ax.get_figure()
    inv = fig.transFigure.inverted()
    tr2 = inv.transform(tr1)
    #left, bottom, width, height are obtained like this:
    datco = [tr2[0,0], tr2[0,1], tr2[1,0]-tr2[0,0],tr2[1,1]-tr2[0,1]]

    return datco

#Plot a new axis with a colorbar inside
def crect(ax,x,y,w,h,c,**kwargs):

    xa, ya, wa, ha = maptodatacoords(ax, [(x,y),(x+w,y+h)])
    fig = ax.get_figure()
    axnew = fig.add_axes([xa, ya, wa, ha])
    cp = mpl.colorbar.ColorbarBase(axnew, cmap=plt.get_cmap("Reds"),
                                   orientation='vertical',                                
                                   ticks=[],
                                   **kwargs)
    cp.outline.set_linewidth(0.)
    plt.sca(ax)

Hopefully this helps anyone in the future who needs similar functionality. I ended up using a grid of patch objects instead.

like image 40
Ed Smith Avatar answered Sep 18 '22 15:09

Ed Smith