marimo-notebooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMarimo Notebooks
Marimo笔记本
Marimo notebooks are reactive Python notebooks stored as pure files. Cells auto-execute when dependencies change, modeled as a directed acyclic graph (DAG).
.pyMarimo笔记本是存储为纯文件的反应式Python笔记本。单元格会在依赖项变化时自动执行,其执行逻辑基于有向无环图(DAG)构建。
.pyCore 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 )—mutate in the same cell that creates the object, or create new variables
list.append()
- 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
undefinedbash
undefinedCreate & 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
undefinedmarimo check notebook.py # 检查并验证笔记本
marimo check notebook.py --fix # 自动修复问题
undefinedCode Visibility in Run Mode
运行模式下的代码可见性
CRITICAL FOR TUTORIALS: By default, hides code. Use to display it.
marimo runmo.show_code()教程场景至关重要:默认情况下,会隐藏代码。使用来显示代码。
marimo runmo.show_code()mo.show_code() - Per-Cell Display
mo.show_code() - 按单元格显示代码
IMPORTANT: Call as a statement on its own line, NOT in the return statement.
mo.show_code()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重要提示:请将作为单独一行的语句调用,不要放在return语句中。
mo.show_code()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
undefinedWRONG - 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 () for LaTeX
r"""...""" - 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 computationpython
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 explorationpython
table = mo.ui.table(df) # 带选择功能的交互式表格
dataframe = mo.ui.dataframe(df) # 可编辑的数据框
data_explorer = mo.ui.data_explorer(df) # 无代码数据探索工具Grouping UI Elements
UI元素分组
python
undefinedpython
undefinedForms (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
undefinedpython
undefinedStacking
堆叠布局
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
undefinedmo.tree({"a": {"b": 1}}) # 树形视图
mo.stat(value="42", label="用户数", caption="+5%")
mo.lazy(expensive_component) # 延迟加载,直到组件可见
undefinedOutput 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
undefinedpython
undefinedProgress 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()
undefinedwith mo.status.spinner(title="加载中..."):
load_data()
undefinedControl Flow
控制流
python
undefinedpython
undefinedStop 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()
undefinedrun_button = mo.ui.run_button()
mo.stop(not run_button.value, mo.md("点击运行以执行"))
expensive_computation()
undefinedCaching
缓存
python
undefinedpython
undefinedIn-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)
)
returnUse 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
undefinedpython
undefinedAltair 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, hvPlotfig, ax = plt.subplots()
ax.plot(x, y)
mo.mpl.interactive(fig)
支持的库:Matplotlib、Seaborn、Plotly、Altair、Bokeh、HoloViews、hvPlotWigglystuff 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
最佳实践
- Wrap reusable code in functions - Keeps intermediate variables local
- Use meaningful, unique variable names - e.g., ,
model1_sigmamodel2_sigma - Don't mutate across cells - Mutate in same cell or create new variables
- Write idempotent cells - Same inputs produce same outputs
- Use mo.stop() - Gate expensive operations behind conditions/buttons
- Use lazy loading - for expensive components in tabs/accordions
mo.lazy() - Cache expensive ops - for session,
@mo.cachefor disk@mo.persistent_cache
- 将可复用代码封装到函数中 - 使中间变量保持局部性
- 使用有意义的唯一变量名 - 例如、
model1_sigmamodel2_sigma - 不要跨单元格进行对象突变 - 在同一单元格内突变,或创建新变量
- 编写幂等单元格 - 相同输入产生相同输出
- 使用mo.stop() - 为耗时操作添加条件/按钮触发机制
- 使用延迟加载 - 对标签页/折叠面板中的耗时组件使用
mo.lazy() - 缓存耗时操作 - 会话级缓存使用,磁盘级持久化缓存使用
@mo.cache@mo.persistent_cache
CRITICAL: Pre-Edit Checklist
重要:编辑前检查清单
BEFORE making ANY edit to a marimo notebook:
- Read the current file state — The file may have been modified by marimo's editor
- Run — Verify valid before and after edits
marimo check notebook.py
AFTER completing edits:
- Grep for — Replace ALL print statements with marimo output (
print(,mo.md(),mo.stat())mo.callout() - Run — Verify no errors introduced
marimo check notebook.py
在对marimo笔记本进行任何编辑之前:
- 读取当前文件状态 — 文件可能已被marimo编辑器修改
- 运行— 编辑前后均需验证文件有效性
marimo check notebook.py
完成编辑后:
- 搜索— 将所有print语句替换为marimo输出方式(
print(、mo.md()、mo.stat())mo.callout() - 运行— 确认未引入错误
marimo check notebook.py
Common Gotchas
常见陷阱
Output & Display
输出与展示
-
NEVER use print() in cells: Print statements do NOT display in run mode. Always use:
- — formatted text
mo.md(f"**Label:** {value}") - — metric cards
mo.stat(value=f"{x}", label="Label") - — callout boxes
mo.callout(content, kind="info") - 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 not
lambda v, i=i: ...lambda v: ... i - on_change handlers: Only work if element is bound to global variable
- Dynamic UI elements: Must wrap in ,
mo.ui.array(), ormo.ui.dictionary()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 before outputting
plt.tight_layout() - 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