Reputation: 483
I use (a version of) the following code to generate a heatmap with adjacent colorbar:
# imports
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from mpl_toolkits.axes_grid1 import make_axes_locatable
# create some dummy-data
matrix = np.array([[1, 2, 3],[2, 1, 3], [3, 1, 2]])
# scale the data
scaled = matrix / matrix.sum(axis=1).reshape(-1,1)
This is what scaled
looks like (scaling does not make a difference in this example, but it does in the intended use-case where the scaled data are used for a hierarchical linkage):
array([[ 0.16666667, 0.33333333, 0.5 ],
[ 0.33333333, 0.16666667, 0.5 ],
[ 0.5 , 0.16666667, 0.33333333]])
Now I create the plot (notice the use of LogNorm
):
_, ax_heatmap = plt.subplots()
heatmap = ax_heatmap.pcolor(
scaled, edgecolors='w',
cmap=mpl.cm.viridis_r,
norm=mpl.colors.LogNorm())
ax_heatmap.autoscale(tight=True)
ax_heatmap.set_aspect('equal')
divider_h = make_axes_locatable(ax_heatmap)
cax = divider_h.append_axes("right", "3%", pad="1%")
plt.colorbar(heatmap, cax=cax, ticks=np.unique(scaled))
cax.yaxis.set_major_formatter(
mpl.ticker.FuncFormatter(
lambda y, pos: ('{:.1f}'.format(y))))
plt.tight_layout()
plt.show()
The resulting figure is as intended, but the tick-labels on the color-bar do not correspond to the intended values, which should correspond to the values found in scaled
. I know that the function supplied to FuncFormatter
should be used to fix this, but it's unclear which combination of transformations it should invert (or if it's the use of LogNorm
that is inappropriate).
Upvotes: 2
Views: 598
Reputation: 483
Just found the solution. It appears that LogNorm
has an inverse method. By first initialising the LogNorm object with the correct vmin and vmax, its inverse can be supplied to FuncFormatter
_, ax_heatmap = plt.subplots()
norm = mpl.colors.LogNorm(vmin=scaled.min(), vmax=scaled.max())
heatmap = ax_heatmap.pcolor(
scaled, edgecolors='w',
cmap=mpl.cm.viridis_r,
norm=norm)
ax_heatmap.autoscale(tight=True)
ax_heatmap.set_aspect('equal')
divider_h = make_axes_locatable(ax_heatmap)
cax = divider_h.append_axes("right", "3%", pad="1%")
plt.colorbar(heatmap, cax=cax, ticks=np.unique(scaled))
cax.yaxis.set_major_formatter(
mpl.ticker.FuncFormatter(
lambda y, pos: ('{:.5f}'.format(norm.inverse(y)))))
plt.tight_layout()
plt.show()
Upvotes: 3