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

Plotly中add_scattergl如何配合facet_row在各分面子图绘制故障线

问题原因

Plotly Express 生成facet_row纵向分面时,本质是创建了多个独立排布的子图坐标系。直接全局调用add_scattergl添加轨迹且不指定子图位置参数时,所有轨迹会默认被添加到第1行第1列的子图中,不会自动按照Unit字段拆分匹配到对应分面,因此所有故障线会堆叠在单个子图内。

修复方案

按分面对应的Unit值拆分故障数据,遍历每个分面单独添加对应故障曲线,显式指定轨迹所属的子图行号即可。

  • 先提取facet分面从上到下对应的Unit顺序,和子图行号一一对应
  • 逐行过滤当前单位下的故障数据,添加轨迹时通过row、col参数指定所属子图
  • 仅在第一个子图显示故障线的图例,避免图例重复

修正后的核心代码

替换原代码中单独调用add_scattergl的部分即可:

# 提取facet从上到下对应的Unit值顺序
unit_order = [anno.text.split('=')[-1] for anno in figline.layout.annotations]

# 逐分面添加对应故障曲线
for row_num, unit_val in enumerate(unit_order, start=1):
    # 过滤当前单位下的故障数据
    fault_subset = df2[(df2["Unit"] == unit_val) & (df2["DataType"] == "Fault")]
    figline.add_scattergl(
        x=fault_subset["DateTime"],
        y=fault_subset["Value"],
        name="Fault",
        line={"color": "red"},
        row=row_num,
        col=1,
        # 仅第一个子图显示图例
        showlegend=(row_num == 1)
    )

完整可运行代码

import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode()

df2 = pd.DataFrame([
        dict(DateTime='2022-01-01 00:00:00', Value=90, Point="A", Unit='%', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:15:00', Value=80, Point="A", Unit='%', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:30:00', Value=85, Point="A", Unit='%', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:45:00', Value=92, Point="A", Unit='%', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:00:00', Value=100, Point="A", Unit='%', DataType='Fault',Type='Demo'),
        dict(DateTime='2022-01-01 01:15:00', Value=72, Point="A", Unit='%', DataType='Fault',Type='Demo'),
        dict(DateTime='2022-01-01 00:00:00', Value=22, Point="B", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:15:00', Value=22, Point="B", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:30:00', Value=23, Point="B", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:45:00', Value=20, Point="B", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:00:00', Value=21, Point="B", Unit='°C', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 01:15:00', Value=23, Point="B", Unit='°C', DataType='Fault', Type='Demo'),    
        dict(DateTime='2022-01-01 00:00:00', Value=24, Point="C", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:15:00', Value=24, Point="C", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:30:00', Value=24, Point="C", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:45:00', Value=24, Point="C", Unit='°C', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:00:00', Value=24, Point="C", Unit='°C', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 01:15:00', Value=24, Point="C", Unit='°C', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 00:00:00', Value=60, Point="D", Unit='Pa', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:15:00', Value=58, Point="D", Unit='Pa', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:30:00', Value=62, Point="D", Unit='Pa', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:45:00', Value=61, Point="D", Unit='Pa', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:00:00', Value=64, Point="D", Unit='Pa', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 01:15:00', Value=59, Point="D", Unit='Pa', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 00:00:00', Value=0, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:15:00', Value=0, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:30:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 00:45:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:00:00', Value=1, Point="E", Unit='Binary', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 01:15:00', Value=1, Point="E", Unit='Binary', DataType='Fault', Type='Demo'),
        dict(DateTime='2022-01-01 01:30:00', Value=0, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 01:45:00', Value=0, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 02:00:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 02:15:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 02:30:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
        dict(DateTime='2022-01-01 02:45:00', Value=1, Point="E", Unit='Binary', DataType='Normal', Type='Demo'),
    ])

figline = px.line(df2, x="DateTime", y="Value", color="Point", line_group="Unit", hover_name="Point", facet_row="Unit",
        line_shape="spline", render_mode="svg")
figline.update_yaxes(autorange=True)
figline.update_layout(hovermode="x unified")
figline.update_yaxes(matches=None)

# 逐分面添加故障曲线
unit_order = [anno.text.split('=')[-1] for anno in figline.layout.annotations]
for row_num, unit_val in enumerate(unit_order, start=1):
    fault_subset = df2[(df2["Unit"] == unit_val) & (df2["DataType"] == "Fault")]
    figline.add_scattergl(
        x=fault_subset["DateTime"],
        y=fault_subset["Value"],
        name="Fault",
        line={"color": "red"},
        row=row_num,
        col=1,
        showlegend=(row_num == 1)
    )

figline.show()
注意事项
  • Plotly 子图的行、列索引从1开始计数,因此enumerate需要设置start=1,否则会出现子图位置匹配错误
  • 提取unit_order时是通过读取facet自动生成的标注文本拆分得到,和子图从上到下的顺序完全一致,不会出现单位和子图错位的问题
  • 故障线会自动适配对应子图的y轴范围,不需要额外手动调整坐标轴参数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:36:26