Repository: pandas-dev/pandas

Issue:
plotting mangled with DatetimeIndex to ax with sharex and dissimilar indices
You can't see anything in the ax1 plot.

```
import pylab
import pandas as pd
pylab.ion(); pylab.show()
idx1 = pd.date_range('2015-01-01', periods=3, freq='1M')
idx2 = idx1[:1] + idx1[2:]
series1 = pd.Series(range(len(idx1)), idx1)
series2 = pd.Series(range(len(idx2)), idx2)


# this doesn't work
pylab.figure()
ax1 = pylab.subplot(211)
series1.plot(ax=ax1)
ax2 = pylab.subplot(212, sharex=ax1)
series2.plot(ax=ax2)

# this works
pylab.figure()
ax3 = pylab.subplot(211)
pylab.plot(series1.index, series1.values)
ax4 = pylab.subplot(212, sharex=ax3)
pylab.plot(series2.index, series2.values)
```

Issue seems to be with how its converting xdata

```
for ax in (ax1, ax2, ax3, ax4):
    print(ax.get_lines()[0].get_xdata())

[Period('2015-01', 'M') Period('2015-02', 'M') Period('2015-03', 'M')]
[datetime.datetime(2015, 1, 31, 0, 0) datetime.datetime(2015, 3, 31, 0, 0)]
['2015-01-31T00:00:00.000000000+0000' '2015-02-28T00:00:00.000000000+0000'
 '2015-03-31T00:00:00.000000000+0000']
['2015-01-31T00:00:00.000000000+0000' '2015-03-31T00:00:00.000000000+0000']

str(ax2.get_xticklabels()[0])
"Text(735636,0,'63273')"

str(ax4.get_xticklabels()[0])
"Text(735630,0,'Feb 01 2015')"
```

```
INSTALLED VERSIONS
------------------
commit: None
python: 3.4.4.final.0
python-bits: 64
OS: Linux
OS-release: 3.14.32-pv-ts1
machine: x86_64
processor:
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8

pandas: 0.18.0
nose: None
pip: 8.1.1
setuptools: 20.7.0
Cython: 0.24
numpy: 1.10.4
scipy: 0.17.0
statsmodels: 0.6.1
xarray: None
IPython: 4.2.0
sphinx: 1.4.1
patsy: 0.4.1
dateutil: 2.5.2
pytz: 2016.3
blosc: None
bottleneck: 1.0.0
tables: 3.2.2
numexpr: 2.5.2
matplotlib: 1.5.1
openpyxl: 2.3.2
xlrd: 0.9.4
xlwt: None
xlsxwriter: 0.8.5
lxml: None
bs4: 4.4.1
html5lib: None
httplib2: None
apiclient: None
sqlalchemy: 1.0.12
pymysql: None
psycopg2: None
jinja2: 2.8
boto: None
```

BUG in plotting timeseries data with twinx (different data representation on each ax)
Simplified the example.
During issue reporting i updated my pandas version from 0.13 to 0.18.1 - with version 0.13 i was able to add the whole DataFrame to my plot, only after i selected some rows between dates it produces the error. After the update the behaviour became worse - also adding the whole DataFrame to the plot now produces the error.
#### A small, complete example of the issue

``` python
import pandas
import dateutil.parser
import matplotlib.pyplot as plt

p_vals = {
    'x_vals' : [
        "2006-12-17 00:00:00+01:00",
        "2006-12-18 00:00:00+01:00",
        "2006-12-19 00:00:00+01:00",
        "2006-12-20 00:00:00+01:00",
        "2006-12-21 00:00:00+01:00",
        "2006-12-22 00:00:00+01:00",
        "2006-12-23 00:00:00+01:00",
        "2006-12-24 00:00:00+01:00",
        "2006-12-25 00:00:00+01:00",
        "2006-12-26 00:00:00+01:00",
    ],
    'y_vals' : [
        10,9,8,7,6,5,4,3,2,1
    ]
}

p_vals2 = {
    'x_vals' : [
        "2006-12-17 00:00:00+01:00",
        "2006-12-18 00:00:00+01:00",
        "2006-12-19 00:00:00+01:00",
        "2006-12-20 00:00:00+01:00",
        "2006-12-21 00:00:00+01:00",
    ],
    'y_vals' : [
        1,2,3,4,5
    ]
}

p_vals['x_vals'] = [ dateutil.parser.parse(x) for x in p_vals['x_vals'] ]
p_vals2['x_vals'] = [ dateutil.parser.parse(x) for x in p_vals2['x_vals'] ]

df = pandas.DataFrame(data = [1,2,3,4,5], index=["2006-12-17","2006-12-18","2006-12-19","2006-12-20","2006-12-21"])
df.index = pandas.to_datetime(df.index, format="%Y-%m-%d")

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()

ax1.plot(p_vals['x_vals'], p_vals['y_vals'], color="r")
#ax2.plot(p_vals2['x_vals'], p_vals2['y_vals'], color="b") # works as intended, see second attached image
df.plot(ax=ax2, color="b") # hides data on ax1, see first image

plt.show()

```
#### Expected Output
#### Output of `pd.show_versions()`

<details>
## INSTALLED VERSIONS

commit: None
python: 3.4.3.final.0
python-bits: 64
OS: Linux
OS-release: 3.19.0-69-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8

pandas: 0.18.1
nose: 1.3.1
pip: 8.1.2
setuptools: 3.3
Cython: None
numpy: 1.11.1
scipy: 0.13.3
statsmodels: None
xarray: None
IPython: 1.2.1
sphinx: None
patsy: None
dateutil: 2.5.3
pytz: 2016.6.1
blosc: None
bottleneck: None
tables: 3.1.1
numexpr: 2.2.2
matplotlib: 1.5.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: 4.2.1
html5lib: 0.999
httplib2: None
apiclient: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
boto: None
pandas_datareader: None
![pandas_how_it_looks](https://cloud.githubusercontent.com/assets/5508360/19013316/a0f93098-87cd-11e6-9450-b1184d3a3b44.png)
![pandas_how_it_should_look](https://cloud.githubusercontent.com/assets/5508360/19013317/a595e484-87cd-11e6-8a6a-a2b842bff8a9.png)

</details>



Discussion:
Workaround: plot the shared axis' data to the new axis, clear the new axis, then plot the new data to the new axis

```
import pylab
import pandas as pd
pylab.ion(); pylab.show()
idx1 = pd.date_range('2015-01-01', periods=3, freq='1M')
idx2 = idx1[:1] + idx1[2:]
series1 = pd.Series(range(len(idx1)), idx1)
series2 = pd.Series(range(len(idx2)), idx2)

pylab.figure()
ax1 = pylab.subplot(211)
series1.plot(ax=ax1)
ax2 = pylab.subplot(212, sharex=ax1)
series1.plot(ax=ax2)
ax2.clear()
series2.plot(ax=ax2)
```

I can confirm this with 0.18.1.

```
import pandas as pd
import matplotlib.pyplot as plt

idx1 = pd.date_range('2015-01-01', periods=3, freq='1M')
idx2 = idx1[:1] + idx1[2:]
series1 = pd.Series(range(len(idx1)), idx1)
series2 = pd.Series(range(len(idx2)), idx2)

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
series1.plot(ax=ax1)
series2.plot(ax=ax2, x_compat=True)
plt.show()
```

The above kills the python process for me.

The reason is probably the combination of the regular and irregular (as you mention, they are processed differently: the first is converted to periods, the second not), but not sure why this kills the python process here.

Some related issues: https://github.com/pydata/pandas/issues/6608, https://github.com/pydata/pandas/issues/9053

FYI: my workaround didn't work an a different dataset.  Not sure what changed, but guessing something to do with xlimits of the data.

Pandas 0.13 is quite old, can you try with a more recent version? Also see if you can simplify your example a bit.

> also the x label look strange.

What do you mean by strange?

i just updated to pandas: 0.18.1 - sry for not trying with updated panda version
now both of my plot calls hide the data on the first axis.

sorry for my bad wording - by strange i meant, just, that is looks different

@cygenb0ck Can you try to simplify the example? Eg try to make it reproducible by not having to read a csv file but just create the data with code. Also try to remove other things that are not essential to the problem as much as possible.

@jorisvandenbossche 
simplified the example and changed the subject

@cygenb0ck Thanks a lot! That let me look at it, and it's a bit a gotcha with the dates.

To start, it's not an issue with the `twinx`. Eg if you try the following similar example (but without using datetimes), you will see it works as expected:

```
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()

ax1.plot([1,3,2], color="r")

df3 = pd.DataFrame({'col': [2,5,1]})
df3.plot(ax=ax2, color="b")
# df3['col'].plot(ax=ax2, color="b") # to plot one column not full dataframe
```

The reason it does not work with the example data you gave, is not because the plot is overwritten, but because the data on the first ax now fall outside the visible plot (if you zoom out enough, you will see both lines). This is because the dates are handled differently in the two cases. 
The reason for that is a problem in pandas' plotting machinery to combine both irregular and regular time series in one plot (and because your data on ax1 have hours (although daily freq), they are regarded as irregular, the data on ax2 are regular). Related issues are #6608, #9053, #13341. We should definitely solve this ... 
However, in this case it seems also specific to using twinx, as not using this does also solve the issue (then the second data are plotted fine).

Workaround you can use for now is by also plotting on `ax2` with the matplotlib `plot` call:

```
fig, ax1 = plt.subplots()
ax1.plot(p_vals['x_vals'], p_vals['y_vals'], color="r")
ax2 = ax1.twinx()
ax2.plot(df.index, df[0].values, color="b")
```

Apparently, using `x_compat=True` is also a way to get this working:

```
fig, ax1 = plt.subplots()
ax1.plot(p_vals['x_vals'], p_vals['y_vals'], color="r")
ax2 = ax1.twinx()
df.plot(ax=ax2, x_compat=True, color="b")
```

It's mentioned in the docs: http://pandas.pydata.org/pandas-docs/stable/visualization.html#suppressing-tick-resolution-adjustment (although for another reason, I am not that familiar with this keyword)


Resolving patch:
diff --git a/pandas/tseries/plotting.py b/pandas/tseries/plotting.py
--- a/pandas/tseries/plotting.py
+++ b/pandas/tseries/plotting.py
@@ -162,18 +162,37 @@ def _decorate_axes(ax, freq, kwargs):
     ax.date_axis_info = None
 
 
-def _get_freq(ax, series):
-    # get frequency from data
-    freq = getattr(series.index, 'freq', None)
-    if freq is None:
-        freq = getattr(series.index, 'inferred_freq', None)
-
+def _get_ax_freq(ax):
+    """
+    Get the freq attribute of the ax object if set.
+    Also checks shared axes (eg when using secondary yaxis, sharex=True
+    or twinx)
+    """
     ax_freq = getattr(ax, 'freq', None)
     if ax_freq is None:
+        # check for left/right ax in case of secondary yaxis
         if hasattr(ax, 'left_ax'):
             ax_freq = getattr(ax.left_ax, 'freq', None)
         elif hasattr(ax, 'right_ax'):
             ax_freq = getattr(ax.right_ax, 'freq', None)
+    if ax_freq is None:
+        # check if a shared ax (sharex/twinx) has already freq set
+        shared_axes = ax.get_shared_x_axes().get_siblings(ax)
+        if len(shared_axes) > 1:
+            for shared_ax in shared_axes:
+                ax_freq = getattr(shared_ax, 'freq', None)
+                if ax_freq is not None:
+                    break
+    return ax_freq
+
+
+def _get_freq(ax, series):
+    # get frequency from data
+    freq = getattr(series.index, 'freq', None)
+    if freq is None:
+        freq = getattr(series.index, 'inferred_freq', None)
+
+    ax_freq = _get_ax_freq(ax)
 
     # use axes freq if no data freq
     if freq is None:
@@ -191,7 +210,7 @@ def _get_freq(ax, series):
 
 def _use_dynamic_x(ax, data):
     freq = _get_index_freq(data)
-    ax_freq = getattr(ax, 'freq', None)
+    ax_freq = _get_ax_freq(ax)
 
     if freq is None:  # convert irregular if axes has freq info
         freq = ax_freq
@@ -244,7 +263,7 @@ def _maybe_convert_index(ax, data):
             freq = freq.rule_code
 
         if freq is None:
-            freq = getattr(ax, 'freq', None)
+            freq = _get_ax_freq(ax)
 
         if freq is None:
             raise ValueError('Could not get frequency alias for plotting')


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
@@ -778,6 +778,41 @@ def test_mixed_freq_irreg_period(self):
         irreg.plot()
         ps.plot()
 
+    def test_mixed_freq_shared_ax(self):
+
+        # GH13341, using sharex=True
+        idx1 = date_range('2015-01-01', periods=3, freq='M')
+        idx2 = idx1[:1].union(idx1[2:])
+        s1 = Series(range(len(idx1)), idx1)
+        s2 = Series(range(len(idx2)), idx2)
+
+        fig, (ax1, ax2) = self.plt.subplots(nrows=2, sharex=True)
+        s1.plot(ax=ax1)
+        s2.plot(ax=ax2)
+
+        self.assertEqual(ax1.freq, 'M')
+        self.assertEqual(ax2.freq, 'M')
+        self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
+                         ax2.lines[0].get_xydata()[0, 0])
+
+        # using twinx
+        fig, ax1 = self.plt.subplots()
+        ax2 = ax1.twinx()
+        s1.plot(ax=ax1)
+        s2.plot(ax=ax2)
+
+        self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
+                         ax2.lines[0].get_xydata()[0, 0])
+
+        # TODO (GH14330, GH14322)
+        # plotting the irregular first does not yet work
+        # fig, ax1 = plt.subplots()
+        # ax2 = ax1.twinx()
+        # s2.plot(ax=ax1)
+        # s1.plot(ax=ax2)
+        # self.assertEqual(ax1.lines[0].get_xydata()[0, 0],
+        #                  ax2.lines[0].get_xydata()[0, 0])
+
     @slow
     def test_to_weekly_resampling(self):
         idxh = date_range('1/1/1999', periods=52, freq='W')