深入解析 Bokeh 文档画廊系统:gallery_detail.rst 模板如何驱动示例页面自动生成

发布时间:2026/11/7 13:47:13

深入解析 Bokeh 文档画廊系统:gallery_detail.rst 模板如何驱动示例页面自动生成 深入解析 Bokeh 文档画廊系统gallery_detail.rst 模板如何驱动示例页面自动生成【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh导读Bokeh 官方文档中那张琳琅满目的示例画廊Gallery页面并不是人工逐个书写的而是由 Sphinx 扩展在文档构建阶段自动批量生成的。本文以 Bokeh 仓库中负责单个示例详情页的 Jinja2 模板 gallery_detail.rst 为核心完整讲解从gallery.json配置、bokeh-gallery指令扫描、模板渲染到bokeh-plot指令执行示例代码、输出交互图与源码块的全链路机制。读完本文你将掌握 Bokeh 画廊的底层工作原理并能在自己的 Sphinx 文档项目中复刻这套配置驱动 模板生成的示例文档流水线。一、gallery_detail.rst单个示例详情页的完整模板gallery_detail.rst位于 src/bokeh/sphinxext/_internal/_templates/gallery_detail.rst全文只有 13 行却承担着为画廊中每一个示例生成独立 RST 详情页的重任。先看它的完整内容:orphan: .. index:: single: examples; {{ filename }} {{ ref }} {{ filename }} {{ - * filename|length }} .. bokeh-plot:: {{ source_path }} :process-docstring: :source-position: below这是一个 Jinja2 模板由三个变量驱动逐行拆解如下行内容作用:orphan:声明该页面是孤儿文档即使没有被任何 toctree 引用Sphinx 也不会发出警告。画廊详情页是程序批量生成的不参与目录树因此必须加此标记.. index:: single: examples; {{ filename }}为 Sphinx 生成索引条目把filename示例名登记到examples索引分组下方便文档内联搜索{{ ref }}插入由生成器构造的 RST 锚点引用形如.. _example_markers_basic_scatters:供其他页面用:ref:交叉引用定位该示例{{ filename }}{{ - * filename\|length }}用示例文件名作为页面标题并用等长的-生成 RST 二级标题下划线.. bokeh-plot:: {{ source_path }}核心指令指向示例 Python 源文件的绝对路径由 Sphinx 扩展实际执行该脚本:process-docstring:布尔选项把示例文件顶部的模块 docstring 单独渲染为格式化说明块:source-position: below枚举选项将格式化后的源码块放在图表下方模板虽然简短但孤儿文档 索引登记 交叉引用锚点 可执行代码指令四个要素缺一不可构成了每个示例页的完整骨架。二、模板从何而来bokeh_gallery 扩展的生成流程gallery_detail.rst 本身不直接出现在文档源码树中而是由 Sphinx 扩展 bokeh_gallery.py 在config-inited阶段动态写出的。该扩展在文档的 conf.py 中通过bokeh.sphinxext._internal.bokeh_gallery注册。2.1 关键数据结构GalleryDetail生成器内部用 TypedDict 描述每个示例的元信息见 bokeh_gallery.pyclass GalleryDetail(TypedDict): name: str # 示例文件名不含 .py path: str # 相对仓库根的路径如 examples/basic/scatters/markers.py ref: str # RST 锚点如 .. _example_markers_basic_scatters: rst_file_path: str # 生成的目标文件相对路径如 basic/scatters/markers.rst2.2 核心函数 get_details扫描示例目录get_details(app)bokeh_gallery.py遍历conf.py中配置的bokeh_example_subdirs列表对每个子目录中的文件做三件事过滤跳过以_开头的文件、非.py文件以及在bokeh_sampledata_xref_skiplist中的示例构造锚点生成ref f.. _example_{name}_{subdir}:形式的交叉引用标签产出条目组装成GalleryDetail并汇总返回。以实际目录 examples/basic/scatters 为例扫描后会产生markers.rst、color_scatter.rst、elements.rst、image_url.rst等条目锚点分别为.. _example_markers_basic_scatters:等。2.3 config_inited_handler写文件与增量构建config_inited_handlerbokeh_gallery.py在 Sphinx 配置初始化后执行完整的生成逻辑检查画廊配置文件gallery.json是否存在缺失则抛SphinxError用ensuredir创建画廊目录docs/gallery与示例目录docs/examples含所有子目录用一个extras集合记录目录中已存在的文件用于构建后清理残留对每个GalleryDetail渲染模板并写入文件source_path abspath(join(app.srcdir, .., .., .., detail[path])) f.write(GALLERY_DETAIL.render(filenamedetail[name], source_pathsource_path, refdetail[ref]))注意这里source_path被换算成绝对路径相对文档源码目录向上三级回到仓库根这样bokeh-plot指令才能准确读取examples/...下的示例脚本。增量构建优化如果目标详情文件已存在且其 mtime 比gallery.json新则跳过重写见第 145 行getmtime判断构建结束后删除extras中剩余文件即本次不再生成的历史残留保持画廊目录干净。渲染时的模板对象来自 templates.py即GALLERY_DETAIL _env.get_template(gallery_detail.rst)三、Gallery 索引页与 gallery_detail 的联动画廊的入口页面 docs/bokeh/source/docs/gallery.rst 本身不含任何示例内容只通过bokeh-gallery指令声明要展示哪些目录下的示例.. tab-set:: :class: bk-gallery-tabs .. tab-item:: Basic plotting .. bokeh-gallery:: basic/scatters basic/lines basic/data basic/axes basic/bars basic/areas basic/layouts basic/annotations3.1 BokehGalleryDirective读取 gallery.jsonBokehGalleryDirectivebokeh_gallery.py运行时定位当前文档所在目录下的gallery.json即 docs/bokeh/source/docs/gallery.json解析指令 content 中列出的每个location如basic/scatters到 JSON 中查找对应的示例条目数组对每个条目构造缩略图选项url默认指向examples/.../*.html若条目含url字段则直接使用并新窗口打开、img、alt、title缺省用文件名 stem、desc用索引页模板gallery_page.rst渲染出整张缩略图网格。3.2 gallery_page.rst缩略图网格模板配套的索引模板 gallery_page.rst 生成如下 HTML 结构节选div classbk-gallery div classbk-thumbnail a href... img classgallery width300 height300 src../_images/{{ opt[img] }}.png srcset../_images/{{ opt[img] }}.png, ../_images/{{ opt[img] }}2x.png 2x alt{{ opt[alt] }} /a div classbk-thumbnail-title{{ opt[title] }}/div div classbk-thumbnail-description{{ opt[desc] }}/div /div /div可见它支持1x/2x 高清缩略图srcset、可选的标题与描述说明。而server/app这类远程 Demo 条目见 gallery.json则带url与desc字段点击后跳转到demo.bokeh.org上的在线演示——这正是BokehGalleryDirective中url in detail分支处理的场景。四、bokeh-plot 指令示例页的执行引擎gallery_detail.rst 中真正跑代码的是.. bokeh-plot::指令其实现位于 bokeh_plot.py。该指令同时支持两种用法用法一指向外部示例文件画廊页采用此方式.. bokeh-plot:: path/to/plot.py用法二内联代码.. bokeh-plot:: from bokeh.plotting import figure, output_file, show output_file(example.html) x [1, 2, 3, 4, 5] y [6, 7, 6, 4, 5] p figure(titleexample, width300, height300) p.line(x, y, line_width2) p.scatter(x, y, size10, fill_colorwhite) show(p)两种方式不能混用同时给出参数与 content 会抛出SphinxError见 bokeh_plot.py。另外 Bokeh 文档内部约定了一个__REPO__/前缀路径以它开头时会被解析为仓库根目录下的相对路径便于文档源码树内引用。4.1 指令选项option_specBokehPlotDirective在 bokeh_plot.py 中定义了完整的选项规格选项取值默认说明:process-docstring:布尔flag无是否将示例文件的模块 docstring 单独渲染为格式化说明块:source-position:above/below/nonebelow格式化源码块放在图表上方、下方还是不显示:linenos:布尔flag无源码块是否显示行号gallery_detail.rst 固定使用:process-docstring:与:source-position: below即说明文字在上、交互图居中、源码在下的经典示例页布局。process_code_blockbokeh_plot.py还负责把 docstring 从源码中剥离_remove_module_docstring避免展示源码时重复出现模块说明。4.2 执行流水线从源码到交互图run()方法的完整调用链bokeh_plot.pyprocess_args_or_content()—— 确定源码与路径来源process_source()—— 依次执行_evaluate_source()调用ExampleHandler运行示例代码产生一个 BokehDocument并要求文档根节点恰好一个len(d.roots) ! 1时报错读取_sphinx_height_hint()获取图表高度提示调用autoload_static(root, RESOURCES, js_filename)生成独立的 JS 文件与script标签构造autoload_script节点将script_tag直接嵌入 HTML必要时用height_hint包一层div styleheight:...px;process_sampledata()正则扫描源码中的sampledata引用登记到all_sampledata_xrefs与all_gallery_overview供后续采样数据交叉引用生成见 bokeh_plot.py返回target intro above autoload below节点序列即锚点 → docstring 说明 → 源码块可选上方→ 交互图 → 源码块可选下方。最终页面结构因此是交叉引用锚点 → 模块 docstring 说明 → 可交互 Bokeh 图通过 autoload 脚本懒加载 JS→ 缩进格式化的 Python 源码块。4.3 ExampleHandler如何安全执行示例脚本示例脚本包含show(p)、output_file(...)等 I/O 调用直接运行会弹浏览器、写文件因此 example_handler.py 提供了ExampleHandler——一个精简版 Bokeh application handler继承Handler内部用CodeRunner编译执行源码记录error/error_detail/docMonkeypatch 策略见_monkeypatchexample_handler.pyoutput_notebook、output_file、reset_output被替换为空操作_passshow、save被替换为_add_root即把对象直接加入当前curdoc()bokeh.document.Document被替换为返回当前文档的_curdoc由于这些函数从bokeh.io传递导入到bokeh.plotting两个模块都会被同时打补丁执行完成后在finally中恢复原函数并还原curdoc确保文档构建环境不被污染。这就是画廊示例页能静默产出图表而不触发任何浏览器或文件输出的原因。五、实际配置conf.py 中的画廊开关Bokeh 文档构建在 conf.py 中配置了整套画廊参数extensions [ ... bokeh.sphinxext.bokeh_plot, bokeh.sphinxext._internal.bokeh_gallery, ... ] bokeh_example_subdirs [ advanced/extensions, basic/annotations, basic/areas, basic/axes, basic/bars, basic/data, basic/layouts, basic/lines, basic/scatters, styling/visuals, styling/plots, styling/mathtext, styling/themes, interaction/js_callbacks, interaction/legends, interaction/linking, interaction/tools, interaction/tooltips, interaction/widgets, models, plotting, output/webgl, topics/categorical, topics/hierarchical, topics/contour, topics/geo, topics/graph, topics/hex, topics/images, topics/pie, topics/stats, topics/timeseries, ] bokeh_missing_google_api_key_ok False bokeh_sampledata_xref_skiplist [ examples/basic/data/ajax_source.py, examples/basic/data/server_sent_events_source.py, examples/basic/layouts/custom_layout.py, examples/styling/dom/css_classes.py, examples/models/widgets.py, ]各配置项含义注册于 bokeh_gallery.py 的setup与 bokeh_plot.py配置项默认值作用bokeh_gallery_dirdocs/gallery画廊详情页的输出目录bokeh_examples_dirdocs/examples生成示例页的目录bokeh_example_subdirs[]需要扫描生成画廊条目的示例子目录列表bokeh_sampledata_xref_skiplist[]跳过采样数据交叉引用的示例路径黑名单bokeh_missing_google_api_key_okTrue见 bokeh_plot.py缺少GOOGLE_API_KEY时是否允许继续构建Bokeh 自身文档将其设为False强制校验若gallery.json缺失config_inited_handler会直接报错可见该文件是画廊系统的配置中枢。六、把新示例加入画廊端到端步骤结合以上源码往画廊中添加一个新示例的完整流程为写示例脚本在 examples 下相应子目录创建my_plot.py文件顶部用模块 docstring 书写说明文字会作为详情页的说明块脚本末尾调用show(p)登记目录确保该子目录如basic/scatters出现在 conf.py 的bokeh_example_subdirs中配置缩略图信息在 gallery.json 对应location数组中追加条目{ name: my_plot.py, alt: Thumbnail link to the examples/basic/scatters/my_plot.py example ... }title、desc、url均为可选字段其中url存在时会作为外部链接新窗口打开 4.在画廊索引页声明在 gallery.rst 对应tab-item的.. bokeh-gallery::下追加basic/scatters若已声明则跳过 5.重新构建文档config_inited_handler扫描目录 → 渲染gallery_detail.rst生成docs/examples/basic/scatters/my_plot.rst→bokeh-plot执行示例并输出交互图与源码块若该文件已存在且较新则跳过增量构建。七、构建性能与并行安全画廊系统为文档构建做了两方面性能考量增量写入详情文件比gallery.json新则跳过重写避免每次全量重建耗时统计与预警BokehPlotDirective记录每个示例的total/evaluate/serialize/write四段耗时_PlotTiming见 bokeh_plot.py在build-finished阶段汇总输出总耗时并用nlargest(5, ...)列出最慢的 5 个示例便于定位拖慢文档构建的脚本。此外两个扩展的setup都返回PARALLEL_SAFE明确声明支持 Sphinx 并行构建同时通过env_merge_info正确合并并行子进程的bokeh_plot_files与耗时数据bokeh_plot.py保证并行模式下生成的 JS 资源与统计信息不丢失。八、总结一套可复用的配置驱动示例文档范式从 gallery_detail.rst 这个 13 行模板出发可以看到 Bokeh 文档团队搭建的完整示例文档流水线数据驱动gallery.json定义画廊内容与元数据conf.py 定义扫描范围模板驱动gallery_detail.rst负责单个示例页gallery_page.rst 负责索引缩略图代码驱动bokeh_gallery.py 批量生成页面bokeh_plot.py 与 example_handler.py 负责安全执行示例并产出可交互图表。这套模式的核心价值在于新增一个示例只需写脚本 改一行 JSON页面、锚点、索引、缩略图全部自动生成且天然支持增量构建与并行构建。对于任何希望以示例即文档方式维护技术文档的 Sphinx 项目Bokeh 这套从模板到指令再到执行器的实现都是一份可直接借鉴的完整范本。相关测试与构建入口可进一步参考 tests/codebase 与 docs/bokeh/Makefile 深入了解。【免费下载链接】bokehInteractive Data Visualization in the browser, from Python项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/23 16:12:06

OpenClaw开源AI助手框架部署与插件开发指南

1. OpenClaw项目概述OpenClaw是一个完全开源的多功能AI助手框架,它最吸引人的特点是提供了6000可扩展的技能插件。这个项目最初由腾讯云团队孵化,现在已经成为GitHub上最活跃的AI开源项目之一。我最近在本地环境完整部署了OpenClaw,实测下来它…

2026/10/27 4:17:13

Java使用Zookeeper实现微服务注册与发现

1. 项目概述在分布式系统中,服务注册与发现是微服务架构的核心组件之一。Zookeeper作为一个高可用的分布式协调服务,常被用作服务注册中心。本文将详细介绍如何使用Java操作Zookeeper实现完整的服务注册与发现方案,重点讲解Curator框架的使用…

2026/11/7 13:44:19

大清包负责电工证吗内部消息:洛阳涧西区应届生必看电工证报考指南

大清包负责电工证吗内部消息:洛阳涧西区应届生必看电工证报考指南 现在找工作动不动就卡在特种作业证上,特别是电工证,没有它连门都进不去。你是不是也在担心,大清包负责电工证吗?有没有内部消息能帮咱们避开坑?别急,这篇就帮你理清楚电工证报考的全部…

2026/11/7 13:44:19

煤矿机电工证考试2026河南最新政策全解析

煤矿机电工证考试2026河南最新政策全解析 你是不是正在找煤矿机电工的工作,却发现没有 煤矿机电工证 根本进不了门?别急,2026年河南最新政策已经出炉,报考流程、考试内容、证书有效期等关键信息都在这了,看完这篇你就知道怎么快速拿到证,顺利…

2026/11/7 13:44:19

睢宁县电工证报名中心官方报名入口怎么找?找工作必须知道

睢宁县电工证报名中心官方报名入口怎么找?找工作必须知道 你有没有想过,找工作时被问:“有电工证吗?”一句话就卡住你了?现在各行各业都要求持证上岗,尤其是特种作业岗位,像电工、焊工、高处作业这些, 没有特种作业操作证,连门都进不去 。而…

2026/11/7 13:44:19

特种工证书遗失后怎么补办 通过率揭秘

特种工证书遗失后怎么补办 通过率揭秘 怕考不过白交培训费,现在很多人在报考特种工证书时最担心的就是钱花了却拿不到证,或者拿到证后因为各种原因遗失了,又得重新补办。尤其是像郑州金水区的学员,很多都是在工作之余抽时间备考,时间紧、任务重,…

2026/11/7 13:44:19

渝北电工证怎么考多少钱?新手必看报名全攻略

渝北电工证怎么考多少钱?新手必看报名全攻略 你是不是正在为找工作发愁?别急,特种作业证就是你打开高薪岗位的“金钥匙”。特别是在渝北地区,电工证已经成为很多岗位的门槛,尤其是像建筑、电力、制造业这些行业, 没有电工证,连面试资格都没有…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/6 10:49:01

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑