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

Plotly Express折线图仅显示部分线条,悬停可查看全量数据

Plotly折线图部分轨迹不显示但悬停可见的问题排查与解决

问题描述

使用px.line创建折线图,同时通过go.Scatter()添加额外轨迹,将多个图表存入同一HTML文件后,出现以下问题:部分图表仅显示部分数据线条,但鼠标悬停时能清晰查看所有轨迹的实际数据点(无法看到线条本身)。

代码详情

# 部分变量在其他位置定义(如title、ylabel),以下是对图表执行的所有操作

# 创建图表
fig = px.line(data, title=title, render_mode='svg', markers=False)
# 更新布局
fig.update_layout(yaxis_title=ylabel, xaxis_title=xlabel)
# 设置悬停数据格式
fig.update_traces(xhoverformat=xhoverformat, yhoverformat=yhoverformat, hovertemplate=hovertemplate)
# 添加最后一条轨迹
fig.add_trace(go.Scatter(x=df.index, y=df['my_column'], name='my name', mode='lines', line=dict(dash='longdash', color='black')))
# 再次设置悬停数据格式,适配有时才添加的最后一条轨迹
fig.update_traces(xhoverformat=xhoverformat, yhoverformat=yhoverformat, hovertemplate=hovertemplate)
fig.update_layout(yaxis=dict(autorange=True, fixedrange=False), xaxis=dict(rangeslider=dict(visible=True), range=range))
# 添加多个注释和垂直线
# fig.add_vline(x=my_val)
# fig.add_annotation()

# 将图表加入列表并重复操作
fig_list.append(fig)

# 以下是将图表写入文件的函数
def plotly_figs_to_html(fig_list,filepath, plotlyjs = 'cdn'):
    """
    接收Plotly图表列表,将其保存为HTML文件。

    :param fig_list: Plotly图表列表
    :param filepath: 输出文件路径字符串(需以.html结尾)
    :param plotlyjs: 可选的plotlyjs类型字符串
    :return: None
    """
    if len(fig_list) > 0:
        # 打开文件
        with open(filepath, 'w') as f:
            # 写入第一个图表,包含完整HTML和plotlyjs
            f.write(fig_list[0].to_html(full_html = True, include_plotlyjs = plotlyjs))
            for fig in fig_list[1:]:
                # 循环写入剩余图表,不包含完整HTML和js
                f.write(fig.to_html(full_html = False, include_plotlyjs = False))
    else:
        logging.warning(f'  无数据可绘制;{filepath.rsplit("/",1)[-1]}')
    return None

plotly_figs_to_html(fig_list, _filepath)

猜测相关因素

  • 图表中的轨迹数量
  • 单个图表的数据点数量
  • 文件中的图表数量或文件总数据点数量

补充说明

  • 文件通常包含8个以上图表,因此特意使用SVG而非WebGL渲染模式
  • 第一个图表设置full_html=True且include_plotlyjs='cdn',后续图表均将这两个参数设为False
  • 正常情况下文件大小小于20MB,但出现问题的文件大小为87MB
  • 传入px.line的DataFrame大小在40k至182k之间:
    • 虽然SVG模式下大量数据会降低交互性,但仍希望将图表分组展示
    • 出现问题的文件包含约25个图表,DataFrame平均大小为110k
  • 数据点类型为Float64(注:原描述中Float68应为笔误)
  • datetime索引已排序
  • 各轨迹常包含NaN值
  • 即使px.line创建的轨迹不显示,go.Scatter()创建的轨迹仍可正常显示

环境版本

pandas 1.4.4、plotly 5.9.0、python 3.9.13

更新记录

更新1:将df.size减少约40%
移除了大量NaN值(已知部分索引始终无数据),文件大小降至50MB,每个df约含65k数据点,但问题仍存在。

更新2
添加markers可显示数据点,但未显示的数据对应格式为[NaN, some_value, NaN]的序列。不过在当前文件规模下渲染markers会导致HTML文件崩溃,求其他解决方案?


问题原因分析

  1. SVG渲染的缺失值处理逻辑:Plotly的SVG渲染模式下,当轨迹中存在孤立的非NaN值(即前后都是NaN,如[NaN, x, NaN])时,默认不会绘制线条——因为线条需要至少两个连续有效数据点才能连接。但数据点本身存在,所以悬停时能看到提示。
  2. 大文件/多图表的SVG渲染压力:单个HTML文件包含25个图表且每个图表数据量较大(平均110k数据点)时,SVG元素数量剧增,浏览器渲染时可能出现部分轨迹渲染失败,尤其是含大量离散NaN值的轨迹更容易被“丢弃”。
  3. px.line与go.Scatter的处理差异:px.line内部对缺失值的处理和go.Scatter有细微区别,go.Scatter的mode='lines'在遇到孤立点时可能仍尝试渲染(或额外轨迹的连续有效数据更多),所以能正常显示。

解决方案

方案1:优化缺失值处理,消除孤立点

对[NaN, some_value, NaN]这类孤立点,用线性插值填充相邻NaN(仅填充前后有值的孤立点),让数据形成连续序列:

# 仅填充前后有值的孤立NaN,避免过度修改数据
data = data.interpolate(method='linear', limit=1, limit_direction='both')

方案2:强制连接间隔点

给px.line创建的轨迹设置connectgaps=True,强制Plotly跳过NaN连接有效点:

fig.update_traces(connectgaps=True)

注意:该操作会直接连接间隔的有效点,可能不符合数据逻辑,需根据需求判断是否使用。

方案3:拆分HTML文件

将25个图表拆分为多个小文件(如每5个图表一个文件),降低单个文件的渲染压力,避免浏览器崩溃或渲染不全。

方案4:切换渲染模式

若SVG压力过大,尝试切换为WebGL渲染模式(需测试浏览器兼容性):

fig = px.line(data, title=title, render_mode='webgl', markers=False)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:37:04