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
相关产品推荐
相关产品推荐

