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

Plotly Express缩放时仅显示可见数据图例值的实现方法问询

在Plotly Express中仅显示可见数据对应的图例

可以实现,但Plotly Express默认不支持这个功能,需要通过自定义交互逻辑来动态更新图例显示。以下分两种常用场景给出解决方案:

场景1:Jupyter Notebook环境(使用FigureWidget)

利用Plotly的FigureWidget监听轴范围变化事件,实时过滤可见数据并更新图例:

import plotly.graph_objects as go
import plotly.express as px
import numpy as np

# 模拟你的数据(替换为实际的proj_2D和topic_nums)
np.random.seed(42)
proj_2D = np.random.randn(500, 2)
topic_nums = np.random.randint(0, 10, 500)

# 生成初始散点图并转为FigureWidget
fig_2d = px.scatter(
    proj_2D, x=0, y=1,
    color=topic_nums.astype(str), labels={'color': 'topic'}
)
fig_2d.update_traces(marker=dict(size=5))
fig_2d.update_layout(autosize=False, width=1000, height=800)
fw = go.FigureWidget(fig_2d)

# 定义图例更新逻辑
def update_legend(trace, layout, fig):
    # 获取当前轴范围
    x_min, x_max = layout.xaxis.range
    y_min, y_max = layout.yaxis.range
    
    # 收集可见的topic
    visible_topics = set()
    for trace in fig.data:
        # 检查当前trace是否有数据点在可视范围内
        x_in_range = np.logical_and(trace.x >= x_min, trace.x <= x_max)
        y_in_range = np.logical_and(trace.y >= y_min, trace.y <= y_max)
        if np.any(np.logical_and(x_in_range, y_in_range)):
            visible_topics.add(trace.legendgroup)
    
    # 更新每个trace的图例可见性
    for trace in fig.data:
        trace.showlegend = (trace.legendgroup in visible_topics)

# 绑定轴范围变化事件
fw.layout.on_change(update_legend, 'xaxis.range', 'yaxis.range')

# 显示交互式图表
fw

场景2:Web应用(使用Dash框架)

如果需要部署为Web应用,用Dash监听图表的relayoutData事件来实现动态更新:

import dash
from dash import dcc, html, Input, Output, State
import plotly.express as px
import numpy as np
import pandas as pd

# 模拟数据(替换为实际数据)
np.random.seed(42)
proj_2D = np.random.randn(500, 2)
topic_nums = np.random.randint(0, 10, 500)
df = pd.DataFrame(proj_2D, columns=['x', 'y'])
df['topic'] = topic_nums.astype(str)

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Graph(id='scatter-graph', figure={}),
])

@app.callback(
    Output('scatter-graph', 'figure'),
    Input('scatter-graph', 'relayoutData'),
    State('scatter-graph', 'figure')
)
def update_legend(relayout_data, fig):
    # 初始渲染图表
    if not fig:
        fig = px.scatter(df, x='x', y='y', color='topic', labels={'color': 'topic'})
        fig.update_traces(marker=dict(size=5))
        fig.update_layout(autosize=False, width=1000, height=800)
        return fig
    
    if not relayout_data:
        return fig
    
    # 获取当前轴范围(优先取relayout事件中的新范围,无则用现有范围)
    x_range = relayout_data.get('xaxis.range', fig['layout']['xaxis']['range'])
    y_range = relayout_data.get('yaxis.range', fig['layout']['yaxis']['range'])
    
    if not x_range or not y_range:
        return fig
    
    # 收集可见的topic
    visible_topics = set()
    for trace in fig['data']:
        x_arr = np.array(trace['x'])
        y_arr = np.array(trace['y'])
        in_range = np.logical_and(
            np.logical_and(x_arr >= x_range[0], x_arr <= x_range[1]),
            np.logical_and(y_arr >= y_range[0], y_arr <= y_range[1])
        )
        if np.any(in_range):
            visible_topics.add(trace['legendgroup'])
    
    # 更新图例可见性
    for trace in fig['data']:
        trace['showlegend'] = (trace['legendgroup'] in visible_topics)
    
    return fig

if __name__ == '__main__':
    app.run_server(debug=True)

注意事项

  • 数据量较大时,建议提前按topic分组存储数据,减少每次过滤的计算量,提升响应速度。
  • 两种方案都是通过判断每个trace是否有数据点落在当前可视范围内,来控制其图例项的显示/隐藏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 02:15:02