news 2026/9/13 23:24:30

Bokeh 3.8.0 新特性全解析:HoverTool 过滤排序、SizeBar 尺寸标注与会话重连机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Bokeh 3.8.0 新特性全解析:HoverTool 过滤排序、SizeBar 尺寸标注与会话重连机制

Bokeh 3.8.0 新特性全解析:HoverTool 过滤排序、SizeBar 尺寸标注与会话重连机制

【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh

本文以 Bokeh 官方 3.8.0 版本发布说明(docs/bokeh/source/docs/releases/3.8.0.rst)为核心脉络,结合当前仓库中的 Python 与 BokehJS 源码、官方示例与测试配置,逐项深入解读该里程碑版本引入的新能力。读完本文,你将掌握:如何用filters/sort_by/limit精确控制 HoverTool 的提示内容与数量、如何用SizeBar为径向散点图补充"第三维度"、如何通过Document.config统一配置会话重连、通知与色彩模式,以及缓冲区压缩、SVG 图标、CSS 变量主题等底层改进的来龙去脉。

版本概览:3.8.0 在 Bokeh 演进中的定位

Bokeh3.8.0(2025 年 8 月发布)是 Bokeh 项目的一个 minor milestone(次要里程碑)。它并非一次破坏性大重构,而是沿着三条主线稳步推进:

  • 交互体验深化:让 HoverTool 具备类表格查询能力的过滤、排序与数量限制;为服务端会话引入自动重连与连接状态通知。
  • 可视化表达能力扩展:新增Plot侧边面板(side panel)布局支持与SizeBar尺寸标注,并引入legend_name参数简化多图例管理。
  • 工程与性能基建升级:序列化协议支持缓冲区压缩、图标全面 SVG 化、CSS 变量主题初探、BokehJS 性能优化以及 TypeScript 5.9 构建系统升级。

下文将逐条展开,每条均给出可复制的配置/代码示例,并附上仓库内的源码证据路径。

HoverTool 的数据洞察能力升级:filters、sort_by 与 limit

3.8.0 之前,HoverTool会对命中点的所有数据行弹出 tooltip;当散点图数据密集、命中点众多时,提示内容会变得杂乱无章。3.8.0 为HoverTool增加了三个互补的能力(对应 src/bokeh/models/tools.py 中HoverTool模型的定义):

属性类型默认值作用
filtersDict(String, Either(Instance(CustomJS), List(Instance(CustomJS)))){}按字段对命中结果做自定义过滤
sort_byNullable(Either(String, List(...)))None按单个字段或字段序列排序悬停结果
limitNullable(Positive(Int))None限制显示 tooltip 的数据点数量

filters:按字段精细过滤命中点

filters以字段名为键、CustomJS回调为值,在渲染 tooltip 之前过滤命中结果。回调函数签名与 BokehJS 侧一致,可解构出valuerowindexfielddata_sourcevars等上下文。源码中的文档示例(src/bokeh/models/tools.py#L1630-L1643)演示了只显示x >= 0的命中点:

from bokeh.models import CustomJS, HoverTool filter_code = ''' export default (args, tool, {value: x, row, index, field, data_source, vars}) => { return x >= 0 } ''' tool = HoverTool(filters={"@x": CustomJS(args={}, code=filter_code)})

从 BokehJS 实现看(bokehjs/src/lib/models/tools/inspectors/hover_tool.tsx),filters变化时会触发_update_filters()(约第 187 行),并在渲染 tooltip 前对每条命中记录逐字段执行过滤器,仅保留全部通过的数据行。

sort_by:让提示内容"按需有序"

sort_by支持两种形态:

  • 简单字符串:sort_by="@y",按单个字段排序;
  • 序列形式:sort_by=[("@y", "descending"), "@x"],支持逐字段指定排序方向("ascending"/"descending",对应 src/bokeh/core/enums.py#L600-L602 的SortDirection枚举)。

需要说明的是,sort_by影响的是 tooltip 列表的展示顺序,而不是数据源本身。默认排序基于数据索引和/或与命中点的邻近程度;一旦指定sort_by,则按指定字段重新排序命中结果。

limit:限制 tooltip 条数上限

limit直接对最终展示的 tooltip 数量做截断(Positive(Int),不可为负)。BokehJS 侧在收集命中条目后执行entries.splice(limit)(hover_tool.tsx 约第 633-635 行)。合理的limit能显著降低密集散点图在 hover 时的渲染开销与视觉噪声。

三者可以组合使用:先filters剔除无关点,再sort_by排列优先级,最后用limit兜底条数,从而把 HoverTool 从"全量罗列"升级为"精准投递"。

会话可靠性:自动重连、连接事件与 UI 通知

3.8.0 为 Bokeh Server 场景引入了会话层面的可靠性机制:当 WebSocket 会话意外断开时,自动尝试恢复连接,并通过 UI 通知用户连接状态的变化。该能力由新增的文档配置模型DocumentConfig统一管理,其实现位于 src/bokeh/document/config.py。

DocumentConfig目前暴露四个可配置属性:

属性类型默认值说明
reconnect_sessionBoolTrue是否启用会话重连逻辑;若禁用,断开后不再自动恢复
notify_connection_statusBoolTrue是否在 UI 中告知用户连接状态;使用自定义通知系统时可关闭
notificationsNullable(Instance(Notifications))Notifications()配置或替换通知 UI 与逻辑
color_schemeEnum(ColorScheme)"auto"界面配色方案,取值auto/light/dark

其中notifications指向的Notifications模型(src/bokeh/models/ui/notifications.py)是一个UIElement,用于"在浏览器视口中显示全局通知(消息/错误)",即连接状态横幅背后的承载组件。color_scheme的取值来自 src/bokeh/core/enums.py#L341-L343 定义的ColorScheme字符串枚举。

一个典型的自定义配置示例:

from bokeh.document import Document from bokeh.models import Notifications doc = Document() doc.config.reconnect_session = True # 保持自动重连(默认即开启) doc.config.notify_connection_status = True # 显示连接状态通知 doc.config.notifications = Notifications() # 可替换为自定义通知组件 doc.config.color_scheme = "dark" # 强制深色 UI

对于部署了自定义前端通知体系(如独立的消息中心)的用户,将notify_connection_status设为False可避免 Bokeh 默认横幅与自有系统重复提示。

Plot 侧边面板布局与 SizeBar 标注

3.8.0 引入的SizeBar是本次发布中最具"可视化表现力"的新增标注:它允许在 2D 散点图上为径向 glyph(如CircleNgon)提供尺寸比例尺,等价于给散点图增加"第三维度"——用圆半径编码数据值,再用SizeBar告诉读者"多大的圆对应多大的数值"。

SizeBar 的完整属性面

SizeBar继承自BaseBar(两者均定义于 src/bokeh/models/annotations/legends.py,SizeBar本体见 第 915-952 行)。从基类继承的布局与刻度属性(legends.py#L785-L913)包括:

  • location"top_right"等锚点枚举或(x, y)屏幕坐标元组;若放置在侧边面板中,通常需要设为(0, 0)
  • orientation"vertical"/"horizontal"/"auto"
  • width/height:像素尺寸,支持"max"或整数,默认 200 / 50;
  • margin/padding:外部边距(默认 30)与内部留白(默认 10);
  • titletitle_standoff:标题文本及与条身的间距;标题默认字号 13px、斜体;
  • ticker/formatter:刻度计算器与格式化器,默认"auto"
  • major_label_overrides/major_label_policy:刻度标签覆盖与防重叠策略(默认NoOverlap);
  • major_tick_in/major_tick_outminor_tick_in/minor_tick_out:主/次刻度内外延伸长度;
  • bar_*/border_*/background_*:条身轮廓、边框与背景填充样式(背景默认白色、alpha 0.95)。

SizeBar自身专属的三个属性(legends.py#L926-L952):

  • rendererEither(GlyphRendererOf(RadialGlyph), Auto),默认"auto"。当图中只有一个径向 glyph renderer 时可安全使用自动模式;多个时需显式指定目标 renderer;
  • boundsEither(Auto, Tuple(Float, Float)),默认"auto",用于限制显示半径的数值范围;
  • glyph_*glyph_line_props/glyph_fill_props/glyph_hatch_props):条内示意 glyph 的线/填充/填充纹理样式,glyph_line_color默认None

BokehJS 侧的实现(bokehjs/src/lib/models/annotations/size_bar.ts)印证了上述设计:renderer == "auto"时会在 plot 的所有 renderer 中筛选径向 glyph renderer,找不到或找到多个时分别给出警告并回退(约第 264-284 行);bounds"auto"时展开为[-Infinity, Infinity],并基于glyph_view.radius的最小/最大值与 bounds 求交集(约第 304-310 行);绘制时按方向组合标题、条身与刻度(约第 123-213 行)。

官方示例:SizeBar 实战

仓库自带可直接运行的示例 examples/basic/annotations/size_bar.py:

import numpy as np from bokeh.models import SizeBar from bokeh.plotting import figure, show N = 100 x = np.random.random(size=N) * 100 y = np.random.random(size=N) * 100 radii = np.random.random(size=N) * 10 colors = np.array([(r, g, 150) for r, g in zip(50 + 2*x, 30 + 2*y)], dtype=np.uint8) p = figure() cr = p.circle(x, y, radius=radii, fill_color=colors, fill_alpha=0.6, line_color=None) size_bar = SizeBar( renderer=cr, # 绑定圆 renderer(也可省略以使用 "auto") title="SizeBar component", width="max", # 条宽占满可用空间 orientation="horizontal", # 水平条 glyph_fill_color="violet", glyph_fill_alpha=0.8, glyph_line_color="black", border_line_color="gray", border_line_dash="dotted", ) p.add_layout(size_bar, "below") # 挂载到下方侧边面板 show(p)

注意p.add_layout(size_bar, "below")正是 3.8.0 侧边面板(side panel)布局能力的一种体现——SizeBar被安放在 plot 的 below 面板中,而非叠加在绘图区域内部。

Document.config:文档级配置的统一入口

DocumentConfig不仅承载会话重连相关配置,它同时也是 3.8.0 引入的"文档配置"(Document.config)入口本身。通过doc.config这一属性,开发者可以在一个位置集中控制文档级行为,避免散落在各处的手工模型属性调整。从 src/bokeh/document/config.py 可以看到,DocumentConfig本身是一个Model子类,因此它同样遵循 Bokeh 的属性系统与序列化流程,可以在服务端设置、随文档传输到前端生效。

这一设计的意义在于:连接策略、通知样式、配色方案等"应用级"偏好,从此有了明确的归属与统一的编程接口,也为后续版本扩展更多文档级配置项预留了空间。

legend_name:更简单的多图例管理

3.8.0 为 glyph API 增加了legend_name关键字参数,用于"按图例名归组",彻底简化了多图例场景下的 renderer 分配。其实现位于 src/bokeh/plotting/_legends.py:

  • pop_legend_kwarg(约第 62-63 行)从调用参数中取出legend_name
  • update_legend(第 65-67 行)根据legend_name查找或创建对应的Legend实例;
  • _get_or_create_legend(第 81-107 行)的核心逻辑是:先收集图中所有legend类型的 renderer,若指定了legend_name,则筛选出name == legend_name的图例——找不到时抛出RuntimeError("can't find Legend instance with '...' name"),找到多个时抛出RuntimeError("found multiple Legend instances with '...' name");若未指定名称,则沿用"图中只允许一个图例"的传统约束,否则提示用户"用 name 区分图例,并用 legend_name 参数将 renderer 指派到对应图例"。

典型用法(区别于旧的p.legend单例模式):

from bokeh.plotting import figure p = figure() p.add_layout(Legend(name="first"), "right") p.add_layout(Legend(name="second"), "right") p.circle(x, y, legend_label="first", legend_name="first") p.square(x, y, legend_label="second", legend_name="second")

配合Legend.name属性,开发者可以在同一张图中维护多个独立图例,并精准控制每个 renderer 归属于哪个图例,无需再手动拼接p.legend的 renderer 列表。

序列化协议:缓冲区压缩的底层实现

3.8.0 为 Bokeh 序列化协议加入了 buffer(如大型数值数组)的压缩支持,这对大数据集的前端传输有明显收益。其 Python 侧核心位于 src/bokeh/core/serialization.py 的Buffer数据类(第 159-180 行):

@dataclass class Buffer: id: ID data: bytes | memoryview def to_compressed_bytes(self) -> bytes: level = settings.compression_level() # Python 3.11/3.12 存在 mtime=0 时 Gzip 头部 OS 字段不稳定的问题, # 因此这里使用 mtime=1 以保证可复现输出 return gzip.compress(self.to_bytes(), mtime=1, compresslevel=level) def to_base64(self) -> str: return base64.b64encode(self.to_compressed_bytes()).decode("utf-8")

对应地,BokehJS 侧的解压逻辑位于 bokehjs/src/lib/core/util/buffer.ts:buffer_to_base64使用fflategzipSync(bytes, {mtime: 0})压缩后 base64 编码(第 32-38 行,注释说明固定mtime=0是为了测试结果可复现),base64_to_buffer则用gunzipSync解压还原(第 40-43 行)。

压缩级别通过BOKEH_COMPRESSION_LEVEL环境变量控制,默认值为 2(src/bokeh/settings.py#L656 附近的compression_level设置),即默认启用但级别偏低、速度优先。此外,bokeh serve命令行也暴露了websocket_compression_levelwebsocket_compression_mem_level参数(见 src/bokeh/command/subcommands/serve.py#L860-L876 的参数收集列表,以及 src/bokeh/server/tornado.py 中对应的 WebSocket 压缩配置),用于调整 WebSocket 通道自身的压缩级别。

视觉与主题:SVG 图标与 CSS 变量主题初探

3.8.0 将原先的 PNG 图标全面转换为 SVG,并对既有图标做了一轮整体刷新。仓库中可见佐证是 bokehjs/src/less/icons/ 目录下 83 个.svg图标文件,它们由 bokehjs/src/less/icons.less 统一组织为图标字体/样式资源。SVG 化的收益在于:任意分辨率下保持清晰、易于通过 CSS 着色与缩放、资源体积更小。

同期引入的"基于 CSS 变量的主题化"属于初步支持(preliminary support)。相关 CSS 变量定义集中在 bokehjs/src/less/vars.less,配合上文的DocumentConfig.color_schemeauto/light/dark)可让 Bokeh UI 初步跟随系统或应用指定的明暗模式。值得强调的是,该特性在 3.8.0 中仍处于早期阶段,主题变量的覆盖面与稳定性会随后续版本逐步完善。

BokehJS 性能改进与 TypeScript 5.9 构建升级

3.8.0 还包含多项 BokehJS 性能改进(涉及渲染管线与序列化相关路径),以及将 bokehjs 构建系统升级至 TypeScript 5.9 的工程调整。TypeScript 版本升级主要影响库内部开发与构建,对最终用户 API 透明。性能改进的细节分散在 bokehjs/src/lib 各模块中,若需进一步定位,可重点检索核心渲染(core/visualsmodels/glyphs)与序列化(core/util)相关目录的近期改动。

升级与验证建议

  • 升级方式:通过pip install bokeh==3.8.0安装对应版本;运行bokeh serve前可通过BOKEH_COMPRESSION_LEVEL调整 buffer 压缩级别(默认 2)。
  • 快速验证新特性:
    • 运行 examples/basic/annotations/size_bar.py 查看SizeBar效果;
    • HoverTool组合filters/sort_by/limit,观察密集散点图 tooltip 的数量与排序变化;
    • 在 Bokeh Server 应用中通过doc.config开启重连并切换color_scheme,测试断线恢复与通知展示。
  • 回归测试参考:仓库的测试套件(tests/unit/bokeh、bokehjs/test)覆盖了上述模型属性与序列化路径,升级后建议运行相关单元测试以确认与自定义扩展的兼容性。

总体而言,3.8.0 是一个"体验与基建并重"的版本:面向用户的新交互能力(HoverTool 三件套、SizeBar、legend_name)直接提升了图表的可用性,而会话重连、缓冲区压缩、SVG 图标与 CSS 变量主题则为更大规模、更可靠、更现代的应用形态打下了基础。开发者可以根据自身场景,优先采用其中与业务最相关的若干项能力。

【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 23:22:10

高效文档压缩技术:原理、工具与实战指南

1. 文档压缩的必要性与痛点分析在日常办公场景中,PPT、Word、Excel等文档的体积膨胀问题已经成为影响工作效率的显著障碍。一个包含高清图片的PPT文件轻松突破50MB,而带有复杂数据透视表的Excel工作簿也可能达到惊人的体积。这种"文档肥胖症"会…

作者头像 李华
网站建设 2026/9/13 23:20:35

B2B战略咨询行业趋势与标杆方法论解析

1. 2026年B2B战略咨询行业格局前瞻过去五年间,B2B战略咨询行业经历了从传统方法论到数据智能驱动的范式转移。根据第三方机构数据显示,2023年全球战略咨询市场规模已达3000亿美元,其中B2B领域占比超过65%。在这个快速演进的赛道中&#xff0c…

作者头像 李华