リアクティブHTMLノートブック
(maxbo.me)- ブラウザが実行する単一のHTMLファイルだけで、データ探索、分析、可視化、組版、配布を1つの文書にまとめ、従来のノートブック→出版ツール→PDFという流れを短縮できる
- 中核となる実装は、
style・scriptを画面に表示するechoセル、contenteditable、Observable Runtimeを組み合わせ、編集可能なリアクティブセルを作る方式 cell(name, inputs, definition)はObservableの依存性モデルに従い、counter、FizzBuzzレンダリング、隠しセル、出力のない中間値セルのように相互接続された実行単位を構成する- 同じHTML文書内でObservable Plot、TeX、Markdown、Graphviz、WASMベースのSQLite、PyodideベースのPython、WebRベースのR、Observable Inputs、Mutable状態までデモしている
- 成果物は別プラットフォームなしでブラウザ上で実行される科学・技術文書となり、実装はその後
@celine/celineライブラリとして公開された
単一HTMLファイルでノートブックと出版の分離を縮める
- HTMLは組版には広く使われているが、データ探索・分析・可視化プラットフォームとしては相対的にあまり活用されてこなかった
- 一般的な作業フローは複数のツールをまたぐ
- 1つのHTMLファイルがこの3段階を担えば、手作業の手順、CLIツール、CI段階、サードパーティープラットフォームへの依存を減らせる
- 実装はAnton ZhiyanovのIn-browser code playgrounds、Cristóbal SciuttoのSelf-modifying HTML notes、Quarto、Observable Frameworkから強い影響を受けている
編集可能なセルを作る
- 最初の段階は、
echoCSSクラスでstyleとscript要素を文書内にそのまま見えるようにする方式 - シンタックスハイライトを内蔵したフォントと
contenteditable属性を加えると、基本的なコードエディタのように使える contenteditableが適用されたscriptは、フォーカスを失うと再評価される- 既存の
scriptを複製して新しいscript要素を作り、元の要素を削除する evalはimport文を含むコードでは動作しないため、この方式が必要になる
- 既存の
- Observableベースの実行のために2つのライブラリを読み込む
- グローバルには
libraryとcellの2つのシンボルだけを公開する
Observable Runtimeベースのリアクティブデータフロー
cell(name, inputs, definition, observerVisibility)関数は、Observable Runtimeのモジュールスコープを使ってセルを定義する- 同じ名前の変数がすでにあれば既存の変数を取得し、なければ新しい変数を作って定義する
- この構造により、
contenteditableセルを再評価すると新しい定義が接続先のセルへ伝播する
- この構造により、
- Observable
Inspectorはセル出力をscriptブロックの上に表示するために使われる counterセルは1秒ごとに数値を出力する非同期ジェネレータとして構成されるscriptのid属性とcellのname引数が同じ- 初期値
iを変更してフォーカスを外すと、新しい値が反映される
counterに依存するセルも作れる- Hypertext Literalを読み込み、
counter値をFizzBuzz形式でレンダリングする htlはHTML5パーサーを実装し、自動エスケープ、イベントリスナー、スタイルオブジェクト、DOMノードのような非シリアライズ値の補間を処理する
- Hypertext Literalを読み込み、
表示セル、隠しセル、出力なしセル
echoクラスを付けなければ、セル定義を隠しつつ出力は観察できる- こうしたセルはレンダリングプリミティブとして使える
- 出力自体を表示しないセル型も作れる
silent(name, inputs, definition)はobserverVisibilityを非表示に設定し、中間値やデータ構造の保存に使える
- セルは宣言順序に関係なく動作できる
- 例では
reallyNegativeセルが後から宣言されるnegativeセルに依存する
- 例では
- 同じセル値はより複雑な出力にも活用される
- Observable Plotを読み込み、数値配列を折れ線グラフとして描き、
counter % 40の位置に縦のルール線を表示する
- Observable Plotを読み込み、数値配列を折れ線グラフとして描き、
文書・可視化出力の拡張
- セルは任意のDOM要素を返せる
- TeX、Markdown、Graphvizのデモはそれぞれ異なる形の要素を返す
texセルはspan要素を返すmdセルはtable要素を返すdotセルはsvg要素を返す
- セルは
Promiseを返したり、Errorを投げたりできる- Observable
Inspectorは実行中のセル外側のdivにobservablehq--runningクラスを適用する - エラーのセルには
observablehq--errorクラスを適用する - 文書はこの状態に合わせてスタイルを指定する
- Observable
ブラウザ内のSQLite、Python、R
- SQLiteデモはChinook sample databaseを
https://maxbo.me/chinook.dbに置き、WASMベースのSQLiteクライアントでクエリする- SQLクエリに
WHERE Milliseconds < 1000000を追加して試せる
- SQLクエリに
- PythonデモはPyodideのCPython WASMディストリビューションを使う
- PyodideにはNumPy、Pandas、Matplotlib、scikit-learn、Scipyが含まれる
- 先に作ったプロットをMatplotlibとPythonの
sqlite3モジュールで再作成する
- RデモはWebRを使う
入力と可変状態
viewofセル型はObservable Inputsと併用するために作られたviewofは2つのリアクティブセルを宣言するNAME: 入力の値viewof NAME: DOM要素そのもの
- 入力をセルの上に表示するには、セルの
idをviewof NAMEに設定する - 例では
Inputs.range([0, 100], { step: 1 })で範囲入力を作り、rangePlotセルがその値に応じて更新される - Observable Inputsの動作方式はやや難解で、Synchronized Inputsデモが参考になる
- 純粋関数型のデータフローだけでは足りない場合に備えて、
mutableヘルパーも作られたmutableは、値が変更されたときに新しい値を出力するMutableオブジェクトを登録する
ライブラリ公開と発表用スライド
- この実装は当初
incelという名前を考えていたが、その後celineと呼ぼうとしていた - ライブラリは@celine/celineとして公開されている
- この文書はSydJSでデモされた
- 文書をスライドショーに変えるためのコードも含まれている
Shift+N: スライドショー開始または次のスライドShift+B: 前のスライドShift+E: スライドショー終了
- 実装ソースはsource codeとして公開されている
1件のコメント
Hacker News の意見
記事の前提には強く同意する。HTML は計算型ノートブックの優れた基盤になり得る。
ただし、ここでの実装上の選択は好みではない。動的・リアクティブな HTML は、これよりはるかに宣言的に作れるし、Observable は素晴らしいものの、標準 JavaScript から外れる面がある。
Heximal というリアクティブ HTML システムを作り始めていて、将来的にはノートブック対応も入れる予定だ。HTML テンプレートとカスタム要素をベースにした宣言的システムで、その上に TC39 Signals 提案に基づく式/リアクティビティの仕組みを載せる構成になっている。
https://github.com/elematic/heximal
HTMX、Tangle、Curvenote、Polymer を混ぜた感じに近く、HTML がもともとリアクティブだったならこういう姿だったのではと思う。グラフィック編集やノートブックのユースケースにはかなり合うと見ている。
そのため Observablehq では通常の JavaScript デバッグ式がきちんと動作する。
https://github.com/observablehq/parser
Observable ランタイムが好きなので、フロントエンドのソースとコンパイル後の純粋な JS 表現の間を双方向に変換できるデコンパイラも作った。
https://observablehq.com/@tomlarkworthy/observablejs-toolcha...
本当に素晴らしい。特に Python と SQLite のデモが良かった。Web 経由の編集ループ(TTW)から始めて、それを quine と呼んでいる点は興味深い。妥当ではあるが、最大の弱点は永続性だ。
TiddlyWiki も実質的に同じことをしているが、作業の保存が厄介だ。何かを永続化するには、結局は別のヘッドレスサーバープロセスが必要になるからだ。
似たようなものを作りたいと思ったときは[0]、個人的には永続性から始めた。そしてそれは当然、ファイルを意味していた。プログラマー向けエディタで編集し、ファイルシステムで保存・配布できるプレーンテキストファイルだ。こうすれば、ブラウザ内にプログラマー向けエディタを再実装しなければならない問題を避けられるが、それは簡単ではない。
代わりに高速なサーバーを書く必要が出てくるが、それはそれでかなり面白い問題でもある[1]。ここでは基本的な contenteditable セクションを使ってその問題を回避しているが、永続性の次に大きな問題だ。
埋め込みスクリプト内で export できない点も、同じ壁に見える。グローバルな window オブジェクトを散らかしたくないなら、こうした機能があるとよいし、私のユースケースではコード生成もより簡単になるだろう。
0 - Literate Markdown: https://simpatico.io/lit.md
1 - Reflector、Markdown を変換・圧縮・キャッシュし、ファイル監視による無効化を行う小さな node サーバー: https://simpatico.io/reflector
注ぎ込まれた思考と努力は尊重するが、このアプローチのユーザビリティはひどい。探索的データ分析をしようとしている最中に、なぜスタイリング要素まで気にしなければならないのか分からない
Jupyter Notebook のようなツールがうまく機能する理由はまさにここにある。それでも、好奇心を持って代替的なアイデアを実装した点は高く評価する
探索的データ分析プラットフォームとしては、まだ十分ではない。Observable Notebooks のような完全な Web コードエディタの即時的なリアクティビティもないし、ファイル監視ベースのホットリロードを提供する Observable Framework でもない。Deno + VSCode 向けの新しい Jupyter カーネルもかなりスムーズな体験を提供している
だから探索分析向けのユーザビリティは、うーん……悪いという点には同意するが、配布のユーザビリティはそこまで悪くないと思う。むしろ良い。単なる単一ファイルだからだ。誰かにグラフやデータ加工の結果を送りたいときに、巨大なツールチェーンを維持したり、サードパーティサービスにお金を払ったりする必要はなく、HTML ファイルを1つ Slack に投げるか、どこかにホストすればよい
分析結果をスタイリングできる柔軟性があるおかげで、ブログや研究論文のようにスタイルが重要な環境にも公開できる
ivoryをredに変えると構文ハイライトがリアルタイムで変わる場面がそれを示しているここに至った背景は理解できるが、JavaScript フレームワークやライブラリをブラウザでもっと簡単にいじれないのは残念だ。結局はただの JS なのだから、軽量な環境で素早く実験できるべきだ。このアプローチはその点で強みがある
HTML/JS の遊び心があり実験的な可能性を取り戻す方法だ。TS、rollup、webpack のようなものより、こういう試みがもっと増えてほしい
追記: もう少し読んでみると、これはデータ分析用として提案されている。その用途にはあまり合わないと思う
使い捨てで終わらない Jupyter Notebook の代替には大きな価値があると思う。今のユーザー体験が本当にひどいことは改善できる。問題はこの構成が Jupyter Notebook の JSON の混沌よりましかどうかだが、個人的にはましだと思う側だ
Lit の元作者が最近 Google を離れており、私の知る限り、これと非常によく似たものに取り組んでいる
https://github.com/elematic/heximal
この記事の形式が気に入った。土台から始めて、興味深い何かへと積み上げている。依存関係の塊や、あちこちのフレームワークをつなぎ合わせる大げさな流れではない
追いかけるには、提示された断片をコピー&ペーストして、段階ごとにどう動くのかを理解すればよさそうだ。自分がこういうものを書くなら、org-mode のリテラルプログラミングで書いたうえで HTML にエクスポートし、ブログ記事にしたと思う
ただし、組み込みの構文ハイライトを持つフォントについては、今でも疑問が残る
リアクティブ HTMLと言っているが、ほぼ全部 JavaScript ではないのか、それとも何かを誤解しているのだろうか?
ブラウザを除けばサードパーティソフトウェアに依存せず、HTML がそうであるように長持ちし、移植可能で、使いやすい
近いうちに、この種の HTML ノートブックを Raku で、あるいは Raku 向けにサポートしてみようと思っている
現在の Raku の「ノートブックソリューション」は Jupyter ベースか Mathematica ベースだ
このプロセスにWeb技術を使って複雑にする理屈がよく分からない。追加された複雑さは何を解決するのか? むしろプロセスを遅くし、オートコンプリート、スニペット、拡張機能のような必要な機能をなくす方向に近い
そのうえ、ほかの人がこの設定に慣れていない可能性が高いので、共同作業もさらに難しくなる
環境は一度だけ設定しておき、技術の変化に合わせて小さな改善だけを加えながら使い続ければよい
n/vimユーザーなら、次で十分できる。1- データ探索: https://github.com/untitled-ai/jupyter_ascending を使ってテキストをJupyterノートブックにつなぐ。jupytextを使うので、テキストエディタで効率よくコードを編集して実行できる
2- 執筆: LaTeX用に https://github.com/lervag/vimtex を使える
ここにtmuxとtmuxpを重ねれば、プロジェクトを即座に開ける。Emacsではorg mode[1][2]および/またはAuctexで滑らかなプロセスを作れる
[1] https://sqrtminusone.xyz/posts/2021-05-01-org-python/
[2] https://martibosch.github.io/jupyter-emacs-universe/
ただ、Pythonがあまり好きではないので、Python中心ではないツールを使いたい。だからRakuとMathematicaの話をした
ちなみに https://github.com/imbue-ai/jupyter_ascending を教えてくれてありがとう
この記事の前提、つまり HTMLが科学的な文章の配布媒体として十分に活用されていない という点には概ね同意する
これに関連するWill Crichtonの最近の取り組みがある
https://willcrichton.net/nota/
https://willcrichton.net/notes/portable-epubs/
最近はノートブックが盛り上がっている。私たちも TypeScriptノートブック 版をリリースしたが[1]、トレードオフではかなり別の方向を選んだ
私たちはバックエンドのnodeコードを実行したいので、この記事の方式やObservableとは違って、ブラウザ環境で実行しようとはしていない。それでも、多くのアプリケーションではこのアイデアのほうがより良い解決策になり得る
作者に拍手を送りたい
https://github.com/srcbookdev/srcbook