From 6936d2ea8b23ed9636d95459694c90559cacc60e Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 3 Nov 2020 20:43:23 +0100 Subject: [PATCH 01/13] Implementing ticklabels keyword in plt.colorbar() --- lib/matplotlib/colorbar.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index c23aa5cf4fd5..ad50cd59339b 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -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, @@ -463,6 +464,7 @@ def __init__(self, ax, cmap=None, 'min': slice(1, None), 'max': slice(0, -1)}, extend=extend) self.spacing = spacing + self.ticklabels = ticklabels self.orientation = orientation self.drawedges = drawedges self.filled = filled @@ -543,6 +545,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]) From 553e26a187b99fff848d275596f19da944f7299f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 4 Nov 2020 04:55:58 +0100 Subject: [PATCH 02/13] Adding testing routing for ticklabels in plt.colorbar() --- lib/matplotlib/tests/test_colorbar.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index bbd1e9c5f590..70b35a9cf057 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -705,3 +705,13 @@ 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(): + 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() From 2d65c33a83a659423bb77b631bae3551243d5bc1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 4 Nov 2020 04:56:27 +0100 Subject: [PATCH 03/13] Adding keyword documentation of ticklabels in plt.colorbar() --- lib/mpl_toolkits/axes_grid1/colorbar.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mpl_toolkits/axes_grid1/colorbar.py b/lib/mpl_toolkits/axes_grid1/colorbar.py index 77af5a1ab7fc..75c84e4713f3 100644 --- a/lib/mpl_toolkits/axes_grid1/colorbar.py +++ b/lib/mpl_toolkits/axes_grid1/colorbar.py @@ -69,6 +69,9 @@ *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. From 60e2b3463b57dd9469c1cbcac611cfb8d4957d9b Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 7 Nov 2020 01:16:24 +0100 Subject: [PATCH 04/13] Make colorbar._ticklabels a private variable --- lib/matplotlib/colorbar.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index ad50cd59339b..b2312b73f2a7 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -464,7 +464,7 @@ def __init__(self, ax, cmap=None, 'min': slice(1, None), 'max': slice(0, -1)}, extend=extend) self.spacing = spacing - self.ticklabels = ticklabels + self._ticklabels = ticklabels self.orientation = orientation self.drawedges = drawedges self.filled = filled @@ -545,8 +545,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._ticklabels: + self.set_ticklabels(self._ticklabels) if self.filled: self._add_solids(X, Y, self._values[:, np.newaxis]) @@ -725,7 +725,9 @@ def set_ticklabels(self, ticklabels, update_ticks=True): if update_ticks: self.update_ticks() else: - cbook._warn_external("set_ticks() must have been called.") + cbook._warn_external('To set ticklabels, ticks with 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): From 245936a77e47855af3066c89c8b2b6b4a38f8d8b Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 10 Nov 2020 14:20:40 +0100 Subject: [PATCH 05/13] implement clear warnings for wrong ticks or ticklabels --- lib/matplotlib/colorbar.py | 46 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index b2312b73f2a7..ef54d613a126 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -464,6 +464,7 @@ def __init__(self, ax, cmap=None, 'min': slice(1, None), 'max': slice(0, -1)}, extend=extend) self.spacing = spacing + self._ticks = None self._ticklabels = ticklabels self.orientation = orientation self.drawedges = drawedges @@ -501,10 +502,8 @@ def __init__(self, ax, cmap=None, self.set_label(label) self._reset_locator_formatter_scale() - if np.iterable(ticks): - self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) - else: - self.locator = ticks # Handle default in _ticker() + if ticks: + self.set_ticks(ticks) if isinstance(format, str): self.formatter = ticker.FormatStrFormatter(format) @@ -692,14 +691,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.""" @@ -720,14 +724,26 @@ 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') + # 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('To set ticklabels, ticks with the same \ - length need to be set explicitly first. This can be done \ - through plt.colorbar(ticks) or set_ticks().') + 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): From 0ab998fa3330eb0a1f9d4099bb1a8f27d1415632 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 10 Nov 2020 14:41:52 +0100 Subject: [PATCH 06/13] fix indent for flake8 --- lib/matplotlib/colorbar.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index ef54d613a126..6944f6721aa5 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -703,7 +703,7 @@ def set_ticks(self, ticks, update_ticks=True): self.stale = True else: cbook._warn_external('The ticks need to be an array of values ' - 'or an instance of ticker.Locator') + 'or an instance of ticker.Locator') def get_ticks(self, minor=False): """Return the x ticks as a list of locations.""" @@ -726,12 +726,13 @@ def set_ticklabels(self, ticklabels, update_ticks=True): """ # 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.') + 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.') + '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') @@ -742,8 +743,9 @@ def set_ticklabels(self, ticklabels, update_ticks=True): self.update_ticks() else: 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().') + '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): From f09711a83904ce45540dfd8c06d14ccec98b45ff Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 10 Nov 2020 14:46:59 +0100 Subject: [PATCH 07/13] fix line length --- lib/matplotlib/colorbar.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 6944f6721aa5..cf2666182e8e 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -727,8 +727,8 @@ def set_ticklabels(self, ticklabels, update_ticks=True): # 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.') + '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 ' @@ -744,8 +744,8 @@ def set_ticklabels(self, ticklabels, update_ticks=True): else: 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().') + 'This can be done through ' + 'plt.colorbar(ticks) or set_ticks().') self.stale = True def minorticks_on(self): From b00d5de061f6d75be8f2f025c358af9201c2eb76 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 13 Nov 2020 04:20:16 +0100 Subject: [PATCH 08/13] fix failing tests --- lib/matplotlib/colorbar.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index cf2666182e8e..d740efe55f17 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -464,7 +464,7 @@ def __init__(self, ax, cmap=None, 'min': slice(1, None), 'max': slice(0, -1)}, extend=extend) self.spacing = spacing - self._ticks = None + self._ticks = ticks self._ticklabels = ticklabels self.orientation = orientation self.drawedges = drawedges @@ -501,9 +501,11 @@ def __init__(self, ax, cmap=None, self.set_label(label) self._reset_locator_formatter_scale() - - if ticks: - self.set_ticks(ticks) + + if np.iterable(ticks): + self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) + else: + self.locator = ticks # Handle default in _ticker() if isinstance(format, str): self.formatter = ticker.FormatStrFormatter(format) From 58ebc94d53a7a9ddcdb70d070cb36c8fda303be9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 13 Nov 2020 04:38:20 +0100 Subject: [PATCH 09/13] implement more test cases --- lib/matplotlib/tests/test_colorbar.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index 70b35a9cf057..8817162cd6b0 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -707,7 +707,7 @@ def test_anchored_cbar_position_using_specgrid(): [x1 * shrink + (1 - shrink) * p0, p0 * (1 - shrink) + x0 * shrink]) -def test_colorbar_ticklabels(): +def test_colorbar_ticklabels_2(): fig = plt.figure() plt.imshow(np.arange(100).reshape((10, 10))) ticklabels = ['cat', 'dog'] @@ -715,3 +715,26 @@ def test_colorbar_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() From 7e6de1869e1ec98d00c18e8ffe765a0c4026c77e Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 13 Nov 2020 04:47:12 +0100 Subject: [PATCH 10/13] whitespace fix --- lib/matplotlib/colorbar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index d740efe55f17..0bdb8ce5a854 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -501,7 +501,7 @@ def __init__(self, ax, cmap=None, self.set_label(label) self._reset_locator_formatter_scale() - + if np.iterable(ticks): self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: From 6d58867e1f527f587f24928575449e61169a3c22 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 14 Nov 2020 04:31:00 +0100 Subject: [PATCH 11/13] Fix regex expression with proper escape characters --- lib/matplotlib/tests/test_colorbar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index 8817162cd6b0..e90bba7099c8 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -733,8 +733,8 @@ def test_colorbar_ticklabels_no_ticks(): 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() ' + 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() From f993a3e8841718d5ba0138d32622215010348ef9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 14 Nov 2020 04:42:34 +0100 Subject: [PATCH 12/13] line length --- lib/matplotlib/tests/test_colorbar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index e90bba7099c8..f5a3d0fb4ec7 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -733,8 +733,8 @@ def test_colorbar_ticklabels_no_ticks(): 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\\(\\) ' + 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() From 239f5ac0ff7ef7b248a75e6b69743e653af0ab3e Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 25 Nov 2020 15:25:51 +0100 Subject: [PATCH 13/13] fix table margin in docstring --- lib/mpl_toolkits/axes_grid1/colorbar.py | 54 ++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/mpl_toolkits/axes_grid1/colorbar.py b/lib/mpl_toolkits/axes_grid1/colorbar.py index 75c84e4713f3..182dcaf9a6d1 100644 --- a/lib/mpl_toolkits/axes_grid1/colorbar.py +++ b/lib/mpl_toolkits/axes_grid1/colorbar.py @@ -55,33 +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. - *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. - =========== ==================================================== + ============ ==================================================== + 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()),