From 1dfdc298f244bfac85afbf3a697577c21eefda78 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 27 Nov 2018 15:31:05 -0800 Subject: [PATCH 1/5] FIX: brokenbarh math before units TST: Add test of broken_barh FIX: make bar work with timedeltas TST: check bar and barh work with timedelta DOC: fix private method docstring FIX: revert list comprehension TST: fix test FIX: throw error xr not tw-tuple --- lib/matplotlib/axes/_axes.py | 55 ++++++++++++++++++++++++------- lib/matplotlib/tests/test_axes.py | 35 ++++++++++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index fd724f55876c..473df00d2759 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2011,6 +2011,26 @@ def step(self, x, y, *args, where='pre', data=None, **kwargs): kwargs['drawstyle'] = 'steps-' + where return self.plot(x, y, *args, data=data, **kwargs) + @staticmethod + def _convert_dx(dx, x0, x, convert): + """ + Small helper to do logic of width conversion flexibly. + + *dx* and *x0* have units, but *x* has already been converted + to unitless. This allows the *dx* to have units that are + different from *x0*, but are still accepted by the ``__add__`` + operator of *x0*. + """ + try: + # attempt to add the width to x0; this works for + # datetime+timedelta, for instance + dx = convert(x0 + dx) - x + except (TypeError, AttributeError): + # but doesn't work for 'string' + float, so just + # see if the converter works on the float. + dx = convert(dx) + return dx + @_preprocess_data() @docstring.dedent_interpd def bar(self, x, height, width=0.8, bottom=None, *, align="center", @@ -2172,23 +2192,25 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", else: raise ValueError('invalid orientation: %s' % orientation) + x, height, width, y, linewidth = np.broadcast_arrays( + # Make args iterable too. + np.atleast_1d(x), height, width, y, linewidth) + # lets do some conversions now since some types cannot be # subtracted uniformly if self.xaxis is not None: + x0 = x x = self.convert_xunits(x) - width = self.convert_xunits(width) + width = self._convert_dx(width, x0, x, self.convert_xunits) if xerr is not None: - xerr = self.convert_xunits(xerr) + xerr = self._convert_dx(xerr, x0, x, self.convert_xunits) if self.yaxis is not None: + y0 = y y = self.convert_yunits(y) - height = self.convert_yunits(height) + height = self._convert_dx(height, y0, y, self.convert_yunits) if yerr is not None: - yerr = self.convert_yunits(yerr) - - x, height, width, y, linewidth = np.broadcast_arrays( - # Make args iterable too. - np.atleast_1d(x), height, width, y, linewidth) + yerr = self._convert_dx(yerr, y0, y, self.convert_yunits) # Now that units have been converted, set the tick locations. if orientation == 'vertical': @@ -2465,10 +2487,19 @@ def broken_barh(self, xranges, yrange, **kwargs): self._process_unit_info(xdata=xdata, ydata=ydata, kwargs=kwargs) - xranges = self.convert_xunits(xranges) - yrange = self.convert_yunits(yrange) - - col = mcoll.BrokenBarHCollection(xranges, yrange, **kwargs) + 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 = 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) self.add_collection(col, autolim=True) self.autoscale_view() diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 6e75ce726963..c8e2a00e0b15 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1498,6 +1498,32 @@ def test_barh_tick_label(): align='center') +def test_bar_timedelta(): + """smoketest that bar can handle width and height in delta units""" + fig, ax = plt.subplots() + ax.bar(datetime.datetime(2018, 1, 1), 1., + width=datetime.timedelta(hours=3)) + ax.bar(datetime.datetime(2018, 1, 1), 1., + xerr=datetime.timedelta(hours=2), + width=datetime.timedelta(hours=3)) + fig, ax = plt.subplots() + ax.barh(datetime.datetime(2018, 1, 1), 1, + height=datetime.timedelta(hours=3)) + ax.barh(datetime.datetime(2018, 1, 1), 1, + height=datetime.timedelta(hours=3), + yerr=datetime.timedelta(hours=2)) + fig, ax = plt.subplots() + ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)], + np.array([1, 1.5]), + height=datetime.timedelta(hours=3)) + ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)], + np.array([1, 1.5]), + height=[datetime.timedelta(hours=t) for t in [1, 2]]) + ax.broken_barh([(datetime.datetime(2018, 1, 1), + datetime.timedelta(hours=1))], + (10, 20)) + + @image_comparison(baseline_images=['hist_log'], remove_text=True) def test_hist_log(): @@ -5433,6 +5459,15 @@ def test_broken_barh_empty(): ax.broken_barh([], (.1, .5)) +def test_broken_barh_timedelta(): + """Check that timedelta works as x, dx pair for this method """ + fig, ax = plt.subplots() + pp = ax.broken_barh([(datetime.datetime(2018, 11, 9, 0, 0, 0), + datetime.timedelta(hours=1))], [1, 2]) + assert pp.get_paths()[0].vertices[0, 0] == 737007.0 + assert pp.get_paths()[0].vertices[2, 0] == 737007.0 + 1 / 24 + + def test_pandas_pcolormesh(pd): time = pd.date_range('2000-01-01', periods=10) depth = np.arange(20) From 7c4b000c423c9e136da52d75ebecdcd312156a8f Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 12 Jan 2019 14:12:50 -0800 Subject: [PATCH 2/5] FIX: make robust to units --- lib/matplotlib/axes/_axes.py | 60 +++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 473df00d2759..b87304ae569d 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2012,20 +2012,51 @@ def step(self, x, y, *args, where='pre', data=None, **kwargs): return self.plot(x, y, *args, data=data, **kwargs) @staticmethod - def _convert_dx(dx, x0, x, convert): + def _convert_dx(dx, x0, xconv, convert): """ Small helper to do logic of width conversion flexibly. - *dx* and *x0* have units, but *x* has already been converted - to unitless. This allows the *dx* to have units that are - different from *x0*, but are still accepted by the ``__add__`` - operator of *x0*. + *dx* and *x0* have units, but *xconv* has already been converted + to unitless (and is an ndarray). This allows the *dx* to have units + that are different from *x0*, but are still accepted by the + ``__add__`` operator of *x0*. """ + + # x should be an array... + assert type(xconv) is np.ndarray + + if xconv.size == 0: + # xconv has already been converted, but maybe empty... + return convert(dx) + try: # attempt to add the width to x0; this works for # datetime+timedelta, for instance - dx = convert(x0 + dx) - x - except (TypeError, AttributeError): + + # only use the first element of x and x0. This saves + # having to be sure addition works across the whole + # vector. This is particularly an issue if + # x0 and dx are lists so x0 + dx just concatenates the lists. + # We can't just cast x0 and dx to numpy arrays because that + # removes the units from unit packages like `pint`. + try: + x0 = x0[0] + except (TypeError, IndexError, KeyError): + x0 = x0 + + try: + x = xconv[0] + except (TypeError, IndexError, KeyError): + x = xconv + + delist = False + if not np.iterable(dx): + dx = [dx] + delist = True + dx = [convert(x0 + ddx) - x for ddx in dx] + if delist: + dx = dx[0] + except (TypeError, AttributeError) as e: # but doesn't work for 'string' + float, so just # see if the converter works on the float. dx = convert(dx) @@ -2192,26 +2223,27 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", else: raise ValueError('invalid orientation: %s' % orientation) - x, height, width, y, linewidth = np.broadcast_arrays( - # Make args iterable too. - np.atleast_1d(x), height, width, y, linewidth) # lets do some conversions now since some types cannot be # subtracted uniformly if self.xaxis is not None: x0 = x - x = self.convert_xunits(x) + x = np.asarray(self.convert_xunits(x)) width = self._convert_dx(width, x0, x, self.convert_xunits) if xerr is not None: xerr = self._convert_dx(xerr, x0, x, self.convert_xunits) - if self.yaxis is not None: y0 = y - y = self.convert_yunits(y) + y = np.asarray(self.convert_yunits(y)) height = self._convert_dx(height, y0, y, self.convert_yunits) if yerr is not None: yerr = self._convert_dx(yerr, y0, y, self.convert_yunits) + x, height, width, y, linewidth = np.broadcast_arrays( + # Make args iterable too. + np.atleast_1d(x), height, width, y, linewidth) + + # Now that units have been converted, set the tick locations. if orientation == 'vertical': tick_label_axis = self.xaxis @@ -2493,7 +2525,7 @@ def broken_barh(self, xranges, yrange, **kwargs): 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 = self.convert_xunits(xr[0]) + 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)) From aa6dfaa6c24b12463c34aa61873edcc3566b73d4 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 12 Jan 2019 14:25:55 -0800 Subject: [PATCH 3/5] FIX: make robust to units --- lib/matplotlib/axes/_axes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index b87304ae569d..9033e0b5f265 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2038,7 +2038,8 @@ def _convert_dx(dx, x0, xconv, convert): # vector. This is particularly an issue if # x0 and dx are lists so x0 + dx just concatenates the lists. # We can't just cast x0 and dx to numpy arrays because that - # removes the units from unit packages like `pint`. + # removes the units from unit packages like `pint` that + # wrap numpy arrays. try: x0 = x0[0] except (TypeError, IndexError, KeyError): From 6e410db5f7ba2036aef4cf62ac29189406b5abde Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 12 Jan 2019 14:32:42 -0800 Subject: [PATCH 4/5] FIX: make robust to units --- lib/matplotlib/axes/_axes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 9033e0b5f265..d4760b9d2eb1 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2224,7 +2224,6 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", else: raise ValueError('invalid orientation: %s' % orientation) - # lets do some conversions now since some types cannot be # subtracted uniformly if self.xaxis is not None: @@ -2244,7 +2243,6 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", # Make args iterable too. np.atleast_1d(x), height, width, y, linewidth) - # Now that units have been converted, set the tick locations. if orientation == 'vertical': tick_label_axis = self.xaxis From f9c43b7457148b9ae511f64554e692ac7655c540 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 12 Jan 2019 15:35:44 -0800 Subject: [PATCH 5/5] FIX: make robust to units --- lib/matplotlib/axes/_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index d4760b9d2eb1..a7164c13cbcb 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2048,7 +2048,7 @@ def _convert_dx(dx, x0, xconv, convert): try: x = xconv[0] except (TypeError, IndexError, KeyError): - x = xconv + x = xconv delist = False if not np.iterable(dx): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy