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

Python Plotly是否有类似R中highlight_key()的跨图交互函数?

Python Plotly 实现类似 R 中 highlight_key() 的多图交互方案

R 的 Plotly 中 highlight_key() 可以快速绑定数据集实现多图联动,Python Plotly 虽然没有直接同名函数,但有两种更简便优化的实现方式:

一、纯客户端静态交互(无需后端,直接生成可交互HTML)

这种方式通过共享legendgroup和customdata绑定关联数据系列,结合highlight()方法实现选中高亮、未选中淡化的联动效果,完全对应 R 示例的交互逻辑:

import plotly.express as px
from plotly.subplots import make_subplots
import pandas as pd

# 加载示例数据集
txhousing = px.data.txhousing()

# 预处理缺失值统计数据(对应R中的summarise+filter)
miss_df = txhousing.groupby('city')['median'].apply(lambda x: x.isna().sum()).reset_index(name='miss')
miss_df = miss_df[miss_df['miss'] > 0]
# 按缺失值排序城市
miss_df['city'] = pd.Categorical(miss_df['city'], categories=miss_df.sort_values('miss')['city'], ordered=True)

# 创建子图布局,匹配R示例的宽度比例
fig = make_subplots(
    rows=1, cols=2,
    column_widths=[0.2, 0.8],
    subplot_titles=("缺失月份数", "房价中位数时间序列")
)

# 添加散点图(对应R的dot_plot)
scatter = px.strip(miss_df, x='miss', y='city', hover_data=['city', 'miss'])
for trace in scatter.data:
    # 绑定城市标识用于联动
    trace.customdata = trace.y
    trace.legendgroup = trace.y[0] if len(trace.y) == 1 else "城市"
    fig.add_trace(trace, row=1, col=1)

# 添加时间序列图(对应R的time_series)
timeseries = px.line(txhousing, x='date', y='median', color='city')
for trace in timeseries.data:
    # 绑定相同的legendgroup,实现跨图联动
    trace.legendgroup = trace.name
    trace.customdata = [trace.name] * len(trace.x)
    fig.add_trace(trace, row=1, col=2)

# 布局配置,隐藏图例
fig.update_layout(
    showlegend=False,
    yaxis_title="",
    xaxis_title="缺失月份数",
    xaxis2_title="日期",
    yaxis2_title="房价中位数"
)

# 启用点击选择模式,配置高亮规则
fig.update_layout(clickmode='event+select')
fig = fig.highlight(
    on='select',
    selected={'marker': {'opacity': 1, 'color': '#ff4136'}, 'line': {'width': 3, 'color': '#ff4136'}},
    unselected={'marker': {'opacity': 0.2}, 'line': {'opacity': 0.2}}
)

fig.show()

优势:

  • 纯前端交互,生成的HTML可直接分享,无需服务器
  • 用plotly.express简化绘图代码,逻辑和R示例完全对齐
  • 支持点选、框选等多种选择方式,高亮效果可自定义

二、Dash 动态双向联动(进阶方案)

如果需要更灵活的交互(比如点击后直接过滤另一张图的数据集),可以用Plotly官方的Dash框架实现双向动态联动:

from dash import Dash, dcc, html, Input, Output, callback
import plotly.express as px
import pandas as pd

# 加载并预处理数据
txhousing = px.data.txhousing()
miss_df = txhousing.groupby('city')['median'].apply(lambda x: x.isna().sum()).reset_index(name='miss')
miss_df = miss_df[miss_df['miss'] > 0]
miss_df['city'] = pd.Categorical(miss_df['city'], categories=miss_df.sort_values('miss')['city'], ordered=True)

# 初始化Dash应用
app = Dash(__name__)

app.layout = html.Div([
    html.Div([
        dcc.Graph(id='dot-plot', style={'height': '80vh'})
    ], style={'width': '20%', 'display': 'inline-block', 'verticalAlign': 'top'}),
    html.Div([
        dcc.Graph(id='time-series', style={'height': '80vh'})
    ], style={'width': '80%', 'display': 'inline-block'})
])

# 散点图选点更新时间序列
@callback(
    Output('time-series', 'figure'),
    Input('dot-plot', 'selectedData')
)
def update_time_series(selected_data):
    if not selected_data:
        filtered_df = txhousing
    else:
        selected_cities = [point['y'] for point in selected_data['points']]
        filtered_df = txhousing[txhousing['city'].isin(selected_cities)]
    return px.line(filtered_df, x='date', y='median', color='city')

# 时间序列选点更新散点图
@callback(
    Output('dot-plot', 'figure'),
    Input('time-series', 'selectedData')
)
def update_dot_plot(selected_data):
    if not selected_data:
        filtered_df = miss_df
    else:
        selected_cities = [trace['name'] for trace in selected_data['points']]
        filtered_df = miss_df[miss_df['city'].isin(selected_cities)]
    return px.strip(filtered_df, x='miss', y='city', hover_data=['city', 'miss'])

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

优势:

  • 双向动态联动,点击任意图的元素,另一张图自动过滤数据
  • 支持复杂的自定义逻辑(比如多条件过滤、数据转换)
  • 官方维护,文档完善,适合构建专业的交互式数据分析应用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:57:07