Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implementing ticklabels keyword in plt.colorbar() #18884

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
44 changes: 35 additions & 9 deletions lib/matplotlib/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ def __init__(self, ax, cmap=None,
extend=None,
spacing='uniform', # uniform or proportional
ticks=None,
ticklabels=None,
format=None,
drawedges=False,
filled=True,
Expand Down Expand Up @@ -463,6 +464,8 @@ def __init__(self, ax, cmap=None,
'min': slice(1, None), 'max': slice(0, -1)},
extend=extend)
self.spacing = spacing
self._ticks = ticks
self._ticklabels = ticklabels
self.orientation = orientation
self.drawedges = drawedges
self.filled = filled
Expand Down Expand Up @@ -543,6 +546,8 @@ def draw_all(self):
self.outline.set_xy(xy)
self.patch.set_xy(xy)
self.update_ticks()
if self._ticklabels:
self.set_ticklabels(self._ticklabels)
if self.filled:
self._add_solids(X, Y, self._values[:, np.newaxis])

Expand Down Expand Up @@ -688,14 +693,19 @@ def set_ticks(self, ticks, update_ticks=True):
user has to call `update_ticks` later to update the ticks.

"""
if np.iterable(ticks):
self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
if np.iterable(ticks) or isinstance(ticks, ticker.Locator):
self._ticks = ticks # self._ticks always holds a valid value
if np.iterable(ticks):
self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
else:
self.locator = ticks
if update_ticks:
self.update_ticks()
self._ticks = self.get_ticks()
self.stale = True
else:
self.locator = ticks

if update_ticks:
self.update_ticks()
self.stale = True
cbook._warn_external('The ticks need to be an array of values '
'or an instance of ticker.Locator')

def get_ticks(self, minor=False):
"""Return the x ticks as a list of locations."""
Expand All @@ -716,12 +726,28 @@ def set_ticklabels(self, ticklabels, update_ticks=True):
Tick labels are updated immediately unless *update_ticks* is *False*,
in which case one should call `.update_ticks` explicitly.
"""
if isinstance(self.locator, ticker.FixedLocator):
# check if explitic ticks have been supplied
if self._ticks is None:
cbook._warn_external('To set explicit ticklabels, call colorbar() '
'with ticks keyword or use set_ticks() '
'method first.')
# check if length of ticks and ticklabels match
elif len(self._ticks) != len(self._ticklabels):
cbook._warn_external('The ticklabels need to be of the same '
'length as the ticks.')
# check if objects in list have valid type
elif not all(type(item) in [str, float, int] for item in ticklabels):
cbook._warn_external('ticklabels need to be a list of str')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to check these warnings and the next one if you have time for that....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, w/o reading the discussion, do we need all these warning checks? I don't think we usually check for mismatched type, for instance...

# this check was in the code previously, not sure if needed
elif isinstance(self.locator, ticker.FixedLocator):
self.formatter = ticker.FixedFormatter(ticklabels)
if update_ticks:
self.update_ticks()
else:
cbook._warn_external("set_ticks() must have been called.")
cbook._warn_external('To set ticklabels, ticks of the same '
'length need to be set explicitly first. '
'This can be done through '
'plt.colorbar(ticks) or set_ticks().')
self.stale = True

def minorticks_on(self):
Expand Down
33 changes: 33 additions & 0 deletions lib/matplotlib/tests/test_colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,3 +705,36 @@ def test_anchored_cbar_position_using_specgrid():
np.testing.assert_allclose(
[cx1, cx0],
[x1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + x0 * shrink])


def test_colorbar_ticklabels_2():
fig = plt.figure()
plt.imshow(np.arange(100).reshape((10, 10)))
ticklabels = ['cat', 'dog']
cbar = plt.colorbar(ticks=[10, 90], ticklabels=ticklabels)
fig.canvas.draw()
for i, item in enumerate(cbar.ax.yaxis.get_ticklabels()):
assert ticklabels[i] == item.get_text()


def test_colorbar_ticklabels_3():
fig = plt.figure()
plt.imshow(np.arange(100).reshape((10, 10)))
ticklabels = ['cat', 'dog', 'elephant']
with pytest.warns(
UserWarning, match='The ticklabels need to be of the same '
'length as the ticks.'):
plt.colorbar(ticks=[10, 90], ticklabels=ticklabels)
fig.canvas.draw()


def test_colorbar_ticklabels_no_ticks():
fig = plt.figure()
plt.imshow(np.arange(100).reshape((10, 10)))
ticklabels = ['cat', 'dog', 'dog']
with pytest.warns(
UserWarning, match='To set explicit ticklabels, call colorbar'
'\\(\\) with ticks keyword or use set_ticks\\(\\) '
'method first.'):
plt.colorbar(ticks=None, ticklabels=ticklabels)
fig.canvas.draw()
51 changes: 27 additions & 24 deletions lib/mpl_toolkits/axes_grid1/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,33 @@

colormap_kw_doc = '''

=========== ====================================================
Property Description
=========== ====================================================
*extend* [ 'neither' | 'both' | 'min' | 'max' ]
If not 'neither', make pointed end(s) for out-of-
range values. These are set for a given colormap
using the colormap set_under and set_over methods.
*spacing* [ 'uniform' | 'proportional' ]
Uniform spacing gives each discrete color the same
space; proportional makes the space proportional to
the data interval.
*ticks* [ None | list of ticks | Locator object ]
If None, ticks are determined automatically from the
input.
*format* [ None | format string | Formatter object ]
If None, the
:class:`~matplotlib.ticker.ScalarFormatter` is used.
If a format string is given, e.g., '%.3f', that is
used. An alternative
:class:`~matplotlib.ticker.Formatter` object may be
given instead.
*drawedges* bool
Whether to draw lines at color boundaries.
=========== ====================================================
============ ====================================================
Property Description
============ ====================================================
*extend* [ 'neither' | 'both' | 'min' | 'max' ]
If not 'neither', make pointed end(s) for out-of-
range values. These are set for a given colormap
using the colormap set_under and set_over methods.
*spacing* [ 'uniform' | 'proportional' ]
Uniform spacing gives each discrete color the same
space; proportional makes the space proportional to
the data interval.
*ticks* [ None | list of ticks | Locator object ]
If None, ticks are determined automatically from the
input.
*ticklabels* sequence of str
List of texts for tick labels; must include values
for non-visible labels.
*format* [ None | format string | Formatter object ]
If None, the
:class:`~matplotlib.ticker.ScalarFormatter` is used.
If a format string is given, e.g., '%.3f', that is
used. An alternative
:class:`~matplotlib.ticker.Formatter` object may be
given instead.
*drawedges* bool
Whether to draw lines at color boundaries.
============ ====================================================

The following will probably be useful only in the context of
indexed colors (that is, when the mappable has norm=NoNorm()),
Expand Down