admin管理员组文章数量:1336304
I've got a dataframe I'd like to represent as a stacked bar chart, and a series that I'd like to represent as a line (but with a different scale). I'd like to draw these as a line chart (for the series) drawn on top of a bar chart (for the dataframe) with a shared x-axis (being the time indices).
Here's a toy example I tried:
import pandas as pd
import numpy as np
idx = pd.date_range(start='2000-01-01', periods=20)
df = pd.DataFrame(np.random.rand(20,3), index=idx)
ax = df.plot.bar(stacked=True)
series = pd.Series(np.random.rand(20), index=idx)
series.plot(ax=ax, secondary_y=True)
However, when I run this I get the following:
It's as if the line chart has overwritten the bar chart somehow. Interestingly, when I remove the index from the dataframe and series (making it just default integers), it seems to work:
What am I doing wrong? I'm using pandas 2.2.2
I've got a dataframe I'd like to represent as a stacked bar chart, and a series that I'd like to represent as a line (but with a different scale). I'd like to draw these as a line chart (for the series) drawn on top of a bar chart (for the dataframe) with a shared x-axis (being the time indices).
Here's a toy example I tried:
import pandas as pd
import numpy as np
idx = pd.date_range(start='2000-01-01', periods=20)
df = pd.DataFrame(np.random.rand(20,3), index=idx)
ax = df.plot.bar(stacked=True)
series = pd.Series(np.random.rand(20), index=idx)
series.plot(ax=ax, secondary_y=True)
However, when I run this I get the following:
It's as if the line chart has overwritten the bar chart somehow. Interestingly, when I remove the index from the dataframe and series (making it just default integers), it seems to work:
What am I doing wrong? I'm using pandas 2.2.2
Share Improve this question asked Nov 19, 2024 at 23:40 quantquant 23.2k36 gold badges131 silver badges222 bronze badges 2 |1 Answer
Reset to default 1To align both charts you can convert your index to strings, using DatetimeIndex.strftime
:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# `default_rng` now preferred random constructor
rng = np.random.default_rng(0)
# using `DatetimeIndex.strftime` to convert to strings
idx = pd.date_range(start='2000-01-01', periods=20).strftime('%Y-%m-%d')
df = pd.DataFrame(rng.random((20, 3)), index=idx)
# adding `alpha` to increase contrast example
ax = df.plot.bar(stacked=True, alpha=0.8)
# series = pd.Series(rng.random(20), index=idx)
# using `df.sum` to better showcase alignment data
series = df.sum(axis=1)
# adding `color` for contrast
series.plot(ax=ax, secondary_y=True, color='black')
# rotation for readability
ax.tick_params(axis='x', rotation=90)
plt.tight_layout()
plt.show()
Output:
The underlying issue here is that df.plot.bar
interprets idx
categorically, while df.plot.line
treats it as a continuous datetime x-axis. The conversion to strings aligns them.
This would also work:
idx = pd.date_range(start='2000-01-01', periods=20)
df = pd.DataFrame(rng.random((20, 3)), index=idx)
# map `series` by *position* to align with categorical x-axis of bar
series = df.sum(axis=1).set_axis(range(len(df)))
Though, as you can see from the result, you would still want strftime
for readability:
Output 2:
Aside: instead of ax.tick_params
, consider improving readability with a step for the labels, combining ax.set_xticks
and ax.set_xticklabels
.
# ax.tick_params(axis='x', rotation=90)
# rest as above
# use a step for the labels
step = 3
ticks = list(range(0, len(idx), step))
tick_labels = idx[ticks]
ax.set_xticks(ticks)
ax.set_xticklabels(tick_labels, rotation=45)
plt.tight_layout()
plt.show()
Output:
本文标签: pythonHow do I plot a line over a bar chart with pandasdate indexStack Overflow
版权声明:本文标题:python - How do I plot a line over a bar chart with pandasdate index? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742390790a2465947.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
reset_index
as you did, and manually assign xtick and xtick-label to each graph. Of course, this is cumbersome for dates. Hopefully there is a better solution, but if nothing else, this is the way to go. I'll also provide the code for the method I've suggested if there's no other answer when I see this later. – Panda Kim Commented Nov 19, 2024 at 23:51