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

Matplotlib 3.8中设置3D堆叠柱状图宽高比的问题

3D堆叠柱状图宽高比调整问题解决

问题描述

我想用Matplotlib绘制特定样式的3D堆叠柱状图,已编写初步代码并得到基础效果,但尝试调整宽高比时,使用set_aspect('equal', adjustable='datalim')未能达到预期。

初始实现代码

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

colors = [ "#2B314D", "#A54836","#5375D4", ]

data = {
    "year": [2004, 2022, 2004, 2022, 2004, 2022],
    "countries" : ["Sweden", "Sweden", "Denmark", "Denmark", "Norway", "Norway"],
    "sites": [13,15,5,8,4,10]
}
df= pd.DataFrame(data)
df['year_lbl'] ="'"+df['year'].astype(str).str[-2:].astype(str)

nr_countries = df.countries.nunique()
nr_years = df.year.nunique()
years = df.year.unique()
x= [1,1,1]
y=[0,0,0]
z= [0,0,0]

dx= [1,1,1]
dy= [1,1,1]

fig = plt.figure(figsize=(15,10))

for i,yrs in zip(range(0,nr_years), years):
    
    # Add the i+1 subplot of the x.shape[0] x 1 grid
    ax = fig.add_subplot(1,nr_years, i+1,  projection='3d')

    temp_df = df[df.year == yrs]
    dz = temp_df.sites.tolist()
    _zpos = z   # the starting zpos for each bar
    for i, c in zip(range(nr_countries), colors):
        ax.bar3d(x,y,_zpos,dx,dy,dz[i],color= c)
        _zpos += np.array(dz[i])  # add the height of each bar to know where to start the next
    ax.set_axis_off()

尝试调整的代码片段

ax.set_ylim(0,15)
ax.set_xlim(0,15)
ax.set_zlim(0,25)
ax.set_aspect('equal', adjustable='datalim')

问题分析与解决

核心问题

  1. 3D轴set_aspect逻辑特殊:Matplotlib 3D轴的equal比例设置和2D逻辑完全不同,因为3D视图涉及投影转换,单纯靠数据范围调整无法实现目标的扁平宽高比。
  2. 轴范围设置不合理:你的数据中x、y的实际取值范围极小(x固定为1,y固定为0),却设置了0-15的大范围,导致柱状图在轴上占比极低,视觉比例严重失调。
  3. 未控制3D视角:目标图的扁平效果核心来自特定的侧面视角,而非单纯的轴比例设置。

修正后的完整代码

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

colors = [ "#2B314D", "#A54836","#5375D4", ]

data = {
    "year": [2004, 2022, 2004, 2022, 2004, 2022],
    "countries" : ["Sweden", "Sweden", "Denmark", "Denmark", "Norway", "Norway"],
    "sites": [13,15,5,8,4,10]
}
df= pd.DataFrame(data)
df['year_lbl'] ="'"+df['year'].astype(str).str[-2:].astype(str)

nr_countries = df.countries.nunique()
nr_years = df.year.nunique()
years = df.year.unique()

# 固定柱子的x、y基准位置
x= [1] * nr_countries
y= [0] * nr_countries
z= [0] * nr_countries

dx= [1] * nr_countries  # 柱子宽度
dy= [3] * nr_countries  # 增大深度值,让柱子呈现扁平效果
fig = plt.figure(figsize=(12, 5))  # 调整画布宽高比,贴合目标横向布局

for i,yrs in zip(range(nr_years), years):
    ax = fig.add_subplot(1, nr_years, i+1, projection='3d')
    temp_df = df[df.year == yrs]
    dz = temp_df.sites.tolist()
    _zpos = z.copy()
    
    for idx, c in enumerate(colors):
        ax.bar3d(x[idx], y[idx], _zpos[idx], dx[idx], dy[idx], dz[idx], color=c)
        _zpos[idx] += dz[idx]
    
    # 缩小轴范围,匹配柱子实际尺寸,避免多余空白
    ax.set_xlim(0.5, 1.5)
    ax.set_ylim(-1.5, 1.5)
    ax.set_zlim(0, sum(dz) + 2)
    
    # 调整3D视角,实现侧面扁平的视觉效果
    ax.view_init(elev=25, azim=-65)
    
    ax.set_axis_off()

plt.tight_layout()
plt.show()

关键调整说明

  • 增大柱子深度(dy):直接调整柱子的y轴方向尺寸,让柱子本身呈现扁平形态。
  • 精准设置轴范围:只保留柱子所在的小范围轴区间,避免空白区域稀释视觉比例。
  • 自定义3D视角:通过view_init调整仰角(elev)和方位角(azim),让柱子以侧面角度展示,这是实现目标样式的核心。
  • 优化画布比例:设置更宽的画布尺寸,让两个子图并排时贴合目标的横向布局。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 10:35:00