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
相关产品推荐
相关产品推荐

