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

Holoviews中实现双标记点图与双流关联DynamicMap时序联动

Holoviews实现不同标记散点图+双流联动时序图

核心问题解决思路

  1. 标记与图例问题:hv.dim动态设置marker无法生成图例,原因是动态映射不会触发图例生成逻辑。解决方案是将两类数据拆分为独立的Points对象,分别设置标记和标签后叠加,自动生成图例。
  2. 双流联动问题:为两个Points分别创建Selection1D流,在DynamicMap的回调函数中同时监听两个流的选中索引,判断哪类数据被点击后返回对应时序图。

完整代码实现

import holoviews as hv
import pandas as pd
hv.extension('bokeh')

# 模拟散点数据(替换为你的真实数据)
scatter_data = pd.DataFrame({
    'x': [1,2,3,4,5],
    'y': [2,4,1,5,3],
    'value': [10,20,15,25,18],
    'type': ['d','h','d','h','d'],
    'id': ['A','B','C','D','E']
})

# 模拟时序数据(替换为你的真实数据,key对应散点的id)
timeseries_data = {
    'A': pd.DataFrame({'time': pd.date_range('2023-01-01', periods=10), 'val': range(10)}),
    'B': pd.DataFrame({'time': pd.date_range('2023-01-01', periods=10), 'val': range(10,20)}),
    'C': pd.DataFrame({'time': pd.date_range('2023-01-01', periods=10), 'val': range(5,15)}),
    'D': pd.DataFrame({'time': pd.date_range('2023-01-01', periods=10), 'val': range(15,25)}),
    'E': pd.DataFrame({'time': pd.date_range('2023-01-01', periods=10), 'val': range(20,30)})
}

# 1. 拆分数据并创建带标记和图例的散点图
data_d = scatter_data[scatter_data['type'] == 'd']
data_h = scatter_data[scatter_data['type'] == 'h']

points_d = hv.Points(data_d, kdims=['x', 'y'], vdims=['value', 'id', 'type']).opts(
    marker='circle', color='value', cmap='viridis', label='Type D',
    colorbar=True, size=10, tools=['tap']
)
points_h = hv.Points(data_h, kdims=['x', 'y'], vdims=['value', 'id', 'type']).opts(
    marker='square', color='value', cmap='viridis', label='Type H',
    size=10, tools=['tap']
)

scatter_plot = points_d * points_h

# 2. 创建双流并关联DynamicMap
sel_d = hv.streams.Selection1D(source=points_d)
sel_h = hv.streams.Selection1D(source=points_h)

def timeseries_callback(index_d, index_h):
    # 判断哪类数据被选中
    if index_d:
        selected_id = data_d.iloc[index_d[0]]['id']
    elif index_h:
        selected_id = data_h.iloc[index_h[0]]['id']
    else:
        return hv.Curve([]).opts(title='Select a point')
    
    ts_df = timeseries_data[selected_id]
    return hv.Curve(ts_df, kdims='time', vdims='val').opts(
        title=f'Timeseries for ID: {selected_id}',
        xlabel='Time', ylabel='Value', width=600
    )

dynamic_ts = hv.DynamicMap(timeseries_callback, streams=[sel_d, sel_h])

# 3. 组合布局并优化样式
layout = (scatter_plot + dynamic_ts).cols(1)
layout.opts(
    hv.opts.Points(legend_position='top_right'),
    hv.opts.Curve(toolbar='above')
)

关键细节说明

  • 图例生成:每个Points对象通过label参数设置图例名称,叠加后Holoviews自动合并图例,支持点击图例切换显示/隐藏对应类别。
  • 双流监听:回调函数的参数顺序必须和streams列表的顺序一致,分别对应两个流的选中索引数组。当无选中点时返回空图,避免报错。
  • 交互工具:必须为每个Points添加tap工具,否则点击不会触发Selection1D流的更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:23:28