3 ポイント 投稿者 GN⁺ 2024-03-04 | 1件のコメント | WhatsAppで共有
  • Observable Frameworkは、一時的なデータ探索に強いノートブックモデルを超えて、高速に読み込まれるデータアプリ・ダッシュボード・レポートを静的サイトとしてデプロイするためのオープンソースツール
  • Markdown内のjsコードブロックとインライン式はブラウザで実行され、nowのようなリアクティブな値が変わると関連する表示も自動更新される
  • FrameworkはObservable Notebooksのリアクティブ性を維持しつつ、単一のMarkdownファイル、標準JavaScript、Gitフレンドリーなワークフローを提供する
  • Inputsd3Plotのようなライブラリは開発中に遅延読み込みされ、ビルド・デプロイ時には参照されたコードだけがjsdelivr CDNから自動読み込みされる
  • Data loaderを使うと、ビルド時に任意の言語でデータを準備してJSON・CSVのような静的ファイルとしてまとめられるため、バックエンド依存を減らしたダッシュボードのデプロイが可能

データアプリのための静的サイトジェネレーター

  • Observable Frameworkは、Markdown、JavaScript、必要であれば他の言語まで組み合わせてインタラクティブなページへコンパイルする静的サイトジェネレーター
  • フル機能のホットリロードサーバーが含まれており、エディタでファイルを修正して保存するとブラウザに変更が即座に反映される
  • 作業が終われば、ビルドコマンドで静的ファイル一式を生成できる
    • これらのファイルはサーバーにデプロイできる
    • npm run deployでObservableの認証済み共有プラットフォームへ直接デプロイすることも可能

Markdown内で実行されるJavaScript

  • Frameworkの中核設計は、Markdown文書の中にJavaScriptを入れてインタラクティブな文書を作る方式
  • jsでタグ付けされたMarkdownコードブロックは、ユーザーのブラウザ上でJavaScriptとして実行される
  • インライン式も使用でき、${new Date(now)}のように現在時刻を文字列で表示できる
  • nowはepoch以降のミリ秒単位の現在時刻を提供し、継続的に更新される特殊変数
    • nowが変わると、それを参照するセルやインライン式も一緒に更新される
  • Observable NotebooksではコードとMarkdownは別々のセルに書かれるが、Frameworkではその両方が1つのテキスト文書の中に入る
  • インライン式とjsブロックでは表示方法が異なる場合がある
    • インライン式はJavaScriptオブジェクトのデフォルトの文字列表現を使う
    • jsブロックはObservableのdisplay()関数を使い、表示ルールはinspect/src/inspect.jsにある

リアクティブな実行モデルを維持

  • Observable Notebooksの中核機能であるリアクティブ性は、FrameworkのJavaScript Markdown文書でも維持されている
  • あるセルが変わると、そのセルに依存する他のセルが自動的に再評価される
  • この方式はJupyter notebooksとの大きな違いであり、Python notebookツールのmarimoの代表的な機能でもある
  • フォーム入力と組み合わせると効果が大きい
    • ページに入力を追加し、その値を文書の別の部分で参照すれば、リアルタイムなインタラクションを簡単に作れる

PyPIダウンロードダッシュボードの例

  • 例のダッシュボードはPythonパッケージごとのPyPIダウンロード統計を表示し、Observable Framework版は57行のMarkdown文書で構成されている
  • ユーザーはInputs.select()packages配列からパッケージを選ぶ
    • Inputs.select()はFrameworkに含まれるメソッドで、Observable Inputsの文書で確認できる
    • view()関数はFrameworkで新たに追加された機能で、入力選択の変更が文書内の他のコードブロックに反映されるようにする
  • packageNameconstとして定義され、ページ内の他のjsブロックで利用できる
  • データはd3.json()で取得する
    • FrameworkではD3全体を利用できる
    • URLには選択されたパッケージ名が含まれる
    • データソースはDatasetteのJSON API
  • SQLiteテーブルはdatasette.io/content/statsにあり、最新のPyPIパッケージ統計で1日1回更新される
    • 関連するGitHub Actionsワークフローは以前のbaked dataの記事で扱われていた
  • URLに.jsonを付けるとJSONが返る
    • 特定パッケージの行だけを要求する
    • 日付の降順で並べる
    • 最大1,000行をオブジェクト配列として受け取る
  • SQLiteの文字列日付はd3.timeParse("%Y-%m-%d")でJavaScriptのDateオブジェクトに変換される
  • チャートはFrameworkに同梱されたObservable Plotでレンダリングされる
  • パッケージ一覧はDatasetteの/contentデータベースに対して直接SQLクエリを実行して取得する
    • クエリはselect package from stats group by package order by max(downloads) desc
    • _shape=arrayfirstは結果行の最初のカラムをJSON配列として受け取るための短縮記法

使うコードだけを含める

  • 例のダッシュボードはInputsd3Plotのような追加ライブラリを使う
  • 開発モードでは遅延読み込みが適用される
    • セルで最初に使おうとしたときだけコードが読み込まれる
  • アプリケーションをビルドしてデプロイすると、Frameworkが参照されたライブラリコードだけをjsdelivr CDNから自動読み込みする

ビルド時点のデータキャッシュ

  • FrameworkのData loaderは、ダッシュボード用データをビルド時点で準備する機能
  • Frameworkのダッシュボードは実行時にfetch()やそのラッパーを使って、どこからでもデータを取得できる
    • Observable Notebooksも同じ方式で動作する
    • この方式ではダッシュボードの性能が接続先バックエンドに左右される
  • Frameworkは、デプロイ時点でダッシュボード用データを作成し、必要なデータの部分集合だけを静的ファイルとしてまとめるパターンを推奨している
    • 静的データファイルは、ダッシュボードコードと同じ静的ホスティングから高速に配信できる
  • Data loaderは任意のプログラミング言語で書いたスクリプト
    • ビルド時にFrameworkがそのスクリプトを実行する
    • スクリプトの標準出力結果をファイルとして保存する
  • 例ではquakes.json.shファイルにcurl https://earthquake.usgs.gov/earthquakes/feed/…を入れる方式
    • ビルド時、このファイル名は出力先ファイルがquakes.jsonで、実行するローダーが.shであることをFrameworkに知らせる
  • 標準出力としてJSON、CSV、または有用な形式を出力できるなら、どんな技術でもデータを取得できる

Observable Notebooksとの違い

  • Observable FrameworkはObservable Notebooksの多くのアイデアやコードを再利用しているが、ファイル形式と実行環境には大きな違いがある
  • 既存のObservable Notebooksは、Jupyter Notebooksと比べると次の特徴を持つ
    • PythonではなくJavaScriptを使う
    • ノートブックエディタ自体はオープンソースではなく、observablehq.comで提供されるホスティング製品
    • ノートブックは静的ファイルとしてエクスポートしてどこでも実行できるが、エディタは独自製品
    • セルはリアクティブで、あるセルが変わるとそれに依存する他のセルがExcelのように自動再評価される
    • リアクティブ性モデルを支えるためにviewofというカスタムキーワードを作ったため、JavaScript文法は完全に標準ではない
    • 編集可能なノートブックは複雑な独自ファイル形式で、Gitのようなツールと相性がよくないため、Observableは独自のバージョン管理とコラボレーションシステムを実装していた
  • Observable Frameworkはこのモデルを、よりシンプルなファイル形式とオープンソースの実行環境へ移したもの
    • 文書はJavaScriptブロックを含む単一のMarkdownファイル
    • 依然としてリアクティブだが、どんなテキストエディタでも編集でき、Gitに入れられる
    • 全体がISCライセンスのオープンソースで、編集スタック全体をローカルマシンで実行できる
    • カスタム構文なしで標準JavaScriptだけを使う

Observableの方向転換

  • Observable Frameworkは、Observableが従来の独自Observable Notebookエディタ中心のコラボレーションツールから、より開発者向けツールへ傾いている変化を示しているように見える
  • ObservableのTwitter紹介文は “The end-to-end solution for developers who want to build and host dashboards that don’t suck”
    • 2023年10月3日のInternet Archiveのスナップショットでは “Build data visualizations, dashboards, and data apps that impact your business — faster.” となっていた
  • Observable Notebooksは、プラットフォームの独自性や無料アカウントの制限、特に無料の非公開ノートブックがないことによって、利用が一部制約されることがある
  • Observable Plotのようなオープンソースライブラリは、すでに積極的に利用できる技術として評価されている
  • Observable Frameworkは、Observable Notebooksを魅力的にしていたアイデアを、オープンソース、標準JavaScript、単一テキストファイル、静的デプロイモデルとして再実装している

1件のコメント

 
GN⁺ 2024-03-04
Hacker Newsのコメント
  • ある意味で Observable Framework は、Mike Bostock シネマティック・ユニバースにおける Avengers: Endgame のようなもの
    d3、Observable、Observable Plot、HTL をひとまとめにし、そこへ新しいアイデアもかなり載せている

    • 個人的には Polymaps が今でも彼の作品の中でいちばん好き
    • 「人間が補強した」AI 開発者エージェント向けのものを作っているようにも感じる
      Observable にはすでに AI 統合があり、これは AI がより簡単に組み合わせて活用できるようにするラッパーのように見える。AI なしで戦略を評価していた部分は少しちぐはぐに感じた
    • 以前 Observable と Observable Framework をブックマークしていたが、詳しくは見ていなかった
      今日、静的な Jupyter Notebook をホスティングしたり、WASM でインタラクティブに動かしたりする方法を見始めたが、ほとんどの用途では Observable Framework のほうが合っていそう
  • Observable の問題は、d3 のサンプルギャラリーのように見えるのに、そのコードがそのフレームワーク内で動くよう設計されていて、そのままコピー&ペーストできないこと
    そもそも d3 はサンプルなしで使いやすいものでもなく、とくにバージョン間の変更に互換性がないことも多い。それでもサイトには驚くようなグラフィックがたくさんある
    [0] https://observablehq.com/@d3/gallery

    • 100% 同意。実際の JavaScript と少し違うという点を最後まで乗り越えられなかった
      基本言語に十分近いので、グラフィック表示用の API を少し足す程度で、そのまま JavaScript を使えたのではと思う
    • コミュニティでは Observable 風 JavaScript を通常の JavaScript に変換する資料が公開されていたことがある
      ほとんどはトップレベルのセル定義を書き換える作業
      [0]: https://observablehq.com/@bumbeishvili/convert-observable-co...
    • そこが本当にいら立たしい。どの会社も誇りたがるような プラットフォーム依存に感じる
      ObservableHQ ノートブックでは特にその不満が大きかった。優れたサンプルであると同時に、役に立たない資料にもなってしまう。ただ、今回の Framework のほうはもう少し開かれているようで、少なくともセルフホスティングはできるので様子を見ている
    • これは Observable の問題というより、d3 が他所にコピー&ペーストできるサンプルを用意してこなかった問題に近い気がする
      しかもこの記事は、新しい Observable Framework が昔の Observable ノートブックの問題の一部をなくしたという話なので、このコメントは記事とは少しずれている。今では「全部標準 JavaScript で、カスタム構文はない」という話なのだから
  • Framework は GitHub Pages にデプロイするのもとても簡単
    手順とサンプルの GitHub Action をまとめてある: https://notes.billmill.org/programming/observable_framework/...

  • 筆者は Framework について的確に言い当てている
    Observable Framework を使って小さなインタラクティブ・プロットを作ってみたが(https://github.com/willmeyers/observable-ssta)、セットアップしてデータを描画するまでが信じられないほど簡単だった。唯一の不満は、Python データローダーが virtualenv を使うよう設定できたらよいのにという点

    • poetry で Python データローダーを poetry 管理の virtualenv 内で実行する構成を使っている
      Python プロジェクトを作成したあと、開発サーバーを起動するときに yarn run dev の代わりに poetry run yarn run dev を実行すれば、Python は virtualenv 内で動く。この構成は、データローダーで再利用可能かつ単体テスト可能なコードをカスタム Python パッケージとして定義し、*.json.py ファイルから import して非常にシンプルに保つのにも使える
    • Python の nodeenv で解決できない? 普段、プロジェクトに JS を追加するときはそうしている
      node や npm/yarn のようなツール、そして JavaScript まで venv の中に一緒に保持される
    • .sh データローダーに shebang を入れて、仮想環境ディレクトリ内の bin/python のフルパスを指すようにできない?
  • 最近、Observable ノートブックで初めて「実運用」プロジェクトを完了した
    Observable Plot、Arquero を学び、JavaScript を少し学び直し、データ生成過程である Rust ベースのシミュレーターと統合する作業も含まれていた。正直、本当に素晴らしかった。ツールを学ぶのにはかなりエネルギーが要り、データジェネレーターをパラメータ化する機能にはまだ不満もあるが、最終的なノートブックは美しく、よく動く
    Markdown とリアクティブ性があることで、こうしたノートブックは本当に実用になると感じる。Jupyter のカスタムフォーマットはバージョン管理を非常に難しくし、リアクティブ性がないと反復的に設計したノートブックは、書くにはいいが読むにはつらい状態依存のごちゃごちゃになりがちだ。Quarto とその Observable 統合でも試したが、場当たり的な寄せ集めのように感じた
    心から、ノートブックを書いて他人と共有することが楽しく、楽しみだと感じられた初めての体験だった。今後も荒削りな部分はあるだろうが、このプロジェクト以降はノートブック用ツールの第一候補になっている

    • Quarto の代替を探しているなら、単一ソースから リアクティブ/静的ドキュメントを書ける最近公開された Living Papers を見てみてもいい
      [0]: https://living-papers.vercel.app/
  • ブラウザで Framework を素早く試して触ってみたいなら、Node と Python 環境を自動構成する Codespace devcontainer が用意されている。
    [0]: https://github.com/dleeftink/observable-codespace

  • Jupyter Notebook から Observable に移るべきだろうか? それとも、両者をそうやって分けること自体が誤った構図なのだろうか?

    • 結局のところ、Python とそのエコシステムのほうが生産的なのか、それとも JavaScript とそのパッケージ群、特に D3 のようなもののほうが生産的なのかが、質問の核心だと思う
  • 記事の内容を言い換えると、js コンテンツヒントが付いたコードブロック内のものはすべて、ユーザーのブラウザで即座に実行される。
    コードを表示したいなら js echo ヒントを使わなければならない。後方互換性を考えると、逆のほうがよかったのではないだろうか? たとえば、ユーザーのブラウザで実行するコードは js exec のようなオプトインヒントにして、広く使われている js ヒントはそのまま残す形だ。現在の構造だと、そのレンダラーを既存アプリに統合する際、どこで実行を許可するかを別途管理しなければならない

    • ブロックのデフォルトオプションを変更できるようにする予定。
      ページごとに front matter で設定したり、プロジェクト設定でプロジェクト全体に適用したりできるようになる。そうすれば js run=false をデフォルトにして、必要な場合だけ js run でライブコードを有効にできる。ただし、私たちの主なユースケースはライブコードなので、これをデフォルトに選んだ
    • その通り。GitHub が Mermaid ダイアグラムを自動レンダリングするのと同じ問題がある。
      いまや言語注釈を外さない限り、Mermaid のコードブロックをそのまま表示できなくなっている
  • Observable Framework にハマって一晩を過ごしたが、とても良かった。
    ほとんど邪魔にならず、Google Maps の履歴を詳しく可視化して探索できた。データローダー環境に関する部分はそれほど明確ではなかったが、Python は poetry 環境で実行されるので解決した。
    Kotlin が好きなので Kotlin スクリプト用のデータローダーも作ってみようとしたが、荒削りな部分があった。Kotlin はスクリプトファイル名が foo.main.kts であることを期待する一方、Observable は実行可能な shebang ローダーに foo.exe 拡張子を期待する。そのため Kotlin スクリプトを呼び出すプロキシ exe スクリプトを作ったが、そうするとデータの自動再読み込みがトリガーされない。
    marimo や Jupyter と比べて少し不便なのは、データローダーとノートブックの間で変数を使う部分だ。たとえば、日付選択ビューコンポーネントでローダーが取得するデータ範囲を変えたいのだが、どうすればよいのかが明確ではない。そのため探索的分析が少し遅くなる。これがパラダイムに反しているのは分かっているが、指摘しておきたかった。結果として、探索しながらデータ加工のかなりの部分をノートブック側へ移すことになり得るが、性能の観点では理想的ではない。
    最後に、データローダーを インラインで定義 できるとよいと思う。単一ファイルが好きなので、Python コードブロックを追加すると Framework がそれをファイルとして抽出してくれる、という形なら小さな QoL 改善になるはずだ。まだ初期段階だが、Framework は有望に見える。すべての Markdown ノートをここに載せて、完全な Emacs まで行かなくても org-mode のような環境を作れたらいいと思う

    • フィードバックありがとう。.sh.exe で回避せずに、新しいインタープリターをもっと簡単に登録できるようにする PR が出ている。
      特定のファイル拡張子に関連付けられたインタープリターを指定できるようになる予定。たとえば Kotlin 用の .kts が可能になる。 https://github.com/observablehq/framework/pull/935
      入力値でデータローダーを動かす方式は、Framework が静的データスナップショットを好むという点で少し方向性が異なる。目的は、ビルドされたサイトを自己完結的で高性能にすることだ。それでもうまく機能する手法として、データローダーで対話対象データの上位集合を Parquet ファイルとして生成し、クライアント側で DuckDB/SQL を使って可視化する部分集合を取り出す方法がある。通常は高性能だが、もちろん扱おうとする上位集合のサイズによって変わる
  • Observable は REST API を通じて ClickHouse と非常にうまく統合される。
    例はここにある: https://observablehq.com/@stas-sl/github-issues-survival-ana...
    新しい Observable Framework はまだ使っていないが、データベースをリアルタイムにクエリする似たような例を見ると面白そうだ。すべてのデータを事前に読み込んでキャッシュすることしかできない構造ではないことを願う。こうしたアプリはインタラクティブであるべきなので、理想的には SQL をライブで編集できるよう公開されているべきだ