Repository: pandas-dev/pandas

Issue:
Can't pickle plots from dataframes with date indexes
Already report this at https://github.com/matplotlib/matplotlib/issues/9828, but it appears that that issue is caused by pandas using a lambda in the format_dateaxis function. I don't know if there is a way around this, but it prevents pandas-produced matplotlib figures from being pickled.

### MPL Bug report

Trying to pickle a figure that was produced using pandas.plot(), which includes a datetime index. Not sure if this is a pandas bug, or MPL.

Here's an example:
```
In [81]: sample
Out[81]: 
time
2002-07-28 08:00:00    0.0
2002-07-28 08:30:00    0.0
2002-07-28 09:00:00    0.0
2002-07-28 09:30:00    0.0
2002-07-28 10:00:00    0.0
2002-07-28 10:30:00    0.0
2002-07-28 11:00:00    0.0
2002-07-28 11:30:00    0.0
2002-07-28 12:00:00    0.0
2002-07-28 12:30:00    0.0
2002-07-28 13:00:00    0.0
2002-07-28 13:30:00    0.0
2002-07-28 14:00:00    0.0
2002-07-28 14:30:00    0.0
2002-07-28 15:00:00    0.0
2002-07-28 15:30:00    0.0
2002-07-28 16:00:00    NaN
2002-07-28 16:30:00    0.0
2002-07-28 17:00:00    0.0
2002-07-28 17:30:00    0.0
Name: Qle_qc, dtype: float64

In [82]: sample.plot()
Out[82]: <matplotlib.axes._subplots.AxesSubplot at 0x7fd5c06a1f60>

In [83]: fig = gcf()

In [84]: pickle.dump(fig, open('test.pkl', 'wb'))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/data/documents/uni/phd/projects/FluxnetTrafficLights/scripts/analysis/site_predictability.py in <module>()
----> 1 pickle.dump(fig, open('test.pkl', 'wb'))

AttributeError: Can't pickle local object 'format_dateaxis.<locals>.<lambda>'

In [85]: pickle.dump(sample, open('sample.pkl', 'wb'))

```

I've tried this with a manually constructed DF, and it worked, so I'm not sure why this is happening. I'm including a pickle of the above sample DF for investigation. It is originally a slice from an xarray, from a netcdf dataset.
[sample.pkl.gz](https://github.com/matplotlib/matplotlib/files/1493592/sample.pkl.gz)


**Matplotlib version**

Using Conda on linux (kubuntu 17.10):

```
ipython                   6.1.0                    py36_0  
matplotlib                2.1.0            py36hba5de38_0
pandas                    0.20.3                   py36_0  

MPL backend: Qt5Agg
```


Discussion:
@naught101 Thanks for reporting this issue.
Your data reproduce the error in my environment, but I cannot create the simple code which reproduce this. Do you have any idea?
Got it. Simple repro. code. The index which length `<= 2` does not repro.
```python
import pandas as pd
from matplotlib import pyplot as plt
import numpy
import pickle
%matplotlib inline

idx = pd.DatetimeIndex(['2002-07-28 08:00:00', '2002-07-28 08:30:00', '2002-07-28 09:00:00'])
s = pd.Series([1, 2, 3], index=idx)

s.plot()
fig = plt.gcf()

pickle.dump(fig, open('test.pkl', 'wb'))
```
Seems that this sets the lambda function.
https://github.com/pandas-dev/pandas/blob/c8dafb5a7ae9fe42b9d15c47082a6fb139e78b5d/pandas/plotting/_timeseries.py#L330

Resolving patch:
diff --git a/pandas/plotting/_timeseries.py b/pandas/plotting/_timeseries.py
--- a/pandas/plotting/_timeseries.py
+++ b/pandas/plotting/_timeseries.py
@@ -1,5 +1,7 @@
 # TODO: Use the fact that axis can have units to simplify the process
 
+import functools
+
 import numpy as np
 
 from matplotlib import pylab
@@ -293,6 +295,10 @@ def format_timedelta_ticks(x, pos, n_decimals):
     return s
 
 
+def _format_coord(freq, t, y):
+    return "t = {0}  y = {1:8f}".format(Period(ordinal=int(t), freq=freq), y)
+
+
 def format_dateaxis(subplot, freq, index):
     """
     Pretty-formats the date axis (x-axis).
@@ -327,8 +333,7 @@ def format_dateaxis(subplot, freq, index):
         subplot.xaxis.set_minor_formatter(minformatter)
 
         # x and y coord info
-        subplot.format_coord = lambda t, y: (
-            "t = {0}  y = {1:8f}".format(Period(ordinal=int(t), freq=freq), y))
+        subplot.format_coord = functools.partial(_format_coord, freq)
 
     elif isinstance(index, TimedeltaIndex):
         subplot.xaxis.set_major_formatter(


Test patch:
diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py
--- a/pandas/tests/plotting/test_datetimelike.py
+++ b/pandas/tests/plotting/test_datetimelike.py
@@ -1,13 +1,14 @@
 """ Test cases for time series specific (freq conversion, etc) """
 
 from datetime import datetime, timedelta, date, time
+import pickle
 
 import pytest
 from pandas.compat import lrange, zip
 
 import numpy as np
 from pandas import Index, Series, DataFrame, NaT
-from pandas.compat import is_platform_mac
+from pandas.compat import is_platform_mac, PY3
 from pandas.core.indexes.datetimes import date_range, bdate_range
 from pandas.core.indexes.timedeltas import timedelta_range
 from pandas.tseries.offsets import DateOffset
@@ -1470,5 +1471,12 @@ def _check_plot_works(f, freq=None, series=None, *args, **kwargs):
 
         with ensure_clean(return_filelike=True) as path:
             plt.savefig(path)
+
+        # GH18439
+        # this is supported only in Python 3 pickle since
+        # pickle in Python2 doesn't support instancemethod pickling
+        if PY3:
+            with ensure_clean(return_filelike=True) as path:
+                pickle.dump(fig, path)
     finally:
         plt.close(fig)