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

Matplotlib如何优雅合并饼图直方图子图并导出为单张PNG文件

解决方案

方案1:调整单画布网格布局(推荐)

你之前使用2行4列的均匀网格布局,第一行仅使用前3个子图位置,剩余1个空白位置会导致布局算法自动分配多余的垂直空间,是两行之间留白过大的核心原因。可以通过GridSpec自定义非均匀网格布局,分别设置两行的列数和高度比例,完美匹配3个饼图+4个直方图的需求:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import seaborn as sn

# 生成测试数据
histo_1 = np.random.choice(500, 100, replace=True)
histo_2 = np.random.choice(250, 7000, replace=True)
histo_3 = np.random.choice(150, 1500, replace=True)
histo_4 = np.random.choice(2000, 250, replace=True)

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]

sn.set()
sn.color_palette("hls", 8)

# 创建画布,自定义网格
fig = plt.figure(figsize=(16, 12))
# 定义GridSpec:2行,最大列数4,设置两行高度比例为1:0.9,可根据实际效果调整
gs = gridspec.GridSpec(2, 4, height_ratios=[1, 0.9], hspace=0.2) # hspace控制两行垂直间距,数值越小间距越小

# 第一行3个饼图,分别占用(0,0),(0,1),(0,2)位置
for i in range(3):
    ax = fig.add_subplot(gs[0, i])
    ax.pie(sizes, labels=labels, autopct='%1.1f%%', textprops={'fontsize': 13})
    ax.set_title("Distribution")

# 第二行4个直方图,占用第1行全部4个位置
hist_list = [histo_1, histo_2, histo_3, histo_4]
color_list = ["cornflowerblue", "indianred", "seagreen", "peru"]
title_list = ["Distribution 1", "Distribution 2", "Distribution 3", "Distribution 4"]

for i in range(4):
    ax = fig.add_subplot(gs[1, i])
    ax.hist(hist_list[i], bins='fd', color=color_list[i], edgecolor='white', linewidth=1.2)
    ax.set_title(title_list[i])

plt.tight_layout()
# 直接保存为单个PNG
plt.savefig("combined_plot.png", dpi=300, bbox_inches='tight')
plt.show()

方案2:拼接两张画布输出

如果你不想修改原有绘图逻辑,也可以把两张独立画布的内容转为图像数组,垂直拼接后保存为单个文件,需要用到PIL库:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sn
from PIL import Image
import io

# 生成测试数据
histo_1 = np.random.choice(500, 100, replace=True)
histo_2 = np.random.choice(250, 7000, replace=True)
histo_3 = np.random.choice(150, 1500, replace=True)
histo_4 = np.random.choice(2000, 250, replace=True)

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]

# 第一个饼图画布
f1 = plt.figure(figsize = (14, 7))
sn.set()
sn.color_palette("hls", 8)
for i in range(3):
    ax = f1.add_subplot(1,3,i+1)
    plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
    plt.title("Distribution")
plt.tight_layout()
# 将画布保存到内存缓冲区
buf1 = io.BytesIO()
f1.savefig(buf1, format='png', dpi=300, bbox_inches='tight')
buf1.seek(0)
img1 = Image.open(buf1)

# 第二个直方图画布
f2 = plt.figure(figsize = (14, 5))
hist_list = [histo_1, histo_2, histo_3, histo_4]
color_list = ["cornflowerblue", "indianred", "seagreen", "peru"]
title_list = ["Distribution 1", "Distribution 2", "Distribution 3", "Distribution 4"]
for i in range(4):
    ax = f2.add_subplot(1,4,i+1)
    plt.hist(hist_list[i], bins='fd', color = color_list[i], edgecolor='white', linewidth=1.2)
    plt.title(title_list[i])
plt.tight_layout()
buf2 = io.BytesIO()
f2.savefig(buf2, format='png', dpi=300, bbox_inches='tight')
buf2.seek(0)
img2 = Image.open(buf2)

# 垂直拼接两张图
combined_width = max(img1.width, img2.width)
combined_height = img1.height + img2.height
combined_img = Image.new('RGB', (combined_width, combined_height), (255,255,255))
combined_img.paste(img1, (0, 0))
combined_img.paste(img2, (0, img1.height))
# 保存拼接后的文件
combined_img.save("combined_plot.png")

plt.close('all')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:54:05