如何在Plotly子图中添加堆叠柱状图及双Y轴折线图?
Plotly 实现2行1列共享X轴子图(堆叠柱状+双Y轴折线)
先看简化版示例DataFrame(实际包含100+列品类数据):
import pandas as pd import plotly.subplots as sp import plotly.graph_objects as go # 构造示例数据 dates = pd.date_range(start='2023-01-01', periods=6, freq='M') df = pd.DataFrame({ 'date': dates, 'category_1': [100, 120, 150, 180, 200, 220], 'category_2': [80, 90, 100, 110, 130, 140], # ... 省略98+个类似category列 'cost': [500, 550, 600, 680, 720, 780], 'numSales': [20, 25, 30, 35, 40, 45] })
实现步骤
初始化共享X轴的子图布局
用make_subplots创建2行1列的子图,指定第一行启用双Y轴,同时开启X轴共享:fig = sp.make_subplots( rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]], shared_xaxes=True, vertical_spacing=0.1 # 调整子图间距 )第一行添加100+列的堆叠柱状图
遍历所有品类列(排除date、cost、numSales),逐个添加柱状图trace,Plotly会自动处理堆叠逻辑:# 筛选出所有品类列 category_cols = [col for col in df.columns if col not in ['date', 'cost', 'numSales']] for col in category_cols: fig.add_trace( go.Bar(x=df['date'], y=df[col], name=col), row=1, col=1, secondary_y=False # 绑定左侧Y轴 )第一行添加右侧Y轴的cost折线图
通过secondary_y=True绑定右侧Y轴,实现类似matplotlibtwinx的效果:fig.add_trace( go.Scatter(x=df['date'], y=df['cost'], name='成本', line=dict(color='red')), row=1, col=1, secondary_y=True )第二行添加numSales折线图
直接在第二行子图添加折线,因为已开启shared_xaxes=True,会自动共享X轴:fig.add_trace( go.Scatter(x=df['date'], y=df['numSales'], name='销量'), row=2, col=1 )布局优化
调整Y轴标题、图例位置等,提升可读性:# 设置左侧Y轴标题(品类数值) fig.update_yaxes(title_text="品类数值", row=1, col=1, secondary_y=False) # 设置右侧Y轴标题(成本) fig.update_yaxes(title_text="成本", row=1, col=1, secondary_y=True) # 设置第二行Y轴标题(销量) fig.update_yaxes(title_text="销量", row=2, col=1) # 设置X轴标题 fig.update_xaxes(title_text="日期", row=2, col=1) # 调整图例位置,避免遮挡图表 fig.update_layout( legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), title_text="品类堆叠柱状+成本&销量趋势" )
完整运行代码
整合上述片段,直接运行即可得到目标图表:
import pandas as pd import plotly.subplots as sp import plotly.graph_objects as go # 构造示例数据 dates = pd.date_range(start='2023-01-01', periods=6, freq='M') df = pd.DataFrame({ 'date': dates, 'category_1': [100, 120, 150, 180, 200, 220], 'category_2': [80, 90, 100, 110, 130, 140], # 可自行添加更多category列测试 'cost': [500, 550, 600, 680, 720, 780], 'numSales': [20, 25, 30, 35, 40, 45] }) # 创建子图 fig = sp.make_subplots( rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]], shared_xaxes=True, vertical_spacing=0.1 ) # 添加堆叠柱状图 category_cols = [col for col in df.columns if col not in ['date', 'cost', 'numSales']] for col in category_cols: fig.add_trace( go.Bar(x=df['date'], y=df[col], name=col), row=1, col=1, secondary_y=False ) # 添加成本折线图(右侧Y轴) fig.add_trace( go.Scatter(x=df['date'], y=df['cost'], name='成本', line=dict(color='red')), row=1, col=1, secondary_y=True ) # 添加销量折线图 fig.add_trace( go.Scatter(x=df['date'], y=df['numSales'], name='销量'), row=2, col=1 ) # 布局调整 fig.update_yaxes(title_text="品类数值", row=1, col=1, secondary_y=False) fig.update_yaxes(title_text="成本", row=1, col=1, secondary_y=True) fig.update_yaxes(title_text="销量", row=2, col=1) fig.update_xaxes(title_text="日期", row=2, col=1) fig.update_layout( legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), title_text="品类堆叠柱状+成本&销量趋势" ) # 显示图表 fig.show()
关键注意点
- 100+列堆叠柱状:Plotly会自动将同位置(
row=1,col=1)的bar trace堆叠,无需额外设置。 - 双Y轴实现:通过
secondary_y=True指定绑定右侧Y轴,逻辑和matplotlib的twinx一致。 - 共享X轴:初始化子图时设置
shared_xaxes=True,第二行子图会自动复用第一行X轴,交互时同步缩放/平移。
内容的提问来源于stack exchange,提问作者Allanqunzi
相关产品推荐
相关产品推荐

