如何用Matplotlib将Pandas GroupBy结果绘制成并排折线图与柱状图?
问题
现有一个包含多列的DataFrame,希望将通过Pandas GroupBy分组后的结果,在同一张图片中并排展示折线图(呈现Score列数据)与柱状图(呈现Thumbs-up列数据)。目前编写的代码会生成两个独立的图表,无法实现同图并排的效果,请问使用Matplotlib如何正确实现该需求?
当前尝试的代码如下:
import matplotlib import matplotlib.pyplot as plt import pandas as pd import numpy as np from io import StringIO csvfile = StringIO( """ Name Year - Month Score Thumbs-up Mike 2022-09 192 5 Mike 2022-08 708 5 Mike 2022-07 140 3 Mike 2022-05 144 8 Mike 2022-04 60 10 Mike 2022-03 108 4 Kate 2022-07 19850 5 Kate 2022-06 19105 2 Kate 2022-05 23740 3 Kate 2022-04 19780 9 Kate 2022-03 15495 4 """ ) df = pd.read_csv(csvfile, sep = '\t', engine='python') for group_name, sub_frame in df.groupby("Name"): fig, axes = plt.subplots(nrows=1,ncols=2,figsize=(12,6)) sub_frame_sorted = sub_frame.sort_values('Year - Month') # sort the data-frame by a column line_chart = sub_frame_sorted.plot("Year - Month", "Score", legend=False) bar_chart = sub_frame_sorted.plot.bar("Year - Month", "Thumbs-up", legend=False) # for data labeling in the charts i=0 for ix, vl in sub_frame_sorted.iterrows(): line_chart.annotate(vl['Score'], (i, vl['Score']), ha='center') bar_chart.annotate(vl['Thumbs-up'], (i, vl['Thumbs-up']), ha='center') i=i+1 plt.show()
解决方法
问题出在你没给Pandas绘图指定具体的Matplotlib子图轴,每次调用plot都会自动创建新图表。只要把plt.subplots生成的子图轴对象传给plot的ax参数,就能让折线图和柱状图并排显示在同一张画布上。
修正后的完整代码:
import matplotlib.pyplot as plt import pandas as pd from io import StringIO csvfile = StringIO( """ Name Year - Month Score Thumbs-up Mike 2022-09 192 5 Mike 2022-08 708 5 Mike 2022-07 140 3 Mike 2022-05 144 8 Mike 2022-04 60 10 Mike 2022-03 108 4 Kate 2022-07 19850 5 Kate 2022-06 19105 2 Kate 2022-05 23740 3 Kate 2022-04 19780 9 Kate 2022-03 15495 4 """ ) df = pd.read_csv(csvfile, sep='\t', engine='python') for group_name, sub_frame in df.groupby("Name"): # 创建1行2列的子图布局,获取两个轴对象 fig, (ax_line, ax_bar) = plt.subplots(nrows=1, ncols=2, figsize=(12, 6)) sub_frame_sorted = sub_frame.sort_values('Year - Month') # 将折线图绘制到第一个子图轴ax_line上 sub_frame_sorted.plot(x="Year - Month", y="Score", kind='line', legend=False, ax=ax_line) # 将柱状图绘制到第二个子图轴ax_bar上 sub_frame_sorted.plot(x="Year - Month", y="Thumbs-up", kind='bar', legend=False, ax=ax_bar) # 为折线图添加数据标注 for i, vl in enumerate(sub_frame_sorted['Score']): ax_line.annotate(str(vl), (i, vl), ha='center', va='bottom') # 为柱状图添加数据标注 for i, vl in enumerate(sub_frame_sorted['Thumbs-up']): ax_bar.annotate(str(vl), (i, vl), ha='center', va='bottom') # 为子图添加标题,区分不同分组 ax_line.set_title(f"{group_name} - Score Trend") ax_bar.set_title(f"{group_name} - Thumbs-up Count") # 调整子图间距,避免标签重叠 plt.tight_layout() plt.show()
关键改动点
- 绑定子图轴:通过
ax参数把折线图、柱状图分别指定到预先创建的两个子图上,确保它们在同一张图里。 - 优化标注逻辑:用
enumerate遍历数据,替代手动计数,代码更简洁。 - 添加子图标题:给每个子图加上对应分组的标题,直观区分内容。
- 自动调整布局:调用
tight_layout()避免标签、标题互相遮挡。
内容的提问来源于stack exchange,提问作者Mark K
相关产品推荐
相关产品推荐

