Skip to content

BUG/CLN: Repeated time-series plot may raise TypeError #9852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 12, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.16.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
107 changes: 42 additions & 65 deletions pandas/tools/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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):
Expand Down Expand Up @@ -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,
Expand Down
32 changes: 32 additions & 0 deletions pandas/tseries/tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down