4

I am trying to plot a bar chart and a line overlay, where my data has datetime as an index. This is the code:

import pandas as pd
import numpy as np
dates = pd.date_range('2019-01-01', '2019-01-31', freq='B')
df = pd.DataFrame(index=dates, 
              columns=['a', 'b', 'c'],
              data = np.random.randn(len(dates), 3))

fig, ax = plt.subplots()
df.plot.bar(ax=ax)
df.sum(axis=1).plot(ax=ax)

Unfortunately, it only ends up showing the last chart requested. enter image description here

I'm using

python 3.6.8
pandas 0.24.0
matplotlib 3.0.2

Regards

Tanguy Bretagne
  • 440
  • 5
  • 15
  • Do you use it in a notebook? – MisterMonk Feb 01 '19 at 11:48
  • For me, it shows only the first graph (bar chart) on matplotlib 2.2.2 – Sheldore Feb 01 '19 at 12:03
  • 1
    According to a comment [here](https://stackoverflow.com/a/23482318/2454357) it has something to do with the index. If I set `use_index=False` in both plot commands, both the bars and the line are visible, but then the xticks are just numbers from 0 to 22. – Thomas Kühn Feb 01 '19 at 12:07
  • 3
    Pandas bar plots are categorical in nature, they put bars as successive integer positions. Hence to draw a line plot in the same axis, the line plot would need to be categorical as well. This can be achieved with `use_index=False` as commented above. So the solution is to replace the last line with `df.sum(axis=1).plot(ax=ax, use_index=False)`. – ImportanceOfBeingErnest Feb 01 '19 at 13:26
  • @ImportanceOfBeingErnest I did this, but it changed the format of the xticks in direction 'much uglier', which most likely means that in addition to the `use_index=False` the final solution should also include proper date formatting for the xticks (which is, of course, also findable on SO). – Thomas Kühn Feb 01 '19 at 13:45
  • Point is, applying date formatting for the categorical ticklabel strings a posteriori is kind of hacky (loop through them, convert strings to datetime, format datetime back to strings), so I suppose one would rather convert the index to nice string representations *before* plotting. – ImportanceOfBeingErnest Feb 01 '19 at 13:52
  • 1
    I believe the most panda-esque way to deal with the problem is to use @ImportanceOfBeingErnest tip of `use_index=False` – Tanguy Bretagne Feb 01 '19 at 14:17

2 Answers2

7

Following the comment by @ImportanceOfBeingErnest I think the best way to answer this is to use the use_index=False kwarg. For the data format etc, this is another problem and depends on what one wants to achieve.

import pandas as pd
import numpy as np
dates = pd.date_range('2019-01-01', '2019-01-31', freq='B')
df = pd.DataFrame(index=dates,
                  columns=['a', 'b', 'c'],
                  data = np.random.randn(len(dates), 3))

fig, ax = plt.subplots()
df.plot.bar(ax=ax)
df.sum(axis=1).plot(ax=ax, use_index=False)

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
Tanguy Bretagne
  • 440
  • 5
  • 15
  • 2
    I swear for a moment I thought the figure is a laptop ;) – Sheldore Feb 01 '19 at 22:35
  • If you are happy with this solution, consider accepting it (even though it's your own answer), so that other people know that the question needs no further attention. – Thomas Kühn Feb 02 '19 at 12:17
-2

You can do it like that:

fig = plt.figure()
ax = df.plot.bar()
ax2 = ax.twinx()
ax2.plot(df.sum(axis=1).values)
plt.show()

df.plot.bar returns an axis you can use for the next plot:

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html#pandas-dataframe-plot

Also discussed:

How to align the bar and line in matplotlib two y-axes chart?

Plot Pandas DataFrame as Bar and Line on the same one chart

enter image description here

MisterMonk
  • 327
  • 1
  • 9