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文件崩溃,求其他解决方案?
问题原因分析
- SVG渲染的缺失值处理逻辑:Plotly的SVG渲染模式下,当轨迹中存在孤立的非NaN值(即前后都是NaN,如
[NaN, x, NaN])时,默认不会绘制线条——因为线条需要至少两个连续有效数据点才能连接。但数据点本身存在,所以悬停时能看到提示。 - 大文件/多图表的SVG渲染压力:单个HTML文件包含25个图表且每个图表数据量较大(平均110k数据点)时,SVG元素数量剧增,浏览器渲染时可能出现部分轨迹渲染失败,尤其是含大量离散NaN值的轨迹更容易被“丢弃”。
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
相关产品推荐
相关产品推荐

