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

Matplotlib中如何为2D子图设置双倍宽度(结合3D投影图)?

调整2D折线图宽度为默认两倍(无需重构代码)

问题描述

已有可运行的Matplotlib代码,通过add_subplot生成3组(accel/angle/avelo)并排的2D折线图与3D投影图,希望将每组中的2D折线图宽度设置为默认值的两倍,询问是否可通过现有add_subplot方式实现,还是必须改用plt.subplots。

原代码如下:

from mpl_toolkits import mplot3d
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# code here loads data into a dataframe df

fig = plt.figure(figsize=(10,8))
fig.suptitle(filename, fontsize=12)
i = 0  # 补充原代码缺失的i初始化
for p in ('accel','angle','avelo'):
    i += 1
    ax = fig.add_subplot(3, 2, i)
    ax.plot(idx,df[p,'x'], label = "x")
    ax.plot(idx,df[p,'y'], label = "y")
    ax.plot(idx,df[p,'z'], label = "z")
    ax.set_ylabel(p)
    ax.legend(loc="best")
    i += 1
    ax = fig.add_subplot(3,2,i,projection='3d')
    ax.plot3D(df[p,'x'],df[p,'y'],df[p,'z'],'black')
    ax.scatter(df[p]['x'][0],df[p]['y'][0],df[p]['z'][0], c='green', marker='o', s=50)
    ax.scatter(df[p]['x'].iloc[-1],df[p]['y'].iloc[-1],df[p]['z'].iloc[-1], c='red', marker='x', s=50)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')    
plt.subplots_adjust(left=0.1,
                    bottom=0.1,
                    right=0.9,
                    top=0.9,
                    wspace=0.4,
                    hspace=0.1)
plt.show()

解决方案:用GridSpec实现自定义宽度比例

不需要重构为plt.subplots,通过matplotlib.gridspec.GridSpec可以直接在add_subplot中指定子图的宽度占比,实现2D图宽度为3D图的两倍。具体操作:

  1. 创建3行3列的GridSpec,设置列宽比例为[2,2,1](前两列合并给2D图,第三列给3D图,这样每组2D图宽度是3D图的两倍)
  2. 循环中为每个参数分配对应的GridSpec位置:2D图占每行的前两列,3D图占每行的第三列

修改后的代码:

from mpl_toolkits import mplot3d
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec  # 导入GridSpec

# code here loads data into a dataframe df
# 示例测试数据(无真实数据时可使用):
# idx = np.arange(100)
# df = pd.DataFrame({
#     ('accel','x'): np.random.randn(100),
#     ('accel','y'): np.random.randn(100),
#     ('accel','z'): np.random.randn(100),
#     ('angle','x'): np.random.randn(100),
#     ('angle','y'): np.random.randn(100),
#     ('angle','z'): np.random.randn(100),
#     ('avelo','x'): np.random.randn(100),
#     ('avelo','y'): np.random.randn(100),
#     ('avelo','z'): np.random.randn(100),
# })
# filename = "Accelerometer Data"

fig = plt.figure(figsize=(12,8))  # 适当加宽画布适配宽子图
fig.suptitle(filename, fontsize=12)

# 创建3行3列的GridSpec,列宽比例为2:2:1(前两列合并给2D图,第三列给3D图)
gs = GridSpec(3, 3, width_ratios=[2, 2, 1])

for row, p in enumerate(('accel','angle','avelo')):
    # 2D折线图:占当前行的第0-1列(合并两列)
    ax_2d = fig.add_subplot(gs[row, :2])
    ax_2d.plot(idx, df[p,'x'], label="x")
    ax_2d.plot(idx, df[p,'y'], label="y")
    ax_2d.plot(idx, df[p,'z'], label="z")
    ax_2d.set_ylabel(p)
    ax_2d.legend(loc="best")
    
    # 3D投影图:占当前行的第2列
    ax_3d = fig.add_subplot(gs[row, 2], projection='3d')
    ax_3d.plot3D(df[p,'x'], df[p,'y'], df[p,'z'], 'black')
    ax_3d.scatter(df[p]['x'][0], df[p]['y'][0], df[p]['z'][0], c='green', marker='o', s=50)
    ax_3d.scatter(df[p]['x'].iloc[-1], df[p]['y'].iloc[-1], df[p]['z'].iloc[-1], c='red', marker='x', s=50)
    ax_3d.set_xlabel('x')
    ax_3d.set_ylabel('y')
    ax_3d.set_zlabel('z')

plt.subplots_adjust(left=0.1,
                    bottom=0.1,
                    right=0.9,
                    top=0.9,
                    wspace=0.3,
                    hspace=0.2)
plt.show()

说明

  • 这种方式完全保留了原代码的add_subplot调用逻辑,仅通过GridSpec替换了原有的3x2网格布局,无需重构为plt.subplots
  • width_ratios=[2,2,1]定义了三列的宽度比例,将前两列合并给2D图,其总宽度是第三列(3D图)的两倍,精准满足需求
  • 适当调整了画布figsize和子图间距wspace,让整体布局更美观协调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:37:09