Bokeh 3.7.0 版本详解:交互工具增强、UI 组件升级与类型声明体系落地
【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh
Bokeh3.7.0(2025 年 3 月发布)是 Bokeh 项目的一个重要小版本里程碑,围绕"交互工具更智能、UI 组件更完整、类型系统更健全"三条主线带来了一系列能力提升:从可见视口自动调整数据范围、支持坐标轴触发 hover/crosshair、新增可携带状态的CustomAction,到Drawer浮动面板、确定/不确定双模式Progress、Scatter自定义标记,以及bokeh.models与figure()的*.pyi类型声明文件。读完本文,你将系统掌握 3.7.0 的全部新增能力、对应的源码实现位置以及可直接上手的用法示例。
版本概览与验证方式
Bokeh3.7.0属于次版本(minor milestone)更新,包含约 24 项新增功能、改进与修复。其中大部分能力由 BokehJS(前端渲染引擎)与 Bokeh Python 模型层协同实现,因此在升级后建议同时更新前后端依赖。
可以通过以下方式确认当前安装的版本(版本号由 src/bokeh/init.py 中的__version__通过importlib.metadata解析获得):
import bokeh print(bokeh.__version__) # 期望输出 3.7.0 或更高交互工具的深度增强
基于可见视口的数据范围自动调整(PR 14353)
3.7.0 新增了基于当前可见视口(viewport)的 auto-ranging 支持。此前 Bokeh 的自动范围计算以全部数据为基准,而在流式数据、大数据量局部浏览等场景下,用户往往希望坐标范围只覆盖当前视口内可见的部分数据。该特性让DataRange1d等相关范围模型能够依据当前实际渲染的视口窗口动态更新范围,减少缩放平移时的无效计算,也避免离屏数据干扰范围判断。启用后,配合流式更新(如ColumnDataSource.stream)可获得更顺滑的"跟随最新可见数据"体验。
PanTool 光标与状态管理改进(PR 14106)
PanTool在 3.7.0 中改进了光标样式与状态管理。在 src/bokeh/models/tools.py 中,PanTool继承自Drag类,其dimensions属性(默认"both")控制平移维度:
from bokeh.models import PanTool # 仅允许水平平移 pan = PanTool(dimensions="width") # 仅允许垂直平移 pan = PanTool(dimensions="height")该版本修复了平移过程中光标未能正确反映"正在拖动"状态的问题,使得拖拽过程中与空闲状态下的光标切换更及时、准确,同时完善了工具内部活动状态的清理逻辑,避免拖拽中断后状态残留。
基于活动工具的 touch-action 处理(PR 14109)
移动端与触控板场景下,浏览器默认的touch-action手势(如页面滚动、双指缩放)可能与绘图工具手势冲突。3.7.0 根据当前活动工具及其所支持的事件类型动态调整touch-action:例如当PanTool激活时允许触摸平移,而当WheelZoomTool激活时禁止浏览器默认的页面缩放,从而让触控交互与桌面鼠标交互行为保持一致。这一改进由前端 BokehJS 在事件绑定层实现,用户无需额外配置即可获得更可靠的触屏体验。
CrosshairTool / HoverTool 支持从坐标轴触发(PR 14124)
此前CrosshairTool与HoverTool只能在绘图区域内部响应鼠标,坐标轴区域默认被排除。3.7.0 允许二者从坐标轴(axes)区域触发,这对于跨图联动、精细读取刻度值等场景十分有用。
CrosshairTool定义于 src/bokeh/models/tools.py,其关键属性包括:
overlay:默认为"auto",按dimensions自动生成一个或两个Span;也可以显式传入共享的Span实例来构造联动十字光标(多图共享同一 Span 时,光标可跨图同步);dimensions:"both"(默认,横竖双线)、"width"(仅横线)或"height"(仅竖线);line_color/line_alpha/line_width:控制十字线外观。
from bokeh.models import CrosshairTool crosshair = CrosshairTool(dimensions="both", line_color="red", line_width=1.5) plot.add_tools(crosshair)有状态动作工具与 CustomAction(PR 14143)
3.7.0 引入了有状态(stateful)动作工具的概念,并重点落地在CustomAction上。CustomAction定义于 src/bokeh/models/tools.py,是ActionTool的子类,允许在工具栏图标被激活时执行自定义回调(如CustomJS)。其核心属性:
active(Bool,默认False):工具当前是否处于激活(engaged)状态;disabled(Bool,默认False):为True时用户无法以任何方式与工具交互;description:默认文案为"Perform a Custom Action",作为工具栏图标的 tooltip;callback:激活图标时执行的回调,可返回布尔值用于指示工具状态(仅在active_callback为None时生效);active_callback:用于确定工具初始及后续状态的回调,必须返回布尔值;取"auto"时每次点击按钮都会切换状态(初始状态由active提供);取None时工具不携带状态。
from bokeh.models import CustomAction, CustomJS from bokeh.plotting import figure p = figure(width=600, height=400) toggle = CustomAction( icon="icon.png", callback=CustomJS(code='alert("foo")'), active_callback="auto", # 点击即切换状态 ) p.add_tools(toggle)这一设计让"开关型"工具(例如显示/隐藏某个叠加层)无需再依赖外部状态变量,工具自身的激活状态即可驱动交互逻辑。
WheelZoomTool 聚焦后自动激活(PR 14112)
3.7.0 支持WheelZoomTool在获得焦点(focus)时自动激活,例如鼠标悬停或点击进入绘图区域后,滚动滚轮即可直接缩放,无需先手动点击工具栏按钮。相关能力与modifiers组合键配置协同工作,见 src/bokeh/models/tools.py:
from bokeh.models import WheelZoomTool tool = WheelZoomTool(modifiers="ctrl+shift") # 仅按住 Ctrl+Shift 时缩放文档中同时提示:设置modifiers后,若Toolbar.active_scroll为"auto",该工具可被自动激活;但修饰键配置属于平台相关特性,在移动设备上可能不可用。
图元、标注与视觉渲染
Legend 支持双画布与 DOM 渲染(PR 14028)
Legend标注在 3.7.0 中新增了双画布(dual canvas)与 DOM 渲染支持。此前图例始终绘制在绘图画布上,遇到画布与 HTML 元素混排、CSS 样式定制等场景时灵活性受限。新版本允许Legend以 DOM 元素方式渲染,从而可以利用完整的 CSS 能力定制图例外观,同时保持与画布渲染结果的一致性。该能力为后续更丰富的图例样式定制(圆角、阴影、动画等)铺平了道路。
Scatter 自定义标记定义(PR 14165)
这是本版本最具可玩性的图元级特性:Scatter字形新增defs属性,允许用户定义完全自定义的标记形状。该属性定义于 src/bokeh/models/glyphs.py,是一个以"@..."正则键名为键、值为CustomJS的字典。
自定义标记有两种实现方式:
方式一:返回一个Path2D实例(适合矢量路径类形状):
from bokeh.models import CustomJS scatter.defs = { "@my_circle": CustomJS(code=''' export default (args, obj, {ctx, i, r, visuals}) => { const path = new Path2D() path.arc(0, 0, r, 0, 2*Math.PI, false) return path } '''), }方式二:直接向Context2d上下文绘制(适合完全手绘控制):
scatter.defs = { "@my_circle": CustomJS(code=''' export default (args, obj, {ctx, i, r, visuals}) => { ctx.arc(0, 0, r, 0, 2*Math.PI, false) visuals.fill.apply(ctx, i) visuals.hatch.apply(ctx, i) visuals.line.apply(ctx, i) } '''), }需要注意三点约束:
- 自定义标记名称必须以
"@"前缀开头,例如"@my_marker"; - 使用
marker="markers"时可以从数据源列中按行指定标记类型(数据列内为"@my_marker"这类名称); - 自定义标记仅支持
"canvas"与"svg"输出后端,WebGL 后端不支持。
from bokeh.models import ColumnDataSource, Scatter source = ColumnDataSource(data=dict(x=[1, 2, 3], y=[4, 5, 6], markers=["@my_circle"] * 3)) glyph = Scatter(x="x", y="y", size="sizes", marker="markers", defs=scatter.defs) p.add_glyph(source, glyph)Hatch 填充视觉全面铺开(PR 14311)
3.7.0 将斜纹/网格填充(hatch)视觉支持扩展到了所有支持填充(fill)视觉的图元与标注上。这意味着矩形、圆、多边形、面积图、柱状图以及BoxAnnotation等都能使用hatch_pattern、hatch_color、hatch_alpha、hatch_scale、hatch_weight、hatch_extra等属性,实现黑白打印友好的区分效果或更丰富的视觉编码。配合上面的自定义标记示例可见,visuals.hatch.apply(ctx, i)已成为自定义绘制中的一等公民。
修复:图像在 log 坐标轴上的 hover(PR 14306)
本版本修复了图像(Image/ImageRGBA)在 log 坐标轴下 hover 信息不准确的问题。此前对数刻度下图像的像素坐标与数据坐标换算存在偏差,导致鼠标悬停时提示的数值与实际位置不符;该修复统一了坐标换算路径,对数轴上的图像交互现已正常。
破坏性变更:ImageURLTexture.url 类型调整(PR 14371)
ImageURLTexture.url的属性类型由String改为Image(即ImageURL模型),这属于潜在破坏性变更:此前直接传字符串 URL 的写法需要改为显式构造ImageURL对象,或使用接受Image类型的新签名。升级时请检查涉及ImageURLTexture的代码。
UI 组件升级
Switch 支持标签与开关图标(PR 14294)
Switch开关控件在 3.7.0 中新增了标签与 on/off 图标支持,定义于 src/bokeh/models/widgets/inputs.py:
on_icon:开关处于开启状态(active = True)时显示的图标;off_icon:开关处于关闭状态(active = False)时显示的图标;indeterminate_icon:开关处于不确定状态(active = None)时显示的图标。
from bokeh.models import Switch switch = Switch(active=True, on_icon="check", off_icon="x")值得关注的是,仓库中的LightDark控件(见 src/bokeh/models/widgets/inputs.py)正是基于Switch构建的典型应用——它通过Override把on_icon设为"light_theme"、off_icon设为"dark_theme"、indeterminate_icon设为"system_theme",并开启tri_state,从而实现亮色/暗色/跟随系统三态切换。这也验证了新图标属性在设计上的通用性。
Progress 支持确定与不确定模式(PR 13546)
Progress进度条新增了双模式运行能力,定义于 src/bokeh/models/widgets/indicators.py。核心属性mode取值:
"determinate"(默认):表示某个任务、计算等的进度,直至完成;"indeterminate":表示停滞或无限运行的任务,此时value、min、max被忽略,显示无限动画且不展示数值标签。
from bokeh.models import Progress # 确定模式 p = Progress(value=40, min=0, max=100) # 切换为不确定模式(运行期间可动态切换) p.mode = "indeterminate"其他属性:value(当前进度)、min/max(进度区间,默认 0~100)、reversed(是否反向推进)、orientation("horizontal"或"vertical")、label(格式化显示文本,默认"@{percent}%",支持@{min}、@{max}等变量)。注意文档提醒:长时间运行或计算密集的任务可能会阻塞进度条更新,直到任务完成。
Drawer 浮动抽屉组件(PR 14081)
Drawer是 3.7.0 新增的可附着于视口或组件边缘的浮动面板,定义于 src/bokeh/models/ui/floating.py。关键属性:
location(必填):附着边缘,取自Location枚举(如"top"、"right"、"bottom"、"left");open(Bool,默认False):组件的初始/实际开合状态;size(默认300):组件尺寸,可以是 CSS 长度("20px"、"1.5em"、"30vw")或像素数值;resizable(Bool,默认False):是否允许拖拽边缘调整大小。
from bokeh.models import Drawer drawer = Drawer(location="right", open=True, size=320, resizable=True, elements=[...])使用方法:若要附着到视口,把Drawer添加为文档根(document root);若要附着到某个 UI 组件,则加入该组件(如LayoutDOM)的elements属性。配合侧边栏筛选器、图例面板等场景非常合适。
UI 组件支持 html_id 与 html_attributes(PR 14357)
3.7.0 为所有 UI 组件新增了html_id与html_attributes属性,定义于 src/bokeh/models/ui/ui_element.py:
html_id:设置底层 HTML 元素的id属性(常用快捷方式,优先级更高);html_attributes:以字典形式配置底层 HTML 元素的任意属性。
from bokeh.models import Div div = Div(text="<p>Hello</p>", html_id="greeting", html_attributes={"data-role": "banner"})<!-- 渲染结果近似 --> <div id="greeting">from bokeh.models import ValueOf ValueOf(obj=slider, attr="value", format="%.2f")这一改动让 DOM 模板(如Paragraph、Markup内的动态占位)可以直接引用控件当前值并按需格式化,是仪表盘"控件取值实时渲染"方案的基石。
工具栏、上下文菜单与分组
绘图与 figure 默认支持工具上下文菜单(PR 14228)
3.7.0 为绘图(Plot)与figure()默认启用工具上下文菜单。用户在画布上右键即可呼出与当前工具相关的上下文操作项,例如缩放相关的"重置视图"等快捷操作。由于默认开启,升级后即可体验,无需额外配置;该设计为后续可扩展的自定义菜单项预留了入口。
工具栏工具分组(PR 14259)
figure()/Plot的工具栏新增了工具分组能力,允许将相关工具(如选择类工具、缩放类工具)在视觉上聚合为一组,配合 examples/interaction/tools/tool_grouping.py 可以直观看到分组后的工具栏布局。这一改进让复杂工具栏的组织与查找更加清晰。
修复:Toolbar 工具按钮可见性处理(PR 14251)
本版本修复了Toolbar中工具按钮的可见性处理逻辑,主要涉及工具在active_inspect/active_drag等激活状态与禁用状态切换时,按钮图标的显示/隐藏是否及时、正确的问题,保证工具栏状态与工具实际可用性一致。
类型系统与开发体验
bokeh.models 初步支持 pyi 类型声明文件(PR 13900)
3.7.0 为bokeh.models引入了初步的*.pyi类型声明文件支持。这些存根文件(如 src/bokeh/models/tools.pyi、src/bokeh/models/glyphs.pyi、src/bokeh/models/widgets/indicators.pyi)与运行时实现文件一一对应,让 IDE 补全、类型检查工具(mypy / pyright)能够获得准确签名。例如CustomAction、Scatter、Progress等类的pyi存根均已生成。
figure() 及其图元方法的初步类型声明(PR 14269、PR 14289)
在模型层存根的基础上,3.7.0 进一步为figure()及其图元方法(如scatter()、line()、vbar()等)补充了初步类型声明(对应文件见 src/bokeh/plotting/figure.py 及同目录下的*.pyi存根)。这意味着在 IDE 中调用figure()时,关键词参数、返回类型与图元特有参数都能得到更准确的补全与校验。文档措辞为"初步(preliminary)",提示仍有部分边界场景的类型标注待完善,但对日常开发体验已是明显提升。
DatetimeTickFormatter 默认上下文增强(PR 13854)
DatetimeTickFormatter的默认格式得到增强,能够根据当前刻度范围自动选择更合适的日期时间上下文(例如秒、分、时、日、月、年等不同粒度的默认格式串),减少手动配置格式化器的工作量,同时保证坐标轴刻度标签在缩放过程中的可读性。
修复:可编辑/可移动 BoxAnnotation 的光标处理(PR 14151)
针对可编辑、可移动的BoxAnnotation(如BoxEditTool、RangeTool的覆盖层),3.7.0 改进了拖拽边界处的光标反馈,使用户在拖拽边缘、移动整体、切换把手等操作间获得更符合直觉的光标提示。
总结
Bokeh3.7.0是一次兼顾广度与深度的次版本更新:交互层面,视口自适应范围、坐标轴触发的 inspect 工具、有状态的CustomAction、聚焦自动激活的滚轮缩放显著提升了交互工具的可用性;UI 层面,Drawer浮动面板、双模式Progress、带图标的Switch、html_id/html_attributes打通了 Bokeh 与外部页面生态的集成;渲染层面,Scatter自定义标记与全量 hatch 支持释放了视觉定制的想象力;而pyi类型声明与figure()存根的落地则标志着 Bokeh 开始系统性投资开发者工具链。
如果你正在使用 3.6.x 或更早版本,升级到 3.7.0 时请特别注意两个变更点:一是ImageURLTexture.url类型由String调整为Image(潜在破坏性变更);二是绘图默认启用工具上下文菜单可能带来右键行为的改变。其余新增特性均可按需渐进采用,不会影响既有代码的运行。
【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考