26

I would like to set the matplotlib colorbar range. Here's what I have so far:

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(20)
y = np.arange(20)
data = x[:-1,None]+y[None,:-1]

fig = plt.gcf()
ax = fig.add_subplot(111)

X,Y = np.meshgrid(x,y)
quadmesh = ax.pcolormesh(X,Y,data)
plt.colorbar(quadmesh)

#RuntimeError: You must first define an image, eg with imshow
#plt.clim(vmin=0,vmax=15)  

#AttributeError: 'AxesSubplot' object has no attribute 'clim'
#ax.clim(vmin=0,vmax=15) 

#AttributeError: 'AxesSubplot' object has no attribute 'set_clim'
#ax.set_clim(vmin=0,vmax=15) 

plt.show()

How do I set the colorbar limits here?

mgilson
  • 300,191
  • 65
  • 633
  • 696

3 Answers3

38

Arg. It's always the last thing you try:

quadmesh.set_clim(vmin=0, vmax=15)

works.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 8
    I would really like to gain a deeper understanding into how this API actually works. If anyone can explain to me why `ax.set_xlim` works but `ax.set_clim` doesn't work from an API standpoint, I'd love to hear (and I'm sure others can come up with much better answers than this -- So please explain more if you can!) – mgilson Mar 07 '13 at 21:36
  • 4
    I'm not sure if this answers your question, but if you look at `quadmesh.__class__.mro()` you'll see the quadmesh's class has the `ScalarMappable` mixin. If you look in `matplotlib/cm.py`, you'll see it is the `ScalarMappable` mixin which handles colormapping, and in particular, it provides the `set_clim` method. – unutbu Mar 07 '13 at 22:06
  • 4
    Each (ScalarMappable) artist controls its own color. The colorbar is attached to one ScalarMappable (by the `plt.colorbar(quadmesh)` call). So the artist's colormapping controls the colorbar's colormapping. It is not an Axes-wide colormapping. Thus, `ax` has not attribute `set_clim`. – unutbu Mar 07 '13 at 22:10
  • 3
    Also look at what `plt.clim` does which is to call `gci` (which gets the current 'image') and calls `set_clim` on the result. There is a `plt.sci()` function which lets you set the current image so `plt.clim` will work. I suspect this didn't get done because you made your `pcolor` call through the OO interface on the `pyplot` interface. – tacaswell Mar 08 '13 at 02:22
  • @unutbu -- Thanks for all your comments here. It's made my journey through the source (and documentation) a lot less random. I appreciate it. – mgilson Mar 08 '13 at 19:57
  • 1
    Thanks. I was looking for this solution. I learned that you can also just do `ax.pcolormesh(X, Y, data, vmin=0, vmax=15)`. – tommy.carstensen Jan 19 '16 at 10:47
  • Actually which module has this `quadmesh` attribute? – Krishnaap Dec 12 '19 at 13:43
  • It's the output of `ax.pcolormesh(X,Y,data)` (see the question) – mgilson Dec 19 '19 at 16:30
  • Actually, it will always the last thing you try, since you stop looking when you found the solution :-D – Taco de Wolff Jan 21 '22 at 20:18
4

Matplotlib 1.3.1 - It looks like the colorbar ticks are only drawn when the colorbar is instanced. Changing the colorbar limits (set_clim) does not cause the ticks to be re-drawn.

The solution I found was to re-instance the colorbar in the same axes entry as the original colorbar. In this case, axes[1] was the original colorbar. Added a new instance of the colorbar with this designated with the cax= (child axes) kwarg.

           # Reset the Z-axis limits
           print "resetting Z-axis plot limits", self.zmin, self.zmax
           self.cbar = self.fig.colorbar(CS1, cax=self.fig.axes[1]) # added
           self.cbar.set_clim(self.zmin, self.zmax)
           self.cbar.draw_all()
4

[Sorry, actually a comment to The Red Gator in Virginias answer, but do not have enough reputation to comment]

I was stuck on updating the colorbar of an imshow object after it was drawn and the data changed with imshowobj.set_data(). Using cbarobj.set_clim() indeed updates the colors, but not the ticks or range of the colorbar. Instead, you have to use imshowobj.set_clim() which will update the image and colorbar correctly.

data = np.cumsum(np.ones((10,15)),0)
imshowobj = plt.imshow(data)
cbarobj = plt.colorbar(imshowobj) #adjusts scale to value range, looks OK
# change the data to some data with different value range:
imshowobj.set_data(data/10) #scale is wrong now, shows only dark color
# update colorbar correctly using imshowobj not cbarobj:
#cbarobj.set_clim(0,1) #! image colors will update, but cbar ticks not
imshowobj.set_clim(0,1) #correct
ldoyle
  • 41
  • 5
  • @Idoyle Could you explain why you used `set_data` with division? – Cloud Cho Dec 17 '19 at 05:35
  • @CloudCho oh I hardly remember today... I suppose I wanted to demonstrate the effect of changing the scale afterwards: 1. set some initial data, 2. change the data (in this case 1/10 of the original values) -> result will look wrong/not use full scale, 3. update colorscale -> looks good again. Hope this helps – ldoyle Jan 03 '20 at 15:36