Community编程与开发github.com

pwquint24/org-babel-notebook

使用 Org Babel 在 Emacs Org Mode 中编写、结构化、执行和发布交互式计算笔记本的综合指南。

org-babel-notebook 是什么?

该技能提供了使用 Org Babel 在 Emacs Org Mode 中创建交互式计算笔记本的全面指南,类似于 Jupyter 或 Mathematica,但基于纯文本,支持 Git 版本控制,并能在单个文档中混合多种编程语言。它详细介绍了五个核心关注点(执行、结果、导出、缠结、组合)及其对应的标头参数,并通过清晰的模板和示例说明了笔记本的标准化前导设置和代码块结构。技能深入解析了 `:results` 参数的关键区别,特别是`value`(功能模式,捕获返回值)与 `output`(脚本模式,捕获标准输出)的区别,这对于避免常见的 Babel 混淆至关重要。此外,它还涵盖了会话管理、缓存、可视化生成、交互式执行工作流、报告导出以及常见问题的故障排查清单,适用于所有支持 Org Babel 的平台(如 Emacs)。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pwquint24/org-babel-agent-skills/tree/HEAD/skills/org-babel-notebook

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

使用 Org Babel 编写计算笔记本

Org Babel 将 Emacs Org Mode 转变为一个交互式的、多语言的计算笔记本环境。与 Jupyter 或 Mathematica 类似,Org Babel 将可执行代码、实时执行结果、图表、表格和叙述性散文交织在一起。与基于 JSON 的笔记本不同,Org 笔记本是纯文本、人类可读、原生支持 Git 版本控制,并且支持在单个文档中混合使用多种编程语言。


1. 核心架构与关注点分离

每个 Org Babel 笔记本都围绕五个由标头参数控制的独特关注点运行。混淆它们是 Org 笔记本中产生 bug 的主要原因:

关注点关键标头参数控制内容
执行:session, :eval, :dir, :var, :cache块是否运行、在哪个进程中运行、在何处运行以及使用什么输入?
结果:results (value vs output, 格式, 类型, 处理)从执行中捕获了什么以及如何在缓冲区中呈现?
导出:exports (code, results, both, none)导出的报告(HTML, PDF, Markdown)中出现什么?
缠结:tangle, :shebang, :noweb提取到磁盘上独立的源代码文件中的内容是什么?
组合:var, #+CALL:, <<noweb>>, org-sbe块如何相互传递数据或代码?

2. 笔记本结构与前导设置

一个 Org 笔记本文件 (.org) 从文档元数据和缓冲区范围的默认设置开始,然后是包含叙述性文本、数学公式和代码块的层级标题。

2.1 标准笔记本前导模板

#+TITLE: 实验 X 的计算分析
#+AUTHOR: 张三
#+DATE: [2025-05-18 Sun]
#+OPTIONS: toc:2 num:t ^:{}
#+STARTUP: overview hideblocks inlineimages

# 此缓冲区中所有块的全局 Babel 默认值:
#+PROPERTY: header-args :eval yes :exports both :results drawer
# 语言特定的默认值:
#+PROPERTY: header-args:python :session *py-analysis* :results value :exports both
#+PROPERTY: header-args:R :session *R-analysis* :results value :exports both
#+PROPERTY: header-args:sh :session none :results output :exports both

关键缓冲区内设置:

  • #+STARTUP: inlineimages:插入结果或打开缓冲区时,自动内联显示生成的图表/图像。
  • #+STARTUP: hideblocks:启动时折叠代码块,仅显示叙述和结果以提高可读性。
  • #+STARTUP: nohideblocks:显示所有展开的代码块。
  • #+PROPERTY: header-args ...:缓冲区范围的默认值。可以使用 header-args+ 进行追加。

2.2 在 Emacs 配置中启用语言

默认情况下,Org 仅启用 Emacs Lisp 求值。所有其他语言必须在你的 Emacs 配置中显式加载:

(org-babel-do-load-languages
 'org-babel-load-languages
 '((emacs-lisp . t)
   (python     . t)
   (R          . t)
   (shell      . t)
   (sqlite     . t)
   (gnuplot    . t)
   (C          . t)))

为了对受信任的笔记本避免交互式执行确认对话框:

;; nil 允许块在无需确认提示的情况下运行
(setq org-confirm-babel-evaluate nil)

3. 代码块结构

#+NAME: <block_name>
#+HEADER: <additional_header_args>
#+BEGIN_SRC <language> <switches> <header_arguments>
  <body>
#+END_SRC
  • #+NAME: <name>:可选的唯一标识符。如果该块将被引用为函数、通过 :var 传递给另一个块作为输入、或通过 #+CALL: 调用,则此标识符是必需的。
  • <language>:Babel 识别的标识符 (python, R, sh, emacs-lisp, sqlite, sql, julia, calc, gnuplot 等)。
  • <switches>:可选开关(例如,-n 用于导出时行号,-r 用于去掉标签)。
  • <header_arguments>:控制执行、结果和导出的键值对。
  • #+HEADER::用于清晰指定长列表标头参数的辅助行。

内联代码块

用于在段落中嵌入动态计算值:

最终计算出的准确率为 src_python[:session *py* :results value]{f"{acc * 100:.2f}%"}。

4. 标头参数参考

4.1 会话管理:交互式探索 vs 封闭式可重现性

  • :session none (默认):在一次性外部解释器进程中求值块。封闭、干净且避免状态污染,但每次运行都会重新初始化导入和环境。
  • :session <name>:在持久的 Emacs 下级 REPL 缓冲区中求值(例如 *py-analysis*)。
    • 变量、函数和导入的模块在共享同一会话名称的多个块之间持续存在。
    • 对于大数据集、大模型权重和探索性工作流至关重要。
    • 最佳实践: 使用 :session <name> 进行原型开发;对于最终验证,请重新启动会话或使用 :session none 测试关键部分以保证可重现性。

4.2 工作目录与远程环境

  • :dir /path/to/project:在指定目录内运行块。
  • :mkdirp yes:如果目标目录不存在,则创建它。
  • 远程执行 (TRAMP): :dir /ssh:user@gpu-cluster:/workspace/data 在服务器上远程执行块,同时将输出渲染到本地 Emacs 缓冲区中。

4.3 缓存昂贵的计算

  • :cache yes:计算块文本、输入和 :var 参数的 SHA1 哈希值。
  • 如果哈希值与存储在 #+RESULTS[hash]: 行上的哈希值匹配,则跳过求值并保留缓存结果。
  • 仅用于没有外部副作用的确定性纯计算。

5. 结果处理:关键区别

:results 参数最多包含四个正交组件:

:results [collection] [type] [format] [handling]

5.1 收集方式:函数式 (value) vs 脚本式 (output)

理解这种区别可以消除 90% 的 Babel 混淆:

收集模式捕获的内容Python 行为Shell 行为
:results value (Python, R, elisp 的默认值)最后一个表达式的返回值或显式 return。必须使用显式的 return <val> 语句。所有 print() 输出被丢弃。返回退出码或字符串值。
:results output (shell, bash 的默认值)执行期间发出的 Stdout 流。捕获所有 print() 语句。任何 return 都被忽略。捕获所有命令的标准输出(echo, ls 等)。

Python 函数式示例 (:results value):

#+BEGIN_SRC python :results value
  data = [1, 2, 3, 4]
  # 在函数式模式下,Python 中需要显式 return:
  return sum(data)
#+END_SRC

#+RESULTS:
: 10

Python 脚本式示例 (:results output):

#+BEGIN_SRC python :results output
  for i in range(3):
      print(f"Epoch {i}: loss={0.5/(i+1):.4f}")
#+END_SRC

#+RESULTS:
: Epoch 0: loss=0.5000
: Epoch 1: loss=0.2500
: Epoch 2: loss=0.1667

5.2 结果类型

  • table / vector:将返回的列表/数组格式化为 Org Mode 表格。
  • scalar / verbatim:将输出格式化为原始引用文本,不进行表格格式化。
  • file:将输出定向到磁盘上的文件(使用 :file <filename> 指定),并在结果中插入一个 Org 文件链接。

5.3 结果格式

  • drawer (推荐):将结果包裹在 :RESULTS: … :END: 分隔符中。保持文档整洁,特别适用于多行输出。
  • raw:将输出直接插入为未转义的 Org 文本(用于生成动态标题或表格)。
  • code:将输出包裹在 #+BEGIN_SRC <lang> … #+END_SRC 中。
  • link / graphics:将结果视为图像/文件的路径并生成 [[file:path]]。

5.4 处理方式

  • replace (默认):替换之前的 #+RESULTS: 块。
  • append:在现有结果下方追加新结果。
  • prepend:在现有结果上方插入新结果。
  • silent:在 Emacs 回显区/迷你缓冲区显示结果,不写入 Org 缓冲区。

6. 笔记本中的可视化与图表

为了生成直接呈现在笔记本中的图表和图形:

6.1 Python Matplotlib 绘图

#+NAME: plot-normal-distribution
#+BEGIN_SRC python :session *py-vis* :results graphics file :file figures/normal_dist.png :exports both
  import matplotlib.pyplot as plt
  import numpy as np

  plt.figure(figsize=(6, 3.5))
  x = np.linspace(-3, 3, 200)
  plt.plot(x, np.exp(-x**2 / 2) / np.sqrt(2 * np.pi), color="#2b5c8f", lw=2)
  plt.title("标准正态分布")
  plt.xlabel("z")
  plt.ylabel("密度")
  plt.tight_layout()
  plt.savefig("figures/normal_dist.png", dpi=150)
  plt.close()
#+END_SRC

#+RESULTS: plot-normal-distribution
[[file:figures/normal_dist.png]]

6.2 R ggplot2 绘图

#+NAME: r-scatter-plot
#+BEGIN_SRC R :session *r-vis* :results graphics file :file figures/r_scatter.png :exports both
  library(ggplot2)
  p <- ggplot(mtcars, aes(x=wt, y=mpg, color=factor(cyl))) +
    geom_point(size=3) +
    theme_minimal() +
    labs(title="燃油效率与重量", x="重量 (1000 lbs)", y="MPG")
  ggsave("figures/r_scatter.png", plot=p, width=6, height=4, dpi=150)
#+END_SRC

#+RESULTS: r-scatter-plot
[[file:figures/r_scatter.png]]

提示: 在 Emacs 中运行 M-x org-toggle-inline-images (C-c C-x C-v) 以切换在缓冲区中显示生成的图形。


7. 交互式执行与编辑工作流

基本快捷键

快捷键命令描述
C-c C-corg-babel-execute-src-block执行光标下的块并插入/更新结果。
C-c 'org-edit-special在专用的主模式缓冲区中打开块体(支持完整 LSP、语法高亮、自动补全)。再次按 C-c ' 保存并返回。
C-c C-v borg-babel-execute-buffer顺序执行笔记本中的所有代码块(如“运行所有单元格”)。
C-c C-v sorg-babel-execute-subtree执行当前标题下的所有代码块。
C-c C-oorg-open-at-point在 #+RESULTS: 链接上时,在外部查看器或缓冲区中打开图像或生成的文件。
M-<down>org-babel-pop-to-session将焦点直接切换到该块会话的交互式 REPL 缓冲区。
C-c C-v vorg-babel-expand-src-block预览完全展开的块(包含所有已解析的 :var 和 noweb 扩展)。

8. 导出与发布报告

一个笔记本可以编织成独立的 HTML、PDF 或 Markdown 文档。

8.1 使用 :exports 控制导出内容

  • :exports code:仅导出代码块。
  • :exports results:仅导出输出/图形(隐藏代码,适用于高管报告)。
  • :exports both:导出代码和输出(适用于技术文档)。
  • :exports none:从导出的文档中隐藏代码和结果(如果需要,在求值期间运行)。

8.2 使用 :eval 控制导出求值

  • :eval never-export:防止在导出期间重新运行块,使用缓冲区中现有的 #+RESULTS:。加快导出速度并防止非确定性更改。
  • :eval query-export:在导出期间执行前提示。

8.3 导出命令

  • C-c C-e h h (org-html-export-to-html):生成 HTML 报告。
  • C-c C-e h o (org-html-export-to-html-and-open):生成 HTML 并在浏览器中打开。
  • C-c C-e l p (org-latex-export-to-pdf):通过 LaTeX 生成排版的 PDF 报告。

9. 常见陷阱与故障排查清单

症状 / 错误原因修复
Python 块不返回结果使用了 :results value 但使用了 print(...) 而不是 return ...将 print(...) 替换为 return ...,或将标头改为 :results output。
No org-babel-execute function for <lang>语言未在 org-babel-load-languages 中注册在 Emacs 配置中向 org-babel-load-languages 添加 (<lang> . t) 并求值。
生成了图像链接但图像未显示Org Mode 中内联图像被关闭运行 M-x org-toggle-inline-images (C-c C-x C-v) 或添加 #+STARTUP: inlineimages。
会话输出包含重复提示 (>>>)REPL 缓冲区中存在残留的交互式提示文本清理或重新启动会话缓冲区 (*session-name*)。
导出慢或挂起Org 在导出期间重新执行所有笔记本块对长时间运行的块设置 :eval never-export,或通过 #+PROPERTY: header-args :eval never-export 全局设置。
表格输入产生水平规则错误水平规则 (`-`) 被视为原始行

10. 完整注释笔记本示例

#+TITLE: 太阳耀斑频率分析
#+AUTHOR: 亚历克斯·里维拉博士
#+DATE: [2025-05-18 Sun]
#+OPTIONS: toc:nil num:nil
#+STARTUP: inlineimages nohideblocks
#+PROPERTY: header-args :session *solar* :results drawer :exports both

* 简介
我们分析在 6 个月的观测窗口内记录的观测耀斑频率。

* 原始观测
以下是基线测量表:

#+NAME: raw_observations
| 月份 | C 级 | M 级 | X 级 |
|-------+---------+---------+---------|
| 一月 |      12 |       3 |       0 |
| 二月 |      19 |       5 |       1 |
| 三月 |      15 |       2 |       0 |
| 四月 |      27 |       8 |       2 |
| 五月 |      31 |      11 |       3 |
| 六月 |      22 |       7 |       1 |

* 数据处理与汇总统计
我们使用 Python 计算总太阳活动:

#+NAME: compute_totals
#+BEGIN_SRC python :var obs=raw_observations :colnames yes :results value table
  total_events = []
  for row in obs:
      month = row[0]
      total = sum(row[1:])
      total_events.append([month, total])
  return [["月份", "总事件数"]] + total_events
#+END_SRC

#+RESULTS: compute_totals
:RESULTS:
| 月份 | 总事件数 |
|-------+-----------|
| 一月 |        15 |
| 二月 |        25 |
| 三月 |        17 |
| 四月 |        37 |
| 五月 |        45 |
| 六月 |        30 |
:END:

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

相关技能