# Period Index plotting method, non standard intervals #14763

Closed
opened this issue Nov 29, 2016 · 7 comments

### quebbs commented Nov 29, 2016 • edited by jorisvandenbossche

#### Code Sample, a copy-pastable example if possible

```import numpy as np, pandas as pd
idx = pd.period_range('2000-01-01', '2000-01-05', freq='6H')
s = pd.Series(np.random.randn(len(idx)), index=idx)
s.plot()```

#### Problem description

Plotting a period index with 'D' or 'H' works fine, but changing the interval to 6-hr throws an error: `IncompatibleFrequency: Input has different freq=6H from PeriodIndex(freq=H)`

#### Expected Output

Should make a nice plot. Using the same example above with alternative frequencies of 'D' or 'H' plots as expected, but 3H, 6H, and even 24H throw an error.

#### Output

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tseries\period.py in _from_arraylike(cls, data, freq, tz) 263 try: --> 264 data = com._ensure_int64(data) 265 except (TypeError, ValueError):

pandas\src\generated.pyx in pandas.algos.ensure_int64 (pandas\algos.c:64659)()

pandas\src\generated.pyx in pandas.algos.ensure_int64 (pandas\algos.c:64550)()

TypeError: int() argument must be a string, a bytes-like object or a number, not 'pandas._period.Period'

During handling of the above exception, another exception occurred:

IncompatibleFrequency Traceback (most recent call last)
in ()
2 idx = ps.period_range('2000-01-01', '2000-01-05', freq='6H')
3 s = ps.Series(np.random.randn(len(idx)), index=idx)
----> 4 s.plot()

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in call(self, kind, ax, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, label, secondary_y, **kwds)
3564 colormap=colormap, table=table, yerr=yerr,
3565 xerr=xerr, label=label, secondary_y=secondary_y,
-> 3566 **kwds)
3567 call.doc = plot_series.doc
3568

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in plot_series(data, kind, ax, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, label, secondary_y, **kwds)
2643 yerr=yerr, xerr=xerr,
2644 label=label, secondary_y=secondary_y,
-> 2645 **kwds)
2646
2647

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in _plot(data, x, y, subplots, ax, kind, **kwds)
2439 plot_obj = klass(data, subplots=subplots, ax=ax, kind=kind, **kwds)
2440
-> 2441 plot_obj.generate()
2442 plot_obj.draw()
2443 return plot_obj.result

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in generate(self)
1026 self._compute_plot_data()
1027 self._setup_subplots()
-> 1028 self._make_plot()
1030 self._make_legend()

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in _make_plot(self)
1705 stacking_id=stacking_id,
1706 is_errorbar=is_errorbar,
-> 1707 **kwds)
1709

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in _ts_plot(cls, ax, x, data, style, **kwds)
1743 ax._plot_data.append((data, cls._kind, kwds))
1744
-> 1745 lines = cls._plot(ax, data.index, data.values, style=style, **kwds)
1746 # set date formatter, locators and rescale limits
1747 format_dateaxis(ax, ax.freq)

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in _plot(cls, ax, x, y, style, column_num, stacking_id, **kwds)
1720 cls._initialize_stacker(ax, stacking_id, len(y))
1721 y_values = cls._get_stacked_values(ax, stacking_id, y, kwds['label'])
-> 1722 lines = MPLPlot._plot(ax, x, y_values, style=style, **kwds)
1723 cls._update_stacker(ax, stacking_id, y)
1724 return lines

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tools\plotting.py in _plot(cls, ax, x, y, style, is_errorbar, **kwds)
1340 else:
1341 args = (x, y)
-> 1342 return ax.plot(*args, **kwds)
1343
1344 def _get_index_name(self):

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib_init_.py in inner(ax, *args, **kwargs)
1816 warnings.warn(msg % (label_namer, func.name),
1817 RuntimeWarning, stacklevel=2)
-> 1818 return func(ax, *args, **kwargs)
1819 pre_doc = inner.doc
1820 if pre_doc is None:

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\axes_axes.py in plot(self, *args, **kwargs)
1381
1382 for line in self._get_lines(*args, **kwargs):
1384 lines.append(line)
1385

1701 line.set_clip_path(self.patch)
1702
-> 1703 self._update_line_limits(line)
1704 if not line.get_label():
1705 line.set_label('_line%d' % len(self.lines))

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\axes_base.py in _update_line_limits(self, line)
1723 Figures out the data limit of the given line, updating self.dataLim.
1724 """
-> 1725 path = line.get_path()
1726 if path.vertices.size == 0:
1727 return

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\lines.py in get_path(self)
936 """
937 if self._invalidy or self._invalidx:
--> 938 self.recache()
939 return self._path
940

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\lines.py in recache(self, always)
619 def recache(self, always=False):
620 if always or self._invalidx:
--> 621 xconv = self.convert_xunits(self._xorig)
623 x = ma.asarray(xconv, np.float
).filled(np.nan)

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\artist.py in convert_xunits(self, x)
188 if ax is None or ax.xaxis is None:
189 return x
--> 190 return ax.xaxis.convert_units(x)
191
192 def convert_yunits(self, y):

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\matplotlib\axis.py in convert_units(self, x)
1442 return x
1443
-> 1444 ret = self.converter.convert(x, self.units, self)
1445 return ret
1446

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tseries\converter.py in convert(values, units, axis)
120 return values.map(lambda x: get_datevalue(x, axis.freq))
121 if com.is_period_arraylike(values):
--> 122 return PeriodIndex(values, freq=axis.freq).values
123 if isinstance(values, (list, tuple, np.ndarray, Index)):
124 return [get_datevalue(x, axis.freq) for x in values]

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tseries\period.py in new(cls, data, ordinal, freq, start, end, periods, copy, name, tz, **kwargs)
188 freq, kwargs)
189 else:
--> 190 ordinal, freq = cls._from_arraylike(data, freq, tz)
191 data = np.array(ordinal, dtype=np.int64, copy=False)
192

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tseries\period.py in _from_arraylike(cls, data, freq, tz)
265 except (TypeError, ValueError):
266 data = com._ensure_object(data)
--> 267 data = _get_ordinals(data, freq)
268
269 return data, freq

C:\Users\jaq\AppData\Local\Continuum\Anaconda\envs\py35\lib\site-packages\pandas\tseries\period.py in _get_ordinals(data, freq)
42 f = lambda x: Period(x, freq=freq).ordinal
43 if isinstance(data[0], Period):
---> 44 return period.extract_ordinals(data, freq)
45 else:
46 return lib.map_infer(data, f)

pandas\src\period.pyx in pandas._period.extract_ordinals (pandas\src\period.c:7030)()

IncompatibleFrequency: Input has different freq=6H from PeriodIndex(freq=H)

### jeffcarey added a commit to jeffcarey/pandas that referenced this issue Dec 7, 2016

``` BUG: Spurious IncompatibleFrequency error prevented plotting of non-s… ```
`…tandard intervals (Fixes pandas-dev#14763)`
``` 725f1b8 ```

### jeffcarey added a commit to jeffcarey/pandas that referenced this issue Dec 10, 2016

``` BUG: Spurious IncompatibleFrequency error prevented plotting of non-s… ```
`…tandard intervals (Fixes pandas-dev#14763)`
``` 239a4f4 ```
referenced this issue Dec 10, 2016

### brylie commented Oct 11, 2017 • edited

 Would it be possible to include this in the 0.20.4 release? It is making it difficult to plot timeseries data: https://stackoverflow.com/questions/43206554/typeerror-float-argument-must-be-a-string-or-a-number-not-period I am getting Type error even when the time series period is set to 'D':
Contributor

### jreback commented Oct 11, 2017

 this would require a community pull request to fix

### brylie commented Oct 11, 2017

 OK, I am just not sure of the underlying cause. Would you help point me in the right direction?

Contributor

### JoElfner commented Apr 26, 2019

 Any news on this?
Contributor

### jreback commented Apr 26, 2019

 @scootty1 pandas is completely volunteer you are welcome to make a PE for any issue
Contributor

### JoElfner commented Apr 29, 2019

 @jreback I know. I tried to find where the bug is coming from and since it is my first "guess" on a matter like this, it took me quite some time... One thing I found confusing was somewhere between `pandas/plotting/_timeseries._maybe_resample` and/or `pandas/plotting/_core._ts_plot`. The frequency of the x-axis `ax.xaxis.freq` seems to be set to the rule code, for example `H` for a frequency of the index of `6H`. But this also seems to be the case for plotting `DateTimeIndex` with a freq of `6H`, so I guess this is ok. Imho the bug is located in `pandas/plotting/_timeseries._maybe_convert_index`. Line 266 only checks for DatetimeIndex. It is assumed that the PeriodIndex already has the correct ax freq set. I changed the code in `_maybe_convert_index` to: ``````def _maybe_convert_index(ax, data): # tsplot converts automatically, but don't want to convert index # over and over for DataFrames if isinstance(data.index, (ABCDatetimeIndex, ABCPeriodIndex)): 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 if freq is None: freq = _get_ax_freq(ax) if freq is None: raise ValueError('Could not get frequency alias for plotting') freq = get_base_alias(freq) freq = frequencies.get_period_alias(freq) if isinstance(data.index, ABCDatetimeIndex): data = data.to_period(freq=freq) elif isinstance(data.index, ABCPeriodIndex): data.index = data.index.asfreq(freq) return data `````` Plotting some tests seems to be working... I'll try to make a pull request. But since this is my first pull request, it may take me some time...

### JoElfner added a commit to JoElfner/pandas that referenced this issue Apr 29, 2019

``` BUG: Enable plotting with PeriodIndex with arbitrary frequencies, res… ```
`…olves pandas-dev#14763`
``` a14edfe ```
referenced this issue Apr 29, 2019

### TomAugspurger added a commit that referenced this issue May 28, 2019

``` BUG: Enable plotting with PeriodIndex with arbitrary frequencies, res… ```
```…olves #14763 (#26241)

* BUG: Enable plotting with PeriodIndex with arbitrary frequencies, resolves #14763```
``` 7629a18 ```