Skip to content

Commit

Permalink
FIX: fix colorbars with no scales
Browse files Browse the repository at this point in the history
  • Loading branch information
jklymak committed May 28, 2021
1 parent c56e3c5 commit 2177d8c
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 12 deletions.
37 changes: 25 additions & 12 deletions lib/matplotlib/colorbar.py
Expand Up @@ -996,6 +996,13 @@ def _inverse_boundaries(self, x):
b = self._boundaries
return np.interp(x, np.linspace(0, b[-1], len(b)), b)

def _forward_from_norm(self, x):
y = self.norm(x)
return y

def _inverse_from_norm(self, x):
return self.norm.inverse(x)

def _reset_locator_formatter_scale(self):
"""
Reset the locator et al to defaults. Any user-hardcoded changes
Expand All @@ -1006,24 +1013,30 @@ def _reset_locator_formatter_scale(self):
self.locator = None
self.minorlocator = None
self.formatter = None
if ((self.spacing == 'uniform') and
((self.boundaries is not None) or
isinstance(self.norm, colors.BoundaryNorm))):
funcs = (self._forward_boundaries, self._inverse_boundaries)
self.ax.set_xscale('function', functions=funcs)
self.ax.set_yscale('function', functions=funcs)
self.__scale = 'function'
if (self.boundaries is not None or
isinstance(self.norm, colors.BoundaryNorm)):
if self.spacing == 'uniform':
funcs = (self._forward_boundaries, self._inverse_boundaries)
self.ax.set_xscale('function', functions=funcs)
self.ax.set_yscale('function', functions=funcs)
self.__scale = 'function'
elif self.spacing == 'proportional':
self.__scale = 'linear'
self.ax.set_xscale('linear')
self.ax.set_yscale('linear')
elif hasattr(self.norm, '_scale') and (self.norm._scale is not None):
self.ax.set_xscale(self.norm._scale)
self.ax.set_yscale(self.norm._scale)
self.__scale = self.norm._scale.name
else:
elif type(self.norm) is colors.Normalize:
self.__scale = 'linear'
self.ax.set_xscale('linear')
self.ax.set_yscale('linear')
if type(self.norm) is colors.Normalize:
self.__scale = 'linear'
else:
self.__scale = 'manual'
else:
funcs = (self._forward_from_norm, self._inverse_from_norm)
self.ax.set_xscale('function', functions=funcs)
self.ax.set_yscale('function', functions=funcs)
self.__scale = 'function'

def _locate(self, x):
"""
Expand Down
10 changes: 10 additions & 0 deletions lib/matplotlib/colors.py
Expand Up @@ -1334,6 +1334,16 @@ def __call__(self, value, clip=None):
result = np.atleast_1d(result)[0]
return result

def inverse(self, value):
if not self.scaled():
raise ValueError("Not invertible until both vmin and vmax are set")
(vmin,), _ = self.process_value(self.vmin)
(vmax,), _ = self.process_value(self.vmax)
(vcenter,), _ = self.process_value(self.vcenter)

result = np.interp(value, [0, 0.5, 1.], [vmin, vcenter, vmax])
return result


class CenteredNorm(Normalize):
def __init__(self, vcenter=0, halfrange=None, clip=False):
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions lib/matplotlib/tests/test_colorbar.py
Expand Up @@ -771,3 +771,17 @@ def test_inset_colorbar_layout():
np.testing.assert_allclose(cb.ax.get_position().bounds,
[0.87, 0.342, 0.0237, 0.315], atol=0.01)
assert cb.ax.outer_ax in ax.child_axes


@image_comparison(['colorbar_twoslope.png'], remove_text=True,
style='mpl20')
def test_twoslope_colorbar():
# Note that the first tick = 20, and should be in the middle
# of the colorbar (white)
fig, ax = plt.subplots()

norm = mcolors.TwoSlopeNorm(20, 0, 100)
pc = ax.pcolormesh(np.arange(1, 11), np.arange(1, 11),
np.arange(100).reshape(10, 10),
norm=norm, cmap='RdBu_r')
fig.colorbar(pc)

0 comments on commit 2177d8c

Please sign in to comment.