Skip to content

Commit b3537e2

Browse files
BUG: mixed freq timeseries plotting with shared axes (GH13341)
1 parent 6dcc238 commit b3537e2

File tree

3 files changed

+65
-8
lines changed

3 files changed

+65
-8
lines changed

doc/source/whatsnew/v0.19.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1584,3 +1584,5 @@ Bug Fixes
15841584
- ``PeridIndex`` can now accept ``list`` and ``array`` which contains ``pd.NaT`` (:issue:`13430`)
15851585
- Bug in ``df.groupby`` where ``.median()`` returns arbitrary values if grouped dataframe contains empty bins (:issue:`13629`)
15861586
- Bug in ``Index.copy()`` where ``name`` parameter was ignored (:issue:`14302`)
1587+
- Bug in plotting regular and irregular timeseries using shared axes
1588+
(``sharex=True`` or ``ax.twinx()``) (:issue:`13341`, :issue:`14322`).

pandas/tests/plotting/test_datetimelike.py

+36
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,42 @@ def test_mixed_freq_irreg_period(self):
778778
irreg.plot()
779779
ps.plot()
780780

781+
def test_mixed_freq_shared_ax(self):
782+
import matplotlib.pyplot as plt
783+
784+
# GH13341, using sharex=True
785+
idx1 = date_range('2015-01-01', periods=3, freq='M')
786+
idx2 = idx1[:1].union(idx1[2:])
787+
s1 = Series(range(len(idx1)), idx1)
788+
s2 = Series(range(len(idx2)), idx2)
789+
790+
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
791+
s1.plot(ax=ax1)
792+
s2.plot(ax=ax2)
793+
794+
self.assertEqual(ax1.freq, 'M')
795+
self.assertEqual(ax2.freq, 'M')
796+
self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
797+
ax2.lines[0].get_xydata()[0, 0])
798+
799+
# using twinx
800+
fig, ax1 = plt.subplots()
801+
ax2 = ax1.twinx()
802+
s1.plot(ax=ax1)
803+
s2.plot(ax=ax2)
804+
805+
self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
806+
ax2.lines[0].get_xydata()[0, 0])
807+
808+
# TODO
809+
# plotting the irregular first does not yet work
810+
# fig, ax1 = plt.subplots()
811+
# ax2 = ax1.twinx()
812+
# s2.plot(ax=ax1)
813+
# s1.plot(ax=ax2)
814+
# self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
815+
# ax2.lines[0].get_xydata()[0, 0])
816+
781817
@slow
782818
def test_to_weekly_resampling(self):
783819
idxh = date_range('1/1/1999', periods=52, freq='W')

pandas/tseries/plotting.py

+27-8
Original file line numberDiff line numberDiff line change
@@ -162,18 +162,37 @@ def _decorate_axes(ax, freq, kwargs):
162162
ax.date_axis_info = None
163163

164164

165-
def _get_freq(ax, series):
166-
# get frequency from data
167-
freq = getattr(series.index, 'freq', None)
168-
if freq is None:
169-
freq = getattr(series.index, 'inferred_freq', None)
170-
165+
def _get_ax_freq(ax):
166+
"""
167+
Get the freq attribute of the ax object if set.
168+
Also checks shared axes (eg when using secondary yaxis, sharex=True
169+
or twinx)
170+
"""
171171
ax_freq = getattr(ax, 'freq', None)
172172
if ax_freq is None:
173+
# check for left/right ax in case of secondary yaxis
173174
if hasattr(ax, 'left_ax'):
174175
ax_freq = getattr(ax.left_ax, 'freq', None)
175176
elif hasattr(ax, 'right_ax'):
176177
ax_freq = getattr(ax.right_ax, 'freq', None)
178+
if ax_freq is None:
179+
# check if a shared ax (sharex/twinx) has already freq set
180+
shared_axes = ax.get_shared_x_axes().get_siblings(ax)
181+
if len(shared_axes) > 1:
182+
for shared_ax in shared_axes:
183+
ax_freq = getattr(shared_ax, 'freq', None)
184+
if ax_freq is not None:
185+
break
186+
return ax_freq
187+
188+
189+
def _get_freq(ax, series):
190+
# get frequency from data
191+
freq = getattr(series.index, 'freq', None)
192+
if freq is None:
193+
freq = getattr(series.index, 'inferred_freq', None)
194+
195+
ax_freq = _get_ax_freq(ax)
177196

178197
# use axes freq if no data freq
179198
if freq is None:
@@ -191,7 +210,7 @@ def _get_freq(ax, series):
191210

192211
def _use_dynamic_x(ax, data):
193212
freq = _get_index_freq(data)
194-
ax_freq = getattr(ax, 'freq', None)
213+
ax_freq = _get_ax_freq(ax)
195214

196215
if freq is None: # convert irregular if axes has freq info
197216
freq = ax_freq
@@ -244,7 +263,7 @@ def _maybe_convert_index(ax, data):
244263
freq = freq.rule_code
245264

246265
if freq is None:
247-
freq = getattr(ax, 'freq', None)
266+
freq = _get_ax_freq(ax)
248267

249268
if freq is None:
250269
raise ValueError('Could not get frequency alias for plotting')

0 commit comments

Comments
 (0)