marimo-notebooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Marimo Notebooks

Marimo笔记本

Marimo notebooks are reactive Python notebooks stored as pure
.py
files. Cells auto-execute when dependencies change, modeled as a directed acyclic graph (DAG).
Marimo笔记本是存储为纯
.py
文件的反应式Python笔记本。单元格会在依赖项变化时自动执行,其执行逻辑基于有向无环图(DAG)构建。

Core Concepts

核心概念

Reactivity Model

反应性模型

  • marimo uses static analysis to build a dependency graph from variable references and definitions
  • When a cell runs, all cells referencing its defined variables automatically re-run
  • Execution order follows the dependency graph, not visual cell order
  • Each global variable must be defined by exactly one cell
  • marimo does not track object mutations (like
    list.append()
    )—mutate in the same cell that creates the object, or create new variables
  • marimo使用静态分析,通过变量引用和定义构建依赖关系图
  • 当某个单元格运行时,所有引用其定义变量的单元格会自动重新运行
  • 执行顺序遵循依赖关系图,而非视觉上的单元格顺序
  • 每个全局变量必须由恰好一个单元格定义
  • marimo不跟踪对象突变(如
    list.append()
    )——请在创建对象的同一单元格内进行突变操作,或创建新变量

Avoiding Variable Name Conflicts

避免变量名冲突

Each global variable must be defined by exactly one cell. Two strategies:
1. Wrap code in functions (preferred for reusable patterns):
python
@app.cell
def _(data):
    def compute_mean_with_new_col(df):
        temp = df.copy()
        temp["new_col"] = temp["x"] * 2
        return temp.mean()

    return (compute_mean_with_new_col(data),)
2. Use meaningful, unique variable names:
python
@app.cell
def _(model1_data):
    model1_transformed = model1_data.copy()
    model1_transformed["new_col"] = model1_transformed["x"] * 2
    return (model1_transformed,)
Never use underscore prefixes to generate unique variable names. No exceptions.
每个全局变量必须由恰好一个单元格定义。以下两种解决策略:
1. 将代码封装到函数中(推荐用于可复用模式):
python
@app.cell
def _(data):
    def compute_mean_with_new_col(df):
        temp = df.copy()
        temp["new_col"] = temp["x"] * 2
        return temp.mean()

    return (compute_mean_with_new_col(data),)
2. 使用有意义的唯一变量名:
python
@app.cell
def _(model1_data):
    model1_transformed = model1_data.copy()
    model1_transformed["new_col"] = model1_transformed["x"] * 2
    return (model1_transformed,)
切勿使用下划线前缀生成唯一变量名,无例外情况。

Notebook Structure

笔记本结构

python
import marimo

__generated_with = "0.10.0"
app = marimo.App(width="medium")

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

@app.cell
def _(mo):
    mo.md("# Hello")
    return

if __name__ == "__main__":
    app.run()
Key rules:
  • Each cell is a function decorated with
    @app.cell
  • Variables shared by returning tuples:
    return (var1, var2,)
  • Cells receive variables as parameters:
    def _(mo, df):
  • Execution order follows dependency graph, not position
  • Name cells descriptively for CellTour targeting:
    def model_specification():
python
import marimo

__generated_with = "0.10.0"
app = marimo.App(width="medium")

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

@app.cell
def _(mo):
    mo.md("# Hello")
    return

if __name__ == "__main__":
    app.run()
关键规则:
  • 每个单元格都是被
    @app.cell
    装饰的函数
  • 通过返回元组共享变量:
    return (var1, var2,)
  • 单元格通过参数接收变量:
    def _(mo, df):
  • 执行顺序遵循依赖关系图,而非位置顺序
  • 为单元格赋予描述性名称,以便CellTour定位:
    def model_specification():

CLI Commands

CLI命令

bash
undefined
bash
undefined

Create & Edit

创建与编辑

marimo new # Create new notebook marimo edit notebook.py # Open editor marimo edit notebook.py --watch # Live reload on file changes
marimo new # 创建新笔记本 marimo edit notebook.py # 打开编辑器 marimo edit notebook.py --watch # 文件变更时实时重载

Run as App

作为应用运行

marimo run notebook.py # Run as app (code hidden by default) marimo run notebook.py --include-code # Show code in app view
marimo run notebook.py # 作为应用运行(默认隐藏代码) marimo run notebook.py --include-code # 在应用视图中显示代码

Convert

转换

marimo convert notebook.ipynb -o notebook.py # Jupyter to marimo
marimo convert notebook.ipynb -o notebook.py # 将Jupyter转换为marimo格式

Export

导出

marimo export html notebook.py -o out.html # Static HTML marimo export ipynb notebook.py -o out.ipynb # To Jupyter
marimo export html notebook.py -o out.html # 导出为静态HTML marimo export ipynb notebook.py -o out.ipynb # 导出为Jupyter格式

Validate

验证

marimo check notebook.py # Lint and validate marimo check notebook.py --fix # Auto-fix issues
undefined
marimo check notebook.py # 检查并验证笔记本 marimo check notebook.py --fix # 自动修复问题
undefined

Code Visibility in Run Mode

运行模式下的代码可见性

CRITICAL FOR TUTORIALS: By default,
marimo run
hides code. Use
mo.show_code()
to display it.
教程场景至关重要:默认情况下,
marimo run
会隐藏代码。使用
mo.show_code()
来显示代码。

mo.show_code() - Per-Cell Display

mo.show_code() - 按单元格显示代码

IMPORTANT: Call
mo.show_code()
as a statement on its own line, NOT in the return statement.
python
@app.cell
def model_definition(mo, pm, X, y):
    with pm.Model() as model:
        alpha = pm.Normal("alpha", mu=0, sigma=10)
        beta = pm.Normal("beta", mu=0, sigma=10)
        mu = alpha + beta * X
        pm.Normal("y", mu=mu, sigma=1, observed=y)

    # Show this cell's code alongside its output
    mo.show_code(model, position="above")
    return (model,)
WRONG vs RIGHT patterns:
python
undefined
重要提示:请将
mo.show_code()
作为单独一行的语句调用,不要放在return语句中。
python
@app.cell
def model_definition(mo, pm, X, y):
    with pm.Model() as model:
        alpha = pm.Normal("alpha", mu=0, sigma=10)
        beta = pm.Normal("beta", mu=0, sigma=10)
        mu = alpha + beta * X
        pm.Normal("y", mu=mu, sigma=1, observed=y)

    # 在输出上方显示本单元格的代码
    mo.show_code(model, position="above")
    return (model,)
错误与正确示例:
python
undefined

WRONG - do not put mo.show_code() in return statement

错误 - 不要将mo.show_code()放在return语句中

return mo.show_code(result)
return mo.show_code(result)

RIGHT - call as statement, then return separately

正确 - 单独调用语句,再单独返回结果

mo.show_code(result, position="above") return (result,)

- `position="above"` shows code first, then output (best for tutorials)
- `position="below"` shows output first, then code (default)
mo.show_code(result, position="above") return (result,)

- `position="above"`先显示代码,再显示输出(最适合教程场景)
- `position="below"`先显示输出,再显示代码(默认设置)

Markdown with mo.md()

使用mo.md()编写Markdown

python
@app.cell
def _(mo):
    mo.md(r"""
    # Title

    Interpolate Python: {slider}

    **LaTeX**: $f(x) = e^x$

    $$\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}$$

    **Icons**: ::lucide:rocket:: or ::mdi:home::
    """)
    return
  • Use raw strings (
    r"""..."""
    ) for LaTeX
  • Interpolate UI elements:
    f"Value: {slider}"
  • For complex objects:
    f"Plot: {mo.as_html(fig)}"
python
@app.cell
def _(mo):
    mo.md(r"""
    # 标题

    插入Python变量:{slider}

    **LaTeX公式**:$f(x) = e^x$

    $$\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}$$

    **图标**:::lucide:rocket:: 或 ::mdi:home::
    """)
    return
  • 对于LaTeX公式,请使用原始字符串(
    r"""..."""
  • 插入UI元素:
    f"数值:{slider}"
  • 对于复杂对象:
    f"图表:{mo.as_html(fig)}"

UI Components (mo.ui.*)

UI组件(mo.ui.*)

Basic Inputs

基础输入组件

python
slider = mo.ui.slider(0, 100, value=50, label="Value")
number = mo.ui.number(0, 100, value=50)
text = mo.ui.text(value="", placeholder="Enter text")
checkbox = mo.ui.checkbox(value=False, label="Enable")
dropdown = mo.ui.dropdown(["a", "b", "c"], value="a")
radio = mo.ui.radio(["option1", "option2"], value="option1")
multiselect = mo.ui.multiselect(["a", "b", "c"])
python
slider = mo.ui.slider(0, 100, value=50, label="数值")
number = mo.ui.number(0, 100, value=50)
text = mo.ui.text(value="", placeholder="输入文本")
checkbox = mo.ui.checkbox(value=False, label="启用")
dropdown = mo.ui.dropdown(["a", "b", "c"], value="a")
radio = mo.ui.radio(["option1", "option2"], value="option1")
multiselect = mo.ui.multiselect(["a", "b", "c"])

Buttons

按钮组件

python
button = mo.ui.button(label="Click")
run_button = mo.ui.run_button(label="Run")  # For triggering computation
python
button = mo.ui.button(label="点击")
run_button = mo.ui.run_button(label="运行")  # 用于触发计算

Data Components

数据组件

python
table = mo.ui.table(df)            # Interactive table with selection
dataframe = mo.ui.dataframe(df)    # Editable dataframe
data_explorer = mo.ui.data_explorer(df)  # No-code exploration
python
table = mo.ui.table(df)            # 带选择功能的交互式表格
dataframe = mo.ui.dataframe(df)    # 可编辑的数据框
data_explorer = mo.ui.data_explorer(df)  # 无代码数据探索工具

Grouping UI Elements

UI元素分组

python
undefined
python
undefined

Forms (require submit button)

表单(需要提交按钮)

form = mo.ui.text().form()
form = mo.ui.text().form()

Batch in markdown

在Markdown中批量组合

form = mo.md(""" Name: {name} Age: {age} """).batch( name=mo.ui.text(), age=mo.ui.number(0, 120) ).form()

See [references/ui_components.md](references/ui_components.md) for complete reference.
form = mo.md(""" 姓名:{name} 年龄:{age} """).batch( name=mo.ui.text(), age=mo.ui.number(0, 120) ).form()

完整参考请查看[references/ui_components.md](references/ui_components.md)。

Layout Functions

布局函数

python
undefined
python
undefined

Stacking

堆叠布局

mo.hstack([el1, el2, el3], justify="center", gap=2) mo.vstack([el1, el2, el3], align="start", gap=1)
mo.hstack([el1, el2, el3], justify="center", gap=2) mo.vstack([el1, el2, el3], align="start", gap=1)

Containers

容器组件

mo.accordion({"Section 1": content1, "Section 2": content2}) mo.tabs({"Tab 1": content1, "Tab 2": content2}) mo.callout(content, kind="info") # info, warn, success, danger, neutral mo.sidebar([nav_content])
mo.accordion({"Section 1": content1, "Section 2": content2}) mo.tabs({"Tab 1": content1, "Tab 2": content2}) mo.callout(content, kind="info") # 类型包括info、warn、success、danger、neutral mo.sidebar([nav_content])

Display

展示组件

mo.tree({"a": {"b": 1}}) # Tree view mo.stat(value="42", label="Users", caption="+5%") mo.lazy(expensive_component) # Defer until visible
undefined
mo.tree({"a": {"b": 1}}) # 树形视图 mo.stat(value="42", label="用户数", caption="+5%") mo.lazy(expensive_component) # 延迟加载,直到组件可见
undefined

Output Functions

输出函数

python
mo.output.replace(new_content)  # Replace cell output
mo.output.append(additional)    # Append to output
mo.output.clear()               # Clear output

with mo.redirect_stdout():
    print("This goes to cell output")
python
mo.output.replace(new_content)  # 替换单元格输出
mo.output.append(additional)    # 追加内容到输出
mo.output.clear()               # 清空输出

with mo.redirect_stdout():
    print("此内容将输出到单元格中")

Status Indicators

状态指示器

python
undefined
python
undefined

Progress bar

进度条

for item in mo.status.progress_bar(items, title="Processing"): process(item)
for item in mo.status.progress_bar(items, title="处理中"): process(item)

Spinner

加载动画

with mo.status.spinner(title="Loading..."): load_data()
undefined
with mo.status.spinner(title="加载中..."): load_data()
undefined

Control Flow

控制流

python
undefined
python
undefined

Stop execution conditionally

条件停止执行

mo.stop(condition, mo.md("Message when stopped"))
mo.stop(condition, mo.md("停止时显示的消息"))

Example: require button click

示例:需要点击按钮才能继续

run_button = mo.ui.run_button() mo.stop(not run_button.value, mo.md("Click Run to execute")) expensive_computation()
undefined
run_button = mo.ui.run_button() mo.stop(not run_button.value, mo.md("点击运行以执行")) expensive_computation()
undefined

Caching

缓存

python
undefined
python
undefined

In-memory cache (session only)

内存缓存(仅当前会话有效)

@mo.cache def expensive_function(x, y): return compute(x, y)
@mo.cache def expensive_function(x, y): return compute(x, y)

Persistent cache (survives restarts)

持久化缓存(重启后仍保留)

@mo.persistent_cache(name="embeddings") def compute_embeddings(text): return model.encode(text)

See [references/caching.md](references/caching.md) for model output caching patterns.
@mo.persistent_cache(name="embeddings") def compute_embeddings(text): return model.encode(text)

模型输出缓存模式请查看[references/caching.md](references/caching.md)。

State Management

状态管理

Warning: Use sparingly—over 99% of cases don't need
mo.state()
.
python
@app.cell
def _(mo):
    get_count, set_count = mo.state(0)
    return get_count, set_count

@app.cell
def _(mo, get_count, set_count):
    mo.ui.button(
        label=f"Count: {get_count()}",
        on_click=lambda _: set_count(lambda n: n + 1)
    )
    return
Use only when maintaining history, synchronizing UI bidirectionally, or introducing cycles.
注意:请谨慎使用——超过99%的场景不需要
mo.state()
python
@app.cell
def _(mo):
    get_count, set_count = mo.state(0)
    return get_count, set_count

@app.cell
def _(mo, get_count, set_count):
    mo.ui.button(
        label=f"计数:{get_count()}",
        on_click=lambda _: set_count(lambda n: n + 1)
    )
    return
仅在需要维护历史记录、双向同步UI或引入循环逻辑时使用。

Interactive Plotting

交互式绘图

python
undefined
python
undefined

Altair with selection

带选择功能的Altair图表

chart = alt.Chart(df).mark_point().encode(x="x", y="y") selection = mo.ui.altair_chart(chart, chart_selection="point") selected_data = selection.value # DataFrame of selected points
chart = alt.Chart(df).mark_point().encode(x="x", y="y") selection = mo.ui.altair_chart(chart, chart_selection="point") selected_data = selection.value # 选中数据的DataFrame

Plotly

Plotly图表

fig = px.scatter(df, x="x", y="y") interactive = mo.ui.plotly(fig) interactive.value # Selected points
fig = px.scatter(df, x="x", y="y") interactive = mo.ui.plotly(fig) interactive.value # 选中的点

Matplotlib interactive

交互式Matplotlib图表

fig, ax = plt.subplots() ax.plot(x, y) mo.mpl.interactive(fig)

Supported: Matplotlib, Seaborn, Plotly, Altair, Bokeh, HoloViews, hvPlot
fig, ax = plt.subplots() ax.plot(x, y) mo.mpl.interactive(fig)

支持的库:Matplotlib、Seaborn、Plotly、Altair、Bokeh、HoloViews、hvPlot

Wigglystuff Widgets

Wigglystuff小部件

python
from wigglystuff import Slider2D, Paint, SortableList, Matrix, CellTour
import marimo as mo

slider2d = mo.ui.anywidget(Slider2D())
slider2d.x, slider2d.y

paint = mo.ui.anywidget(Paint(width=400, height=300))
paint.to_pil()

tour = mo.ui.anywidget(CellTour(
    steps=[
        {"cell_name": "intro", "title": "Welcome", "description": "..."},
        {"cell_name": "model", "title": "Model", "description": "..."},
    ],
    auto_start=False
))
See references/wigglystuff.md for all widgets.
python
from wigglystuff import Slider2D, Paint, SortableList, Matrix, CellTour
import marimo as mo

slider2d = mo.ui.anywidget(Slider2D())
slider2d.x, slider2d.y

paint = mo.ui.anywidget(Paint(width=400, height=300))
paint.to_pil()

tour = mo.ui.anywidget(CellTour(
    steps=[
        {"cell_name": "intro", "title": "欢迎", "description": "..."},
        {"cell_name": "model", "title": "模型", "description": "..."},
    ],
    auto_start=False
))
所有小部件请查看references/wigglystuff.md

Best Practices

最佳实践

  1. Wrap reusable code in functions - Keeps intermediate variables local
  2. Use meaningful, unique variable names - e.g.,
    model1_sigma
    ,
    model2_sigma
  3. Don't mutate across cells - Mutate in same cell or create new variables
  4. Write idempotent cells - Same inputs produce same outputs
  5. Use mo.stop() - Gate expensive operations behind conditions/buttons
  6. Use lazy loading -
    mo.lazy()
    for expensive components in tabs/accordions
  7. Cache expensive ops -
    @mo.cache
    for session,
    @mo.persistent_cache
    for disk
  1. 将可复用代码封装到函数中 - 使中间变量保持局部性
  2. 使用有意义的唯一变量名 - 例如
    model1_sigma
    model2_sigma
  3. 不要跨单元格进行对象突变 - 在同一单元格内突变,或创建新变量
  4. 编写幂等单元格 - 相同输入产生相同输出
  5. 使用mo.stop() - 为耗时操作添加条件/按钮触发机制
  6. 使用延迟加载 - 对标签页/折叠面板中的耗时组件使用
    mo.lazy()
  7. 缓存耗时操作 - 会话级缓存使用
    @mo.cache
    ,磁盘级持久化缓存使用
    @mo.persistent_cache

CRITICAL: Pre-Edit Checklist

重要:编辑前检查清单

BEFORE making ANY edit to a marimo notebook:
  1. Read the current file state — The file may have been modified by marimo's editor
  2. Run
    marimo check notebook.py
    — Verify valid before and after edits
AFTER completing edits:
  1. Grep for
    print(
    — Replace ALL print statements with marimo output (
    mo.md()
    ,
    mo.stat()
    ,
    mo.callout()
    )
  2. Run
    marimo check notebook.py
    — Verify no errors introduced
在对marimo笔记本进行任何编辑之前:
  1. 读取当前文件状态 — 文件可能已被marimo编辑器修改
  2. 运行
    marimo check notebook.py
    — 编辑前后均需验证文件有效性
完成编辑后:
  1. 搜索
    print(
    — 将所有print语句替换为marimo输出方式(
    mo.md()
    mo.stat()
    mo.callout()
  2. 运行
    marimo check notebook.py
    — 确认未引入错误

Common Gotchas

常见陷阱

Output & Display

输出与展示

  • NEVER use print() in cells: Print statements do NOT display in run mode. Always use:
    • mo.md(f"**Label:** {value}")
      — formatted text
    • mo.stat(value=f"{x}", label="Label")
      — metric cards
    • mo.callout(content, kind="info")
      — callout boxes
    • Return the dataframe/object directly — automatic display
  • mo.show_code() must be called as a statement, not in return
  • Never delete output without replacing: When removing print statements, replace with equivalent marimo output
  • 切勿在单元格中使用print():print语句在运行模式下不会显示。请始终使用:
    • mo.md(f"**标签:** {value}")
      — 格式化文本
    • mo.stat(value=f"{x}", label="标签")
      — 指标卡片
    • mo.callout(content, kind="info")
      — 提示框
    • 直接返回数据框/对象 — 自动展示
  • mo.show_code()必须作为单独语句调用,不能放在return中
  • 删除输出时务必替换:移除print语句时,需替换为等效的marimo输出方式

Reactivity & Variables

反应性与变量

  • Closures in loops: Use default args
    lambda v, i=i: ...
    not
    lambda v: ... i
  • on_change handlers: Only work if element is bound to global variable
  • Dynamic UI elements: Must wrap in
    mo.ui.array()
    ,
    mo.ui.dictionary()
    , or
    mo.ui.batch()
  • Type annotations: Registered as references unless quoted:
    x: "SomeType"
  • 循环中的闭包:使用默认参数
    lambda v, i=i: ...
    ,而非
    lambda v: ... i
  • on_change处理器:仅当元素绑定到全局变量时有效
  • 动态UI元素:必须封装在
    mo.ui.array()
    mo.ui.dictionary()
    mo.ui.batch()
  • 类型注解:除非用引号包裹,否则会被视为引用:
    x: "SomeType"

Libraries

第三方库

  • matplotlib cut-off: Call
    plt.tight_layout()
    before outputting
  • dotenv: Use
    dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True))
  • matplotlib图表被截断:输出前调用
    plt.tight_layout()
  • dotenv:使用
    dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True))

References

参考资料

  • UI components: references/ui_components.md
  • Wigglystuff widgets: references/wigglystuff.md
  • Caching patterns: references/caching.md
  • Advanced features: references/advanced.md (SQL, deployment, testing, routing)
  • Official docs: https://docs.marimo.io
  • UI组件references/ui_components.md
  • Wigglystuff小部件references/wigglystuff.md
  • 缓存模式references/caching.md
  • 高级功能references/advanced.md(SQL、部署、测试、路由)
  • 官方文档https://docs.marimo.io