Bokeh 进阶开发指南:自定义扩展、BokehJS 与第三方生态集成
Bokeh 进阶开发指南自定义扩展、BokehJS 与第三方生态集成【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh导读本文基于 Bokeh 官方用户指南的 Advanced usage 章节系统讲解 Bokeh 面向进阶场景的三条核心路径通过自定义扩展Custom Extensions在 Python 侧声明模型、在 BokehJS 侧实现渲染逻辑从而把第三方 JavaScript 库接入 Bokeh直接使用 BokehJS 客户端库进行纯 JavaScript 开发以及与 hvPlot、Panel、HoloViews、Datashader 等数据科学生态库的组合使用。读完本文你将掌握__implementation__扩展机制、bokeh init/bokeh build预构建扩展工作流以及Bokeh.Plotting与Bokeh.Charts两套高层 JS API 的完整用法。进阶能力总览Bokeh 核心库自带丰富的内置功能足以在浏览器中构建复杂的交互式可视化与数据应用。但当某些能力如过于特定领域的模型或需要引入第三方库没有进入核心库时进阶用户需要借助以下机制扩展 Bokeh自定义扩展Custom Extensions修改既有 Bokeh 模型的行为、把第三方 JavaScript 库连接到 Python、为特定领域创建高度定制化的模型BokehJS 直接开发跳过 Python以纯 JavaScript 方式创建交互式图形与应用第三方生态集成与 hvPlot、Panel、HoloViews、Datashader 等库协同各取所长。本章的完整索引页位于 docs/bokeh/source/docs/user_guide/advanced.rst下文将按「第三方集成 → 自定义扩展 → BokehJS」三个主题逐一展开。一、与第三方生态库集成Bokeh 与大量其他库集成良好让你能为每个任务选用最合适的工具。集成方向主要有五类。BokehJS浏览器端的基石要在浏览器中显示可视化Bokeh 会把 Python 数据与事件序列化为 JSON再交给配套的 JavaScript 库 BokehJS 通信与渲染。BokehJS 也可以作为独立库使用或与 React、Vue、Angular 等 JavaScript 框架组合使用。关于 BokehJS 的完整开发方式见本文第三部分。hvPlotpandas 风格的极简绘图hvPlot提供了一套精简 API让你可以用 pandas 的.plot()函数配合各种数据容器直接在 Bokeh 上绘图。它特别适合交互式数据分析场景能快速产出常见类型的图。Panel构建数据密集型仪表盘Panel 库提供高层响应式接口方便在 Bokeh 之上构建数据密集型仪表盘与 Web 应用。它打通了 Jupyter notebook 与 Bokeh server 之间的互操作——你可以在 notebook 中开发、原型验证应用再部署到服务器上。Panel 同时兼容其他绘图库能把多个数据科学产物整合进同一个 Bokeh 应用中并内置多种 JavaScript 模板用于定制应用外观。HoloViews声明式高层接口HoloViews 是独立维护的声明式接口包专注于 Jupyter notebook 交互适合快速原型化数据分析图形。例如用 HoloViews 构建三个联动 Bokeh 图只需一行代码叠加图层、添加滑块/下拉选择控件、选择工具、标签页等操作也同样简洁。Datashader处理数十亿级数据点默认情况下Bokeh 会把数据点从 Python 复制到浏览器中的 JavaScript 进程以提供响应式的本地交互。但浏览器能承载的数据量有限直接在 JS 中绘制数百万乃至数十亿个点并不可行且常规渲染技术在大数据量下会因 overplotting过度绘制产生误导性图形。Datashader 是独立的 Python 库它把再大的数据集也渲染为固定尺寸的栅格图像忠实呈现底层数据。用 Datashader 构建 Bokeh 图时缩放、平移操作会在 Python 端动态重新渲染图像从而让任意规模的数据集都能在标准浏览器中以交互方式展示。Datashader 还与 hvPlot、HoloViews 协作良好可以在基础图与渲染图之间切换、交错排布 Datashader 图与普通 Bokeh 图等。二、自定义扩展Custom ExtensionsBokeh 自带功能丰富但某些有用能力未必进入核心库——或因主题过于特殊或因缺乏资源。自定义扩展可以修改既有 Bokeh 模型的行为新增模型以连接第三方 JavaScript 库与 Python为特定领域创建高度定制的模型。使用标准发行版即可创建和使用扩展无需搭建开发环境或从源码构建。这是参与 Bokeh 开发最轻松的入口。需要说明的是扩展仍是正在积极演进的高级特性部分环节属于实验性质。2.1 Bokeh 模型的结构Python 侧模型Python 侧的 Bokeh 模型大多是纯声明式类。创建自定义扩展的方式是继承Model更具体地可继承UIElement、LayoutDOM、Tool、Glyph等内置基类并通过特殊类属性声明需要在 JavaScript 侧镜像的属性。所有可用属性类型参见 bokeh/core/properties 与参考指南。以下示例创建一个为 Slider 定制的读数显示组件from bokeh.core.properties import String, Instance from bokeh.models import UIElement, Slider class Custom(UIElement): text String(defaultCustom text) slider Instance(Slider)这里继承UIElement让扩展可以融入 DOM 布局并声明了两个属性String类型属性text配置读数显示的文本消息Instance类型属性slider持有一个Slider实例从而在 JavaScript 侧创建与之对应的Slider对象。2.2 JavaScript 侧模型与视图Python 侧几乎没有代码但 JavaScript 侧必须实现模型本身的代码并在必要时提供对应的视图View代码。内置模型正是以这种形式直接打进最终的 BokehJS 脚本中的。以下是Custom及其CustomView的带注释 TypeScript 实现完整源码见 examples/advanced/extensions/custom.tsimport {UIElement, UIElementView} from models/ui/ui_element import {Slider} from models/widgets/sliders/slider import {div} from core/dom import * as p from core/properties export class CustomView extends UIElementView { declare model: Custom private content_el: HTMLElement override connect_signals(): void { super.connect_signals() // 监听 slider 的 change 信号滑块移动时刷新文本 this.connect(this.model.slider.change, () this._update_text()) } override render(): void { super.render() this.content_el div({style: { textAlign: center, fontSize: 1.2em, padding: 2px, color: #b88d8e, backgroundColor: #2a3153, }}) this.shadow_el.append(this.content_el) this._update_text() } private _update_text(): void { this.content_el.textContent ${this.model.text}: ${this.model.slider.value} } } export namespace Custom { export type Attrs p.AttrsOfProps export type Props UIElement.Props { text: p.Propertystring slider: p.PropertySlider } } export interface Custom extends Custom.Attrs {} export class Custom extends UIElement { declare properties: Custom.Props declare __view_type__: CustomView constructor(attrs?: PartialCustom.Attrs) { super(attrs) } static { // 关联视图属于样板代码 this.prototype.default_view CustomView // define() 块为 JS 模型声明与 Python 侧一一对应的属性。 // 大多数属性类型都有对应物例如 Python 的 bokeh.core.properties.String // 对应 JS 的 StringJS 缺少对应类型时可用 p.Any 作为通配类型。 this.defineCustom.Props(({Str, Ref}) ({ text: [ Str, Custom text ], slider: [ Ref(Slider) ], })) } }要点说明connect_signals()中通过this.connect(this.model.slider.change, ...)订阅信号实现滑块值变化驱动的响应式更新视图默认创建div元素this.el可像本例这样修改其内容也可忽略它改画到 HTML canvasstatic {}块中default_view指定视图类this.define()声明属性及其默认值与 Python 侧保持一一对应从源码注释可见bokeh.core.properties.String对应 JS 的StrInstance(Slider)对应Ref(Slider)。2.3 把 Python 与 TypeScript 拼装起来内置模型在构建过程中会自动把 BokehJS 实现与 Python 模型匹配起来。对自定义模型Python 类需要提供一个名为__implementation__的类属性其值为定义客户端模型及可选视图的 JavaScript/TypeScript 代码。假设上例的 TypeScript 代码保存在custom.ts文件中完整的 Python 类如下from bokeh.core.properties import String, Instance from bokeh.models import UIElement, Slider class Custom(UIElement): __implementation__ custom.ts text String(defaultCustom text) slider Instance(Slider)假设custom.py模块定义了上述类那么自定义扩展的使用方式与内置模型完全一致。仓库中的完整可运行示例见 examples/advanced/extensions/putting_together.pyfrom bokeh.io import show from bokeh.layouts import column from bokeh.models import Slider, UIElement from bokeh.core.properties import Instance, Required, String class Custom(UIElement): __implementation__ custom.ts text String(defaultCustom text) slider Required(Instance(Slider)) slider Slider(start0, end10, step0.1, value0, titlevalue) custom Custom(textSpecial Slider Display, sliderslider) layout column(slider, custom) show(layout)渲染出的文档会自动包含实现的 JavaScript 代码。拖动滑块即可看到特殊样式的标题随滑块值实时更新。注意示例中把slider声明为Required(Instance(Slider))强制要求传入 slider 实例。2.4 指定实现语言当__implementation__的值是单行且以.js或.ts结尾时Bokeh 会把它解释为文件名打开该文件并按扩展名对应的语言编译其内容。若使用内联实现则通过JavaScript或TypeScript类显式指定源码语言class Custom(Model): __implementation__ JavaScript( JS code here )仓库示例中examples/advanced/extensions/ticking.py 正是用TypeScript(CODE)内联实现了一个自定义TickFormatterfrom bokeh.util.compiler import TypeScript CODE import {TickFormatter} from models/formatters/tick_formatter export class MyFormatter extends TickFormatter { // 接受一组数字刻度返回一组字符串 doFormat(ticks: string[] | number[]) { const formatted [${ticks[0]}] for (let i 1; i ticks.length; i) { formatted.push(${(Number(ticks[i]) - Number(ticks[0])).toPrecision(2)}) } return formatted } } class MyFormatter(TickFormatter): __implementation__ TypeScript(CODE)随后只需p.xaxis.formatter MyFormatter()即可替换坐标轴刻度格式。2.5 指定默认值如果属性有默认值则必须在 Python 侧和 JavaScript 侧同时提供且两边的值应当一致。出于效率考虑Bokeh 只传输用户显式修改过的属性值因此默认值必须两端对齐。以默认值为True的布尔属性flag为例Python 侧flag Bool(defaultTrue)BokehJS 侧TypeScript 属性声明flag: [ Boolean, true ]2.6 引入外部资源实现自定义模型时可能需要第三方 JavaScript 库或 CSS 资源可通过自定义模型的__javascript__与__css__类属性提供。把资源 URL 加进 HTML 文档头部后JS 库将进入全局命名空间自定义 CSS 也会生效。以下示例引入 KaTeX支持 LaTeX 的 JS 库来创建一个LatexLabel自定义模型class LatexLabel(Label): A subclass of the built-in Bokeh model Label that supports rendering LaTeX with the KaTeX typesetting library. __javascript__ https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js __css__ https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css __implementation__ # do something here 仓库中 examples/advanced/extensions/widget.py 是更完整的实战样例——它用__javascript__同时加载 jQuery 与 ion.rangeSlider包装出双端滑块扩展IonRangeSliderclass IonRangeSlider(InputWidget): __implementation__ ion_range_slider.ts __javascript__ [ https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js, https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.4/js/ion.rangeSlider.js, ] disable Bool(defaultTrue, helpEnable or disable the slider.) grid Bool(defaultTrue, helpShow or hide the grid beneath the slider.) start Float(default0, helpThe minimum allowable value.) end Float(default1, helpThe maximum allowable value.) range Tuple(Float, Float, helpThe start and end values for the range.) step Float(default0.1, helpThe step between consecutive values.)该扩展通过js_on_change(range, callback)与自定义CustomJS回调联动实现拖拽范围滑块即重算幂函数曲线的交互效果。2.7 与 Bokeh server 集成自定义扩展集成进 Bokeh server 无需任何额外工作。与独立文档一样渲染出的应用会自动包含 JavaScript 实现同时Bokeh 模型属性的标准同步机制对自定义扩展透明生效与内置模型完全一致。2.8 扩展示例速览进阶用户经常需要研读 bokehjs/src/lib/models 下基类的源码才能继续深入。仓库提供了四个方向的基础示例示例文件技术要点坐标轴刻度examples/advanced/extensions/ticking.py继承内置TickFormatter子类化用TypeScript内联实现自定义刻度格式全新工具examples/advanced/extensions/tool.py继承Tool创建可在画布上拖拽绘图的DrawTool通过_pan事件把屏幕坐标反算为数据坐标写入ColumnDataSource包装第三方库examples/advanced/extensions/wrapping.py继承LayoutDOM包装 vis.js 的 Graph3d把 Bokeh 数据源映射为 vis.js DataSet 并监听变更扩展控件examples/advanced/extensions/widget.py继承InputWidget引入 ion.rangeSlider通过__javascript__加载外部资源以 examples/advanced/extensions/tool.py 为例自定义工具需要同时提供 View处理事件与 Model声明属性from bokeh.core.properties import Instance from bokeh.models import ColumnDataSource, Tool from bokeh.plotting import figure, show from bokeh.util.compiler import TypeScript CODE import {GestureTool, GestureToolView} from models/tools/gestures/gesture_tool import {ColumnDataSource} from models/sources/column_data_source import {PanEvent} from core/ui_events import * as p from core/properties export class DrawToolView extends GestureToolView { declare model: DrawTool _pan_start(_e: PanEvent): void { this.model.source.data {x: [], y: []} } _pan(e: PanEvent): void { const {frame} this.plot_view const {sx, sy} e if (!frame.bbox.contains(sx, sy)) return const x frame.x_scale.invert(sx) const y frame.y_scale.invert(sy) const {source} this.model source.get_array(x).push(x) source.get_array(y).push(y) source.change.emit() } _pan_end(_e: PanEvent): void {} } export namespace DrawTool { export type Attrs p.AttrsOfProps export type Props GestureTool.Props { source: p.PropertyColumnDataSource } } export interface DrawTool extends DrawTool.Attrs {} export class DrawTool extends GestureTool { declare properties: DrawTool.Props declare __view_type__: DrawToolView tool_name Draw Tool tool_icon bk-tool-icon-lasso-select event_type pan as pan default_order 12 static { this.prototype.default_view DrawToolView this.defineDrawTool.Props(({Ref}) ({ source: [ Ref(ColumnDataSource) ], })) } } class DrawTool(Tool): __implementation__ TypeScript(CODE) source Instance(ColumnDataSource) source ColumnDataSource(datadict(x[], y[])) plot figure(x_range(0,10), y_range(0,10), titleClick and drag to draw, background_fill_color#efefef, tools) plot.add_tools(DrawTool(sourcesource)) plot.line(x, y, line_width3, sourcesource) show(plot)可见自定义工具只需实现_pan_start/_pan/_pan_end事件钩子并通过frame.x_scale.invert(sx)等 API 完成屏幕坐标到数据坐标的转换。2.9 预构建扩展Pre-built Extensions前面介绍的简单内联扩展适合临时性扩展但在严肃开发中不够方便——例如package.json、tsconfig.json这类隐式配置文件的存在使得 IDE 无法充分发挥 TypeScript/JavaScript 编写时的补全与检查能力。预构建扩展解决了这个问题。工作流如下运行bokeh init创建全部必要文件包括bokeh.ext.json、package.json和tsconfig.json运行bokeh init --interactive可逐步交互式创建并定制扩展运行bokeh build构建扩展必要时执行npm install、编译 TypeScript、转译 JavaScript、解析模块并链接成可分发的 bundle若构建缓存引发问题可用bokeh build --rebuild从零重建扩展Bokeh 会缓存编译产物以提升性能。三、BokehJS纯 JavaScript 开发BokehJS 是客户端库负责绘图、渲染与事件处理。Bokeh Python 库以及 R、Scala、Julia 等语言的库提供了与 BokehJS 的高层交互让你无需关心 JavaScript 与 Web 开发。但 BokehJS 也有自己的 API支持纯 JavaScript 开发自定义扩展模型通常也需要直接与 BokehJS 交互。注意BokehJS API 仍在开发中未来版本可能发生变化。3.1 获取 BokehJSBokehJS 可通过 CDN 与npm获取安装细节见安装文档的 BokehJS 章节对应仓库安装说明见 README.md 与 bokehjs/package.json。3.2 低级模型与 Python 模型一一对应通常图与应用的底层模型坐标轴、网格、字形、控件等与 Python 侧模型完全一致因此 Python 参考指南也是 BokehJS 模型的首要参考。Python 库按层级组织而 JavaScript 模型全部位于扁平的Bokeh模块中——任何 PythonClassName通常都能以Bokeh.ClassName形式在 JavaScript 中使用。完整模型清单见 bokehjs/src/lib/api/models.ts。在 JavaScript 中创建模型时把传给 Python 对象初始化器的关键字参数组织为一个 JS 对象。以初始化Range1d为例Pythonxdr Range1d(start-0.5, end20.5)JavaScriptconst xdr new Bokeh.Range1d({ start: -0.5, end: 20.5 });这种模式适用于所有类似场景。模型创建后属性设置方式在两种语言中也完全一致例如xdr.end 30在 Python 与 JavaScript 中都会把该Range1d的end设为 30。以下是从零构建带坐标轴、网格与线字形的图示例与 examples/models 中的样例对比可见这一层面的 Python 与 JavaScript 代码几乎一致。完整文件见 examples/advanced/bokehjs/simple_line.js// 创建数据与 ColumnDataSource const x Bokeh.LinAlg.linspace(-0.5, 20.5, 10); const y x.map(function (v) { return v * 0.5 3.0; }); const source new Bokeh.ColumnDataSource({ data: { x: x, y: y } }); // 创建坐标范围 const xdr new Bokeh.Range1d({ start: -0.5, end: 20.5 }); const ydr new Bokeh.Range1d({ start: -0.5, end: 20.5 }); // 创建图 const plot new Bokeh.Plot({ title: BokehJS Plot, x_range: xdr, y_range: ydr, width: 400, height: 400, background_fill_color: #F2F2F7 }); // 添加坐标轴 const xaxis new Bokeh.LinearAxis({ axis_line_color: null }); const yaxis new Bokeh.LinearAxis({ axis_line_color: null }); plot.add_layout(xaxis, below); plot.add_layout(yaxis, left); // 添加网格 const xgrid new Bokeh.Grid({ ticker: xaxis.ticker, dimension: 0 }); const ygrid new Bokeh.Grid({ ticker: yaxis.ticker, dimension: 1 }); plot.add_layout(xgrid); plot.add_layout(ygrid); // 添加 Line 字形 const line new Bokeh.Line({ x: { field: x }, y: { field: y }, line_color: #666699, line_width: 2 }); plot.add_glyph(line, source); Bokeh.Plotting.show(plot);3.3 高层接口与 Python 库类似BokehJS 也提供多个高层接口用于操作与组合低级模型对象主要包括Bokeh.Plotting与Bokeh.Charts。自版本0.12.2起这两套 API 组成bokeh-api.js文件中的 BokehJS API——除了bokeh.js还需要额外导入bokeh-api.js才能启用它们。Bokeh.PlottingPython plotting 接口的移植JavaScript 的Bokeh.PlottingAPI 是 Python 侧bokeh.plotting接口的移植因此用户指南基础绘图章节的内容同样可作为参考。以下示例与 Python 的 examples/basic/scatters/color_scatter.py 非常相似const plt Bokeh.Plotting; // 准备数据 const M 100; const xx []; const yy []; const colors []; const radii []; for (let y 0; y M; y 4) { for (let x 0; x M; x 4) { xx.push(x); yy.push(y); colors.push(plt.color([502*x, 302*y, 150])); radii.push(Math.random() * 1.5); } } // 创建数据源 const source new Bokeh.ColumnDataSource({ data: { x: xx, y: yy, radius: radii, colors: colors } }); // 创建图并添加工具 const tools pan,crosshair,wheel_zoom,box_zoom,reset,save; const p plt.figure({ title: Colorful Scatter, tools: tools }); // 调用 circle 字形方法添加圆形 const circles p.circle({ field: x }, { field: y }, {field: radius}, { source: source, fill_color: { field: colors }, fill_alpha: 0.6, line_color: null, }); // 显示图 plt.show(p);Bokeh.ChartsBokehJS 专属高层图表Bokeh.Charts是 BokehJS 独有的高层图表接口支持两种图表pie与bar。其类型定义与实现见 bokehjs/src/lib/api/charts.ts导出函数为pie(data, opts)与bar(data, opts)。Bokeh.Charts.pieBokeh.Charts.pie(data, { options })其中data是含labels与values键的 JavaScript 对象options可选键如下选项类型说明widthnumber图表宽度像素heightnumber图表高度像素inner_radiusnumber扇区内半径像素outer_radiusnumber扇区外半径像素start_anglenumber扇区起始角弧度end_anglenumber扇区结束角弧度center[number, number]饼图中心的(x, y)位置像素palettePalette | ArrayColor命名调色板或颜色列表用于对数值着色slice_labelslabels | values | percentagestooltip 显示内容从 bokehjs/src/lib/api/charts.ts 的源码可以看出实现细节pie内部只取values 0的扇区默认start_angle为 0、end_angle为start_angle 2πinner_radius默认 0、outer_radius默认 1调色板默认取Spectral11并按value / total归一化后累计计算各扇区角度。默认情况下pie图自动添加 tooltip 与 hover 策略。const plt Bokeh.Plotting; const pie_data { labels: [Work, Eat, Commute, Sport, Watch TV, Sleep], values: [8, 2, 2, 4, 0, 8], }; const p1 Bokeh.Charts.pie(pie_data); const p2 Bokeh.Charts.pie(pie_data, { inner_radius: 0.2, start_angle: Math.PI / 2 }); const p3 Bokeh.Charts.pie(pie_data, { inner_radius: 0.2, start_angle: Math.PI / 6, end_angle: 5 * Math.PI / 6 }); const p4 Bokeh.Charts.pie(pie_data, { inner_radius: 0.2, palette: Oranges9, slice_labels: percentages }); // 加入文档并显示 const doc new Bokeh.Document(); doc.add_root(plt.gridplot( [[p1, p2], [p3, p4]], {width: 250, height: 250})); Bokeh.embed.add_document_standalone(doc, document.currentScript.parentElement);Bokeh.Charts.barBokeh.Charts.bar(data, { options })其中data是数组每个元素代表数据表的一行首行是列标题。例如各地区各年份的销售数据const data [ [Region, Year, Sales], [East, 2015, 23000 ], [East, 2016, 35000 ], [West, 2015, 16000 ], [West, 2016, 34000 ], [North, 2016, 12000 ], ];与pie类似options是对象可选键如下选项类型说明widthnumber图表宽度像素heightnumber图表高度像素stackedboolean条形是否堆叠orientationhorizontal | vertical条形方向bar_widthnumber每条宽度像素palettePalette | ArrayColor命名调色板或颜色列表axis_number_formatstring坐标轴刻度的格式字符串默认情况下bar图同样自动添加 tooltip 与 hover 策略。示例const plt Bokeh.Plotting; const bar_data [ [City, 2010 Population, 2000 Population], [NYC, 8175000, 8008000], [LA, 3792000, 3694000], [Chicago, 2695000, 2896000], [Houston, 2099000, 1953000], [Philadelphia, 1526000, 1517000], ]; const p1 Bokeh.Charts.bar(bar_data, { axis_number_format: 0.[00]a }); const p2 Bokeh.Charts.bar(bar_data, { axis_number_format: 0.[00]a, stacked: true }); const p3 Bokeh.Charts.bar(bar_data, { axis_number_format: 0.[00]a, orientation: vertical }); const p4 Bokeh.Charts.bar(bar_data, { axis_number_format: 0.[00]a, orientation: vertical, stacked: true }); plt.show(plt.gridplot([[p1, p2], [p3, p4]], {width: 350, height: 350}));3.4 最小示例导入、创建与修改图以下最小示例展示如何导入库、创建图并动态修改数据// 创建数据源 const source new Bokeh.ColumnDataSource({ data: { x: [], y: [] } }); // 创建带工具的图 const plot Bokeh.Plotting.figure({ title: Example of random data, tools: pan,wheel_zoom,box_zoom,reset,save, height: 300, width: 300 }); // 从数据源添加一条线 plot.line({ field: x }, { field: y }, { source: source, line_width: 2 }); // 显示图追加到当前章节末尾 Bokeh.Plotting.show(plot); function addPoint() { // 添加数据——所有字段长度必须一致 source.data.x.push(Math.random()) source.data.y.push(Math.random()) // 用本地变更更新数据源 source.change.emit() } const addDataButton document.createElement(Button); addDataButton.appendChild(document.createTextNode(Some data.)); document.currentScript.parentElement.appendChild(addDataButton); addDataButton.addEventListener(click, addPoint); addPoint(); addPoint();这个示例揭示了 BokehJS 的核心数据流先修改source.data数组再调用source.change.emit()广播变更事件绘图才会刷新。四、实践建议与资料入口自定义扩展的四个方向性示例刻度、工具、包装第三方库、扩展控件集中在 examples/advanced/extensions 目录每个示例同时给出 Python 模型与 TypeScript 实现是学习扩展机制的最佳起点。若需深入基类细节BokehJS 模型源码位于 bokehjs/src/lib/models高层 API 清单见 bokehjs/src/lib/api/models.tsCharts 实现见 bokehjs/src/lib/api/charts.ts。BokehJS 纯 JS 示例见 examples/advanced/bokehjs/simple_line.js其余低级模型示例位于 examples/models。官方参考指南reference guide中的 bokeh.core.properties 是属性类型String、Instance、Bool、Float、Tuple、Required等的权威清单编写自定义模型前建议先通读。综合来看Bokeh 的进阶能力遵循「Python 声明 BokehJS 实现 生态协同」的分层设计数据科学场景优先组合 hvPlot、Panel、HoloViews、Datashader 快速交付需要新交互或接入第三方 JS 库时用__implementation__或bokeh init/bokeh build构建自定义扩展而追求极致控制时可直接用 BokehJS 的Plotting与ChartsAPI 编写纯前端可视化。【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →