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

如何为Plotly每个子图添加独立水平线?附共享轴异常问题

解决Plotly子图水平线不对应及Y轴共享问题

问题根源分析

  1. 水平线未匹配对应子图:原代码中create_min_ruler/create_max_ruler会遍历所有列添加水平线,且未指定row和col参数,导致所有子图叠加了全量水平线;同时列循环中嵌套行循环,重复调用函数造成大量重复绘制。
  2. Y轴仍强制共享:嵌套循环错误导致每个列的柱状图被重复添加到所有行的子图中,子图内容混乱,Y轴被强制统一,看似共享。

修正后的完整代码

import math
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from typing import List

def calculate_average(df: pd.DataFrame) -> go.Figure:
    """生成包含各数值列平均值柱状图及对应最小/最大值水平线的子图"""
    bad_column_str = ["_id", "id_", "_id_", " id ", " id", "id "]
    numeric_columns = cl.get_numeric_columns(df)
    numeric_columns = cl.remove_columns_containing_str(numeric_columns, bad_column_str)

    # 计算子图行数:每4列一行
    subplot_rows = math.ceil(len(numeric_columns) / 4)
    fig = make_subplots(
        rows=subplot_rows,
        cols=4,
        shared_xaxes=False,
        shared_yaxes=False,
        subplot_titles=numeric_columns  # 为每个子图添加列名标题
    )

    for idx, col in enumerate(numeric_columns):
        # 计算当前列对应的子图位置(Plotly子图行列从1开始计数)
        row = (idx // 4) + 1
        col_pos = (idx % 4) + 1

        # 获取当前列的核心统计值
        mean_val = df[col].mean()
        min_val = df[col].min()
        max_val = df[col].max()

        # 添加平均值柱状图到对应子图
        fig.add_trace(
            go.Bar(x=[col], y=[mean_val]),
            row=row,
            col=col_pos
        )

        # 添加最小值水平线(指定对应子图)
        fig.add_hline(
            y=min_val,
            annotation_text=f"Min: {min_val:.2f}",
            annotation_position="bottom left",
            line_dash="dash",
            line_color="#ff4d4f",
            row=row,
            col=col_pos
        )

        # 添加最大值水平线(指定对应子图)
        fig.add_hline(
            y=max_val,
            annotation_text=f"Max: {max_val:.2f}",
            annotation_position="top right",
            line_dash="dash",
            line_color="#52c41a",
            row=row,
            col=col_pos
        )

    # 优化布局
    fig.update_layout(
        template="plotly_white",
        title_text="数值列平均值(含最小/最大值标线)",
        height=300 * subplot_rows,  # 根据子图行数动态调整高度
        showlegend=False
    )

    # 避免水平线被Y轴截断
    fig.update_yaxes(range=[0, None])

    return fig

关键改动说明

  • 精准定位子图:通过idx // 4和idx % 4计算每个列对应的子图行列,彻底避免嵌套循环导致的重复绘制。
  • 水平线绑定子图:调用add_hline时传入row和col参数,确保每条水平线仅出现在对应列的子图中。
  • 简化统计计算:直接使用df[col].min()/max()替代排序取首行,提升效率并减少冗余代码。
  • 修复Y轴共享问题:修正循环逻辑后,每个子图仅包含对应列的内容,shared_yaxes=False参数正常生效,各子图Y轴独立。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 15:33:14