From 1403a30876acb3ab2e2662961cbf2343637c69d4 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 30 Dec 2022 00:55:31 +0100 Subject: [PATCH] Deprecate BrokenBarHCollection. It doesn't warrant a separate class; also, directly doing the unit conversion in broken_barh is actually easier (one doesn't need to go through _convert_dx, instead we directly move to using xmin/xmax). --- .../deprecations/24864-AL.rst | 10 ++++ .../lines_bars_and_markers/span_regions.py | 30 ++++-------- lib/matplotlib/axes/_axes.py | 48 ++++++++----------- lib/matplotlib/collections.py | 36 +++++++------- 4 files changed, 57 insertions(+), 67 deletions(-) create mode 100644 doc/api/next_api_changes/deprecations/24864-AL.rst diff --git a/doc/api/next_api_changes/deprecations/24864-AL.rst b/doc/api/next_api_changes/deprecations/24864-AL.rst new file mode 100644 index 000000000000..bdeba7a85e65 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/24864-AL.rst @@ -0,0 +1,10 @@ +``BrokenBarHCollection`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It was just a thin wrapper inheriting from `.PolyCollection`; +`~.Axes.broken_barh` has now been changed to return a `.PolyCollection` +instead. + +The ``BrokenBarHCollection.span_where`` helper is likewise deprecated; for the +duration of the deprecation it has been moved to the parent `.PolyCollection` +class. Use `~.Axes.fill_between` as a replacement; see +:doc:`/gallery/lines_bars_and_markers/span_regions` for an example. diff --git a/examples/lines_bars_and_markers/span_regions.py b/examples/lines_bars_and_markers/span_regions.py index 9a5e8e3428d1..f5d1cce9cf9b 100644 --- a/examples/lines_bars_and_markers/span_regions.py +++ b/examples/lines_bars_and_markers/span_regions.py @@ -1,34 +1,23 @@ """ -======================================================================== -Shade regions defined by a logical mask using fill_between or span_where -======================================================================== - -Shade regions where a logical mask is True with `.Axes.fill_between` or with -`matplotlib.collections.BrokenBarHCollection.span_where`. +========================================================== +Shade regions defined by a logical mask using fill_between +========================================================== """ import numpy as np import matplotlib.pyplot as plt -import matplotlib.collections as collections t = np.arange(0.0, 2, 0.01) s = np.sin(2*np.pi*t) -fig, axs = plt.subplots(2, sharex=True, sharey=True) -for ax in axs: - ax.plot(t, s, color='black') - ax.axhline(0, color='black') +fig, ax = plt.subplots() -axs[0].set_title('using fill_between') -axs[0].fill_between(t, 1, where=s > 0, facecolor='green', alpha=.5) -axs[0].fill_between(t, -1, where=s < 0, facecolor='red', alpha=.5) +ax.plot(t, s, color='black') +ax.axhline(0, color='black') -axs[1].set_title('using span_where') -axs[1].add_collection(collections.BrokenBarHCollection.span_where( - t, ymin=0, ymax=1, where=s > 0, facecolor='green', alpha=0.5)) -axs[1].add_collection(collections.BrokenBarHCollection.span_where( - t, ymin=-1, ymax=0, where=s < 0, facecolor='red', alpha=0.5)) +ax.fill_between(t, 1, where=s > 0, facecolor='green', alpha=.5) +ax.fill_between(t, -1, where=s < 0, facecolor='red', alpha=.5) plt.show() @@ -41,6 +30,3 @@ # in this example: # # - `matplotlib.axes.Axes.fill_between` -# - `matplotlib.collections.BrokenBarHCollection` -# - `matplotlib.collections.BrokenBarHCollection.span_where` -# - `matplotlib.axes.Axes.add_collection` diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 58d95912665b..87800951f90d 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2826,10 +2826,6 @@ def broken_barh(self, xranges, yrange, **kwargs): A rectangle is drawn for each element of *xranges*. All rectangles have the same vertical position and size defined by *yrange*. - This is a convenience function for instantiating a - `.BrokenBarHCollection`, adding it to the Axes and autoscaling the - view. - Parameters ---------- xranges : sequence of tuples (*xmin*, *xwidth*) @@ -2841,13 +2837,13 @@ def broken_barh(self, xranges, yrange, **kwargs): Returns ------- - `~.collections.BrokenBarHCollection` + `~.collections.PolyCollection` Other Parameters ---------------- data : indexable object, optional DATA_PARAMETER_PLACEHOLDER - **kwargs : `.BrokenBarHCollection` properties + **kwargs : `.PolyCollection` properties Each *kwarg* can be either a single argument applying to all rectangles, e.g.:: @@ -2862,32 +2858,28 @@ def broken_barh(self, xranges, yrange, **kwargs): Supported keywords: - %(BrokenBarHCollection:kwdoc)s + %(PolyCollection:kwdoc)s """ # process the unit information - if len(xranges): - xdata = cbook._safe_first_finite(xranges) - else: - xdata = None - if len(yrange): - ydata = cbook._safe_first_finite(yrange) - else: - ydata = None + xdata = cbook._safe_first_finite(xranges) if len(xranges) else None + ydata = cbook._safe_first_finite(yrange) if len(yrange) else None self._process_unit_info( [("x", xdata), ("y", ydata)], kwargs, convert=False) - xranges_conv = [] - for xr in xranges: - if len(xr) != 2: - raise ValueError('each range in xrange must be a sequence ' - 'with two elements (i.e. an Nx2 array)') - # convert the absolute values, not the x and dx... - x_conv = np.asarray(self.convert_xunits(xr[0])) - x1 = self._convert_dx(xr[1], xr[0], x_conv, self.convert_xunits) - xranges_conv.append((x_conv, x1)) - - yrange_conv = self.convert_yunits(yrange) - - col = mcoll.BrokenBarHCollection(xranges_conv, yrange_conv, **kwargs) + + vertices = [] + y0, dy = yrange + y0, y1 = self.convert_yunits((y0, y0 + dy)) + for xr in xranges: # convert the absolute values, not the x and dx + try: + x0, dx = xr + except Exception: + raise ValueError( + "each range in xrange must be a sequence with two " + "elements (i.e. xrange must be an (N, 2) array)") from None + x0, x1 = self.convert_xunits((x0, x0 + dx)) + vertices.append([(x0, y0), (x0, y1), (x1, y1), (x1, y0)]) + + col = mcoll.PolyCollection(np.array(vertices), **kwargs) self.add_collection(col, autolim=True) self._request_autoscale_view() diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 0694f4293c6d..bf88dd2b68a3 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1225,7 +1225,26 @@ def set_verts_and_codes(self, verts, codes): for xy, cds in zip(verts, codes)] self.stale = True + @classmethod + @_api.deprecated("3.7", alternative="fill_between") + def span_where(cls, x, ymin, ymax, where, **kwargs): + """ + Return a `.BrokenBarHCollection` that plots horizontal bars from + over the regions in *x* where *where* is True. The bars range + on the y-axis from *ymin* to *ymax* + + *kwargs* are passed on to the collection. + """ + xranges = [] + for ind0, ind1 in cbook.contiguous_regions(where): + xslice = x[ind0:ind1] + if not len(xslice): + continue + xranges.append((xslice[0], xslice[-1] - xslice[0])) + return BrokenBarHCollection(xranges, [ymin, ymax - ymin], **kwargs) + +@_api.deprecated("3.7") class BrokenBarHCollection(PolyCollection): """ A collection of horizontal bars spanning *yrange* with a sequence of @@ -1251,23 +1270,6 @@ def __init__(self, xranges, yrange, **kwargs): (xmin, ymin)] for xmin, xwidth in xranges] super().__init__(verts, **kwargs) - @classmethod - def span_where(cls, x, ymin, ymax, where, **kwargs): - """ - Return a `.BrokenBarHCollection` that plots horizontal bars from - over the regions in *x* where *where* is True. The bars range - on the y-axis from *ymin* to *ymax* - - *kwargs* are passed on to the collection. - """ - xranges = [] - for ind0, ind1 in cbook.contiguous_regions(where): - xslice = x[ind0:ind1] - if not len(xslice): - continue - xranges.append((xslice[0], xslice[-1] - xslice[0])) - return cls(xranges, [ymin, ymax - ymin], **kwargs) - class RegularPolyCollection(_CollectionWithSizes): """A collection of n-sided regular polygons."""