使用Julia

概述

Quarto支持在Markdown中嵌入可执行的Julia代码块。这使您能够创建完全可重现的文档和报告——生成输出的Julia代码本身就包含在文档中,并且在每次渲染文档时都会自动重新运行。

Quarto有两个可用的Julia代码执行引擎。较旧的一个使用IJulia Jupyter内核,依赖于Python运行。较新的引擎使用QuartoNotebookRunner.jl包来渲染笔记本,除了Julia安装之外没有任何额外的依赖。

使用jupyter引擎

下面我们将描述如何安装IJulia及相关要求,但首先我们将介绍创建和渲染带有Julia代码块文档的基础知识。

代码块

使用大括号包围语言名称(例如```{julia})的代码块是可执行的,并且将在渲染时由Quarto运行。下面是一个简单的例子:

---
title: "图表演示"
author: "Norah Jones"
date: "2021/5/22"
format:
  html:
    code-fold: true
jupyter: julia-1.8
---

### 参数图

绘制函数对(x(u), y(u))。
参见@fig-parametric示例。

```{julia}
#| label: fig-parametric
#| fig-cap: "参数图"

using Plots

plot(sin, 
     x->sin(2x), 
     0, 
     2π, 
     leg=false, 
     fill=(0,:lavender))
```

您会注意到代码块顶部有一些特殊的注释。这些是单元格级别的选项,使图形可交叉引用

该文档将生成以下渲染输出:

示例图表演示输出,包含标题、作者、发布日期和关于参数图的主要部分,包含文本、可切换的代码字段以及带有标题为“图1 参数图”的图表输出。

您可以从可执行代码块生成各种输出类型,包括图表、数据框的表格输出和纯文本输出(例如打印统计摘要的结果)。

有许多选项控制代码执行和输出的行为,您可以在执行选项文章中了解更多信息。

除了中断Markdown流程的代码块外,您还可以包含内联代码。更多关于内联代码的信息,请参阅内联代码文章。

多重输出

默认情况下,Julia单元格会自动打印其最后一条语句的值(如上面的示例中plot()调用生成了图表输出)。如果您想从一个单元格中显示多个图表(或其他类型的输出),您应该显式调用display()函数。例如,这里我们并排输出两个带有子标题的图表:

```{julia}
#| label: fig-plots
#| fig-cap: "多图表"
#| fig-subcap:
#|   - "图表1"
#|   - "图表2"
#| layout-ncol: 2

using Plots
display(plot(sin, x -> sin(2x), 0, 2))
display(plot(x -> sin(4x), y -> sin(5y), 0, 2))
```

渲染

Quarto 会自动运行包含可执行代码块的任何 Markdown 文档中的计算。例如,上面的示例可以通过以下方式渲染为各种格式:

终端
quarto render document.qmd # 所有格式
quarto render document.qmd --to pdf
quarto render document.qmd --to docx

render 命令将渲染文档 YAML 中列出的所有格式。如果没有指定格式,则将渲染为 HTML。您还可以提供 --to 参数以针对特定格式。

Quarto 还可以渲染任何 Jupyter 笔记本(.ipynb):

终端
quarto render document.ipynb

请注意,目标文件(在本例中为 document.qmd)应始终是命令行参数中的第一个参数。

请注意,在渲染 .ipynb 时,Quarto 默认不会执行笔记本中的单元格(假设您在编辑笔记本时已经执行了它们)。如果您想执行这些单元格,可以传递 --execute 标志给 render:

终端
quarto render notebook.ipynb --execute

安装

为了渲染嵌入Julia代码的文档,您需要安装以下组件:

  1. IJulia
  2. Revise.jl
  3. 可选,Jupyter缓存

下面我们将逐一介绍这些内容。

IJulia

IJulia是Jupyter的Julia语言执行内核。您可以在Julia REPL中如下安装IJulia:

using Pkg
Pkg.add("IJulia")
using IJulia
notebook()

第一次运行notebook()时,它会提示您是否应该安装Jupyter。按回车键让它使用Conda.jl包安装一个仅限于Julia的Python+Jupyter最小发行版(通过Miniconda)(不在您的PATH中)。在Linux上,它默认首先在您的PATH中查找jupyter,只有在失败时才会询问是否安装Conda Jupyter。

如果您选择不使用Conda.jl安装Python和Jupyter,您需要确保系统上还有其他安装(如果您需要帮助,请参阅安装Jupyter部分)。 除了 IJulia 之外,您还需要安装 Revise.jl 并配置它以便与 IJulia 一起使用。Revise.jl 是一个库,它可以帮助您延长 Julia 会话的运行时间,减少在修改代码时重启的必要性。

Quarto 为每个文档维护一个持久的 内核守护进程,以减轻在迭代工作期间 Jupyter 的启动时间。Revise.jl 将使这个持久过程在面对包更新、git 分支检出等情况下更加稳健。使用以下命令安装 Revise.jl:

using Pkg
Pkg.add("Revise")

要配置 Revise 在 IJulia 中自动启动,请创建一个 .julia/config/startup_ijulia.jl 文件,内容如下:

try
  @eval using Revise
catch e
  @warn "Revise init" exception=(e, catch_backtrace())
end

您可以在 https://timholy.github.io/Revise.jl/stable 了解更多关于 Revise.jl 的信息。

Jupyter 缓存

Jupyter Cache 允许您缓存笔记本的所有单元格输出。如果笔记本中的任何单元格发生变化,则所有单元格都将重新执行。

如果您使用的是 IJulia.notebook() 安装的集成的 Jupyter 版本,那么您需要将 jupyter-cache 添加到 IJulia 管理的 Python 环境中。您可以这样做:

using Conda
Conda.add("jupyter-cache")

或者,如果您使用的是 IJulia 未管理的任何其他版本的 Python 中的 Jupyter,请参阅下面的 安装 Jupyter 部分以了解有关安装 jupyter cache 的详细信息。

工作流程

您可以使用任何文本或笔记本编辑器编写包含Julia代码的Quarto文档。无论您使用哪种编辑工具,始终首先运行quarto preview来设置文档更改的实时预览。实时预览适用于HTML和PDF输出。例如:

终端
# 以HTML预览
quarto preview document.qmd

# 以PDF预览
quarto preview document.qmd --to pdf

# 预览Jupyter笔记本
quarto preview document.ipynb

请注意,当渲染一个 .ipynb 文件时,Quarto 默认不会 执行笔记本中的单元格(假设你在编辑笔记本时已经执行过这些单元格)。如果你想执行这些单元格,可以在渲染时传递 --execute 标志:

Terminal
quarto render notebook.ipynb --execute

你也可以在笔记本的 YAML 前文中指定这种行为:

---
title: "My Notebook"
execute: 
  enabled: true
---

嵌入笔记本

除了在Quarto文档中包含可执行的Julia代码块外,您还可以嵌入外部Jupyter笔记本(.ipynb)中的单元格。有关更多详细信息,请参阅嵌入Jupyter笔记本单元格

VS Code

VS Code的Quarto扩展为在VS Code中处理.qmd文件提供了多种工具。该扩展直接与Julia扩展集成,提供以下Julia特定功能:

  1. 代码补全
  2. 单元格执行
  3. 上下文帮助

VS Code屏幕截图,左侧为包含Julia代码的Quarto文档,右侧为Julia代码生成的图表输出,底部为Quarto帮助窗格。

您可以通过在扩展面板中搜索’quarto’或从扩展市场安装VS Code扩展。

您还可以使用VS Code笔记本编辑器创建Julia笔记本,这些笔记本将使用Quarto进行渲染。下一节将讨论在Jupyter Lab上下文中使用笔记本与Quarto,但同样的概念也适用于VS Code。

Jupyter Lab

我们可以使用quarto convert命令将上面示例中使用的简单document.qmd转换为Jupyter笔记本。例如:

终端
quarto convert document.qmd

如果我们在Jupyter Lab中打开此笔记本并执行单元格,我们会看到以下内容:

左侧为笔记本的并排预览,右侧为浏览器中的实时预览。

请注意,这里有三种不同类型的单元格:

  1. 顶部的YAML文档选项位于Raw单元格中。
  2. 标题和解释位于Markdown单元格中。
  3. Julia代码及其输出位于Code单元格中。

在Jupyter笔记本中工作时,您可以使用quarto preview来提供渲染文档的实时预览:

终端
quarto preview document.ipynb

每次在Jupyter Lab中保存笔记本时,预览都会更新。

缓存

Jupyter Cache 允许您缓存笔记本中所有单元格的输出。如果笔记本中的任何单元格发生变化,则所有单元格都将重新执行。

要使用 Jupyter Cache,您首先需要安装 jupyter-cache 包:

平台 命令
Mac/Linux
Terminal
python3 -m pip install jupyter-cache
Windows
Terminal
py -m pip install jupyter-cache

要为文档启用缓存,请添加 cache 选项。例如:

---
title: "我的文档"
format: html
execute: 
  cache: true
---

您还可以在项目级别指定缓存。例如,在项目文件中:

project:
  type: website
  
format:
  html:
    theme: united
    
execute:
  cache: true

请注意,文档中不在代码单元格内的更改(例如 Markdown 叙述)不会使文档缓存失效。这使得缓存在您仅处理文档的散文部分时成为一个非常方便的选项。

Jupyter Cache 包含一个 jcache 命令行工具,您可以使用它来分析和管理笔记本缓存。有关更多详细信息,请参阅 Jupyter Cache 文档。

渲染

你可以使用 quarto render 命令行选项来控制缓存行为,而无需更改文档代码。使用这些选项可以强制所有代码块使用缓存,禁用所有代码块的缓存(即使选项中指定了缓存),或者强制刷新缓存,即使它未失效:

终端
# 使用缓存(即使未在选项中启用)
quarto render example.qmd --cache 

# 不使用缓存(即使选项中启用了缓存)
quarto render example.qmd --no-cache 

# 使用缓存并强制刷新
quarto render example.qmd --cache-refresh 

替代方案

如果你使用缓存来缓解长时间渲染的问题,你应该考虑一些与缓存并行的替代方案。

禁用执行

如果你只处理散文/Markdown,你可能希望完全禁用执行。通过指定 enabled: false 执行选项来实现这一点。例如:

---
title: "我的文档"
format: html
execute: 
  enabled: false
---

请注意,如果你使用 Jupyter .ipynb 笔记本(而不是纯文本 .qmd 文件)进行创作,那么这已经是默认行为:当你调用 quarto render 时不会发生执行(相反,执行会在你使用笔记本时发生)。

冻结执行

如果你在一个项目中工作,并且你主要关心的是同时渲染许多文档的累积影响,请考虑使用 freeze 选项。

你可以使用 freeze 选项来表示在全局项目渲染期间,计算文档不应重新渲染,或者仅在源文件更改时重新渲染:

execute:
  freeze: true  # 在项目渲染期间永不重新渲染
execute:
  freeze: auto  # 仅在源文件更改时重新渲染

请注意,freeze 控制的是在全局项目渲染期间是否执行。如果你对单个文档或项目子目录进行增量渲染,那么代码总是会被执行。例如:

Terminal
# 渲染单个文档(总是执行代码)
quarto render document.qmd

# 渲染项目子目录(总是执行代码)
quarto render articles

在关于 管理项目执行 的文章中了解更多关于使用 freeze 的信息。

内核选择

您会注意到在我们的第一个示例中,我们在文档选项中明确指定了使用 julia-1.7 内核(为简洁起见缩短):

---
title: "StatsPlots Demo"
jupyter: julia-1.7
---

如果没有明确指定 jupyter 内核,那么 Quarto 将尝试自动在系统上发现支持 Julia 的内核。

您可以使用 quarto check 命令发现系统上可用的 Jupyter 内核:

Terminal
quarto check jupyter

内核守护进程

为了减少Jupyter内核的启动时间,Quarto为每个文档保持一个运行中的Jupyter内核的守护进程。这使得后续的渲染可以立即进行,而无需等待内核启动。

守护进程的目的是在交互会话期间使渲染更加响应迅速。因此,当文档在没有活动tty的情况下渲染或作为批量渲染的一部分时(例如在Quarto项目中),不会创建守护进程。

请注意,Quarto默认情况下不会在Windows上使用守护进程(因为某些Windows系统不允许守护进程所需的套接字连接)。

您可以使用daemon执行选项自定义此行为。将其设置为false以防止使用守护进程,或将其设置为一个值(以秒为单位)以确定守护进程超时的时间段(默认值为300秒)。例如:

execute:
  daemon: false
execute:
  daemon: 60

请注意,如果您想在Windows上使用守护进程,您需要显式启用它:

execute:
  daemon: true

命令行

您还可以使用以下命令行选项控制Jupyter守护进程的使用:

终端
# 使用默认超时(300秒)的守护进程
quarto render document.qmd --execute-daemon

# 使用显式超时的守护进程
quarto render document.qmd --execute-daemon 60

# 防止使用守护进程
quarto render document.qmd --no-execute-daemon

您还可以使用--execute-daemon-restart命令行标志强制重新启动现有的守护进程:

终端
quarto render document.qmd --execute-daemon-restart 

如果您怀疑重用笔记本会话会导致错误,这可能会有用。

最后,您可以使用--execute-debug标志打印有关守护进程使用情况的扩展调试信息(启动、关闭、连接等):

终端
quarto render document.qmd --execute-debug

安装 Jupyter

您可以依赖 IJulia 自动安装的最小版本的 Python 和 Jupyter,或者您可以选择单独安装 Python 和 Jupyter。如果您需要安装另一个版本的 Jupyter,本节将介绍如何操作。

如果你系统上还没有 Python 3,我们建议你使用来自 https://www.python.org/downloads/ 的标准安装程序安装一个版本。

如果你在一个全新的 Python 3 环境中,安装 jupyter 包将提供运行 Quarto 的 Jupyter 内核所需的一切:

包管理器 命令
Pip
(Mac/Linux)
Terminal
python3 -m pip install jupyter
Pip
(Windows)
Terminal
py -m pip install jupyter
Conda
Terminal
conda install jupyter

你可以通过以下命令验证 Quarto 是否正确配置了 Jupyter:

Terminal
quarto check jupyter

Quarto 将在 Windows 上使用 Python 启动器 或在 MacOS 和 Linux 上使用系统 PATH 选择一个 Python 版本。你可以通过设置 QUARTO_PYTHON 环境变量来覆盖 Quarto 使用的 Python 版本。

Jupyter 缓存

Jupyter Cache 允许您缓存笔记本的所有单元格输出。如果笔记本中的任何单元格发生变化,则所有单元格都将重新执行。

要使用 Jupyter Cache,您需要首先安装 jupyter-cache 包:

平台 命令
Mac/Linux
Terminal
python3 -m pip install jupyter-cache
Windows
Terminal
py -m pip install jupyter-cache
Conda
Terminal
conda install jupyter-cache

要为文档启用缓存,请添加 cache 选项。例如:

使用 julia 引擎

用于低功耗蓝牙 5.3 的 BlueNRG-LP 系统级芯片

主要特性

  • 超低功耗无线电:
    • 接收模式下电流消耗:3.2 mA(典型值)
    • 发射模式下电流消耗:3.6 mA(典型值,0 dBm 输出功率)
    • 深度睡眠模式下电流消耗:< 1 µA
  • 高性能:
    • 灵敏度:-96 dBm(典型值)
    • 输出功率:高达 +8 dBm
  • 完全符合蓝牙 5.3 核心规范
  • 工作电压范围:1.7 V 至 3.6 V
  • 集成的 DC-DC 转换器
  • 128 KB 闪存
  • 16 KB RAM
  • 丰富的外设:
    • 18 个 GPIO
    • 1 个 UART
    • 2 个 SPI
    • 2 个 I2C
    • 2 个 I2S
    • 1 个 PDM
    • 1 个 SPU
    • 1 个 QDEC
    • 1 个 TRNG
    • 1 个 WKUP
    • 1 个 PWM
  • 封装:
    • 5 mm x 5 mm QFN40

应用

  • 无线音频设备
  • 智能家居设备
  • 可穿戴设备
  • 工业传感器网络
  • 医疗保健设备

文档

开发资源

支持

购买

相关产品

  • BlueNRG-2:用于低功耗蓝牙 5.0 的系统级芯片
  • BlueNRG-M:用于低功耗蓝牙的模块

法律信息

© 2023 STMicroelectronics - 保留所有权利。

本文件所含信息可能会随时更改,恕不另行通知。STMicroelectronics 不对因使用本文件而产生的任何直接或间接损害承担责任。

本文件所含信息“按原样”提供,不作任何明示或暗示的保证。在任何情况下,STMicroelectronics 均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于利润损失、数据丢失、业务中断等)承担责任,即使 STMicroelectronics 已被告知可能发生此类损害。

安装

julia 引擎使用 QuartoNotebookRunner.jl 包来渲染笔记本。当您首次尝试使用 julia 引擎渲染笔记本时,Quarto 将自动将此包安装到由 Quarto 拥有的私有环境中。这意味着您无需在全局 Julia 环境中安装任何东西即可让 Quarto 工作,并且 Quarto 不会干扰系统上的任何其他 Julia 环境。Quarto 默认使用 PATH 上的 julia 二进制文件,但您可以使用 QUARTO_JULIA 环境变量覆盖此设置。

使用 QuartoNotebookRunner 的自定义版本

在特殊情况下,您可能不希望使用Quarto为您安装的特定QuartoNotebookRunner版本。例如,您可能正在开发QuartoNotebookRunner本身,或者您需要使用带有错误修复的分叉版或未发布的版本。在这种情况下,请将环境变量 QUARTO_JULIA_PROJECT设置为一个安装了QuartoNotebookRunner的Julia环境的目录。

例如,您可以通过在Julia REPL中执行]activate /some/dir,然后执行]add QuartoNotebookRunner#main,将QuartoNotebookRunner的主分支安装到目录/some/dir中。只要当前没有服务器在运行,在终端中运行类似QUARTO_JULIA_PROJECT=/some/dir quarto render some_notebook.qmd的命令将确保服务器进程使用自定义的QuartoNotebookRunner启动。您还可以设置quarto--execute-debug标志并检查输出以验证是否正在使用自定义环境。

渲染笔记本

要使用julia引擎,您必须在frontmatter中指定它:

---
title: "一个使用julia引擎的笔记本"
engine: julia
---

```{julia}
1 + 2
```

渲染笔记本将启动一个持久的服务器进程(如果尚未启动)。该服务器进程首先从Quarto的私有环境中加载QuartoNotebookRunner。然后,QuartoNotebookRunner为每个要渲染的笔记本启动一个单独的Julia工作进程。

笔记本环境

默认情况下,QuartoNotebookRunner在启动工作进程时会使用--project=@.标志。这使得Julia从存储quarto笔记本的目录开始搜索环境(一个Project.tomlJuliaProject.toml文件),并从那里向上遍历目录树。

例如,对于文件/some/dir/notebook.qmd,它将查看/some/dir/[Julia]Project.toml/some/[Julia]Project.toml等。您可以使用此行为,通过将其放置在项目的顶级目录中,让quarto项目中的所有笔记本共享相同的Julia环境。

如果在这些目录中没有预先设置任何环境,工作进程将以空环境启动。这意味着只有Julia的标准库包可以在笔记本中使用。

Note

为每个笔记本或每组紧密相关的笔记本创建单独的环境被认为是最佳实践。 如果太多不同的笔记本共享相同的环境(例如Julia通常默认加载的主要共享环境),当您对环境进行更改时,可能会无意中破坏其中的一些。

您可以通过多种方式创建Julia环境,更多信息请查看官方文档。向新quarto笔记本的默认环境添加包的一个简单选项是将一些Pkg安装命令添加到笔记本中并运行一次。之后,可以删除这些命令,并且笔记本的目录中应该存在表示环境的Project.tomlManifest.toml文件。

---
engine: julia
---

```{julia}
using Pkg
Pkg.add("DataFrames")
```

另一个选项是在终端中启动julia,加载REPL,然后按]切换到Pkg REPL模式。在这种模式下,您可以首先通过运行activate /some/dir激活所需的环境,然后,例如,使用命令add DataFrames安装DataFrames包。

如果您不想使用笔记本的目录作为环境,可以通过exeflags frontmatter设置中的--project标志指定不同的目录:

---
engine: julia
julia:
  exeflags: ["--project=/some/other/dir"]
---

工作进程重用

默认情况下,空闲的工作进程将保持活动状态5分钟,这可以通过将所需秒数传递给daemon键来更改:

---
title: "一个带有十分钟超时的julia笔记本"
engine: julia
execute:
  daemon: 600
---

每次重新渲染笔记本时,都会重用已经加载所有依赖项的工作进程,从而减少延迟。只要技术上可能,QuartoNotebookRunner.jl将从之前的运行中释放资源给垃圾收集器。在每次运行中,代码都会被评估到一个新的模块中,因此您不会遇到与之前运行中定义的变量发生冲突的情况。但是,某些状态更改,如包运行时设置的修改或函数方法的移除或添加,将在运行中持续存在。如果需要,您可以使用--execute-daemon-restart标志强制重启笔记本的工作进程。

您还可以禁用守护进程,这将使用一个新的进程进行每次渲染(由于包的重新加载,延迟较高):

execute:
  daemon: false

如果没有更多的工作进程存在,服务器进程本身将在五分钟后超时。

引擎选项

引擎选项可以在 julia 顶级键下传递:

---
title: "一个Julia引擎笔记本"
engine: julia
julia:
  key: value
---

目前可用的选项有:

  • exeflags:一个字符串数组,这些字符串附加到启动工作进程的 julia 命令中。例如,笔记本默认以 --project=@. 运行(存储笔记本的目录中的环境),但这可以通过设置 exeflags: ["--project=/some/directory/"] 来覆盖。
  • env:一个字符串数组,其中每个字符串指定传递给工作进程的一个环境变量。例如,env: ["SOMEVAR=SOMEVALUE"]

限制

目前,必须在每个 .qmd 文件中指定 engine: julia 选项。通过 _quarto.yml 设置项目范围的引擎尚不支持