Matplotlib:add_gridspec布局下如何让同行饼图占满垂直空间
问题描述
尝试绘制2×2的不同类型子图网格,当同一行包含柱状图和饼图时,若柱状图的轴标签过长,会占据大量空间导致柱子变小(此情况可接受),但同行的饼图会随之调整尺寸。希望让饼图使用全部垂直空间。已将问题简化为单行2个子图的示例,最终版本为2行布局且同列子图宽度不一定相同,因此使用add_gridspec而非简单的subplots(2,2)。
示例代码如下:
import pandas as pd import numpy as np import matplotlib.pyplot as plt # Set the seed for reproducibility np.random.seed(42) # Define the list of countries countries = ['USA', 'Canada', 'Germany', 'France', 'Japan', 'Australia', 'Brazil', 'India', 'China', 'Mexico'] # Add a country with a long name countries.append('United Kingdom of Great Britain and Northern Ireland') # Define the list of possible statuses statuses = ['Active', 'Inactive', 'Error', 'Warning'] # Generate random data data = { 'Country': np.random.choice(countries, 500), 'Status': np.random.choice(statuses, 500) } # Create the DataFrame df = pd.DataFrame(data) # Create the figure and axes fig = plt.figure(layout="constrained", figsize=(10, 8)) gs0 = fig.add_gridspec(1, 2) ax1 = fig.add_subplot(gs0[0]) ax2 = fig.add_subplot(gs0[1]) # Plot the data df.reset_index().pivot_table('index', 'Country', 'Status', aggfunc='count').plot.bar(stacked=True, ax=ax1) ax1.legend(loc='center left',bbox_to_anchor=(1.0, 0.5)) s = df.Status.value_counts() s.plot.pie(ax=ax2)
当前效果:
解决方案
要让饼图充分利用垂直空间,核心是让饼图所在的坐标轴保持正方形比例,同时不受左侧柱状图标签的挤压影响,以下是两种实用方法:
方法1:直接设置饼图坐标轴宽高比
在绘制饼图后,为坐标轴添加固定宽高比设置,强制饼图保持圆形并填充可用垂直空间:
# 绘制饼图后添加该行代码 ax2.set_aspect('equal', adjustable='box')
这个设置会让饼图强制维持圆形,同时自动调整子图框的尺寸来适配这个比例,最大限度利用垂直空间。
方法2:嵌套Gridspec精细化布局控制
如果后续需要扩展为2行多列的复杂布局,可以通过嵌套Gridspec为饼图单独分配空间,确保其不受其他子图的布局干扰:
# 修改Gridspec创建逻辑 fig = plt.figure(layout="constrained", figsize=(10, 8)) gs0 = fig.add_gridspec(1, 2) # 柱状图子图 ax1 = fig.add_subplot(gs0[0]) # 为饼图创建嵌套Gridspec,确保空间独立控制 gs_pie = gs0[1].subgridspec(1, 1) ax2 = fig.add_subplot(gs_pie[0]) ax2.set_aspect('equal')
这种方式适合后续调整不同行、列的子图尺寸比例,灵活性更高。
优化后的完整代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt np.random.seed(42) countries = ['USA', 'Canada', 'Germany', 'France', 'Japan', 'Australia', 'Brazil', 'India', 'China', 'Mexico'] countries.append('United Kingdom of Great Britain and Northern Ireland') statuses = ['Active', 'Inactive', 'Error', 'Warning'] data = { 'Country': np.random.choice(countries, 500), 'Status': np.random.choice(statuses, 500) } df = pd.DataFrame(data) fig = plt.figure(layout="constrained", figsize=(10, 8)) gs0 = fig.add_gridspec(1, 2) ax1 = fig.add_subplot(gs0[0]) ax2 = fig.add_subplot(gs0[1]) # 绘制柱状图 df.reset_index().pivot_table('index', 'Country', 'Status', aggfunc='count').plot.bar(stacked=True, ax=ax1) ax1.legend(loc='center left', bbox_to_anchor=(1.0, 0.5)) # 绘制饼图并设置宽高比 s = df.Status.value_counts() s.plot.pie(ax=ax2) ax2.set_aspect('equal', adjustable='box') plt.show()
内容的提问来源于stack exchange,提问作者user3348670
相关产品推荐
相关产品推荐

