Skip to content

Commit 78b1bfe

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
1 parent af8a720 commit 78b1bfe

File tree

2 files changed

+63
-10
lines changed

2 files changed

+63
-10
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,19 @@ 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(x0, x, dx, convert):
2016+
""" Small helper to do logic of width conversion flexibly """
2017+
try:
2018+
# attempt to add the width to x0; this works for
2019+
# datetime+timedelta, for instance
2020+
dx = convert(x0 + dx) - x
2021+
except (TypeError, AttributeError):
2022+
# but doesn't work for 'string' + float, so just
2023+
# see if the converter works on the float.
2024+
dx = convert(dx)
2025+
return dx
2026+
20142027
@_preprocess_data()
20152028
@docstring.dedent_interpd
20162029
def bar(self, x, height, width=0.8, bottom=None, *, align="center",
@@ -2172,23 +2185,25 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
21722185
else:
21732186
raise ValueError('invalid orientation: %s' % orientation)
21742187

2188+
x, height, width, y, linewidth = np.broadcast_arrays(
2189+
# Make args iterable too.
2190+
np.atleast_1d(x), height, width, y, linewidth)
2191+
21752192
# lets do some conversions now since some types cannot be
21762193
# subtracted uniformly
21772194
if self.xaxis is not None:
2195+
x0 = x
21782196
x = self.convert_xunits(x)
2179-
width = self.convert_xunits(width)
2197+
width = self._convert_dx(x0, x, width, self.convert_xunits)
21802198
if xerr is not None:
2181-
xerr = self.convert_xunits(xerr)
2199+
xerr = self._convert_dx(x0, x, xerr, self.convert_xunits)
21822200

21832201
if self.yaxis is not None:
2202+
y0 = y
21842203
y = self.convert_yunits(y)
2185-
height = self.convert_yunits(height)
2204+
height = self._convert_dx(y0, y, height, self.convert_yunits)
21862205
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)
2206+
yerr = self._convert_dx(y0, y, yerr, self.convert_yunits)
21922207

21932208
# Now that units have been converted, set the tick locations.
21942209
if orientation == 'vertical':
@@ -2465,10 +2480,16 @@ def broken_barh(self, xranges, yrange, **kwargs):
24652480
self._process_unit_info(xdata=xdata,
24662481
ydata=ydata,
24672482
kwargs=kwargs)
2468-
xranges = self.convert_xunits(xranges)
2483+
xnew = []
2484+
for xr in xranges:
2485+
# convert the absolute values, not the x and dx...
2486+
x0 = self.convert_xunits(xr[0])
2487+
x1 = self._convert_dx(xr[0], x0, xr[1], self.convert_xunits)
2488+
xnew.append((x0, x1))
2489+
24692490
yrange = self.convert_yunits(yrange)
24702491

2471-
col = mcoll.BrokenBarHCollection(xranges, yrange, **kwargs)
2492+
col = mcoll.BrokenBarHCollection(xnew, yrange, **kwargs)
24722493
self.add_collection(col, autolim=True)
24732494
self.autoscale_view()
24742495

lib/matplotlib/tests/test_axes.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,29 @@ 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+
1523+
15011524
@image_comparison(baseline_images=['hist_log'],
15021525
remove_text=True)
15031526
def test_hist_log():
@@ -5433,6 +5456,15 @@ def test_broken_barh_empty():
54335456
ax.broken_barh([], (.1, .5))
54345457

54355458

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

0 commit comments

Comments
 (0)