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

Plotly如何为多子图配置双Y轴实现柱状图绘制

多子图布局下配置独立双Y轴实现方案

你之前代码运行失败的核心原因是:调用make_subplots创建多子图网格时,没有给每个需要双Y轴的子图位置开启次轴配置,Plotly默认只为每个子图创建单个Y轴,直接绑定不存在的次轴就会触发报错。

关键配置要点

  • 初始化子图时,specs参数的结构必须和子图网格完全匹配:2行1列的布局需要传入2组子图配置,每个需要双Y轴的子图都要设置{"secondary_y": True}
  • 添加trace时,除了指定row、col定位子图位置,还要通过secondary_y参数声明该系列绑定主轴还是次轴
  • 保留单图双Y轴时的offsetgroup参数,避免同一X坐标下的两个柱子重叠
  • 更新坐标轴属性时,必须明确指定坐标轴所属的行、列位置,避免标签错配到其他子图
  • 可以通过legendgroup参数统一多子图的同系列图例,避免重复显示相同图例项

可直接运行的完整示例代码

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd

# --------------------------
# 模拟测试数据,替换为你自己的c1/c2/con_pie/con_pie2数据源即可
# 第一行子图(国家维度)数据
c1 = pd.DataFrame({"country": ["US", "UK", "JP", "DE"], "cost": [120, 230, 180, 300]})
c2 = pd.DataFrame({"country": ["US", "UK", "JP", "DE"], "revenue": [400, 600, 520, 850]})
# 第二行子图(产品维度)数据
con_pie = pd.DataFrame({"product": ["P1", "P2", "P3", "P4"], "cost": [80, 150, 90, 210]})
con_pie2 = pd.DataFrame({"product": ["P1", "P2", "P3", "P4"], "revenue": [220, 410, 300, 580]})
# --------------------------

# 初始化2行1列子图,为两个子图均开启双Y轴
fig = make_subplots(
    rows=2,
    cols=1,
    subplot_titles=("Cost in % of Total", "Revenue by Product"),
    specs=[
        [{"secondary_y": True}],  # 第一行子图开启双Y轴
        [{"secondary_y": True}]   # 第二行子图开启双Y轴
    ],
    row_heights=[0.5, 0.5] # 自定义两行子图高度占比,可按需调整
)

# 绘制第一行(国家维度)子图
fig.add_trace(
    go.Bar(
        name="cost",
        x=c1["country"],
        y=c1["cost"],
        offsetgroup=1,
        legendgroup="cost"
    ),
    row=1,
    col=1,
    secondary_y=False
)
fig.add_trace(
    go.Bar(
        name="revenue",
        x=c2["country"],
        y=c2["revenue"],
        offsetgroup=2,
        legendgroup="revenue"
    ),
    row=1,
    col=1,
    secondary_y=True
)

# 绘制第二行(产品维度)子图
fig.add_trace(
    go.Bar(
        name="cost",
        x=con_pie["product"],
        y=con_pie["cost"],
        offsetgroup=1,
        legendgroup="cost",
        showlegend=False # 隐藏重复图例项
    ),
    row=2,
    col=1,
    secondary_y=False
)
fig.add_trace(
    go.Bar(
        name="revenue",
        x=con_pie2["product"],
        y=con_pie2["revenue"],
        offsetgroup=2,
        legendgroup="revenue",
        showlegend=False # 隐藏重复图例项
    ),
    row=2,
    col=1,
    secondary_y=True
)

# 全局布局配置
fig.update_layout(
    title_text="<b>Cost & Revenue Comparison</b>",
    title_x=0.5,
    barmode="group"
)

# 逐个配置子图坐标轴
# 第一行子图坐标轴
fig.update_xaxes(title_text="<b>Country</b>", row=1, col=1)
fig.update_yaxes(title_text="<b>cost</b>", secondary_y=False, row=1, col=1)
fig.update_yaxes(title_text="<b>revenue</b>", secondary_y=True, row=1, col=1)

# 第二行子图坐标轴
fig.update_xaxes(title_text="<b>Product</b>", row=2, col=1)
fig.update_yaxes(title_text="<b>cost</b>", secondary_y=False, row=2, col=1)
fig.update_yaxes(title_text="<b>revenue</b>", secondary_y=True, row=2, col=1)

# 调整子图标题字号
for i in fig['layout']['annotations']:
    i['font'] = dict(size=14)

fig.show()

补充说明

如果需要调整为其他网格布局(比如2行2列),只需要对应调整rows/cols参数,同时把specs补全为对应行列数的二维数组,给需要双Y轴的子图位置加上secondary_y: True即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 21:12:35