Description
Hi matplotlib developers,
I discovered that the tick values and tick locations on a colorbar can be incorrect when the colorbar extend
keyword is set to anything other than the default value of 'neither'
. The ticks are sometimes displayed when they should be out of range, and even so, they are located in the wrong places, often overlapping with other correctly-placed ticks. Here is a minimal working example:
from __future__ import print_function
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from matplotlib import cm
from numpy.random import rand
Z = rand(6, 10)*0.25
cmap = cm.jet
cmap.set_bad('k')
cmap.set_under('k')
cmap.set_over('w')
plt.subplot(221)
im0 = plt.pcolormesh(Z,cmap=cmap)
im0.set_clim(0.02,0.2)
cb0 = plt.colorbar(im0,extend='both')
print(cb0.ax.get_yticks())
print([i.get_text() for i in cb0.ax.get_yticklabels()])
plt.subplot(222)
im1 = plt.pcolormesh(Z,cmap=cmap)
im1.set_clim(0.02,0.2)
cb1 = plt.colorbar(im1,extend='neither')
print(cb1.ax.get_yticks())
print([i.get_text() for i in cb1.ax.get_yticklabels()])
plt.subplot(223)
im2 = plt.pcolormesh(Z,cmap=cmap,norm=LogNorm())
im2.set_clim(0.02,0.2)
cb2 = plt.colorbar(im2,extend='both')
print(cb2.ax.get_yticks())
print([i.get_text() for i in cb2.ax.get_yticklabels()])
plt.subplot(224)
im3 = plt.pcolormesh(Z,cmap=cmap,norm=LogNorm())
im3.set_clim(0.02,0.2)
cb3 = plt.colorbar(im3,extend='neither')
print(cb3.ax.get_yticks())
print([i.get_text() for i in cb3.ax.get_yticklabels()])
plt.show()
Tested with matplotlib 1.4.3, python 2.7, on Linux and Windows.
In the example above, the colorbars on the left subplots, created with extend='both'
, have extra ticks that are incorrect and are not present in the colorbars on the right created using extend='neither'
. The existence of incorrect ticks depends strongly on the chosen clim range and the chosen tick Locator. On a linear colorscale, in the example above, the tick Locator adds an extra tick value of 0.22 even though the maximum clim value is set to 0.2, and the extra tick overlaps with the valid tick at 0.2. On a log colorscale, in the example above, the tick Locator add two extra ticks with values of 1e-2 and 1e-3, even though the minimum clim value is set to 2e-2.
As a temporary workaround, I have been using this function to filter out the bad ticks and then set them manually:
import matplotlib.ticker as ticker
def bugfix_colorbar_extend_ticks(colorbar):
vmin,vmax = colorbar.get_clim()
if isinstance(colorbar.norm,LogNorm):
cticks = ticker.LogLocator().tick_values(vmin,vmax)
else:
cticks = ticker.MaxNLocator().tick_values(vmin,vmax)
cticks = cticks[cticks >= vmin]
cticks = cticks[cticks <= vmax]
return colorbar.set_ticks(cticks)
But this only fixes the symptom, not the underlying problem, which I believe has something to do with the way the colorbar axes view limits are handled at draw time.
I appreciate anyone's help in finding a more permanent fix to this bug.
Thanks.