Skip to content

Commit 1dfdc29

Browse files
committed
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
1 parent af8a720 commit 1dfdc29

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,26 @@ def step(self, x, y, *args, where='pre', data=None, **kwargs):
20112011
kwargs['drawstyle'] = 'steps-' + where
20122012
return self.plot(x, y, *args, data=data, **kwargs)
20132013

2014+
@staticmethod
2015+
def _convert_dx(dx, x0, x, convert):
2016+
"""
2017+
Small helper to do logic of width conversion flexibly.
2018+
2019+
*dx* and *x0* have units, but *x* has already been converted
2020+
to unitless. This allows the *dx* to have units that are
2021+
different from *x0*, but are still accepted by the ``__add__``
2022+
operator of *x0*.
2023+
"""
2024+
try:
2025+
# attempt to add the width to x0; this works for
2026+
# datetime+timedelta, for instance
2027+
dx = convert(x0 + dx) - x
2028+
except (TypeError, AttributeError):
2029+
# but doesn't work for 'string' + float, so just
2030+
# see if the converter works on the float.
2031+
dx = convert(dx)
2032+
return dx
2033+
20142034
@_preprocess_data()
20152035
@docstring.dedent_interpd
20162036
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",
21722192
else:
21732193
raise ValueError('invalid orientation: %s' % orientation)
21742194

2195+
x, height, width, y, linewidth = np.broadcast_arrays(
2196+
# Make args iterable too.
2197+
np.atleast_1d(x), height, width, y, linewidth)
2198+
21752199
# lets do some conversions now since some types cannot be
21762200
# subtracted uniformly
21772201
if self.xaxis is not None:
2202+
x0 = x
21782203
x = self.convert_xunits(x)
2179-
width = self.convert_xunits(width)
2204+
width = self._convert_dx(width, x0, x, self.convert_xunits)
21802205
if xerr is not None:
2181-
xerr = self.convert_xunits(xerr)
2206+
xerr = self._convert_dx(xerr, x0, x, self.convert_xunits)
21822207

21832208
if self.yaxis is not None:
2209+
y0 = y
21842210
y = self.convert_yunits(y)
2185-
height = self.convert_yunits(height)
2211+
height = self._convert_dx(height, y0, y, self.convert_yunits)
21862212
if yerr is not None:
2187-
yerr = self.convert_yunits(yerr)
2188-
2189-
x, height, width, y, linewidth = np.broadcast_arrays(
2190-
# Make args iterable too.
2191-
np.atleast_1d(x), height, width, y, linewidth)
2213+
yerr = self._convert_dx(yerr, y0, y, self.convert_yunits)
21922214

21932215
# Now that units have been converted, set the tick locations.
21942216
if orientation == 'vertical':
@@ -2465,10 +2487,19 @@ def broken_barh(self, xranges, yrange, **kwargs):
24652487
self._process_unit_info(xdata=xdata,
24662488
ydata=ydata,
24672489
kwargs=kwargs)
2468-
xranges = self.convert_xunits(xranges)
2469-
yrange = self.convert_yunits(yrange)
2470-
2471-
col = mcoll.BrokenBarHCollection(xranges, yrange, **kwargs)
2490+
xranges_conv = []
2491+
for xr in xranges:
2492+
if len(xr) != 2:
2493+
raise ValueError('each range in xrange must be a sequence '
2494+
'with two elements (i.e. an Nx2 array)')
2495+
# convert the absolute values, not the x and dx...
2496+
x_conv = self.convert_xunits(xr[0])
2497+
x1 = self._convert_dx(xr[1], xr[0], x_conv, self.convert_xunits)
2498+
xranges_conv.append((x_conv, x1))
2499+
2500+
yrange_conv = self.convert_yunits(yrange)
2501+
2502+
col = mcoll.BrokenBarHCollection(xranges_conv, yrange_conv, **kwargs)
24722503
self.add_collection(col, autolim=True)
24732504
self.autoscale_view()
24742505

lib/matplotlib/tests/test_axes.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,32 @@ def test_barh_tick_label():
14981498
align='center')
14991499

15001500

1501+
def test_bar_timedelta():
1502+
"""smoketest that bar can handle width and height in delta units"""
1503+
fig, ax = plt.subplots()
1504+
ax.bar(datetime.datetime(2018, 1, 1), 1.,
1505+
width=datetime.timedelta(hours=3))
1506+
ax.bar(datetime.datetime(2018, 1, 1), 1.,
1507+
xerr=datetime.timedelta(hours=2),
1508+
width=datetime.timedelta(hours=3))
1509+
fig, ax = plt.subplots()
1510+
ax.barh(datetime.datetime(2018, 1, 1), 1,
1511+
height=datetime.timedelta(hours=3))
1512+
ax.barh(datetime.datetime(2018, 1, 1), 1,
1513+
height=datetime.timedelta(hours=3),
1514+
yerr=datetime.timedelta(hours=2))
1515+
fig, ax = plt.subplots()
1516+
ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)],
1517+
np.array([1, 1.5]),
1518+
height=datetime.timedelta(hours=3))
1519+
ax.barh([datetime.datetime(2018, 1, 1), datetime.datetime(2018, 1, 1)],
1520+
np.array([1, 1.5]),
1521+
height=[datetime.timedelta(hours=t) for t in [1, 2]])
1522+
ax.broken_barh([(datetime.datetime(2018, 1, 1),
1523+
datetime.timedelta(hours=1))],
1524+
(10, 20))
1525+
1526+
15011527
@image_comparison(baseline_images=['hist_log'],
15021528
remove_text=True)
15031529
def test_hist_log():
@@ -5433,6 +5459,15 @@ def test_broken_barh_empty():
54335459
ax.broken_barh([], (.1, .5))
54345460

54355461

5462+
def test_broken_barh_timedelta():
5463+
"""Check that timedelta works as x, dx pair for this method """
5464+
fig, ax = plt.subplots()
5465+
pp = ax.broken_barh([(datetime.datetime(2018, 11, 9, 0, 0, 0),
5466+
datetime.timedelta(hours=1))], [1, 2])
5467+
assert pp.get_paths()[0].vertices[0, 0] == 737007.0
5468+
assert pp.get_paths()[0].vertices[2, 0] == 737007.0 + 1 / 24
5469+
5470+
54365471
def test_pandas_pcolormesh(pd):
54375472
time = pd.date_range('2000-01-01', periods=10)
54385473
depth = np.arange(20)

0 commit comments

Comments
 (0)
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