Plotly 3D图表中绘制2D柱状图的实现方案
Plotly 3D画布绘制分面2D柱状图实现方案
Plotly 3D场景暂未内置原生柱状图类型,通过Mesh3d图元手动构造柱体网格是兼容性最好的实现方式,完全支持原生的旋转、缩放、悬停交互,效果和Matplotlib实现的参考效果一致。

核心实现逻辑
- 每个柱体为固定y轴位置(对应单条轨迹)的薄长方体
- x轴方向:对应日期维度,柱体宽度设为0.7个日期间隔,避免相邻柱重叠
- y轴方向:对应轨迹维度,柱体厚度设为0.3个轨迹间隔,不同轨迹的柱子沿y轴排布互不遮挡
- z轴方向:对应指标数值,柱体高度直接映射指标大小
- 提前预定义长方体的三角剖分索引,不用每次做自动三角剖分,渲染效率更高
可直接运行的完整代码
import plotly.graph_objects as go import pandas as pd import numpy as np # ---------------------- 1. 模拟测试数据 可替换成自己的业务数据 ---------------------- # 轨迹列表 trace_names = ["轨迹A", "轨迹B", "轨迹C"] # 日期维度 dates = pd.date_range(start="2024-01-01", end="2024-01-07") # 随机生成指标值 np.random.seed(42) df = pd.DataFrame({ "date": np.repeat(dates, len(trace_names)), "trace": np.tile(trace_names, len(dates)), "value": np.random.randint(low=10, high=100, size=len(dates)*len(trace_names)) }) # 把分类维度映射成数值坐标 trace_y_map = {name:i for i, name in enumerate(trace_names)} df["y_pos"] = df["trace"].map(trace_y_map) df["x_pos"] = df["date"].astype(np.int64) // 10**9 # 日期转时间戳作为x数值坐标 # 柱体尺寸配置 bar_width_x = 0.7 * 86400 # x方向宽度 对应0.7天的时间戳长度 bar_thickness_y = 0.3 # y方向厚度 # 预定义长方体的12个三角面索引 固定复用 cube_faces = [ [0,1,2], [0,2,3], # 底面 [4,5,6], [4,6,7], # 顶面 [0,1,5], [0,5,4], # 前侧面 [2,3,7], [2,7,6], # 后侧面 [0,3,7], [0,7,4], # 左侧面 [1,2,6], [1,6,5] # 右侧面 ] # 轨迹配色 trace_colors = ["#1f77b4", "#ff7f0e", "#2ca02c"] # ---------------------- 2. 生成每个柱体的Mesh3d轨迹 ---------------------- fig = go.Figure() for _, row in df.iterrows(): x0 = row["x_pos"] - bar_width_x/2 x1 = row["x_pos"] + bar_width_x/2 y0 = row["y_pos"] - bar_thickness_y/2 y1 = row["y_pos"] + bar_thickness_y/2 z0 = 0 z1 = row["value"] # 长方体8个顶点坐标 x_verts = [x0, x1, x1, x0, x0, x1, x1, x0] y_verts = [y0, y0, y1, y1, y0, y0, y1, y1] z_verts = [z0, z0, z0, z0, z1, z1, z1, z1] # 展开面索引 i_idx, j_idx, k_idx = [], [], [] for face in cube_faces: i_idx.append(face[0]) j_idx.append(face[1]) k_idx.append(face[2]) # 添加柱体到画布 fig.add_trace(go.Mesh3d( x=x_verts, y=y_verts, z=z_verts, i=i_idx, j=j_idx, k=k_idx, color=trace_colors[trace_y_map[row["trace"]]], opacity=0.9, hovertemplate=f"日期: {row['date'].date()}<br>轨迹: {row['trace']}<br>数值: {row['value']}<extra></extra>" )) # ---------------------- 3. 坐标轴配置 还原分类轴效果 ---------------------- fig.update_layout( scene=dict( xaxis=dict( title="日期", tickmode="array", tickvals=df["x_pos"].unique(), ticktext=[d.date() for d in dates] ), yaxis=dict( title="轨迹名称", tickmode="array", tickvals=list(trace_y_map.values()), ticktext=list(trace_y_map.keys()) ), zaxis=dict(title="指标数值"), camera=dict(eye=dict(x=1.5, y=1.5, z=1.2)) # 初始视角 可按需调整 ), margin=dict(l=0, r=0, t=30, b=0), showlegend=False ) fig.show()
自定义调整说明
- 替换数据:把模拟数据部分换成自己的数据集即可,只要保证每条数据对应一个(日期、轨迹、数值)三元组
- 柱体尺寸:调整
bar_width_x和bar_thickness_y参数可以修改柱子的宽窄厚薄,适配自己的数据密度 - 配色:修改
trace_colors列表可以自定义不同轨迹的柱体颜色 - 初始视角:修改
camera.eye参数可以调整打开图表时的默认观察角度
内容的提问来源于stack exchange,提问作者mark377
相关产品推荐
相关产品推荐

