添加plt.text()后图像尺寸超限报错,如何在柱线图显示数据标签?
柱状图+折线图添加数据标签时触发超大画布报错的解决方法
我有一个包含日期、成本和点击量的DataFrame,想绘制柱状图(展示点击量)+折线图(展示成本)的组合图表,同时在每个柱子和折线点上方显示对应的数据标签。但添加plt.text()循环代码后触发报错:"Image size of 2864591x628 pixels is too large. It must be less than 2^16 in each direction.",移除这段循环代码图表能正常显示,但看不到数据标签,求解决方法。
我的DataFrame数据
Day Cost Clicks 0 2022-07-20 8.17 37 1 2022-07-21 12.02 56 2 2022-07-22 15.30 96 3 2022-07-23 14.86 117 4 2022-07-24 16.44 145 5 2022-07-25 1.13 3 6 2022-07-26 0.00 0
数据类型
- Day:datetime64[ns]
- Cost:float64
- Clicks:int64
原代码(触发报错)
import matplotlib.pyplot as plt x = df['Day'] # 原代码中DayDate为笔误,实际应为Day y1 = df['Clicks'] y2 = df['Cost'] plt.figure(figsize=(20,10)) plt.title('Cost to Clicks', fontsize = 20, fontweight='bold') plt.xticks(fontsize = 20) plt.yticks(fontsize = 20) plt.xlabel('Date', fontsize = 20) plt.grid(axis = 'y') # 触发报错的代码段 for i in range(len(x)): plt.text(i,y1[i],y1[i], ha='center', va='top',fontsize=15, color='darkblue') plt.text(i,y2[i],y2[i], ha='center', va='bottom',fontsize=15, color='red') plt.bar(x,y1,color='cyan') plt.plot(x,y2,color='red',marker='o') plt.legend(['Cost','Clicks'], fontsize=15)
报错原因
核心问题是x轴使用了datetime类型数据,但plt.text()传入的x坐标是整数i。matplotlib会自动将datetime类型的x轴映射为从1970年到当前日期的毫秒级大数值,而你传入的i是0-6的小整数,这会让matplotlib误以为画布需要覆盖从极小整数到极大datetime数值的范围,从而生成超大尺寸的画布,触发报错。
修复方案(两种任选其一)
方法1:通过柱状图对象获取x坐标
先绘制柱状图,直接从柱子实例中读取每个柱子的x轴位置,避免坐标系统冲突:
import matplotlib.pyplot as plt x = df['Day'] y1 = df['Clicks'] y2 = df['Cost'] plt.figure(figsize=(20,10)) plt.title('Cost to Clicks', fontsize = 20, fontweight='bold') plt.xticks(fontsize = 20, rotation=45) # 旋转日期标签避免重叠 plt.yticks(fontsize = 20) plt.xlabel('Date', fontsize = 20) plt.grid(axis = 'y') # 绘制柱状图并获取柱子对象 bars = plt.bar(x, y1, color='cyan') # 给柱状图添加数据标签 for bar in bars: height = bar.get_height() plt.text(bar.get_x() + bar.get_width()/2., height, f'{height}', ha='center', va='top', fontsize=15, color='darkblue') # 绘制折线图并添加数据标签 line, = plt.plot(x, y2, color='red', marker='o') for xi, yi in zip(x, y2): plt.text(xi, yi, f'{yi:.2f}', ha='center', va='bottom', fontsize=15, color='red') plt.legend(['Cost','Clicks'], fontsize=15) plt.tight_layout() # 自动调整布局防止内容被截断 plt.show()
方法2:统一使用索引作为x轴坐标
将datetime列转换为自定义标签,x轴统一使用整数索引,确保坐标系统一致:
import matplotlib.pyplot as plt # 生成整数索引作为x轴坐标,格式化日期为显示标签 x_idx = range(len(df)) x_labels = df['Day'].dt.strftime('%Y-%m-%d') y1 = df['Clicks'] y2 = df['Cost'] plt.figure(figsize=(20,10)) plt.title('Cost to Clicks', fontsize = 20, fontweight='bold') plt.xticks(x_idx, x_labels, fontsize = 20, rotation=45) # 设置自定义日期标签 plt.yticks(fontsize = 20) plt.xlabel('Date', fontsize = 20) plt.grid(axis = 'y') # 添加数据标签 for i in x_idx: plt.text(i, y1[i], y1[i], ha='center', va='top', fontsize=15, color='darkblue') plt.text(i, y2[i], f'{y2[i]:.2f}', ha='center', va='bottom', fontsize=15, color='red') plt.bar(x_idx, y1, color='cyan') plt.plot(x_idx, y2, color='red', marker='o') plt.legend(['Cost','Clicks'], fontsize=15) plt.tight_layout() plt.show()
两种方法都能正常显示数据标签,且不会触发画布过大的报错,实现你期望的双图带标签效果。
内容的提问来源于stack exchange,提问作者Splatboy
相关产品推荐
相关产品推荐

