Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set limits on a matplotlib colorbar without changing the actual plot

I would like create a pseudocolor plot (e.g. contour or contourf) and a colorbar. For practical reason, I want the range of the colorbar different from the underlying mappable.

In the example below, the data Z has a range from 0 to 10000, which is mapped to a colormap. The range of the colorbar is the same.

import numpy
from matplotlib import pyplot

X = numpy.arange(100)
Y = numpy.arange(100)
Z = numpy.arange(100**2).reshape((100,100))

f = pyplot.figure()
ax = f.gca()
cf = ax.contourf(X,Y,Z,100)
cbar = f.colorbar(cf, ticks=[3000,4000,5000,6000])

pyplot.show()

plot

Now, I would like to "zoom in" on the colorbar, i.e. generate a colorbar with a range from 3000 to 6000 only. This new colorbar shall still serve as a legend and give proper colors for each tick (3000 = blue, 6000 = yellow). Neither cbar.set_clim() nor cf.set_clim() accomplish this.

like image 273
Jan Avatar asked Oct 05 '22 01:10

Jan


1 Answers

In general suppressing sections of your color bar is a Bad Idea, but here is a super hacky way to do it.

import numpy
from matplotlib import pyplot

X = numpy.arange(100)
Y = numpy.arange(100)
Z = numpy.arange(100**2).reshape((100,100))

f = pyplot.figure()
ax = f.gca()
cf = ax.contourf(X,Y,Z,100)
cbar = f.colorbar(cf, ticks=[3000,4000,5000,6000])
cbar.ax.set_ylim([cbar.norm(3000), cbar.norm(6000)])
cbar.outline.set_ydata([cbar.norm(3000)] * 2 + [cbar.norm(6000)] * 4 + [cbar.norm(3000)] * 3)
cbar.ax.set_aspect(60)  # <- tweak this to get the aspect ratio you want
pyplot.show()

I call this hacky because it touches a whole bunch of the internals of the colorbar. cbar.outline is a Line2D object that is the black box around the colorbar, the set_ydata sets the ydata on the corners to match the sub-region you want to look at. Try it with out that line and see what happens.

You might want to look into colormap's clip feature.

like image 98
tacaswell Avatar answered Oct 10 '22 13:10

tacaswell