はじめに
先日開催されたTokyo.R#112ではじめてのLTをしました。発表資料に、quarto-webr
をしれっと利用してみたところ、使用感がかなり良かったです。チョットダケ需要がありそうなので記事にしておくことにします。
追記期待(webRの利用例として貴重) https://t.co/kEZJ0rvAfn
— Uryu Shinya (@u_ribo) April 22, 2024
だれかに書いてもらいたいやつ
— T-3 (@tea3jp) May 12, 2024
公式ドキュメント以上のことは特に記載していないので、発展的な内容に興味がある方は公式ドキュメントを参照してください。
quarto-webrとは
quarto-webr
はその名の通りQuartoでwebRを利用できるようにするQuartoの拡張機能です。そもそもwebRってなんだっけ?という方は、先にえいつぴさんのブログ記事を読むとよさそうです。現時点でおそらく唯一の日本語文献です。
webRについて適当な説明をすると、「ブラウザでRを使えてうれしい!」みたいな感じです。 ですが、webRを直接利用するのは結構大変です。たとえば、次のようなインタラクティブなコードエディターを描写するためには、そこそこたくさんのJavaScriptを書く必要があります1。
コード(非同期処理なにも分からない)
<button class="btn btn-success btn-sm" disabled type="button" id="runButton">Loading webR...</button>
<div id="editor">fit <- lm(mpg ~ am, data=mtcars)
</div>
summary(fit)<pre><code id="out"></code></pre>
<canvas
id="canvas"
width="1008"
height="1008"
style="display: none; margin: auto; width: 700px;"
></canvas>
<script type="module">
var editor = ace.edit("editor");
.setOptions({ fontSize: "11pt", maxLines: Infinity });
editor.session.setMode("ace/mode/r");
editor
import { WebR } from 'https://webr.r-wasm.org/v0.3.3/webr.mjs';
const webR = new WebR();
await webR.init();
await webR.evalRVoid('options(device=webr::canvas)');
const shelter = await new webR.Shelter();
// Handle webR output messages in an async loop
async ()=>{
(for (;;) {
const output = await webR.read();
switch (output.type) {
case 'canvas':
let canvas = document.getElementById('canvas');
if (output.data.event === 'canvasNewPage') {
.style.display = 'block';
canvas.getContext('2d').clearRect(0, 0, 1008, 1008);
canvas
}if (output.data.event === 'canvasImage') {
.getContext('2d').drawImage(output.data.image, 0, 0);
canvas
}break;
default:
break;
}
};
})()
async function runR() {
document.getElementById('canvas').style.display = 'none';
let code = editor.getValue();
const result = await shelter.captureR(code, {
withAutoprint: true,
captureStreams: true,
captureConditions: false
;
})try {
const out = result.output.filter(
=> evt.type == 'stdout' || evt.type == 'stderr'
evt .map((evt) => evt.data);
)document.getElementById('out').innerText = out.join('\n');
finally {
} .purge();
shelter
}
}document.getElementById('runButton').onclick = runR;
document.getElementById('runButton').innerText = 'Run code';
document.getElementById('runButton').disabled = false;
</script>
quarto-webr
は、この苦しさをいい感じにラッピングすることでeasyにwebRを利用可能としてくれます。とてもうれしいです。
インストール
まずは拡張機能を利用したいプロジェクトフォルダの配下で以下のコマンドを実行して、拡張機能をインストールします。
quarto add coatless/quarto-webr
Quarto の拡張機能はRのパッケージとは異なり、globalな場所にインストールされるわけでは無いので注意してください。_extensions
配下に拡張機能が追加されたことを確認したら次に進みましょう。
利用法
適当な.qmd
ファイルを作成しましょう。作成したら次の手順でquarto-webr
を利用出来ます。
- ドキュメントのyamlヘッダーに
webr
を追加する
filters:
- webr
- コードブロックで
{webr-r}
を利用する
---
title: ねこになりたいね
format: html
engine: knitr
filters:
- webr
---
`quarto-webr`のおかげで、成績も上がったしねこにもなれました!
```{webr-r}
fit = lm(mpg ~ am, data = mtcars)
summary(fit)
```
- レンダリングする
いい感じにインタラクティブなコードエディターが現れます。生のwebRを利用するよりも圧倒的に簡単ですね。しかもHTML、RevealJS、 ウェブサイト、ブログ、 書籍の形式に対応しているのでいろいろなシーンで使えます。
Tipsとか
個人的に知っておくと便利そうだと思ったこと、引っかかったことをいくつか記載しておきます。
パッケージのinstallについて
webRではwebr::install()
関数で対話的にパッケージをインストールできます。
::install("ggplot2") webr
講義資料やハンズオンでquarto-webr
を利用する場合では、ドキュメント内で利用するパッケージはあらかじめインストールしておきたいのではないかと思います。ドキュメントを開いたときにパッケージのインストールを開始したい場合は次のようにyamlヘッダーを修正しましょう。
---
webr:
packages: ['dplyr', 'tidylog']
---
パッケージは記述した順にインストールが行われるため、競合するパッケージをインストールする場合は気を付けましょう(一敗)。
データの読み込み
次の二つの方法がサポートされているようです。
- パッケージ内のデータを読み込む
- webから読み込む
指定のurlか次のように読み込むことが出来ます。
<- "https://example.com/data.csv"
url download.file(url, "data.csv")
<- read.csv("data.csv") data
ドキュメントとセルのオプション
生のquartoで利用できるオプションがquarto-webr
では利用できないことがあります(一敗)。指定したのに適用されていないな~と思った場合は、ドキュメントを確認しましょう。
バージョンの互換性
古いバージョンのQuartoで作業していたら拡張機能をインストールしてもコードエディターがレンダリングされず、長い間苦しみました(一敗)2。quarto-webr
は公式の拡張機能ではないこともあり、特定のバージョンでは動作しない、予期せぬバグが発生する事がありそうです。僕のケースではQuartoを最新版にするだけで期待通り動くようになりましたが、逆に最新版のQuartoにquarto-webr
のアップデートが追い付いていないケースも見受けられます。公式レポジトリのissueなどをチェックしてあげるといいと思います。
終わりに
R最高!