Bokeh 3.10.0 版本深度解读:WebGL 补丁渲染、LightDark 主题切换与全新架构升级
2026/9/14 22:21:45 网站建设 项目流程

Bokeh 3.10.0 版本深度解读:WebGL 补丁渲染、LightDark 主题切换与全新架构升级

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

Bokeh3.10.0(2026 年 5 月发布)是 Bokeh 项目的一个重要次要里程碑版本。本次版本围绕渲染性能(WebGL 支持 Patch 图形)、主题系统(LightDark 组件)、架构重构(虚拟 DOM 与 TypeScript 原生编译器)以及 Python 版本策略调整四大主线展开,同时带来导出后端、错误诊断、回调 API 等一系列体验改进。阅读本文后,你将掌握 3.10.0 的全部核心变更点、对应的源码实现位置与可运行的示例用法,能够快速评估升级影响并上手新特性。

一、版本总览与兼容性变化

1.1 版本定位

3.10.0 属于 Bokeh 的 minor(次版本)里程碑,整体保持 API 兼容的前提下,重点完成渲染管线、UI 组件内部实现与构建系统的换代,为后续版本铺路。官方发布说明收录于仓库的 releases/3.10.0.rst。

1.2 终止支持 Python 3.10 与 3.11

本次版本正式放弃对 Python 3.10(:bokeh-pull:14865)与 Python 3.11(:bokeh-pull:15174)的支持。这意味着:

  • 升级到 3.10.0 之前,请确认运行环境为Python 3.12 及以上
  • 仍在 Python 3.10/3.11 上的既有应用应保持锁定旧版 Bokeh,或先完成解释器升级再升级 Bokeh;
  • 放弃旧版本解释器为后续采用 Python 3.14 新语法(如模板字符串回调)扫清了障碍(见下文 CustomJS 部分)。

从仓库的 CI 与打包配置(pyproject.toml、setup.py)也可以看到项目整体向新版 Python 生态收敛的趋势。

二、WebGL 渲染正式支持 Patch 与 Patches 图形

2.1 变更内容

3.10.0 为PatchPatches两类图形添加了WebGL 渲染后端(:bokeh-pull:14853)。此前 WebGL 加速仅覆盖 Circle、Line 等常用 glyph,Patch(单块多边形填充)与 Patches(多块多边形集合)在数据量大时依赖 Canvas 2D 绘制,性能受限;本次改动让它们也能走 GPU 管线。

2.2 源码实现

BokehJS 侧的实现位于 bokehjs/src/lib/models/glyphs/webgl,其中:

  • patch.ts 与 patches.ts 分别对应单个 Patch 与批量 Patches 的 WebGL 绘制逻辑;
  • types.ts 定义了与 patch 相关的 WebGL 着色器/缓冲类型协议。

从源码结构看,这两类 glyph 的 WebGL 实现沿用了 bokehjs 现有 glyph 渲染框架:在初始化时创建 GPU 缓冲区、编译着色器,并在视口变换时同步更新变换矩阵,最终在每一帧通过统一的 WebGL 渲染器批量提交绘制。

2.3 使用建议

该特性对用户透明,无需修改代码:只要浏览器支持 WebGL(或启用webgl=True),绘制 Patch/Patches 时 Bokeh 会自动选择 GPU 渲染路径。适合在地理区域着色、等高线填充、大规模多边形标注等场景获得更流畅的交互体验。仓库中 examples 目录下已有的 patch 相关示例(如 examples/basic/areas/multipolygons.py、examples/topics/geo 等)可直接用于验证渲染效果。

三、新增 LightDark 组件:一键切换明暗主题

3.1 组件定位

3.10.0 新增LightDark组件(:bokeh-pull:14807),用于在浅色与深色主题之间切换。同时(:bokeh-pull:14915)为其增加auto/system 选项,并对 Toggle 一类的组件引入三态(tri-state)处理,使组件支持“浅色 / 深色 / 跟随系统”三种状态。

3.2 源码定义

在 Python 侧,LightDark定义于 src/bokeh/models/widgets/inputs.py#L351-L366:

class LightDark(Switch): """ A switch widget to change between themes (light and dark). """ active = Override(default=None) on_icon = Override(default="light_theme") off_icon = Override(default="dark_theme") indeterminate_icon = Override(default="system_theme") tri_state = Override(default=True)

关键设计点:

  • 继承自Switch(开关类控件),因此天然具备开关的交互语义;
  • active默认被覆盖为None(三态中的“未定/跟随系统”态);
  • 三种状态分别使用内置图标light_themedark_themesystem_theme标识;
  • tri_state = True开启三态能力,点击会在light → dark → system → light之间循环。

3.3 与文档级颜色方案的联动

主题切换并非孤立组件,它与 Bokeh 文档配置中的color_scheme属性联动:

  • 颜色方案枚举定义在 src/bokeh/core/enums.py#L341-L343,取值为"auto" | "light" | "dark"
  • 文档配置项color_scheme定义于 src/bokeh/document/config.py#L77,默认"auto"

也就是说,切换LightDark组件会同步改变curdoc().config.color_scheme,进而驱动整个文档的主题渲染。

3.4 实战示例

仓库自带的服务器示例 examples/server/app/light_dark.py 演示了完整联动流程:

from bokeh import events from bokeh.core.enums import ColorScheme from bokeh.io import curdoc from bokeh.layouts import row from bokeh.models import Div, Dropdown, LightDark def on_dropdown_click(event): curdoc().config.color_scheme = event.item def on_config_color_scheme_change(attr, old, new): div.text = f"Current scheme: {new}" color_scheme = ColorScheme.auto curdoc().config.color_scheme = color_scheme curdoc().title = "LightDark" curdoc().config.on_change("color_scheme", on_config_color_scheme_change) menu = [("Dark", ColorScheme.dark), ("Auto", ColorScheme.auto), ("Light", ColorScheme.light)] color_scheme_dropdown = Dropdown(label="Update color scheme", menu=menu) color_scheme_dropdown.on_event(events.MenuItemClick, on_dropdown_click) light_dark = LightDark() div = Div(text=f"Current scheme: {color_scheme}") curdoc().add_root( row([color_scheme_dropdown, light_dark, div], stylesheets=[ ":host { background-color: light-dark(white, black); color: light-dark(black, white);}", ]), )

要点:

  1. 通过curdoc().config.color_scheme设置初始方案,并注册on_change监听方案变化;
  2. LightDark()直接使用默认三态配置;
  3. 外层布局通过 CSS 的light-dark()函数同时适配两种主题背景/前景色;
  4. 纯前端场景可参考 examples/interaction/widgets/light_dark.py——它用js_on_change+CustomJS读取cb_obj.document.config.color_scheme,无需 Python 回调。

在各类样式示例(examples/styling/office-style/office_style.py、examples/styling/accessible-style/accessible_style.py、examples/styling/xkcd-style/xkcd_style.py)中也都能看到LightDark(active=True, stylesheets=[...])的用法,说明它可以与自定义stylesheets无缝组合。

四、主题与 UI 组件的 vDOM 化重构

4.1 视图层全面迁移到虚拟 DOM

3.10.0 对 BokehJS 的视图内部与组件实现进行了虚拟 DOM(virtual DOM)重构(:bokeh-pull:14829)。这意味着组件渲染不再直接操作真实 DOM,而是先在虚拟节点上完成差异计算再批量应用到真实 DOM,减少不必要的重排与重绘。

4.2 Tooltip 组件改造

配合 vDOM 迁移,Tooltip 组件被迁移到 vDOM 并大幅简化了主题定制(:bokeh-pull:14955)。此前定制 Tooltip 样式往往需要覆盖深层 CSS 选择器,现在可以通过更直接的样式表路径进行定制,具体样式入口可参考 bokehjs/src/less/tooltips.less 与对应的工具提示示例 examples/interaction/tooltips。

4.3 Tabs 组件重构与无障碍改进

Tabs 组件被重写为 vDOM 实现(:bokeh-pull:15168),并新增:

  • 键盘导航:可通过方向键在标签页之间切换;
  • 无障碍(accessibility)改进:标签语义、焦点管理、ARIA 属性的生成更规范。

这使依赖 Tab 布局的仪表盘应用(参考 examples/basic/layouts/tabs_scrollable.py)在可访问性上直接受益。

4.4 UI 组件迁移到 adopted CSS stylesheets

UI 组件改为使用adopted CSS stylesheets(:bokeh-pull:14973)。该机制允许样式表被多个文档节点共享、按需注入,降低了组件样式隔离与注入的开销,与 vDOM 渲染管线相辅相成。底层样式源可参见 bokehjs/src/less 目录下的ui.lessbuttons.lessmenus.less等文件。

五、构建系统:迁移到 TypeScript 原生编译器(tsgo)

5.1 变更内容

BokehJS 的构建系统被重新设计,改用 TypeScript 原生的tsgo(TypeScript-native Go)编译器(:bokeh-pull:14812),取代此前基于 tsc 的编译链路。从源码看,构建任务定义于 bokehjs/make/tasks(含compiler.tsesm.tspack.ts等),构建入口配置位于 bokehjs/make/package.json 与 bokehjs/tsconfig.base.json。

5.2 影响

  • 对最终用户透明:发布包中的 BokehJS 产物行为不变;
  • 对 BokehJS 开发/自定义扩展(custom extension)开发者:编译速度与内存占用有望改善,且编译语义更贴近 TypeScript 官方原生实现;
  • 开发自定义扩展(参考 examples/advanced/extensions)时,建议以 3.10.0 的bokehjs构建链为准重新编译验证。

六、新增 perform_error_diagnostics 设置项

6.1 设置定义

3.10.0 新增perform_error_diagnostics设置标志(:bokeh-pull:14947),用于控制 Bokeh 是否执行代价较高的错误诊断。其定义位于 src/bokeh/settings.py#L772-L780:

  • 设置键:perform_error_diagnostics
  • 环境变量:BOKEH_PERFORM_ERROR_DIAGNOSTICS
  • 默认值:True

6.2 开启时的诊断行为

依据 settings.py 的文档注释,当开启(默认)时:

  • on_changeon_event中校验回调签名是否正确;
  • 访问未定义属性时给出近似匹配建议(close-match suggestions)。

这两项行为在源码中有直接落点:回调管理器 src/bokeh/util/callback_manager.py#L202 与属性访问核心 src/bokeh/core/has_props.py#L444 均会检查settings.perform_error_diagnostics()后再决定是否执行额外检查。

6.3 关闭方式与代价

export BOKEH_PERFORM_ERROR_DIAGNOSTICS=false # 关闭

关闭后可减少运行时开销,适合对性能敏感的长驻服务,但会失去回调签名校验与属性名拼写提示,开发期排查问题会更困难。建议仅在线上高吞吐场景考虑关闭。

七、CustomJS 构造简化:支持模板字符串(Python 3.14+)

7.1 变更内容

3.10.0 简化了CustomJS的构造方式(:bokeh-pull:14977),在Python 3.14+上支持直接使用模板字符串编写回调代码。CustomJS类定义于 src/bokeh/models/callbacks.py#L104,其code属性承载 JavaScript 源码。

7.2 用法示意

Python 3.14 的模板字符串(t前缀)允许在字符串内直接嵌入表达式,使回调代码中的变量注入更直观。结合 examples/interaction/widgets/light_dark.py 中的既有写法,升级后的典型形态为:

from bokeh.models import CustomJS js = CustomJS(args=dict(source=source), code=t"""\ const data = source.data; // 模板字符串内可直接使用 Python 表达式插值的结果 data.x = data.x.map(v => v * ${scale}); source.change.emit(); """)

需要特别注意的是:该语法依赖 Python 3.14 的模板字符串特性,在低于 3.14 的解释器上请继续使用普通字符串拼接或 f-string 转义的方式,这一前提也与本版本放弃 Python 3.10/3.11 支持的策略相呼应。

八、导出系统:Playwright 成为 PNG/SVG 导出的替代后端

8.1 变更内容

3.10.0 新增Playwright 作为 PNG 与 SVG 导出的可选后端(:bokeh-pull:14940),并在实现上将其设为默认优先的导出方案。导出模块源码位于 src/bokeh/io/export.py:

  • 后端类型枚举为"selenium" | "playwright"ExportBackendType);
  • 自动探测逻辑(_get_screenshot_backend相关实现):默认"auto"优先使用 Playwright,未安装时回退到已被标记弃用的 Selenium 后端;
  • 可通过环境变量BOKEH_EXPORT_BACKEND显式指定playwrightseleniumauto
  • 若两者都未安装,会提示安装命令:pip install playwright && playwright install --only-shell chromium

8.2 使用方式

调用export_png/export_svg(或file_html之外的服务端导出 API)时无需改动代码,默认即走 Playwright。如需显式指定:

from bokeh.io.export import export_png export_png(fig, filename="plot.png", backend="playwright")

Playwright 后端简化了浏览器驱动依赖(不再要求额外的 WebDriver 二进制),对 CI 环境中的图像回归测试(仓库的基线测试体系见 bokehjs/test 与 tests)是更轻量的选择。官方文档说明位于 docs/bokeh/source/docs 的 export 相关章节。

九、修复与细节改进

9.1 修复 LogColorMapper 的反向颜色映射

修复了使用LogColorMapper 时反向颜色映射(inverted color mapping)失效的问题(:bokeh-pull:15035)。此前在low_color/high_color与对数色标组合时,边界颜色的映射方向可能错误;该修复保证对数色标下的颜色语义与线性色标一致。相关颜色映射器实现位于 src/bokeh/models/mappers.py,对应示例见 examples/basic/data/color_mappers.py 与 examples/basic/annotations/colorbar_log.py。

9.2 修复表格中 DateFormatter 的 TIMESTAMP 格式

修复了表格中DateFormatter 选择"TIMESTAMP"格式时失效的问题(:bokeh-pull:15221)。此前在 DataTable 列格式化中选择 TIMESTAMP 无法正确输出毫秒时间戳,本次修复恢复其行为。相关格式化器实现可查 src/bokeh/models/widgets/tables.py(DateFormatter),表格示例见 examples/interaction/widgets/data_table.py。

9.3 ContinuousTicker 参数新增 NonNegative 类型约束

ContinuousTicker上的num_minor_ticksdesired_num_ticks添加了NonNegative类型约束(:bokeh-pull:15227),从类型系统层面禁止传入负数,避免刻度计算出现异常。ContinuousTicker定义位于 src/bokeh/models/tickers.py。

9.4 移除 PNG 图标相关 CSS 并简化图标样式

移除了PNG 图标相关的 CSS,并对图标样式表进行了简化(:bokeh-pull:14579)。图标体系现完全基于 SVG(仓库 bokehjs/src/less/icons 下 80 余个 SVG 文件),图标使用方式保持不变,但样式加载更轻量、更统一。

十、升级清单与总结

面向 3.10.0 的升级,可按以下清单自查:

  1. Python 版本:确保 ≥ 3.12(3.10/3.11 已不再支持);
  2. 主题切换:新项目可直接使用LightDark+curdoc().config.color_scheme实现明暗主题,三态(light/dark/system)默认开启;
  3. 性能:Patch/Patches 大数据量绘制自动获得 WebGL 加速;生产环境可通过BOKEH_PERFORM_ERROR_DIAGNOSTICS=false关闭高开销诊断;
  4. 导出:PNG/SVG 导出默认改用 Playwright 后端,可显式设置BOKEH_EXPORT_BACKEND
  5. 回调:Python 3.14+ 可尝试模板字符串简化CustomJS编写;
  6. 扩展开发:自定义 BokehJS 扩展需基于新的 tsgo 构建链重新编译,并留意组件 vDOM 化对视图层 API 的影响。

总体而言,3.10.0 在保持 API 稳定的前提下完成了渲染、组件与构建三条技术线的换代:WebGL 覆盖到 Patch 图形、UI 全面 vDOM 化、构建迁移到 tsgo,同时通过LightDark与文档级color_scheme让明暗主题成为一等公民。这些改动既带来了立即可用的体验提升(主题切换、导出简化、诊断开关),也为后续版本在渲染性能与可访问性上的持续演进奠定了架构基础。

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询