Skip to content

timezone aware datetime64 object converter fails when plot #22859

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

Closed
enritoomey opened this issue Sep 27, 2018 · 7 comments
Closed

timezone aware datetime64 object converter fails when plot #22859

enritoomey opened this issue Sep 27, 2018 · 7 comments
Labels
Datetime Datetime data dtype Visualization plotting

Comments

@enritoomey
Copy link

Code Sample, a copy-pastable example if possible

import pandas
import dateutil.parser
import datetime


start = dateutil.parser.parse("2018-05-17 19:00:00").replace(tzinfo=datetime.timezone.utc)
end = dateutil.parser.parse("2018-05-17 20:00:00").replace(tzinfo=datetime.timezone.utc)
df = pandas.DataFrame(index=[start, end], data=[0,1])
df.plot()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-848b80e64df8> in <module>()
----> 1 df.plot()

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in __call__(self, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)                                                                                                                                                        
   2939                           fontsize=fontsize, colormap=colormap, table=table,
   2940                           yerr=yerr, xerr=xerr, secondary_y=secondary_y,
-> 2941                           sort_columns=sort_columns, **kwds)
   2942     __call__.__doc__ = plot_frame.__doc__
   2943 

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in plot_frame(data, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)                                                                                                                                                      
   1975                  yerr=yerr, xerr=xerr,
   1976                  secondary_y=secondary_y, sort_columns=sort_columns,
-> 1977                  **kwds)
   1978 
   1979 

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in _plot(data, x, y, subplots, ax, kind, **kwds)
   1802         plot_obj = klass(data, subplots=subplots, ax=ax, kind=kind, **kwds)
   1803 
-> 1804     plot_obj.generate()
   1805     plot_obj.draw()
   1806     return plot_obj.result

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in generate(self)
    258         self._compute_plot_data()
    259         self._setup_subplots()
--> 260         self._make_plot()
    261         self._add_table()
    262         self._make_legend()

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in _make_plot(self)
    983                              stacking_id=stacking_id,
    984                              is_errorbar=is_errorbar,
--> 985                              **kwds)
    986             self._add_legend_handle(newlines[0], label, index=i)
    987 

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in _plot(cls, ax, x, y, style, column_num, stacking_id, **kwds)
    999             cls._initialize_stacker(ax, stacking_id, len(y))
   1000         y_values = cls._get_stacked_values(ax, stacking_id, y, kwds['label'])
-> 1001         lines = MPLPlot._plot(ax, x, y_values, style=style, **kwds)
   1002         cls._update_stacker(ax, stacking_id, y)
   1003         return lines

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_core.py in _plot(cls, ax, x, y, style, is_errorbar, **kwds)
    613             else:
    614                 args = (x, y)
--> 615             return ax.plot(*args, **kwds)
    616 
    617     def _get_index_name(self):

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1783                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1784                         RuntimeWarning, stacklevel=2)
-> 1785             return func(ax, *args, **kwargs)
   1786 
   1787         inner.__doc__ = _add_data_doc(inner.__doc__,

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axes/_axes.py in plot(self, scalex, scaley, *args, **kwargs)
   1602         kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D._alias_map)
   1603 
-> 1604         for line in self._get_lines(*args, **kwargs):
   1605             self.add_line(line)
   1606             lines.append(line)

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axes/_base.py in _grab_next_args(self, *args, **kwargs)
    391                 this += args[0],
    392                 args = args[1:]
--> 393             yield from self._plot_args(this, kwargs)
    394 
    395 

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axes/_base.py in _plot_args(self, tup, kwargs)
    368             x, y = index_of(tup[-1])
    369 
--> 370         x, y = self._xy_from_xy(x, y)
    371 
    372         if self.command == 'plot':

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axes/_base.py in _xy_from_xy(self, x, y)
    202     def _xy_from_xy(self, x, y):
    203         if self.axes.xaxis is not None and self.axes.yaxis is not None:
--> 204             bx = self.axes.xaxis.update_units(x)
    205             by = self.axes.yaxis.update_units(y)
    206 

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axis.py in update_units(self, data)
   1473         default = self.converter.default_units(data, self)
   1474         if default is not None and self.units is None:
-> 1475             self.set_units(default)
   1476 
   1477         if neednew:

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axis.py in set_units(self, u)
   1546                 pchanged = True
   1547         if pchanged:
-> 1548             self._update_axisinfo()
   1549             self.callbacks.process('units')
   1550             self.callbacks.process('units finalize')

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/matplotlib/axis.py in _update_axisinfo(self)
   1488             return
   1489 
-> 1490         info = self.converter.axisinfo(self.units, self)
   1491 
   1492         if info is None:

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_converter.py in axisinfo(unit, axis)
    351 
    352         majloc = PandasAutoDateLocator(tz=tz)
--> 353         majfmt = PandasAutoDateFormatter(majloc, tz=tz)
    354         datemin = pydt.date(2000, 1, 1)
    355         datemax = pydt.date(2010, 1, 1)

~/pyvenvs/matplotlib_issue/lib/python3.5/site-packages/pandas/plotting/_converter.py in __init__(self, locator, tz, defaultfmt)
    365         # matplotlib.dates._UTC has no _utcoffset called by pandas
    366         if self._tz is dates.UTC:
--> 367             self._tz._utcoffset = self._tz.utcoffset(None)
    368 
    369         # For mpl > 2.0 the format strings are controlled via rcparams

AttributeError: 'datetime.timezone' object has no attribute '_utcoffset'

Problem description

Pandas converter, use to extract date str for axis labels, fails when index is timezone aware. This happends only if matplotlib>=3.0.0 version is installed. I reported the bug first to matplotlib (matplotlib/matplotlib#12310), but the close it as they believe that the bug is in pandas converter.

Output of pd.show_versions()

INSTALLED VERSIONS ------------------ commit: None python: 3.5.3.final.0 python-bits: 64 OS: Linux OS-release: 4.9.0-4-amd64 machine: x86_64 processor: byteorder: little LC_ALL: None LANG: en_US.UTF-8 LOCALE: en_US.UTF-8

pandas: 0.23.4
pytest: None
pip: 18.0
setuptools: 40.4.3
Cython: None
numpy: 1.15.2
scipy: None
pyarrow: None
xarray: None
IPython: 6.5.0
sphinx: None
patsy: None
dateutil: 2.7.3
pytz: 2018.5
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 3.0.0
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None

@TomAugspurger
Copy link
Contributor

xref #22790

doesn't seem to be in that output, so likely untested. Any help debugging / writing a failing unittest would be appreciated.

@TomAugspurger TomAugspurger added Datetime Datetime data dtype Visualization plotting labels Sep 27, 2018
@TomAugspurger TomAugspurger added this to the 0.24.0 milestone Sep 27, 2018
@mroeschke
Copy link
Member

Pandas also does not support datetime.timezones yet #17173

@jreback jreback modified the milestones: 0.24.0, Contributions Welcome Dec 2, 2018
@medlin01GA
Copy link

Here's a nice, neat reproduction of the problem with a one-line hack that magically fixes it. Uncomment hack to see the fix.

import pandas
import dateutil.parser
import datetime
import matplotlib.pyplot as plt

from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

start = dateutil.parser.parse("2018-05-17 19:00:00").replace(tzinfo=datetime.timezone.utc)
end = dateutil.parser.parse("2018-05-17 20:00:00").replace(tzinfo=datetime.timezone.utc)
df = pandas.DataFrame(data=[start, end], index=[0,1], columns=['x'])
# *** HACK: CONVERT datetime column to string and back again - who knows why this works? ***
# df['x'] = pandas.to_datetime(df['x'].astype(str))
print(df)
print(df.dtypes)

plt.plot(df['x'], [0,1], '--o')

Here's my local versions I could repro this issue on:

INSTALLED VERSIONS

commit: None
python: 3.6.6.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.24.1
pytest: 4.1.1
pip: 18.1
setuptools: 40.6.3
Cython: 0.29.2
numpy: 1.15.4
scipy: 1.1.0
pyarrow: None
xarray: None
IPython: 7.2.0
sphinx: 1.8.3
patsy: 0.5.1
dateutil: 2.7.5
pytz: 2018.9
blosc: None
bottleneck: 1.2.1
tables: 3.4.4
numexpr: 2.6.9
feather: None
matplotlib: 3.0.1
openpyxl: 2.5.12
xlrd: 1.2.0
xlwt: 1.3.0
xlsxwriter: 1.1.2
lxml.etree: 4.3.0
bs4: 4.7.1
html5lib: 1.0.1
sqlalchemy: 1.2.16
pymysql: None
psycopg2: None
jinja2: 2.10
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
gcsfs: None

@TomAugspurger
Copy link
Contributor

@medlin01GA your timezone types are different

In [30]: type(pandas.to_datetime(df['x'].astype(str))[0].tz)
Out[30]: pytz.UTC

In [31]: type(df.x[0].tz)
Out[31]: datetime.timezone

You might want to try again once
#17173 is in master.

@mrwsl
Copy link

mrwsl commented Jun 17, 2019

This is happening to me as well after I upgraded from Ubuntu 18.10 to 19.04. Before my code was running and now I also get:
AttributeError: 'datetime.timezone' object has no attribute '_utcoffset'

@charlesdong1991
Copy link
Member

charlesdong1991 commented Aug 10, 2019

Screen Shot 2019-08-10 at 4 19 40 PM

this issue might also be solved already, tried in pandas 0.25 @mroeschke @TomAugspurger probably this issue can be closed.

@mroeschke
Copy link
Member

Yes I think #27367 closed this.

brandon-rhodes added a commit to skyfielders/python-skyfield that referenced this issue Dec 9, 2020
* Move the plot into its own Python file for faster iteration.
* Switch the x-axis from ordinal dates to datetime objects, to dodge a
  breaking change in matplotlib: its default epoch for floating point
  days moved from the year AD 1 to the year AD 1970.
* Upgrade Pandas to 1.0.0 to avoid:
  matplotlib/matplotlib#12310
  pandas-dev/pandas#22859
* Switch to relying on `message` to determine if SGP4 failed.
* Spruce up the axis labelling, just for fun.
* Use the same plot in both places it’s discussed in the docs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Datetime Datetime data dtype Visualization plotting
Projects
None yet
Development

No branches or pull requests

7 participants