如何将循环生成的matplotlib箱线图排布到指定子图网格
问题背景
我知晓该问题此前已被多次提问,但我耗费了大量时间仍未找到解决方案,尽管我确信其实现逻辑十分简单。我的数据来源于3个结构完全一致的独立DataFrame,为绘制箱线图,我已经完成了数据转置等预处理操作。
原有实现代码如下:
columnname = list(cm) max = len(columnname)-1 for i in range(0,max): cm2 = cm[columnname[i]] vz2 = vz[columnname[i]] models2 = models[columnname[i]] columns = [cm2, vz2, models2] name = str(cm2.name) fig, ax = plt.subplots() ax.boxplot(columns) ax.set_ylabel('$') ax.set_title(name)
遇到的问题:尝试直接在subplots中传入(2,4)参数将循环生成的图表排布到指定网格时,代码无法运行,抛出如下报错:
AttributeError: 'numpy.ndarray' object has no attribute 'boxplot'
报错原因
当给plt.subplots()传入多行多列的网格参数时,返回的坐标轴对象是对应网格结构的numpy数组,不是单个可直接调用绘图方法的坐标轴实例,直接对数组调用boxplot就会触发属性不存在的报错。另外原代码在每次循环内都新建独立画布,本身也无法实现多图排布到同一网格的效果。
解决方案
按以下步骤修改即可实现指定网格排布:
- 循环外提前初始化指定网格尺寸的画布和坐标轴组,按需设置画布大小避免内容拥挤
- 将二维结构的坐标轴数组展平为一维,方便循环时按顺序索引到单个子图的坐标轴
- 移除循环内新建画布的代码,每次循环取对应位置的单个坐标轴对象完成绘图
- 所有图绘制完成后自动调整子图间距,避免标题、标签互相遮挡
修改后的参考代码:
import matplotlib.pyplot as plt columnname = list(cm) # 初始化2行4列的子图网格,figsize可根据展示需求调整尺寸 fig, axes = plt.subplots(nrows=2, ncols=4, figsize=(16, 8)) # 将2*4的二维坐标轴数组展平为长度8的一维数组,方便按索引取值 axes = axes.flatten() for i in range(len(columnname)-1): cm2 = cm[columnname[i]] vz2 = vz[columnname[i]] models2 = models[columnname[i]] columns = [cm2, vz2, models2] name = str(cm2.name) # 取出当前循环对应的单个坐标轴对象 ax = axes[i] ax.boxplot(columns) ax.set_ylabel('$') ax.set_title(name) # 如果实际绘图数量少于网格总数(比如仅5张图),隐藏多余的空白子图 for j in range(len(columnname)-1, len(axes)): axes[j].axis('off') # 自动调整子图间距,避免文字遮挡 plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Dave_G7
相关产品推荐
相关产品推荐

