Skip to content

Commit 00ea10c

Browse files
Matplotlib 3.3 compatibility fixups (pandas-dev#35393)
1 parent d3343d9 commit 00ea10c

File tree

9 files changed

+34
-40
lines changed

9 files changed

+34
-40
lines changed

ci/deps/azure-37-locale.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dependencies:
1818
- ipython
1919
- jinja2
2020
- lxml
21-
- matplotlib <3.3.0
21+
- matplotlib>=3.3.0
2222
- moto
2323
- nomkl
2424
- numexpr

doc/source/whatsnew/v1.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ change, as ``fsspec`` will still bring in the same packages as before.
274274
Other enhancements
275275
^^^^^^^^^^^^^^^^^^
276276

277+
- Compatibility with matplotlib 3.3.0 (:issue:`34850`)
277278
- :meth:`IntegerArray.astype` now supports ``datetime64`` dtype (:issue:`32538`)
278279
- :class:`IntegerArray` now implements the ``sum`` operation (:issue:`33172`)
279280
- Added :class:`pandas.errors.InvalidIndexError` (:issue:`34570`).

pandas/plotting/_matplotlib/boxplot.py

+5
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,11 @@ def plot_group(keys, values, ax):
299299
if fontsize is not None:
300300
ax.tick_params(axis="both", labelsize=fontsize)
301301
if kwds.get("vert", 1):
302+
ticks = ax.get_xticks()
303+
if len(ticks) != len(keys):
304+
i, remainder = divmod(len(ticks), len(keys))
305+
assert remainder == 0, remainder
306+
keys *= i
302307
ax.set_xticklabels(keys, rotation=rot)
303308
else:
304309
ax.set_yticklabels(keys, rotation=rot)

pandas/plotting/_matplotlib/compat.py

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ def inner():
2121
_mpl_ge_3_0_0 = _mpl_version("3.0.0", operator.ge)
2222
_mpl_ge_3_1_0 = _mpl_version("3.1.0", operator.ge)
2323
_mpl_ge_3_2_0 = _mpl_version("3.2.0", operator.ge)
24+
_mpl_ge_3_3_0 = _mpl_version("3.3.0", operator.ge)

pandas/plotting/_matplotlib/converter.py

+7-27
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from pandas._libs.tslibs.offsets import BaseOffset
1717

1818
from pandas.core.dtypes.common import (
19-
is_datetime64_ns_dtype,
2019
is_float,
2120
is_float_dtype,
2221
is_integer,
@@ -246,19 +245,6 @@ def get_datevalue(date, freq):
246245
raise ValueError(f"Unrecognizable date '{date}'")
247246

248247

249-
def _dt_to_float_ordinal(dt):
250-
"""
251-
Convert :mod:`datetime` to the Gregorian date as UTC float days,
252-
preserving hours, minutes, seconds and microseconds. Return value
253-
is a :func:`float`.
254-
"""
255-
if isinstance(dt, (np.ndarray, Index, Series)) and is_datetime64_ns_dtype(dt):
256-
base = dates.epoch2num(dt.asi8 / 1.0e9)
257-
else:
258-
base = dates.date2num(dt)
259-
return base
260-
261-
262248
# Datetime Conversion
263249
class DatetimeConverter(dates.DateConverter):
264250
@staticmethod
@@ -274,15 +260,11 @@ def convert(values, unit, axis):
274260
def _convert_1d(values, unit, axis):
275261
def try_parse(values):
276262
try:
277-
return _dt_to_float_ordinal(tools.to_datetime(values))
263+
return dates.date2num(tools.to_datetime(values))
278264
except Exception:
279265
return values
280266

281-
if isinstance(values, (datetime, pydt.date)):
282-
return _dt_to_float_ordinal(values)
283-
elif isinstance(values, np.datetime64):
284-
return _dt_to_float_ordinal(Timestamp(values))
285-
elif isinstance(values, pydt.time):
267+
if isinstance(values, (datetime, pydt.date, np.datetime64, pydt.time)):
286268
return dates.date2num(values)
287269
elif is_integer(values) or is_float(values):
288270
return values
@@ -303,12 +285,10 @@ def try_parse(values):
303285

304286
try:
305287
values = tools.to_datetime(values)
306-
if isinstance(values, Index):
307-
values = _dt_to_float_ordinal(values)
308-
else:
309-
values = [_dt_to_float_ordinal(x) for x in values]
310288
except Exception:
311-
values = _dt_to_float_ordinal(values)
289+
pass
290+
291+
values = dates.date2num(values)
312292

313293
return values
314294

@@ -411,8 +391,8 @@ def __call__(self):
411391
interval = self._get_interval()
412392
freq = f"{interval}L"
413393
tz = self.tz.tzname(None)
414-
st = _from_ordinal(dates.date2num(dmin)) # strip tz
415-
ed = _from_ordinal(dates.date2num(dmax))
394+
st = dmin.replace(tzinfo=None)
395+
ed = dmin.replace(tzinfo=None)
416396
all_dates = date_range(start=st, end=ed, freq=freq, tz=tz).astype(object)
417397

418398
try:

pandas/tests/plotting/test_converter.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
pass
2828

2929
pytest.importorskip("matplotlib.pyplot")
30+
dates = pytest.importorskip("matplotlib.dates")
3031

3132

3233
def test_registry_mpl_resets():
@@ -146,7 +147,7 @@ def test_convert_accepts_unicode(self):
146147

147148
def test_conversion(self):
148149
rs = self.dtc.convert(["2012-1-1"], None, None)[0]
149-
xp = datetime(2012, 1, 1).toordinal()
150+
xp = dates.date2num(datetime(2012, 1, 1))
150151
assert rs == xp
151152

152153
rs = self.dtc.convert("2012-1-1", None, None)
@@ -155,9 +156,6 @@ def test_conversion(self):
155156
rs = self.dtc.convert(date(2012, 1, 1), None, None)
156157
assert rs == xp
157158

158-
rs = self.dtc.convert(datetime(2012, 1, 1).toordinal(), None, None)
159-
assert rs == xp
160-
161159
rs = self.dtc.convert("2012-1-1", None, None)
162160
assert rs == xp
163161

pandas/tests/plotting/test_datetimelike.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def test_freq_with_no_period_alias(self):
331331
bts = tm.makeTimeSeries(5).asfreq(freq)
332332
_, ax = self.plt.subplots()
333333
bts.plot(ax=ax)
334-
assert ax.get_lines()[0].get_xydata()[0, 0] == bts.index[0].toordinal()
334+
335335
idx = ax.get_lines()[0].get_xdata()
336336
msg = "freq not specified and cannot be inferred"
337337
with pytest.raises(ValueError, match=msg):
@@ -1279,6 +1279,8 @@ def test_mpl_nopandas(self):
12791279
@pytest.mark.slow
12801280
def test_irregular_ts_shared_ax_xlim(self):
12811281
# GH 2960
1282+
from pandas.plotting._matplotlib.converter import DatetimeConverter
1283+
12821284
ts = tm.makeTimeSeries()[:20]
12831285
ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]]
12841286

@@ -1289,8 +1291,8 @@ def test_irregular_ts_shared_ax_xlim(self):
12891291

12901292
# check that axis limits are correct
12911293
left, right = ax.get_xlim()
1292-
assert left <= ts_irregular.index.min().toordinal()
1293-
assert right >= ts_irregular.index.max().toordinal()
1294+
assert left <= DatetimeConverter.convert(ts_irregular.index.min(), "", ax)
1295+
assert right >= DatetimeConverter.convert(ts_irregular.index.max(), "", ax)
12941296

12951297
@pytest.mark.slow
12961298
def test_secondary_y_non_ts_xlim(self):
@@ -1345,6 +1347,8 @@ def test_secondary_y_mixed_freq_ts_xlim(self):
13451347
@pytest.mark.slow
13461348
def test_secondary_y_irregular_ts_xlim(self):
13471349
# GH 3490 - irregular-timeseries with secondary y
1350+
from pandas.plotting._matplotlib.converter import DatetimeConverter
1351+
13481352
ts = tm.makeTimeSeries()[:20]
13491353
ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]]
13501354

@@ -1356,8 +1360,8 @@ def test_secondary_y_irregular_ts_xlim(self):
13561360
ts_irregular[:5].plot(ax=ax)
13571361

13581362
left, right = ax.get_xlim()
1359-
assert left <= ts_irregular.index.min().toordinal()
1360-
assert right >= ts_irregular.index.max().toordinal()
1363+
assert left <= DatetimeConverter.convert(ts_irregular.index.min(), "", ax)
1364+
assert right >= DatetimeConverter.convert(ts_irregular.index.max(), "", ax)
13611365

13621366
def test_plot_outofbounds_datetime(self):
13631367
# 2579 - checking this does not raise

pandas/tests/plotting/test_frame.py

+1
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,7 @@ def test_boxplot(self):
15631563
ax.xaxis.get_ticklocs(), np.arange(1, len(numeric_cols) + 1)
15641564
)
15651565
assert len(ax.lines) == self.bp_n_objects * len(numeric_cols)
1566+
tm.close()
15661567

15671568
axes = series.plot.box(rot=40)
15681569
self._check_ticks_props(axes, xrot=40, yrot=0)

pandas/tests/plotting/test_series.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,14 @@ def test_rotation(self):
274274
self._check_ticks_props(axes, xrot=30)
275275

276276
def test_irregular_datetime(self):
277+
from pandas.plotting._matplotlib.converter import DatetimeConverter
278+
277279
rng = date_range("1/1/2000", "3/1/2000")
278280
rng = rng[[0, 1, 2, 3, 5, 9, 10, 11, 12]]
279281
ser = Series(randn(len(rng)), rng)
280282
_, ax = self.plt.subplots()
281283
ax = ser.plot(ax=ax)
282-
xp = datetime(1999, 1, 1).toordinal()
284+
xp = DatetimeConverter.convert(datetime(1999, 1, 1), "", ax)
283285
ax.set_xlim("1/1/1999", "1/1/2001")
284286
assert xp == ax.get_xlim()[0]
285287

@@ -684,11 +686,13 @@ def test_kind_both_ways(self):
684686
kinds = (
685687
plotting.PlotAccessor._common_kinds + plotting.PlotAccessor._series_kinds
686688
)
687-
_, ax = self.plt.subplots()
688689
for kind in kinds:
689-
690+
_, ax = self.plt.subplots()
690691
s.plot(kind=kind, ax=ax)
692+
self.plt.close()
693+
_, ax = self.plt.subplots()
691694
getattr(s.plot, kind)()
695+
self.plt.close()
692696

693697
@pytest.mark.slow
694698
def test_invalid_plot_data(self):

0 commit comments

Comments
 (0)