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

如何在Plotly子图不同row_heights下调整legend_tracegroupgap?

适配row_heights自动调整Plotly子图图例间隙的方案

问题

用Plotly创建带分组图例的垂直子图时,手动设置row_heights(行高比例)后,固定值的legend_tracegroupgap(图例分组间隙)无法适配不同高度的子图,导致每组图例和对应子图的位置错位。需要实现根据row_heights自动计算间隙,让每组图例精准对应到子图顶部旁侧。

解决方案

核心是通过row_heights的相对比例计算子图实际像素高度,结合图例项的默认行高,动态生成legend_tracegroupgap值:

  • 先计算row_heights的总比例,推导每个子图占总图高度的实际像素值
  • 根据每组图例的项数,计算每组图例的总高度
  • 调整legend_tracegroupgap为子图高度减去对应组图例总高度,再微调标题偏移,让下一组图例对齐下一个子图顶部
  • 同时设置图例位置到子图右侧旁侧,顶部对齐

修改后的代码

import pandas as pd
import plotly.express as px

df = px.data.gapminder().query("continent=='Americas'")

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

# 定义子图行高比例和图表总高度
row_heights = [2, 1, 0.75]
total_row_ratio = sum(row_heights)
fig_total_height = 800

# 创建子图
fig = make_subplots(rows=3, cols=1, row_heights=row_heights) 

# 添加第一子图轨迹(加拿大、美国)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Canada'")['year'],
    y=df.query("country == 'Canada'")['lifeExp'],
    name='Canada',
    legendgroup='1'
), row=1, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'United States'")['year'],
    y=df.query("country == 'United States'")['lifeExp'],
    name='United States',
    legendgroup='1'
), row=1, col=1)

# 添加第二子图轨迹(墨西哥、哥伦比亚、巴西)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Mexico'")['year'],
    y=df.query("country == 'Mexico'")['lifeExp'],
    name='Mexico',
    legendgroup='2'
), row=2, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Colombia'")['year'],
    y=df.query("country == 'Colombia'")['lifeExp'],
    name='Colombia',
    legendgroup='2'
), row=2, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Brazil'")['year'],
    y=df.query("country == 'Brazil'")['lifeExp'],
    name='Brazil',
    legendgroup='2'
), row=2, col=1)

# 添加第三子图轨迹(阿根廷、智利)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Argentina'")['year'],
    y=df.query("country == 'Argentina'")['lifeExp'],
    name='Argentina',
    legendgroup='3'
), row=3, col=1)
fig.append_trace(go.Scatter(
    x=df.query("country == 'Chile'")['year'],
    y=df.query("country == 'Chile'")['lifeExp'],
    name='Chile',
    legendgroup='3'
), row=3, col=1)

# 自动计算图例分组间隙
legend_item_default_height = 20  # Plotly图例项默认行高(像素)
group_legend_counts = [2, 3, 2]  # 每组图例的项数,对应三个legendgroup

# 计算每个子图的实际像素高度
subplot_actual_heights = [(ratio / total_row_ratio) * fig_total_height for ratio in row_heights]

# 计算第一组和第二组之间的间隙,让第二组图例对齐第二子图顶部
# 减去30是标题和顶部边距的微调值,可根据实际效果调整
calculated_tracegroupgap = int(subplot_actual_heights[0] - group_legend_counts[0] * legend_item_default_height - 30)

# 更新布局,设置图例位置和间隙
fig.update_layout(
    height=fig_total_height,
    width=800,
    title_text="美洲国家预期寿命变化",
    xaxis3_title='年份',
    yaxis1_title='预期寿命',
    yaxis2_title='预期寿命',
    yaxis3_title='预期寿命',
    legend_tracegroupgap=calculated_tracegroupgap,
    yaxis1_range=[50, 90],
    yaxis2_range=[50, 90],
    yaxis3_range=[50, 90],
    legend=dict(
        yanchor="top",
        y=0.95,  # 对齐标题下方
        xanchor="left",
        x=1.02  # 图例放在子图右侧旁侧
    )
)
fig.show()

说明

  • 如果调整row_heights或图表总高度fig_total_height,只需要修改对应变量,间隙值会自动重新计算
  • legend_item_default_height和微调的30像素可根据实际显示效果调整,适配不同的图例样式
  • 图例通过legend参数固定在子图右侧顶部旁侧,避免位置偏移

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:25:56