Description
Bug report
Bug summary
When using a decreasing Norm, colorbars show no ticks.
Code for reproduction
This example uses a PowerNorm-like norm which first applies the power, then does linear rescaling to (0, 1) (as opposed to matplotlib's PowerNorm which first linearly rescales to (0, 1) then applies the power) -- as argued in #10234 the behavior here is often more desirable, though that's not the point of this bug report.
PNorms with a negative gamma are decreasing (the builtin PowerNorm wouldn't work here because the first linear rescaling step would put the minimum to zero, which doesn't like being raised to a negative power...).
from matplotlib import pyplot as plt
from matplotlib.colors import Normalize
import numpy as np
class PNorm(Normalize):
def __init__(self, vmin=None, vmax=None, clip=False, *, gamma):
super().__init__(vmin=vmin, vmax=vmax, clip=clip)
self.gamma = gamma
def __call__(self, value, clip=None):
if clip is None:
clip = self.clip
result, is_scalar = self.process_value(value)
self.autoscale_None(result)
vmin, vmax = self.vmin, self.vmax
gamma = self.gamma
if vmin > vmax:
raise ValueError("minvalue must be less than or equal to maxvalue")
elif vmin == vmax:
result.fill(0)
else:
if clip:
mask = np.ma.getmask(result)
result = np.ma.array(np.clip(result.filled(vmax), vmin, vmax),
mask=mask)
resdat = result.data
resdat = resdat ** gamma
resdat -= min(vmin ** gamma, vmax ** gamma)
resdat /= abs(vmax ** gamma - vmin ** gamma)
result = np.ma.array(resdat, mask=result.mask, copy=False)
if is_scalar:
result = result[0]
return result
def inverse(self, value):
if not self.scaled():
raise ValueError("Not invertible until scaled")
if np.iterable(value):
return np.vectorize(self.inverse)(value)
else:
vmin, vmax = self.vmin, self.vmax
gamma = self.gamma
return (value * abs(vmax ** gamma - vmin ** gamma)
+ min(vmin ** gamma, vmax ** gamma)) ** (1 / gamma)
fig, axs = plt.subplots(1, 2)
im = axs[0].imshow(np.arange(1., 101.).reshape((10, 10)), norm=PNorm(gamma=2))
fig.colorbar(im, ax=axs[0])
im = axs[1].imshow(np.arange(1., 101.).reshape((10, 10)), norm=PNorm(gamma=-2))
fig.colorbar(im, ax=axs[1])
plt.show()
(as a side note, creating new norms is a bit ridiculously verbose)
Actual outcome
left is gamma=2, right is gamma=-2.
Expected outcome
Some ticks on the right (gamma=-2) colorbar.
Matplotlib version
- Operating system: Arch Linux
- Matplotlib version: 3.0.1
- Matplotlib backend (
print(matplotlib.get_backend())
): any - Python version: 3.7