You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Matplotlib新增子图时报ValueError:图像像素尺寸过大问题求助

matplotlib多子图合并时Image size too large报错排查

问题现象

使用matplotlib的add_subplot函数将多个绘图合并到同一张画布时,抛出Image size pixels is too large错误,单个绘图均可正常生成,合并时触发异常。

复现代码

from matplotlib import pyplot as plt
import numpy as np
import os

def plot_in_subplots():
    fig = plt.figure(figsize=(15, 10))
    axis1 = fig.add_subplot(311)
    # 取消下一行注释复现报错
    # axis2 = fig.add_subplot(312)
    plot_bar_plot_in_given_axis(axis1)
    # plot_in_given_axis(axis2)
    figFile = os.path.join('/Users/burcakotlu/Desktop/Test_subplot.png')
    fig.savefig(figFile, dpi=100, bbox_inches="tight")
    plt.cla()
    plt.close(fig)

def plot_in_given_axis(ax):
    xticklabels_list = ['a','b','c','d','e','f'] * 6
    rows = ['row1']
    ax.set_xlim([0, 36])
    ax.set_xticklabels([])
    ax.tick_params(axis='x', which='minor', length=0, labelsize=35)
    ax.set_xticks(np.arange(0, 36, 1))
    ax.set_xticks(np.arange(0, 36, 1) + 0.5, minor=True)
    ax.set_xticklabels(xticklabels_list, minor=True)
    ax.xaxis.set_label_position('top')
    ax.xaxis.set_ticks_position('top')
    # 原代码此处为全局plt操作,改为ax调用
    ax.tick_params(
        axis='x',
        which='major',
        bottom=False,
        top=False
    )
    ax.set_ylim([0, len(rows)])
    ax.set_yticklabels([])
    ax.tick_params(axis='y', which='minor', length=0, labelsize=40)
    ax.set_yticks(np.arange(0, len(rows), 1))
    ax.set_yticks(np.arange(0, len(rows), 1) + 0.5, minor=True)
    ax.set_yticklabels(rows, minor=True)
    # 原代码此处为全局plt操作,改为ax调用
    ax.tick_params(
        axis='y',
        which='major',
        left=False
    )
    ax.grid(which='major', color='black', zorder=3)

def plot_bar_plot_in_given_axis(ax):
    x_axis_labels = ['a', 'b', 'c', 'd', 'e', 'f']
    real_values1 = [266655.0, 0.0, 14072.0, 4137.0, 6752.5, 0.0]
    real_values2 = [273342.5, 0.0, 12598.5, 4240.0, 7425.5, 0.0]
    unreal_values1 = [326188.16, 0.0, 15828.42, 4666.825000000001, 8109.87, 0.0]
    unreal_values2 = [344462.07, 0.0, 16368.664999999999, 5180.2, 8721.64, 0.0]
    q_values = [2.5309603790195403e-28, 1.0, 1.8194829804783173e-33, 0.003603381046779825, 1.0, 1.0]
    name1 = 'X'
    name2 = 'Y'
    color1 = 'r'
    color2 = 'b'
    width = 0.1
    ind = np.arange(len(x_axis_labels))
    legend = None
    rects3 = None
    rects4 = None
    rects1 = ax.bar(ind, real_values1, width=width, edgecolor='black', color=color1)
    rects2 = ax.bar(ind + width, real_values2, width=width, edgecolor='black', color=color2)
    if (unreal_values1 is not None) and unreal_values1:
        rects3 = ax.bar(ind + 2*width, unreal_values1, width=width, edgecolor='black', color=color1, hatch='X')
    if (unreal_values2 is not None) and unreal_values2:
        rects4 = ax.bar(ind + 3*width, unreal_values2, width=width, edgecolor='black', color=color2, hatch='X')
    ax.tick_params(axis='x', labelsize=35)
    ax.tick_params(axis='y', labelsize=35)
    # 原代码此处为全局plt.yticks,改为ax调用
    locs = ax.get_yticks()
    ax.set_ylim(0, locs[-1] + 5000)
    ax.set_title('%s vs. %s' % (name1, name2), fontsize=20, fontweight='bold')
    ax.set_xticklabels(x_axis_labels, fontsize=35)
    # 原代码此处为全局plt.ylabel,改为ax调用
    ax.set_ylabel('Y axis label', fontsize=35, fontweight='normal')
    ax.set_xticks(ind + (3 * width) / 2)
    realStrand1Name = 'Real %s' % (name1)
    realStrand2Name = 'Real %s' % (name2)
    simulationsStrand1Name = 'Unreal %s' % (name1)
    simulationsStrand2Name = 'Unreal %s' % (name2)
    if (rects1 is not None) and (rects2 is not None) and (rects3 is not None) and (rects4 is not None):
        if (len(rects1) > 0) and (len(rects2) > 0) and (len(rects3) > 0) and (len(rects4) > 0):
            legend = ax.legend((rects1[0], rects2[0], rects3[0], rects4[0]),
                               (realStrand1Name, realStrand2Name, simulationsStrand1Name, simulationsStrand2Name),
                               prop={'size': 25}, ncol=1, loc='best')
    ax.set_facecolor('white')
    ax.spines["bottom"].set_color('black')
    ax.spines["left"].set_color('black')
    ax.spines["top"].set_color('black')
    ax.spines["right"].set_color('black')
    if legend is not None:
        frame = legend.get_frame()
        frame.set_facecolor('white')
        frame.set_edgecolor('black')
    if q_values is not None:
        for q_value, rect1, rect2 in zip(q_values, rects1, rects2):
            y_value = max(rect1.get_height(), rect2.get_height())
            x_value = rect1.get_x() + rect1.get_width()
            space = 3
            va = 'bottom'
            if y_value < 0:
                space *= -1
                va = 'top'
            if (q_value is not None) and (q_value <= 0.05):
                # 原代码此处为全局plt.annotate,改为ax调用
                ax.annotate(
                    '***',
                    (x_value, y_value),
                    xytext=(0, space),
                    textcoords="offset points",
                    ha='center',
                    va=va,
                    fontsize=20
                )

plot_in_subplots()

报错信息

ValueError: Image size of 3719x61904113 pixels is too large. It must be less than 2^16 in each direction

待合并的两张示例图

绘图1
绘图2

问题原因

核心原因是代码混用了全局plt接口和指定子图ax接口的操作:当创建多个子图时,全局plt的操作默认作用在最后创建的子图上,会导致其他子图的轴边界、刻度等参数被异常修改,savefig传入bbox_inches="tight"时会自动计算画布所有内容的边界,异常的轴参数会导致计算出超大的画布尺寸,触发报错。

修复方案
  • 所有绘图操作全部绑定到传入的子图ax对象,不要使用全局plt接口操作指定子图的属性,上面代码块中已经标注了所有需要修改的位置
  • 可以根据布局需要适当调小刻度、标签的字号,避免自动边界计算时溢出
  • 如果不需要自动裁剪画布空白,可以直接去掉savefig的bbox_inches="tight"参数,也能避免该报错

内容的提问来源于stack exchange,提问作者burcak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 16:54:02