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

如何使用ipywidgets+Plotly实现无全局变量可嵌入HBox的交互式散点图

解决方案

调整要点

  • 补全了FloatRangeSlider的事件监听,滑块值变更时同步更新色条显示范围
  • 切换颜色字段的回调中新增滑块范围同步逻辑,同时更新色条的全局取值范围和悬停提示标签
  • 移除全局变量依赖,所有数据和组件逻辑在同一上下文内运行
  • 所有数据变更场景(筛选ID、切换字段、调整色条范围)都同步更新对应图表属性,保证交互一致性

完整可运行代码

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import ipywidgets as widgets

# 初始化测试数据
big_grid=pd.DataFrame(data=dict(
    id_col=[1,2,3,4,5],
    col1=[0.1,0.2,0.3,0.4,0.5],
    col2=[10,20,30,40,50],
    coord1=[6,7,8,9,10],
    coord2=[6,7,8,9,10]
))
list_elem=["col1","col2"]
list_id=big_grid.id_col.values

# 初始化交互组件
dropm_elem=widgets.Dropdown(options=list(list_elem)) 
dropm_id=widgets.SelectMultiple(options=list_id,description="Active",disabled=False, value=list_id) # 默认全选ID
rangewidg=widgets.FloatRangeSlider(
    value=[big_grid[dropm_elem.value].min(),big_grid[dropm_elem.value].max()],
    min=big_grid[dropm_elem.value].min(),
    max=big_grid[dropm_elem.value].max(),
    step=0.001,
    readout_format='.3f',
    description="Color Range",
    continuous_update=False
)

# 初始化FigureWidget
fig = go.FigureWidget(
    data=px.scatter(
        big_grid, 
        x="coord1",
        y="coord2",
        color=dropm_elem.value, # 直接传字段名,自动关联hover属性
        color_continuous_scale="Turbo",
    )
)

# ID筛选变更回调
def handle_id_change(change):
    filtered = big_grid[big_grid['id_col'].isin(dropm_id.value)]
    with fig.batch_update():
        fig.data[0]['x'] = filtered["coord1"]
        fig.data[0]['y'] = filtered["coord2"]
        fig.data[0]['marker']['color'] = filtered[dropm_elem.value]
        fig.data[0]['marker']['cmin'] = rangewidg.value[0]
        fig.data[0]['marker']['cmax'] = rangewidg.value[1]
        # 同步更新悬停提示
        fig.data[0]['customdata'] = filtered[[dropm_elem.value, 'id_col']]
        fig.data[0]['hovertemplate'] = f'coord1: %{{x}}<br>coord2: %{{y}}<br>id_col: %{{customdata[1]}}<br>{dropm_elem.value}: %{{customdata[0]}}<extra></extra>'

# 颜色字段切换回调
def handle_elem_change(change):
    selected_col = dropm_elem.value
    # 同步更新滑块范围
    with rangewidg.hold_trait_notifications():
        rangewidg.min = big_grid[selected_col].min()
        rangewidg.max = big_grid[selected_col].max()
        rangewidg.value = [big_grid[selected_col].min(), big_grid[selected_col].max()]
    filtered = big_grid[big_grid['id_col'].isin(dropm_id.value)]
    with fig.batch_update():
        fig.data[0]['marker']['color'] = filtered[selected_col]
        fig.data[0]['marker']['cmin'] = rangewidg.value[0]
        fig.data[0]['marker']['cmax'] = rangewidg.value[1]
        fig.layout.coloraxis.colorbar.title = selected_col
        # 同步更新悬停提示
        fig.data[0]['customdata'] = filtered[[selected_col, 'id_col']]
        fig.data[0]['hovertemplate'] = f'coord1: %{{x}}<br>coord2: %{{y}}<br>id_col: %{{customdata[1]}}<br>{selected_col}: %{{customdata[0]}}<extra></extra>'

# 色条范围滑块变更回调
def handle_range_change(change):
    cmin, cmax = rangewidg.value
    with fig.batch_update():
        fig.data[0]['marker']['cmin'] = cmin
        fig.data[0]['marker']['cmax'] = cmax

# 绑定事件监听
dropm_elem.observe(handle_elem_change, names='value')
dropm_id.observe(handle_id_change, names='value')
rangewidg.observe(handle_range_change, names='value')

# 组装布局,输出的box为标准Widget组件可直接嵌套到其他布局
right_box1 = widgets.HBox([fig])
right_box2 = widgets.VBox([dropm_elem, dropm_id, rangewidg])
box = widgets.HBox([right_box1, right_box2])
box

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 08:27:01