You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

解决Matplotlib 3D渐变柱状图添加轮廓后柱子透明的问题

解决Matplotlib 3D渐变柱状图添加轮廓后柱子透明的问题

我完全懂你遇到的这个糟心问题——给3D渐变柱状图加轮廓后,原本好好的渐变柱子突然变得透明,这确实是Matplotlib 3D渲染的一个小坑。咱们直接来解决它:

问题根源

你原本的思路是先画100层渐变的小柱子,再在上面叠一层带黑边的透明大柱子当轮廓。但Matplotlib的3D渲染是按绘制顺序决定层级的:后画的物体会被放在“视觉前面”,哪怕它是全透明的,也会干扰底层渐变柱的深度检测,导致渐变层看起来像被“挖空”变透明了。

修复方案

只需要把轮廓的绘制放在渐变层之前:先画带黑边的透明大柱子,再在它上面叠渐变的小柱子。这样渐变层就会覆盖在轮廓的“框架”上,既保留了渐变效果,又能看到清晰的黑色轮廓。

修复后的完整代码

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import to_rgb
from mpl_toolkits.mplot3d import Axes3D

# =============================
# 数据准备
# =============================
models = ['1', '2', '3', '4', '5']
scenarios = ['Scenario 1', 'Scenario 2', 'Scenario 3']
performance = [
    [0.794, 0.732, 0.665],
    [0.783, 0.722, 0.664],
    [0.786, 0.729, 0.664],
    [0.799, 0.732, 0.667],
    [0.704, 0.696, 0.669],
]
performance = np.array(performance)
performanceT = performance.T   # 转置适配3D坐标

# =============================
# 创建画布和3D轴
# =============================
fig = plt.figure(figsize=(10, 10), dpi=300)
ax1 = fig.add_subplot(111, projection='3d')
ax1.set_xlabel('Models', labelpad=10)
ax1.set_ylabel('Scenarios', labelpad=10)
ax1.set_zlabel('Precision 1')

xpos = np.array([0,1,2,3,4])
ypos = np.array([0, 0.5, 1])
xposM, yposM = np.meshgrid(xpos, ypos, copy=False)
dx = 0.8
dy = 0.4
dz = performanceT.ravel()

scenario_colors = ['#377e22', '#0480A6', '#FF0000']
yellow = np.array(to_rgb("yellow"))
layers = 100
max_height = 1  # 用固定值统一渐变比例,让所有柱子的渐变趋势一致

# =============================
# 第一步:先画带轮廓的"空柱子"(关键:放在渐变层之前!)
# =============================
ax1.bar3d(
    xposM.ravel(),
    yposM.ravel(),
    dz*0,
    dx,
    dy,
    dz,
    color=(0,0,0,0),  # 全透明填充
    edgecolor='black',
    linewidth=0.3,  # 线宽调大一点,轮廓更清晰
    shade=False
)

# =============================
# 第二步:再画渐变柱子层
# =============================
for idx in range(len(dz)):
    x = xposM.ravel()[idx]
    y = yposM.ravel()[idx]
    height = dz[idx]
    scenario_index = idx // len(models)
    base_color = np.array(to_rgb(scenario_colors[scenario_index]))
    step = height / layers
    z_current = 0
    for k in range(layers):
        z_top = z_current + step
        ratio = z_top / max_height
        color = base_color * (1 - ratio) + yellow * ratio
        color = np.clip(color, 0, 1)
        ax1.bar3d(
            x,
            y,
            z_current,
            dx,
            dy,
            step,
            color=color,
            edgecolor=None,  # 渐变层不需要轮廓,避免线条重叠
            shade=False
        )
        z_current = z_top

# =============================
# 轴标签和视图设置
# =============================
ax1.set_xticks(xpos + dx/2)
ax1.set_xticklabels(models, rotation=20, ha='right')
ax1.set_yticks(ypos + dy/2)
ax1.set_yticklabels(scenarios)

ax1.set_proj_type('ortho')
ax1.set_box_aspect((1,1,0.6))
ax1.view_init(elev=25, azim=60)
plt.tight_layout()
plt.show()

额外优化小技巧

  • 如果觉得轮廓和渐变柱有轻微错位,可以把轮廓的dxdy调小一点点(比如dx=0.79dy=0.39),让轮廓刚好"包裹"住渐变柱子。
  • 可以根据需求调整linewidth的数值,让轮廓粗细更符合你的可视化风格。

这样修改后,你就能同时看到清晰的渐变效果和黑色轮廓,而且不会再出现柱子透明的问题啦!

火山引擎 最新活动