I am trying to plot a colorbar that uses a limited number of colors (discrete). The problem is that the colors don't change where the major and minor ticks appear. The issue is worse with a log scale (which is what I need), but also happen with a linear scale!
One can readily note that the colors change either before or after the tick marks. I opened the image with Gimp, annotated the horizontal position for the center pixel of each tick mark, and they are at the correct position. Hence I'm sure the problem lies with the drawing of the colored rectangles.
Here is a zoom for both colorbars:
And this is the code to generate this image:
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
# fix the seed to reproduce the output exactly
np.random.seed(19680801)
# 2d normal distribution
data = np.random.normal(loc=0, scale=1., size=(2, 1000))
hist = np.histogram2d(data[0,:], data[1,:], range=[[-4, 4],[-3, 3]])
x = hist[1]
y = hist[2]
h = hist[0]/np.max(hist[0])
fig, ax = plt.subplots(1,2)
# plot with linear scale
ax[1].set_title('linear scale')
im1 = ax[1].pcolormesh(x, y, h, cmap=plt.get_cmap('jet',5))
cb1 = fig.colorbar(im1, ax=ax[1], orientation='horizontal')
cb1.ax.xaxis.set_major_locator (mticker.FixedLocator((0,1)))
cb1.ax.xaxis.set_minor_locator (mticker.FixedLocator((.2,.4,.6,.8)))
cb1.ax.xaxis.set_minor_formatter(mticker.FormatStrFormatter('%.1f'))
cb1.ax.tick_params(axis='x',which='major',length=7)
cb1.ax.tick_params(axis='x',which='minor',length=4,colors='red')
# plot with log scale
ax[0].set_title('log scale')
im0 = ax[0].pcolormesh(x, y, h, cmap=plt.get_cmap('jet', 6),
norm=matplotlib.colors.LogNorm(vmin=0.01,vmax=1))
cb0 = fig.colorbar(im0, ax=ax[0], orientation='horizontal')
cb0.ax.xaxis.set_major_locator (mticker.FixedLocator((.01,.1,1)))
cb0.ax.xaxis.set_minor_locator (mticker.FixedLocator((.02,.05,.2,.5)))
cb0.ax.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.2f'))
cb0.ax.xaxis.set_minor_formatter(mticker.FormatStrFormatter('%.2f'))
cb0.ax.tick_params(axis='x',which='major',length=7)
cb0.ax.tick_params(axis='x',which='minor',length=4,colors='red')
fig.savefig('teste.png',dpi=300)
Looking at some old threads here, I could notice that this problem was already there many years ago (see tick #5 in the first response here: Matplotlib discrete colorbar).
How can we do this?