pyplot: keep calendar coordinates for pandas datetime plots (#549)
Merged
FA
2d ago+289+289+012345678901234567890123456789-12-12-01234567890123456789
Fixes #549.
Problem
In native xy.pyplot, pandas datetime-indexed Series.plot() / DataFrame.plot() had two problems:
- Period numbers instead of dates. pandas 3.1 passes
ax.plot()the raw integers behind itsPeriodIndex(asi8) where 3.0 passedPeriodobjects. The shim left those integers alone, soax.get_xlim()[0]came out as15340.0instead of1325376000000.0. Business-day (freq="B") series take a separate pandas path with their own day counts and had the same problem. - PNG export crash. pandas' minor
TimeSeries_Date*locator and formatter were stored and then called during export, raisingNotImplementedError: Derived must override. Only the major setters were guarded before.
Fix (python/xy/pyplot/_axes.py)
_restore_pandas_period_timestampsconverts the integers back to timestamps. It only does this when the array shares memory with, and equals, the index pandas just recorded inax._plot_data. A later numeric overlay keeps its own units, even when its values match period numbers (e.g.[0, 1, 2]after a daily index that starts on 1970-01-01). Business-day numbers are converted withnp.busday_offsetfrom the epoch, which is pandas' own inverse. Checks are duck-typed, so the shim never imports pandas.set_minor_locator/set_minor_formatternow ignore pandas' tickers, as the major setters already did.
Tests
tests/pyplot/test_pdsh_gap_features.py: daily, monthly, hourly and business-day indexes, each as a Series and a DataFrame. Each checks datetime xdata, millisecondget_xdata(orig=False)and limits, and PNG export. Also new: a numeric-overlay test and a pandas minor-ticker test. All new tests, plus the existingtest_pandas_datetime_series_plot_completes, fail before the fix.- New corpus case
tests/pyplot/corpus/59_pandas_datetime_plot.pyreproduces the export failure before the fix. It now passes the native corpus run and the comparison against Matplotlib 3.11. - pandas' plotting backend imports Matplotlib itself. A
REQUIREStable intest_corpus.pyskips this case where pandas or Matplotlib is missing and keeps it out of the Matplotlib-blocked boundary test.xy.pyplotitself is still asserted Matplotlib-free. pandas>=3added to thedevgroup, so CI runs this path. pandas is not a runtime dependency.uv.lockanddocs/app/uv.lockupdated.- Focused tests also pass on pandas 3.0.3.
Spec / changelog
spec/matplotlib/compat.md: updated the datetime coordinates row and the corpus paragraph.news/549.bugfix.md
Validation
uv run --with pre-commit pre-commit run --all-files,ruff check,ruff format --check,ty check: passuv run pytest tests/pyplot: 1444 passed
Generated by Claude Code
Summary by CodeRabbit
- Bug Fixes
- Fixed pandas datetime-indexed plots so daily, monthly, hourly, and business-day data use correctly scaled date coordinates and limits.
- Numeric overlays retain their original coordinate units when plotted alongside pandas date data.
- Fixed PNG export failures caused by pandas minor date tickers.
- Compatibility
- Improved support for pandas 3.0 and 3.1 plotting in native mode, including calendar-based coordinates and limits.