如何修正Matplotlib与Pandas GroupBy折线图添加数据标签的报错?
为Pandas分组后的折线图添加数据标签的代码修正
问题描述
用户编写了以下代码,试图为Pandas GroupBy分组后绘制的Matplotlib折线图添加数据标签,但运行时抛出错误:
import matplotlib.pyplot as plt import pandas as pd from io import StringIO csvfile = StringIO( """ Name Year - Month Score Mike 2022-09 192 Mike 2022-08 708 Mike 2022-07 140 Mike 2022-05 144 Mike 2022-04 60 Mike 2022-03 108 Kate 2022-07 19850 Kate 2022-06 19105 Kate 2022-05 23740 Kate 2022-04 19780 Kate 2022-03 15495 Peter 2022-08 51 Peter 2022-07 39 Peter 2022-06 49 Peter 2022-05 49 Peter 2022-04 79 Peter 2022-03 13 Lily 2022-11 2 David 2022-11 3 David 2022-10 6 David 2022-08 2""") df = pd.read_csv(csvfile, sep = '\t', engine='python') for group_name, sub_frame in df.groupby("Name"): if sub_frame.shape[0] >= 2: 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") label = sub_frame_sorted['Score'] line_chart.annotate(label, (sub_frame_sorted['Year - Month'], sub_frame_sorted['Score']), ha='center') plt.show()
错误信息
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
修正方案
错误根源在于matplotlib.axes.Axes.annotate()方法只能处理单个数据点的标注,不能直接传入Pandas Series作为参数。需要遍历排序后的数据框中的每一行,为每个点单独添加标签。
修正后的代码如下:
import matplotlib.pyplot as plt import pandas as pd from io import StringIO csvfile = StringIO( """ Name Year - Month Score Mike 2022-09 192 Mike 2022-08 708 Mike 2022-07 140 Mike 2022-05 144 Mike 2022-04 60 Mike 2022-03 108 Kate 2022-07 19850 Kate 2022-06 19105 Kate 2022-05 23740 Kate 2022-04 19780 Kate 2022-03 15495 Peter 2022-08 51 Peter 2022-07 39 Peter 2022-06 49 Peter 2022-05 49 Peter 2022-04 79 Peter 2022-03 13 Lily 2022-11 2 David 2022-11 3 David 2022-10 6 David 2022-08 2""") df = pd.read_csv(csvfile, sep = '\t', engine='python') for group_name, sub_frame in df.groupby("Name"): if sub_frame.shape[0] >= 2: sub_frame_sorted = sub_frame.sort_values('Year - Month') line_chart = sub_frame_sorted.plot("Year - Month", "Score", title=f"Score Trend for {group_name}") # 遍历每一行,逐个添加数据标签 for x, y in zip(sub_frame_sorted['Year - Month'], sub_frame_sorted['Score']): line_chart.annotate(str(y), (x, y), ha='center', va='bottom', fontsize=8) plt.tight_layout() plt.show()
关键修改点
- 用
zip()将x轴(年份月份)和y轴(分数)的元素一一配对,遍历每个数据点 - 调用
annotate()时传入单个的标签值(转为字符串避免格式问题)、单个坐标点 - 添加
va='bottom'参数让标签在数据点上方显示,避免重叠;可选调整fontsize让标签更美观 - 为每个子图添加标题,区分不同用户的趋势图
- 加入
plt.tight_layout()自动调整子图间距,防止标签或标题被截断
内容的提问来源于stack exchange,提问作者Mark K
相关产品推荐
相关产品推荐

