streamlit-to-marimo

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Converting Streamlit Apps to Marimo

将Streamlit应用转换为Marimo

For general marimo notebook conventions (cell structure, PEP 723 metadata, output rendering,
marimo check
, variable naming, etc.), refer to the
marimo-notebook
skill. This skill focuses specifically on mapping Streamlit concepts to marimo equivalents.
有关marimo笔记本的通用规范(单元格结构、PEP 723元数据、输出渲染、
marimo check
、变量命名等),请参考
marimo-notebook
技能。本技能专门聚焦于将Streamlit概念映射为marimo等效实现

Steps

步骤

  1. Read the Streamlit app to understand its widgets, layout, and state management.
  2. Create a new marimo notebook following the
    marimo-notebook
    skill conventions. Add all dependencies the Streamlit app uses (pandas, plotly, altair, etc.) — but replace
    streamlit
    with
    marimo
    . You should not overwrite the original file.
  3. Map Streamlit components to marimo equivalents using the reference tables below. Key principles:
    • UI elements are assigned to variables and their current value is accessed via
      .value
      .
    • Cells that reference a UI element automatically re-run when the user interacts with it — no callbacks needed.
  4. Handle conceptual differences in execution model, state, and caching (see below).
  5. Run
    uvx marimo check
    on the result and fix any issues.
  1. 阅读Streamlit应用代码,了解其组件、布局和状态管理逻辑。
  2. 按照
    marimo-notebook
    技能规范创建新的marimo笔记本
    。添加Streamlit应用使用的所有依赖(pandas、plotly、altair等)——但要将
    streamlit
    替换为
    marimo
    。请勿覆盖原文件。
  3. 参考下方对照表将Streamlit组件映射为marimo等效组件,核心原则:
    • UI元素赋值给变量,通过
      .value
      访问其当前值。
    • 引用了UI元素的单元格会在用户交互时自动重新运行——无需回调函数。
  4. 处理执行模型、状态、缓存方面的概念差异(见下文说明)。
  5. 对转换后的文件执行
    uvx marimo check
    ,修复所有问题。

Widget Mapping Reference

组件映射对照表

Input Widgets

输入组件

StreamlitmarimoNotes
st.slider()
mo.ui.slider()
st.select_slider()
mo.ui.slider(steps=[...])
Pass discrete values via
steps
st.text_input()
mo.ui.text()
st.text_area()
mo.ui.text_area()
st.number_input()
mo.ui.number()
st.checkbox()
mo.ui.checkbox()
st.toggle()
mo.ui.switch()
st.radio()
mo.ui.radio()
st.selectbox()
mo.ui.dropdown()
st.multiselect()
mo.ui.multiselect()
st.date_input()
mo.ui.date()
st.time_input()
mo.ui.text()
No dedicated time widget
st.file_uploader()
mo.ui.file()
Use
.contents()
to read bytes
st.color_picker()
mo.ui.text(value="#000000")
No dedicated color picker
st.button()
mo.ui.button()
or
mo.ui.run_button()
Use
run_button
for triggering expensive computations
st.download_button()
mo.download()
Returns a download link element
st.form()
+
st.form_submit_button()
mo.ui.form(element)
Wraps any element so its value only updates on submit
Streamlitmarimo说明
st.slider()
mo.ui.slider()
st.select_slider()
mo.ui.slider(steps=[...])
通过
steps
参数传入离散值
st.text_input()
mo.ui.text()
st.text_area()
mo.ui.text_area()
st.number_input()
mo.ui.number()
st.checkbox()
mo.ui.checkbox()
st.toggle()
mo.ui.switch()
st.radio()
mo.ui.radio()
st.selectbox()
mo.ui.dropdown()
st.multiselect()
mo.ui.multiselect()
st.date_input()
mo.ui.date()
st.time_input()
mo.ui.text()
无专门的时间组件
st.file_uploader()
mo.ui.file()
使用
.contents()
读取字节流
st.color_picker()
mo.ui.text(value="#000000")
无专门的颜色选择器
st.button()
mo.ui.button()
mo.ui.run_button()
触发高开销计算时使用
run_button
st.download_button()
mo.download()
返回下载链接元素
st.form()
+
st.form_submit_button()
mo.ui.form(element)
包裹任意元素,仅在提交时更新其值

Display Elements

展示元素

StreamlitmarimoNotes
st.write()
mo.md()
or last expression
st.markdown()
mo.md()
Supports f-strings:
mo.md(f"Value: {x.value}")
st.latex()
mo.md(r"$...$")
marimo uses KaTeX; see
references/latex.md
st.code()
mo.md("```python\n...\n```")
st.dataframe()
df
(last expression)
DataFrames render as interactive marimo widgets natively; use
mo.ui.dataframe(df)
only for no-code transformations
st.table()
df
(last expression)
Use
mo.ui.table(df)
if you need row selection
st.metric()
mo.stat()
st.json()
mo.json()
or
mo.tree()
mo.tree()
for interactive collapsible view
st.image()
mo.image()
st.audio()
mo.audio()
st.video()
mo.video()
Streamlitmarimo说明
st.write()
mo.md()
或最后一个表达式
st.markdown()
mo.md()
支持f-string:
mo.md(f"Value: {x.value}")
st.latex()
mo.md(r"$...$")
marimo使用KaTeX;参考
references/latex.md
st.code()
mo.md("```python\n...\n```")
st.dataframe()
df
(最后一个表达式)
DataFrame默认渲染为交互式marimo组件;仅当需要无代码转换时使用
mo.ui.dataframe(df)
st.table()
df
(最后一个表达式)
如果需要行选择功能可使用
mo.ui.table(df)
st.metric()
mo.stat()
st.json()
mo.json()
mo.tree()
mo.tree()
可提供交互式折叠视图
st.image()
mo.image()
st.audio()
mo.audio()
st.video()
mo.video()

Charts

图表

StreamlitmarimoNotes
st.plotly_chart(fig)
fig
(last expression)
Use
mo.ui.plotly(fig)
for selections
st.altair_chart(chart)
chart
(last expression)
Use
mo.ui.altair_chart(chart)
for selections
st.pyplot(fig)
fig
(last expression)
Use
mo.ui.matplotlib(fig)
for interactive matplotlib
Streamlitmarimo说明
st.plotly_chart(fig)
fig
(最后一个表达式)
需要选择功能时使用
mo.ui.plotly(fig)
st.altair_chart(chart)
chart
(最后一个表达式)
需要选择功能时使用
mo.ui.altair_chart(chart)
st.pyplot(fig)
fig
(最后一个表达式)
需要交互式matplotlib时使用
mo.ui.matplotlib(fig)

Layout

布局

StreamlitmarimoNotes
st.sidebar
mo.sidebar([...])
Pass a list of elements
st.columns()
mo.hstack([...])
Use
widths=[...]
for column ratios
st.tabs()
mo.ui.tabs({...})
Dict of
{"Tab Name": content}
st.expander()
mo.accordion({...})
Dict of
{"Title": content}
st.container()
mo.vstack([...])
st.empty()
mo.output.replace()
st.progress()
mo.status.progress_bar()
st.spinner()
mo.status.spinner()
Context manager
Streamlitmarimo说明
st.sidebar
mo.sidebar([...])
传入元素列表
st.columns()
mo.hstack([...])
使用
widths=[...]
设置列宽比例
st.tabs()
mo.ui.tabs({...})
传入字典
{"标签名称": 内容}
st.expander()
mo.accordion({...})
传入字典
{"标题": 内容}
st.container()
mo.vstack([...])
st.empty()
mo.output.replace()
st.progress()
mo.status.progress_bar()
st.spinner()
mo.status.spinner()
上下文管理器

Key Conceptual Differences

核心概念差异

Execution Model

执行模型

Streamlit reruns the entire script top-to-bottom on every interaction. Marimo uses a reactive cell DAG — only cells that depend on changed variables re-execute.
  • No need for
    st.rerun()
    — reactivity is automatic.
  • No need for
    st.stop()
    — structure cells so downstream cells naturally depend on upstream values.
Streamlit在每次交互时会从上到下重新运行整个脚本。Marimo使用响应式单元格DAG——仅依赖变更变量的单元格才会重新执行。
  • 无需使用
    st.rerun()
    ——响应式是自动生效的。
  • 无需使用
    st.stop()
    ——合理组织单元格结构,让下游单元格自然依赖上游值即可。

State Management

状态管理

Streamlitmarimo
st.session_state["key"]
Regular Python variables between cells
Callback functions (
on_change
)
Cells referencing
widget.value
re-run automatically
st.query_params
mo.query_params
Streamlitmarimo
st.session_state["key"]
单元格之间的普通Python变量
回调函数 (
on_change
)
引用了
widget.value
的单元格会自动重新运行
st.query_params
mo.query_params

Caching

缓存

Streamlitmarimo
@st.cache_data
@mo.cache
@st.cache_resource
@mo.persistent_cache
@mo.cache
is the primary caching decorator — it works like
functools.cache
but is aware of marimo's reactivity.
@mo.persistent_cache
goes further by persisting results to disk across sessions, useful for expensive computations like model training.
Streamlitmarimo
@st.cache_data
@mo.cache
@st.cache_resource
@mo.persistent_cache
@mo.cache
是核心缓存装饰器——它的作用类似
functools.cache
但能感知marimo的响应式逻辑。
@mo.persistent_cache
更进一步,会将结果持久化到磁盘跨会话保留,适合模型训练等高开销计算场景。

Multi-Page Apps

多页应用

Marimo offers two approaches for multi-page Streamlit apps:
  • Single notebook with routing: Use
    mo.routes
    with
    mo.nav_menu
    or
    mo.sidebar
    to build multiple "pages" (tabs/routes) inside one notebook.
  • Multiple notebooks as a gallery: Run a folder of notebooks with
    marimo run folder/
    to serve them as a gallery with navigation.
Marimo为多页Streamlit应用提供两种迁移方案:
  • 单笔记本加路由:配合
    mo.nav_menu
    mo.sidebar
    使用
    mo.routes
    ,在单个笔记本内构建多个「页面」(标签页/路由)。
  • 多笔记本作为画廊:使用
    marimo run folder/
    运行一个文件夹内的笔记本,将它们作为带导航的应用画廊提供服务。

Deploying

部署

marimo features molab to host marimo apps instead of the streamlit community cloud. You can generate an "open in molab" button via the
add-molab-badge
skill.
marimo提供molab服务来托管marimo应用,替代Streamlit社区云。你可以通过
add-molab-badge
技能生成「在molab中打开」按钮。

Custom components

自定义组件

streamlit has a feature for custom components. These are not compatible with marimo. You might be able to generate an equivalent anywidget via the
marimo-anywidget
skill but discuss this with the user before working on that.
Streamlit支持自定义组件,这些组件与marimo不兼容。你可以通过
marimo-anywidget
技能生成等效的anywidget,但在实施前请先与用户沟通确认。