AI時代のノートブック? Jupyter Labの代わりにmarimoを使ってみる

X(Twitter)のおすすめで流れてきたmarimoというJupyter Lab(Jupyter Notebook)風のツールを使ってみました。

Jupyter Lab (Jupyter Notebook)では拡張子が.ipynbというファイル形式に保存するので、内部構造が分かりにくく、Gitで管理しづらい(管理できないわけではない)のは同意ですが、marimoでは.pyファイルとして保存するので、自分の使い方(写真の画像処理)にも使えるかどうか気になるところです。

uvを使ってmarimoをインストールする

marimoのホームページにはpipを使ってインストールする手順が記載されていますが、お試しとして使うのであれば作業用ディレクトリを作ってその中にインストールするのが安心です。ターミナルから以下のようにコマンドを入力します。uvを使うので、あらかじめインストールしておきます。

# 作業用ディレクトリの作成
mkdir -p work/marimo-trial
cd work/marimo-trial

# 作業用ディレクトリの中にmarimoのインストール
uv venv
uv pip install marimo

まずはmarimoのホームページに書かれているmarimoのチュートリアルのイントロを動かしてみます。

uv run marimo tutorial intro

ターミナルには以下のメッセージが表示されます。たくさんメッセージを出力するJupyter Labより読みやすいです。

同時にブラウザも開くのですが、私はデフォルトブラウザ(MacのSafari)とノートブック用のブラウザ(Google Chrome)を使い分けているので、いったんブラウザを閉じて、ターミナルのURLをコピーしてChromeを開き直します。


        Edit intro.py in your browser 📝

        ➜  URL: http://localhost:2718?access_token=xxxxxxxxxxxxxxxxxxxx

直感的にJupyter Labのノートブックと同じように操作できます。ファイル保存するまでは、一時ファイルを作っているようです。Save fileボタンを押してファイル名を付けると、作業ディレクトリ内に.pyファイルが作成されます。

marimoが保存した.pyファイルの中を読むと、import marimoapp = marimo.App()といった処理の後に、以下のような関数定義が見られます。

@app.cell
def _():
    import marimo as mo

    mo.md("# Welcome to marimo! 🌊🍃")
    return (mo,)

def文の次の行からreturn文の前の行までが1番目のセルの内容になっています。以降は同様の書式で2番目以降のセルが続きます。

def文には引数なしの関数と引数ありの関数があり、return文はタプルを返している関数と何も返さない(Noneを返す)関数がいますが、どうやらセルにimport文や代入文などで新しい名前(変数名やモジュール名など)を作り、かつ、他のセルでその名前を参照すると、関数の引数やreturn文に追加しているようです。

サンプルのintro.pyの4番目のセルはMarkdown形式ですが、ソースコードを読むとf文字列で変数sliderの値を置き換えられるようになっています。Jupyter Labではipywidgetsを入れないと使えないスライダーのようなコントロール(GUI部品)もmarimoでは標準で備わっています。

marimoを使って画像処理のノートブックをAIに作ってもらう

私がノートブックを使う目的・理由は、pillowなどのパッケージを使って結果を確認しながら画像処理を行うことです。marimoでも同じことができるのかやってみました。新しいノートブックを作成します。

uv run marimo new

このコマンドのパラメータはプロンプトです。プロンプトを省略すると、空のノートブックが作成されます。

空のノートブックでもよいのですが、せっかくなので簡単な画像処理(リサイズ処理)をプロンプトに書いてみます。ヒアドキュメントを使って複数行で入力していますが、AIエージェントを使わずに手入力するのであれば、テキストファイルに保存してファイル名を渡すほうが無難でしょう。

uv run marimo new <<END
- pillowのImage.openを使って、Picturesフォルダ直下にある画像ファイルを開きます。
- 次のセルでは、画像の幅と高さを取得して、縦横比を変えないように、長辺を400ピクセルにリサイズしてください。
END

プロンプトを初めて使う際、以下のようなメッセージが表示されるので、yを入力します。2回目以降は表示されません。

Before using marimo's Text-To-Notebook AI feature, you should know:

1. Your prompt will be sent to marimo's API at `https://ai.marimo.app/`
2. The API uses OpenAI/Anthropic's models to convert your prompt into a notebook
3. Your prompt is securely stored for caching purposes (fast response times)
4. No personal data beyond the prompt itself is collected
5. You can revoke consent at any time by modifying ~/.marimo/state.toml

Do you accept these terms? (y/n)

出来上がったノートブックの内容はこちらです。概ね私の期待した通りの処理が作られていて良いと思うのですが、、、

1つ目のセルに、WebAssembly環境ではローカルファイルアクセス不可というコメントに困惑してしまいました。

import marimo as mo
from PIL import Image
import io

# ファイルアップロードUIを作成(WebAssembly環境ではローカルファイルアクセス不可のため)
image_file = mo.ui.file(label="画像ファイルを選択", full_width=True)
image_file

Jupyter LabのようにKernelがホストのPythonで動いているのであれば、ローカルファイルの一覧ぐらい取得できるはずです。

いったんノートブックを閉じて、uv run marimo newで空のノートブックを作り、pathlib.Pathを使ってカレントディレクトリのファイル一覧(含ディレクトリ)を取得してみました。

問題なく、カレントディレクトリ内の一覧を取得できたので、KernelはホストのPythonで動いているようです。

もう一度、最初のプロンプトを使ってノートブックを作り直し、1番目と2番目のセルを修正してPicturesフォルダにある画像ファイルを開くようにしてみました。

# 1番目のセル
import marimo as mo
from PIL import Image
from pathlib import Path

# 2番目のセル
path = Path('~/Pictures/500TypeEva2560x1440.jpg').expanduser()
img = Image.open(path)
img

1番目のセルを最初に実行したときはpillowをインストールし忘れていたのでエラーになりましたが、marimoの画面でpillowをインストールするか確認メッセージが表示されるので、marimoを再起動することなくパッケージを追加インストールできました。

2番目のセルを実行すると、Your output is too largeというエラーになってしまいました。pyproject.tomloutput_max_bytesの設定値を追加するか、MARIMO_OUTPUT_MAX_BYTES環境変数で設定値を渡す必要があるとのこと。

resize_image.pyというファイルにいったん保存して、以下のコマンドを実行します。

MARIMO_OUTPUT_MAX_BYTES=20_000_000 uv run marimo edit resize_image.py

ようやく、やりたいことができました。

今回はノートブック作成時にAIを利用しましたが、ドキュメントのGenerate with AIを読むと、セルの作成や編集でもAIを使うことができるようになっています。

ちなみに、2番目のセルでpath変数の画像ファイル名を変えて実行すると、3番目のセルも即座に変更後の画像処理の結果が表示されます。Jupyter Labでは2番目のセルを変更しても、3番目のセルを実行するまで画像処理の結果は変わりません。marimoの大きな特徴の一つであるreactive notebookの恩恵を受けることができています。

1枚の画像処理であればmarimoのreactiveな振る舞いで問題はありませんが、これが複数の画像や動画処理の場合はどうなるのか、気になるところです。

  • generating new cells from a prompt
  • refactoring existing cells from a prompt
  • generating entire notebooks

marimoのノートブックの処理結果はどこに保存される

resize_image.pyというファイルにはPythonのスクリプトだけが保存されています。上のスクリーンショットのようにセルの実行結果の画像はresize_image.pyに含まれません。

しかし、uv run marimo edit resize_image.pyを実行すると、セルの実行結果は復元されて画像処理の結果も見ることができます。開き直した直後は画像の色が薄くなっていますが、セルを再実行すると元の色に戻ります。以前の実行結果であることが判別できるようですね。

カレントディレクトリの中を確認すると、__marimo__ディレクトリが作られており、この中にresize_image.py.jsonというファイルが見つかります。セルの実行結果はこの中に含まれていました。

ノートブックの.pyファイルとは別に処理結果が保存されるようになったので、.gitignore__marimo__を追加しておくと、処理結果を含まないノートブックをGitで管理できるようになるので、これは便利です。.ipynbファイルは画像の処理結果も含んでいたので、ファイルサイズが大きくなりがちでした。

jsonファイルを開くと、2番目のセルの実行結果はimgオブジェクトの内容である画像データがbase64形式で格納されていました。3番目のセルの実行結果はmo.image関数の戻り値であるHTMLが格納されていました。

ここで厄介なことに気付きました。mo.image関数の戻り値は<img src='./@file/xxxxxx-xxxxxxx-xxxxxxxx.png' />という形式のHTMLで保存されることです。このpngファイルがディスク内を探しても見つかりません。Google Chromeのデベロッパーツールで確認すると、サーバにはGET /@file/xxxxxx-xxxxxxx-xxxxxxxx.pngというリクエストで画像を取得していますが、画像データは(disk cache)から取得しているので、ブラウザのキャッシュをクリアしたり、あるいはSafariなどの別ブラウザで開くと404 Not Foundになってしまいます。

この./@file/で始まる画像データは、marimoのKernelが動いている間は別ブラウザでも表示できるので、おそらくですがKernelの中で画像データを保持しているのではないかと推測します。

画像処理の結果をローカルのファイルに保存するときは、mo.image関数を使わずにpillowのイメージオブジェクトをそのまま返すほうが良さそうです。

とりあえず、今後も使ってみる

とりあえず私のやりたい画像処理はできる目処が立ったので、今後も使ってみようと思います。ドキュメントを見ていると、WebAssembly Notebooksのような機能が見受けられるので、marimoに興味を惹かれています。

タイトルとURLをコピーしました