diff --git a/doc/source/v0.14.1.txt b/doc/source/v0.14.1.txt index 42041cceeb81b..9f9a87f642a4d 100644 --- a/doc/source/v0.14.1.txt +++ b/doc/source/v0.14.1.txt @@ -270,6 +270,9 @@ Bug Fixes - Bug in non-monotonic ``Index.union`` may preserve ``name`` incorrectly (:issue:`7458`) - Bug in ``DatetimeIndex.intersection`` doesn't preserve timezone (:issue:`4690`) +- Bug with last plotted timeseries dictating ``xlim`` (:issue:`2960`) +- Bug with ``secondary_y`` axis not being considered for timeseries ``xlim`` (:issue:`3490`) + - Bug in ``Float64Index`` assignment with a non scalar indexer (:issue:`7586`) - Bug in ``pandas.core.strings.str_contains`` does not properly match in a case insensitive fashion when ``regex=False`` and ``case=False`` (:issue:`7505`) diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index 9e7badc836054..2b02523c143b4 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -1563,6 +1563,8 @@ def _make_plot(self): kwds = self.kwds.copy() self._maybe_add_color(colors, kwds, style, i) + lines += _get_all_lines(ax) + errors = self._get_errorbars(label=label, index=i) kwds = dict(kwds, **errors) @@ -3064,6 +3066,20 @@ def _flatten(axes): return axes +def _get_all_lines(ax): + lines = ax.get_lines() + + # check for right_ax, which can oddly sometimes point back to ax + if hasattr(ax, 'right_ax') and ax.right_ax != ax: + lines += ax.right_ax.get_lines() + + # no such risk with left_ax + if hasattr(ax, 'left_ax'): + lines += ax.left_ax.get_lines() + + return lines + + def _get_xlim(lines): left, right = np.inf, -np.inf for l in lines: diff --git a/pandas/tseries/plotting.py b/pandas/tseries/plotting.py index 9eecfc21be189..e390607a0e7e2 100644 --- a/pandas/tseries/plotting.py +++ b/pandas/tseries/plotting.py @@ -22,6 +22,8 @@ from pandas.tseries.converter import (PeriodConverter, TimeSeries_DateLocator, TimeSeries_DateFormatter) +from pandas.tools.plotting import _get_all_lines + #---------------------------------------------------------------------- # Plotting functions and monkey patches @@ -78,7 +80,7 @@ def tsplot(series, plotf, **kwargs): # set date formatter, locators and rescale limits format_dateaxis(ax, ax.freq) - left, right = _get_xlim(ax.get_lines()) + left, right = _get_xlim(_get_all_lines(ax)) ax.set_xlim(left, right) # x and y coord info @@ -115,7 +117,7 @@ def _get_ax_freq(ax): if ax_freq is None: if hasattr(ax, 'left_ax'): ax_freq = getattr(ax.left_ax, 'freq', None) - if hasattr(ax, 'right_ax'): + elif hasattr(ax, 'right_ax'): ax_freq = getattr(ax.right_ax, 'freq', None) return ax_freq diff --git a/pandas/tseries/tests/test_plotting.py b/pandas/tseries/tests/test_plotting.py index f0641b6389ebf..84c131ad0ffc6 100644 --- a/pandas/tseries/tests/test_plotting.py +++ b/pandas/tseries/tests/test_plotting.py @@ -919,6 +919,84 @@ def test_mpl_nopandas(self): assert_array_equal(np.array([x.toordinal() for x in dates]), line2.get_xydata()[:, 0]) + @slow + def test_irregular_ts_shared_ax_xlim(self): + # GH 2960 + ts = tm.makeTimeSeries()[:20] + ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]] + + # plot the left section of the irregular series, then the right section + ax = ts_irregular[:5].plot() + ts_irregular[5:].plot(ax=ax) + + # check that axis limits are correct + left, right = ax.get_xlim() + self.assertEqual(left, ts_irregular.index.min().toordinal()) + self.assertEqual(right, ts_irregular.index.max().toordinal()) + + @slow + def test_secondary_y_non_ts_xlim(self): + # GH 3490 - non-timeseries with secondary y + index_1 = [1, 2, 3, 4] + index_2 = [5, 6, 7, 8] + s1 = Series(1, index=index_1) + s2 = Series(2, index=index_2) + + ax = s1.plot() + left_before, right_before = ax.get_xlim() + s2.plot(secondary_y=True, ax=ax) + left_after, right_after = ax.get_xlim() + + self.assertEqual(left_before, left_after) + self.assertLess(right_before, right_after) + + @slow + def test_secondary_y_regular_ts_xlim(self): + # GH 3490 - regular-timeseries with secondary y + index_1 = date_range(start='2000-01-01', periods=4, freq='D') + index_2 = date_range(start='2000-01-05', periods=4, freq='D') + s1 = Series(1, index=index_1) + s2 = Series(2, index=index_2) + + ax = s1.plot() + left_before, right_before = ax.get_xlim() + s2.plot(secondary_y=True, ax=ax) + left_after, right_after = ax.get_xlim() + + self.assertEqual(left_before, left_after) + self.assertLess(right_before, right_after) + + @slow + def test_secondary_y_mixed_freq_ts_xlim(self): + # GH 3490 - mixed frequency timeseries with secondary y + rng = date_range('2000-01-01', periods=10000, freq='min') + ts = Series(1, index=rng) + + ax = ts.plot() + left_before, right_before = ax.get_xlim() + ts.resample('D').plot(secondary_y=True, ax=ax) + left_after, right_after = ax.get_xlim() + + # a downsample should not have changed either limit + self.assertEqual(left_before, left_after) + self.assertEqual(right_before, right_after) + + @slow + def test_secondary_y_irregular_ts_xlim(self): + # GH 3490 - irregular-timeseries with secondary y + ts = tm.makeTimeSeries()[:20] + ts_irregular = ts[[1, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 17, 18]] + + ax = ts_irregular[:5].plot() + # plot higher-x values on secondary axis + ts_irregular[5:].plot(secondary_y=True, ax=ax) + # ensure secondary limits aren't overwritten by plot on primary + ts_irregular[:5].plot(ax=ax) + + left, right = ax.get_xlim() + self.assertEqual(left, ts_irregular.index.min().toordinal()) + self.assertEqual(right, ts_irregular.index.max().toordinal()) + def _check_plot_works(f, freq=None, series=None, *args, **kwargs): import matplotlib.pyplot as plt