Skip to content

Commit 87e9c4a

Browse files
authored
BUG: Make xticks from _quarterly_finder() line up better (#47602)
* Make xticks from _quarterly_finder() line up better When I plot a series of quarterly data that spans more than 11 years, my vertical grid lines get placed a year before where they should, i.e., one year before a year that is divisible by the default annual spacing. Changing one line in the _quarterly_finder() function, from +1 to +1970, fixes this for me. Can anyone please confirm the issue and that this fixes it? * Create test for _quarterly_finder() * Shorten comment * Style refinements * Style * Sort imports * Simplify test and move to test_converter.py file * Newline at end of file * Make 4 individual asserts * Add Github discussion link as comment * Remove newline from end of file * Replace newline at end of file (minus tab) * Add one line of white space * Added release note in bug fixes/visualization section * Moved release note to different section and noted public method
1 parent ff74bb6 commit 87e9c4a

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

doc/source/whatsnew/v1.5.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,7 @@ Plotting
976976
- Bug in :meth:`DataFrame.plot.scatter` that prevented specifying ``norm`` (:issue:`45809`)
977977
- The function :meth:`DataFrame.plot.scatter` now accepts ``color`` as an alias for ``c`` and ``size`` as an alias for ``s`` for consistency to other plotting functions (:issue:`44670`)
978978
- Fix showing "None" as ylabel in :meth:`Series.plot` when not setting ylabel (:issue:`46129`)
979+
- Bug in :meth:`DataFrame.plot` that led to xticks and vertical grids being improperly placed when plotting a quarterly series (:issue:`47602`)
979980

980981
Groupby/resample/rolling
981982
^^^^^^^^^^^^^^^^^^^^^^^^

pandas/plotting/_matplotlib/converter.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,8 @@ def _quarterly_finder(vmin, vmax, freq):
867867
info_fmt[year_start] = "%F"
868868

869869
else:
870-
years = dates_[year_start] // 4 + 1
870+
# https://github.com/pandas-dev/pandas/pull/47602
871+
years = dates_[year_start] // 4 + 1970
871872
nyears = span / periodsperyear
872873
(min_anndef, maj_anndef) = _get_default_annual_spacing(nyears)
873874
major_idx = year_start[(years % maj_anndef == 0)]

pandas/tests/plotting/test_converter.py

+31
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
from pandas import (
1616
Index,
1717
Period,
18+
PeriodIndex,
1819
Series,
1920
Timestamp,
21+
arrays,
2022
date_range,
2123
)
2224
import pandas._testing as tm
@@ -375,3 +377,32 @@ def get_view_interval(self):
375377
tdc = converter.TimeSeries_TimedeltaFormatter()
376378
monkeypatch.setattr(tdc, "axis", mock_axis())
377379
tdc(0.0, 0)
380+
381+
382+
@pytest.mark.parametrize("year_span", [11.25, 30, 80, 150, 400, 800, 1500, 2500, 3500])
383+
# The range is limited to 11.25 at the bottom by if statements in
384+
# the _quarterly_finder() function
385+
def test_quarterly_finder(year_span):
386+
vmin = -1000
387+
vmax = vmin + year_span * 4
388+
span = vmax - vmin + 1
389+
if span < 45: # the quarterly finder is only invoked if the span is >= 45
390+
return
391+
nyears = span / 4
392+
(min_anndef, maj_anndef) = converter._get_default_annual_spacing(nyears)
393+
result = converter._quarterly_finder(vmin, vmax, "Q")
394+
quarters = PeriodIndex(
395+
arrays.PeriodArray(np.array([x[0] for x in result]), freq="Q")
396+
)
397+
majors = np.array([x[1] for x in result])
398+
minors = np.array([x[2] for x in result])
399+
major_quarters = quarters[majors]
400+
minor_quarters = quarters[minors]
401+
check_major_years = major_quarters.year % maj_anndef == 0
402+
check_minor_years = minor_quarters.year % min_anndef == 0
403+
check_major_quarters = major_quarters.quarter == 1
404+
check_minor_quarters = minor_quarters.quarter == 1
405+
assert np.all(check_major_years)
406+
assert np.all(check_minor_years)
407+
assert np.all(check_major_quarters)
408+
assert np.all(check_minor_quarters)

0 commit comments

Comments
 (0)