Bokeh中经CDSView过滤的vbar如何统计散点选中的分组数据计数
核心实现底层逻辑
要打通三类能力的联动,首先得摸清楚Bokeh各模块的状态存储边界,这是做交集计算的核心基础:
- 共享同一个
ColumnDataSource时,用户的选中状态是全局同步的:不管在哪个关联的图表上触发点选/框选,选中的行索引都会统一存在这个源的selected.indices属性里,不会因为图表的不同拆分存储 CDSView的本质是维护一组指向原始CDS的有效索引列表,所有挂载了这个视图的图表,都只会渲染这组索引对应的原始数据,不会额外改动原始CDS里的选中状态、数据本身- 你需要的有效计数样本,本质就是「CDSView过滤后的有效索引集合」和「用户选中的索引集合」的交集——因为两个索引体系都是直接指向原始CDS的行号,完全对齐,不存在跨源的索引错位问题
分步实现流程
- 第一步:搭好统一的数据源架构
- 全程用同一个基础
ColumnDataSource存全量原始样本,别给散点、柱状图分别建独立源,不然索引对不上,选中的状态根本没法联动 - 提前定义好全局通用的
CDSView实例,把项目要用到的过滤规则都挂在这个视图上,这个视图一方面绑给散点图控制散点的渲染范围,另一方面供计数回调调用,确定计数的样本范围 - 单独给vbar建一个轻量的聚合用
ColumnDataSource,结构只存两个字段:分类轴的取值列表x、对应分类的计数值top,专门给垂直柱状图做数据绑定
- 全程用同一个基础
- 第二步:写动态计数的回调逻辑
- 把同一个计数回调挂两个触发源,避免联动失效:
- 基础CDS的
selected属性变更事件:只要用户在散点图上调整选中范围,就自动触发重算 - 全局CDSView的过滤规则变更事件:只要调整筛选条件导致过滤范围变化,就自动触发重算
- 基础CDS的
- 回调内部的计算分三步走:
- 调用
view.get_array_indices(),拿到当前视图过滤后对应的所有原始数据的行号 - 读基础CDS的
selected.indices,拿到用户当前选中的所有原始数据行号 - 把两个行号集合求交集,把交集里对应样本的分类字段做频次统计,把统计好的分类列表、对应计数值直接更新到柱状图专属的聚合CDS的
data里,vbar会自动跟着刷新
- 调用
- 把同一个计数回调挂两个触发源,避免联动失效:
容易踩的坑
- 别做多余的索引转换:CDSView返回的有效索引、CDS存的选中索引,都是直接对应原始CDS的行号,没有偏移、没有重映射,直接求集合交就行,不需要额外做视图层级的转换
- 逻辑不需要额外加优先级判断:如果用户选中的点刚好不在当前过滤规则的有效范围内,这部分点自动会被排除在交集外,天然就满足“同时满足两个条件才计数”的要求
- 别把vbar直接绑到存原始样本的大CDS上:vbar要的是聚合后的分组结果,和原始样本的结构完全不一样,用独立的聚合CDS能避免数据结构不匹配导致的渲染异常
内容的提问来源于stack exchange,提问作者Alessia Marcolini
相关产品推荐
相关产品推荐

