Skip to content

Commit bfa9bc5

Browse files
committed
Merge pull request #7733 from sinhrks/tsplot_bug
BUG: Repeated timeseries plot may result in incorrect kind
2 parents 211a967 + 5ee54e6 commit bfa9bc5

File tree

4 files changed

+103
-13
lines changed

4 files changed

+103
-13
lines changed

doc/source/v0.15.0.txt

+6
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,18 @@ Bug Fixes
245245
- Bug in ``combine_first`` with ``PeriodIndex`` data raises ``TypeError`` (:issue:`3367`)
246246

247247

248+
248249
- Bug in pickles contains ``DateOffset`` may raise ``AttributeError`` when ``normalize`` attribute is reffered internally (:issue:`7748`)
249250

250251
- Bug in pickle deserialization that failed for pre-0.14.1 containers with dup items trying to avoid ambiguity
251252
when matching block and manager items, when there's only one block there's no ambiguity (:issue:`7794`)
252253

253254

255+
256+
- Bug in repeated timeseries line and area plot may result in ``ValueError`` or incorrect kind (:issue:`7733`)
257+
258+
259+
254260
- Bug in ``is_superperiod`` and ``is_subperiod`` cannot handle higher frequencies than ``S`` (:issue:`7760`, :issue:`7772`, :issue:`7803`)
255261

256262
- Bug in ``DataFrame.reset_index`` which has ``MultiIndex`` contains ``PeriodIndex`` or ``DatetimeIndex`` with tz raises ``ValueError`` (:issue:`7746`, :issue:`7793`)

pandas/tools/plotting.py

+20-7
Original file line numberDiff line numberDiff line change
@@ -1564,10 +1564,8 @@ def _make_plot(self):
15641564

15651565
label = com.pprint_thing(label) # .encode('utf-8')
15661566
kwds['label'] = label
1567-
y_values = self._get_stacked_values(y, label)
15681567

1569-
newlines = plotf(ax, x, y_values, style=style, **kwds)
1570-
self._update_prior(y)
1568+
newlines = plotf(ax, x, y, style=style, column_num=i, **kwds)
15711569
self._add_legend_handle(newlines[0], label, index=i)
15721570

15731571
lines = _get_all_lines(ax)
@@ -1586,6 +1584,18 @@ def _get_stacked_values(self, y, label):
15861584
else:
15871585
return y
15881586

1587+
def _get_plot_function(self):
1588+
f = MPLPlot._get_plot_function(self)
1589+
def plotf(ax, x, y, style=None, column_num=None, **kwds):
1590+
# column_num is used to get the target column from protf in line and area plots
1591+
if column_num == 0:
1592+
self._initialize_prior(len(self.data))
1593+
y_values = self._get_stacked_values(y, kwds['label'])
1594+
lines = f(ax, x, y_values, style=style, **kwds)
1595+
self._update_prior(y)
1596+
return lines
1597+
return plotf
1598+
15891599
def _get_ts_plot_function(self):
15901600
from pandas.tseries.plotting import tsplot
15911601
plotf = self._get_plot_function()
@@ -1678,11 +1688,13 @@ def _get_plot_function(self):
16781688
raise ValueError("Log-y scales are not supported in area plot")
16791689
else:
16801690
f = MPLPlot._get_plot_function(self)
1681-
def plotf(ax, x, y, style=None, **kwds):
1682-
lines = f(ax, x, y, style=style, **kwds)
1691+
def plotf(ax, x, y, style=None, column_num=0, **kwds):
1692+
if column_num == 0:
1693+
self._initialize_prior(len(self.data))
1694+
y_values = self._get_stacked_values(y, kwds['label'])
1695+
lines = f(ax, x, y_values, style=style, **kwds)
16831696

1684-
# get data from the line
1685-
# insert fill_between starting point
1697+
# get data from the line to get coordinates for fill_between
16861698
xdata, y_values = lines[0].get_data(orig=False)
16871699

16881700
if (y >= 0).all():
@@ -1696,6 +1708,7 @@ def plotf(ax, x, y, style=None, **kwds):
16961708
kwds['color'] = lines[0].get_color()
16971709

16981710
self.plt.Axes.fill_between(ax, xdata, start, y_values, **kwds)
1711+
self._update_prior(y)
16991712
return lines
17001713

17011714
return plotf

pandas/tseries/plotting.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ def tsplot(series, plotf, **kwargs):
6060
# how to make sure ax.clear() flows through?
6161
if not hasattr(ax, '_plot_data'):
6262
ax._plot_data = []
63-
ax._plot_data.append((series, kwargs))
64-
63+
ax._plot_data.append((series, plotf, kwargs))
6564
lines = plotf(ax, series.index, series.values, **kwargs)
6665

6766
# set date formatter, locators and rescale limits
@@ -118,7 +117,7 @@ def _is_sup(f1, f2):
118117

119118
def _upsample_others(ax, freq, plotf, kwargs):
120119
legend = ax.get_legend()
121-
lines, labels = _replot_ax(ax, freq, plotf, kwargs)
120+
lines, labels = _replot_ax(ax, freq, kwargs)
122121

123122
other_ax = None
124123
if hasattr(ax, 'left_ax'):
@@ -127,7 +126,7 @@ def _upsample_others(ax, freq, plotf, kwargs):
127126
other_ax = ax.right_ax
128127

129128
if other_ax is not None:
130-
rlines, rlabels = _replot_ax(other_ax, freq, plotf, kwargs)
129+
rlines, rlabels = _replot_ax(other_ax, freq, kwargs)
131130
lines.extend(rlines)
132131
labels.extend(rlabels)
133132

@@ -139,7 +138,7 @@ def _upsample_others(ax, freq, plotf, kwargs):
139138
ax.legend(lines, labels, loc='best', title=title)
140139

141140

142-
def _replot_ax(ax, freq, plotf, kwargs):
141+
def _replot_ax(ax, freq, kwargs):
143142
data = getattr(ax, '_plot_data', None)
144143
ax._plot_data = []
145144
ax.clear()
@@ -148,7 +147,7 @@ def _replot_ax(ax, freq, plotf, kwargs):
148147
lines = []
149148
labels = []
150149
if data is not None:
151-
for series, kwds in data:
150+
for series, plotf, kwds in data:
152151
series = series.copy()
153152
idx = series.index.asfreq(freq, how='S')
154153
series.index = idx

pandas/tseries/tests/test_plotting.py

+72
Original file line numberDiff line numberDiff line change
@@ -704,9 +704,81 @@ def test_from_weekly_resampling(self):
704704
low = Series(np.random.randn(len(idxl)), idxl)
705705
low.plot()
706706
ax = high.plot()
707+
708+
expected_h = idxh.to_period().asi8
709+
expected_l = np.array([1514, 1519, 1523, 1527, 1531, 1536, 1540, 1544, 1549,
710+
1553, 1558, 1562])
707711
for l in ax.get_lines():
708712
self.assertTrue(PeriodIndex(data=l.get_xdata()).freq.startswith('W'))
709713

714+
xdata = l.get_xdata(orig=False)
715+
if len(xdata) == 12: # idxl lines
716+
self.assert_numpy_array_equal(xdata, expected_l)
717+
else:
718+
self.assert_numpy_array_equal(xdata, expected_h)
719+
720+
@slow
721+
def test_from_resampling_area_line_mixed(self):
722+
idxh = date_range('1/1/1999', periods=52, freq='W')
723+
idxl = date_range('1/1/1999', periods=12, freq='M')
724+
high = DataFrame(np.random.rand(len(idxh), 3),
725+
index=idxh, columns=[0, 1, 2])
726+
low = DataFrame(np.random.rand(len(idxl), 3),
727+
index=idxl, columns=[0, 1, 2])
728+
729+
# low to high
730+
for kind1, kind2 in [('line', 'area'), ('area', 'line')]:
731+
ax = low.plot(kind=kind1, stacked=True)
732+
ax = high.plot(kind=kind2, stacked=True, ax=ax)
733+
734+
# check low dataframe result
735+
expected_x = np.array([1514, 1519, 1523, 1527, 1531, 1536, 1540, 1544, 1549,
736+
1553, 1558, 1562])
737+
expected_y = np.zeros(len(expected_x))
738+
for i in range(3):
739+
l = ax.lines[i]
740+
self.assertTrue(PeriodIndex(data=l.get_xdata()).freq.startswith('W'))
741+
self.assert_numpy_array_equal(l.get_xdata(orig=False), expected_x)
742+
# check stacked values are correct
743+
expected_y += low[i].values
744+
self.assert_numpy_array_equal(l.get_ydata(orig=False), expected_y)
745+
746+
# check high dataframe result
747+
expected_x = idxh.to_period().asi8
748+
expected_y = np.zeros(len(expected_x))
749+
for i in range(3):
750+
l = ax.lines[3 + i]
751+
self.assertTrue(PeriodIndex(data=l.get_xdata()).freq.startswith('W'))
752+
self.assert_numpy_array_equal(l.get_xdata(orig=False), expected_x)
753+
expected_y += high[i].values
754+
self.assert_numpy_array_equal(l.get_ydata(orig=False), expected_y)
755+
756+
# high to low
757+
for kind1, kind2 in [('line', 'area'), ('area', 'line')]:
758+
ax = high.plot(kind=kind1, stacked=True)
759+
ax = low.plot(kind=kind2, stacked=True, ax=ax)
760+
761+
# check high dataframe result
762+
expected_x = idxh.to_period().asi8
763+
expected_y = np.zeros(len(expected_x))
764+
for i in range(3):
765+
l = ax.lines[i]
766+
self.assertTrue(PeriodIndex(data=l.get_xdata()).freq.startswith('W'))
767+
self.assert_numpy_array_equal(l.get_xdata(orig=False), expected_x)
768+
expected_y += high[i].values
769+
self.assert_numpy_array_equal(l.get_ydata(orig=False), expected_y)
770+
771+
# check low dataframe result
772+
expected_x = np.array([1514, 1519, 1523, 1527, 1531, 1536, 1540, 1544, 1549,
773+
1553, 1558, 1562])
774+
expected_y = np.zeros(len(expected_x))
775+
for i in range(3):
776+
l = ax.lines[3 + i]
777+
self.assertTrue(PeriodIndex(data=l.get_xdata()).freq.startswith('W'))
778+
self.assert_numpy_array_equal(l.get_xdata(orig=False), expected_x)
779+
expected_y += low[i].values
780+
self.assert_numpy_array_equal(l.get_ydata(orig=False), expected_y)
781+
710782
@slow
711783
def test_mixed_freq_second_millisecond(self):
712784
# GH 7772, GH 7760

0 commit comments

Comments
 (0)