diff --git a/doc/source/whatsnew/v0.16.1.txt b/doc/source/whatsnew/v0.16.1.txt index b80e341d4156a..1750ec64025a7 100644 --- a/doc/source/whatsnew/v0.16.1.txt +++ b/doc/source/whatsnew/v0.16.1.txt @@ -108,6 +108,7 @@ Bug Fixes - Bug in plotting continuously using ``secondary_y`` may not show legend properly. (:issue:`9610`, :issue:`9779`) - Bug in ``DataFrame.plot(kind="hist")`` results in ``TypeError`` when ``DataFrame`` contains non-numeric columns (:issue:`9853`) +- Bug where repeated plotting of ``DataFrame`` with a ``DatetimeIndex`` may raise ``TypeError`` (:issue:`9852`) - Bug in ``Series.quantile`` on empty Series of type ``Datetime`` or ``Timedelta`` (:issue:`9675`) - Bug in ``where`` causing incorrect results when upcasting was required (:issue:`9731`) diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index 1accc48b0d3c4..6a284e547433a 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -885,28 +885,16 @@ def _iter_data(self, data=None, keep_index=False, fillna=None): if fillna is not None: data = data.fillna(fillna) - from pandas.core.frame import DataFrame - if isinstance(data, (Series, np.ndarray, Index)): - label = self.label if self.label is not None else data.name + if self.sort_columns: + columns = com._try_sort(data.columns) + else: + columns = data.columns + + for col in columns: if keep_index is True: - yield label, data + yield col, data[col] else: - yield label, np.asarray(data) - elif isinstance(data, DataFrame): - if self.sort_columns: - columns = com._try_sort(data.columns) - else: - columns = data.columns - - for col in columns: - # # is this right? - # empty = df[col].count() == 0 - # values = df[col].values if not empty else np.zeros(len(df)) - - if keep_index is True: - yield col, data[col] - else: - yield col, data[col].values + yield col, data[col].values @property def nseries(self): @@ -1006,7 +994,15 @@ def result(self): return self.axes[0] def _compute_plot_data(self): - numeric_data = self.data.convert_objects()._get_numeric_data() + data = self.data + + if isinstance(data, Series): + label = self.kwds.pop('label', None) + if label is None and data.name is None: + label = 'None' + data = data.to_frame(name=label) + + numeric_data = data.convert_objects()._get_numeric_data() try: is_empty = numeric_data.empty @@ -1027,12 +1023,7 @@ def _add_table(self): if self.table is False: return elif self.table is True: - from pandas.core.frame import DataFrame - if isinstance(self.data, Series): - data = DataFrame(self.data, columns=[self.data.name]) - elif isinstance(self.data, DataFrame): - data = self.data - data = data.transpose() + data = self.data.transpose() else: data = self.table ax = self._get_ax(0) @@ -1099,18 +1090,15 @@ def _apply_axis_properties(self, axis, rot=None, fontsize=None): @property def legend_title(self): - if hasattr(self.data, 'columns'): - if not isinstance(self.data.columns, MultiIndex): - name = self.data.columns.name - if name is not None: - name = com.pprint_thing(name) - return name - else: - stringified = map(com.pprint_thing, - self.data.columns.names) - return ','.join(stringified) + if not isinstance(self.data.columns, MultiIndex): + name = self.data.columns.name + if name is not None: + name = com.pprint_thing(name) + return name else: - return None + stringified = map(com.pprint_thing, + self.data.columns.names) + return ','.join(stringified) def _add_legend_handle(self, handle, label, index=None): if not label is None: @@ -1256,12 +1244,10 @@ def _get_ax(self, i): return ax def on_right(self, i): - from pandas.core.frame import DataFrame if isinstance(self.secondary_y, bool): return self.secondary_y - if (isinstance(self.data, DataFrame) and - isinstance(self.secondary_y, (tuple, list, np.ndarray, Index))): + if isinstance(self.secondary_y, (tuple, list, np.ndarray, Index)): return self.data.columns[i] in self.secondary_y def _get_style(self, i, col_name): @@ -1553,16 +1539,14 @@ def __init__(self, data, **kwargs): self.x_compat = bool(self.kwds.pop('x_compat')) def _index_freq(self): - from pandas.core.frame import DataFrame - if isinstance(self.data, (Series, DataFrame)): - freq = getattr(self.data.index, 'freq', None) - if freq is None: - freq = getattr(self.data.index, 'inferred_freq', None) - if freq == 'B': - weekdays = np.unique(self.data.index.dayofweek) - if (5 in weekdays) or (6 in weekdays): - freq = None - return freq + freq = getattr(self.data.index, 'freq', None) + if freq is None: + freq = getattr(self.data.index, 'inferred_freq', None) + if freq == 'B': + weekdays = np.unique(self.data.index.dayofweek) + if (5 in weekdays) or (6 in weekdays): + freq = None + return freq def _is_dynamic_freq(self, freq): if isinstance(freq, DateOffset): @@ -1574,9 +1558,7 @@ def _is_dynamic_freq(self, freq): def _no_base(self, freq): # hack this for 0.10.1, creating more technical debt...sigh - from pandas.core.frame import DataFrame - if (isinstance(self.data, (Series, DataFrame)) - and isinstance(self.data.index, DatetimeIndex)): + if isinstance(self.data.index, DatetimeIndex): base = frequencies.get_freq(freq) x = self.data.index if (base <= frequencies.FreqGroup.FR_DAY): @@ -1686,17 +1668,13 @@ def _update_prior(self, y): def _maybe_convert_index(self, data): # tsplot converts automatically, but don't want to convert index # over and over for DataFrames - from pandas.core.frame import DataFrame - if (isinstance(data.index, DatetimeIndex) and - isinstance(data, DataFrame)): + if isinstance(data.index, DatetimeIndex): freq = getattr(data.index, 'freq', None) if freq is None: freq = getattr(data.index, 'inferred_freq', None) if isinstance(freq, DateOffset): freq = freq.rule_code - freq = frequencies.get_base_alias(freq) - freq = frequencies.get_period_alias(freq) if freq is None: ax = self._get_ax(0) @@ -1705,9 +1683,10 @@ def _maybe_convert_index(self, data): if freq is None: raise ValueError('Could not get frequency alias for plotting') - data = DataFrame(data.values, - index=data.index.to_period(freq=freq), - columns=data.columns) + freq = frequencies.get_base_alias(freq) + freq = frequencies.get_period_alias(freq) + + data.index = data.index.to_period(freq=freq) return data def _post_plot_logic(self): @@ -2522,9 +2501,7 @@ def plot_series(data, kind='line', ax=None, # Series unique if ax is None and len(plt.get_fignums()) > 0: ax = _gca() ax = getattr(ax, 'left_ax', ax) - # is there harm in this? - if label is None: - label = data.name + return _plot(data, kind=kind, ax=ax, figsize=figsize, use_index=use_index, title=title, grid=grid, legend=legend, diff --git a/pandas/tseries/tests/test_plotting.py b/pandas/tseries/tests/test_plotting.py index c4e642ffe43b0..bdc0aa02f2715 100644 --- a/pandas/tseries/tests/test_plotting.py +++ b/pandas/tseries/tests/test_plotting.py @@ -636,6 +636,38 @@ def test_mixed_freq_irregular_first(self): x2 = lines[1].get_xdata() assert_array_equal(x2, s1.index.asobject.values) + def test_mixed_freq_regular_first_df(self): + # GH 9852 + import matplotlib.pyplot as plt + s1 = tm.makeTimeSeries().to_frame() + s2 = s1.iloc[[0, 5, 10, 11, 12, 13, 14, 15], :] + ax = s1.plot() + ax2 = s2.plot(style='g', ax=ax) + lines = ax2.get_lines() + idx1 = PeriodIndex(lines[0].get_xdata()) + idx2 = PeriodIndex(lines[1].get_xdata()) + self.assertTrue(idx1.equals(s1.index.to_period('B'))) + self.assertTrue(idx2.equals(s2.index.to_period('B'))) + left, right = ax2.get_xlim() + pidx = s1.index.to_period() + self.assertEqual(left, pidx[0].ordinal) + self.assertEqual(right, pidx[-1].ordinal) + + @slow + def test_mixed_freq_irregular_first_df(self): + # GH 9852 + import matplotlib.pyplot as plt + s1 = tm.makeTimeSeries().to_frame() + s2 = s1.iloc[[0, 5, 10, 11, 12, 13, 14, 15], :] + ax = s2.plot(style='g') + ax = s1.plot(ax=ax) + self.assertFalse(hasattr(ax, 'freq')) + lines = ax.get_lines() + x1 = lines[0].get_xdata() + assert_array_equal(x1, s2.index.asobject.values) + x2 = lines[1].get_xdata() + assert_array_equal(x2, s1.index.asobject.values) + def test_mixed_freq_hf_first(self): idxh = date_range('1/1/1999', periods=365, freq='D') idxl = date_range('1/1/1999', periods=12, freq='M')