如何用Python和Matplotlib为双Y轴子图标注(数量,价格)有序对
双Y轴子图标注(y1,y2)形式有序对的问题与解决
问题说明
需为双Y轴子图标注(数量,价格)即(y1,y2)格式的标签:子图包含产品总数量柱状图、对应产品平均价格折线图,X轴为产品类别,Y1轴对应总数量,Y2轴对应平均价格。当前报错:变量label的列表元素不被识别为“可下标对象”,怀疑需将列表元素转为字符串,但不确定操作是否正确。
示例DataFrame
| Products | Quantity | Price |
|---|---|---|
| Product1 | 10 | 100.00 |
| Product2 | 15 | 200.00 |
| Product3 | 20 | 150.00 |
| Product2 | 30 | 200.00 |
| Product3 | 50 | 150.00 |
尝试的代码
quantity = df.groupby("Products")["Quantity"].sum() price = df.groupby("Products")["Price"].mean() fig, ax1 = plt.subplots() ax2 = ax1.twinx() ax1.bar(Products, quantity, color='.8', alpha =.8) ax2.plot(Products, price, 'bo-') ax1.set_xlabel('', fontweight='bold') ax1.set_ylabel('Quantity', color = 'k', fontweight='bold') ax2.set_ylabel('Price $', color = 'b', fontweight='bold') ax1.set_xticklabels(Products, rotation=45, size = 8) y1 = [i for i in quantity] y2 = [j for j in price] label = [] for x, y in zip(y1,y2): label.append(f"({x:.2f},{y:.2f})") for i, label in enumerate(labels): plt.annotate(label, xy=(x[i], y[i]), xytext=(5, 5), textcoords='offset points', ha='left', va='bottom') plt.show()
问题区域代码
# 找不到方法在label.append()中把列表元素从float转为字符串(其实f-string已经完成转换) label = [] for x, y in zip(y1,y2): label.append(f"({x:.2f},{y:.2f})")
错误原因与修正方案
核心错误点
- 变量名不一致:循环时用了
enumerate(labels),但实际定义的列表是label,拼写错误导致“可下标对象”报错。 - 坐标参数错误:
plt.annotate的xy参数需对应X轴位置(产品类别)和目标Y轴值(折线图的价格),原代码的x[i], y[i]完全不符合坐标逻辑。 - 误解字符串转换:你用的
f"({x:.2f},{y:.2f})"已经自动将float转为字符串,这部分操作是正确的,无需额外处理。
修正后的完整代码
import pandas as pd import matplotlib.pyplot as plt # 构造示例数据 data = { "Products": ["Product1", "Product2", "Product3", "Product2", "Product3"], "Quantity": [10,15,20,30,50], "Price": [100.00,200.00,150.00,200.00,150.00] } df = pd.DataFrame(data) # 分组计算 quantity = df.groupby("Products")["Quantity"].sum() price = df.groupby("Products")["Price"].mean() products = quantity.index # 创建双Y轴子图 fig, ax1 = plt.subplots() ax2 = ax1.twinx() # 绘制图形 ax1.bar(products, quantity, color='.8', alpha=.8) ax2.plot(products, price, 'bo-') # 设置轴标签 ax1.set_xlabel('', fontweight='bold') ax1.set_ylabel('Quantity', color='k', fontweight='bold') ax2.set_ylabel('Price $', color='b', fontweight='bold') ax1.set_xticklabels(products, rotation=45, size=8) # 生成标注文本(f-string自动完成转字符串) labels = [f"({qty:.0f}, {prc:.2f})" for qty, prc in zip(quantity, price)] # 标注每个点 for idx, (prod, prc) in enumerate(zip(products, price)): ax2.annotate(labels[idx], xy=(prod, prc), xytext=(5, 5), textcoords='offset points', ha='left', va='bottom') plt.tight_layout() plt.show()
关键修正细节
- 统一变量命名:将列表名改为
labels,确保循环时引用正确 - 修正标注坐标:X轴用产品类别,Y轴用对应平均价格(匹配ax2的轴数据)
- 确认字符串转换:f-string已完成数值到字符串的转换,无需额外操作
内容的提问来源于stack exchange,提问作者DerekJohn13
相关产品推荐
相关产品推荐

