解决3×4子图循环绘制的索引错误并移除空白子图
解决3×4面板图的索引错误与空白子图问题
问题原因
- 你设置了3行4列共12个子图,但只有11列数据,循环执行12次时,第12次循环(
m=11)会访问fname_col[11],而fname_col长度为11,索引仅到10,触发IndexError。 - 最后一个子图因无数据可绘制,呈现空白。
修复方案
修改循环逻辑,仅对有数据的子图绘图,超出数据数量的子图直接移除:
修改后的代码
import matplotlib.pyplot as plt import pandas as pd from math import ceil csv_path_cont = 'path_to_my_data/data.csv' fname = pd.read_csv(csv_path_cont) fname['time'] = pd.to_datetime(fname['time']) fname['month'] = fname['time'].dt.strftime('%b') # 修正索引设置:set_index默认返回新对象,需赋值或加inplace=True fname = fname.set_index('time') #=== 设置3x4面板图 fname_col = fname.columns[1:-2] month_name = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] cols = 4 rows = ceil(len(fname_col) / cols) fig, ax = plt.subplots(rows, cols, figsize=(45,24)) m = 0 # 将二维子图数组展平,简化遍历 for sub_ax in ax.flat: if m < len(fname_col): # 绘制当前列的月度柱状图 event_occurrence = fname[[fname_col[m],'month']][fname[fname_col[m]]>0] num_event = event_occurrence.groupby('month').count().reindex(month_name) num_event = num_event.fillna(0) sub_ax.bar(num_event.index, num_event[fname_col[m]]) # 给子图设置对应列名的标题 sub_ax.set_title(fname_col[m]) m += 1 else: # 移除空白子图 sub_ax.remove() # 调整子图间距,避免标题与图表重叠 fig.tight_layout() fig.savefig('bar_chart', dpi=300)
关键修改点
- 修复索引越界:通过
if m < len(fname_col)判断,仅在有数据时执行绘图逻辑,避免访问超出范围的列索引。 - 移除空白子图:对超出数据数量的子图调用
sub_ax.remove()直接删除,也可替换为sub_ax.axis('off')隐藏(保留空白区域)。 - 优化遍历逻辑:用
ax.flat将二维子图数组展平,无需嵌套循环,代码更简洁易维护。 - 修正标题设置:将全局的
plt.title(m)改为子图的sub_ax.set_title(),确保每个子图标题对应列名,更清晰。 - 修正索引赋值:
fname.set_index('time')需赋值给原变量,否则原DataFrame的索引不会被修改。
内容的提问来源于stack exchange,提问作者hilorywilsmart
相关产品推荐
相关产品推荐

