FAQ#
Choosing marimo#
How is marimo different from Jupyter?
marimo is a brand new Python notebook that is both interactive, with UI elements like sliders, dropdowns, etc., and reactive, like a spreadsheet. marimo solves many well-documented problems associated with traditional notebooks like Jupyter [1] [2]:
no hidden state: running a cell automatically runs all cells that depend on it, and deleting a cell automatically deletes its variables, eliminating hidden state and hidden bugs
interactive data exploration: UI elements and reactivity make your data tangible
sharing: use the marimo CLI to run notebooks as apps
Python, not JSON: stored as executable Python, with clean git diffs and potential for code reuse
fast, reliable autocomplete: code completion is fast and works out of the box
How is marimo.ui
different from Jupyter widgets?
Unlike Jupyter widgets, marimo’s interactive elements are automatically synchronized with the Python kernel: no callbacks, no observers, no manually re-running cells.
Using marimo#
Is marimo a notebook or a library?
marimo is both a notebook and a library.
Create marimo notebooks with the editor that opens in your browser when you run
marimo edit
.Use the marimo library (
import marimo as mo
) in marimo notebooks. Write markdown withmo.md(...)
, create stateful interactive elements withmo.ui
(mo.ui.slider(...)
), and more. See the docs for an API reference.
What’s the difference between a marimo notebook and a marimo app?
marimo programs are notebooks, apps, or both, depending on how you use them.
There are two ways to interact with a marimo program:
open it as a computational notebook with
marimo edit
run it as an interactive app with
marimo run
All marimo programs start as notebooks, since they are created with marimo edit
. Because marimo notebooks are reactive and have built-in interactive
elements, many can easily be made into useful and beautiful apps by simply
hiding the notebook code: this is what marimo run
does.
Not every notebook needs to be run as an app — marimo notebooks are useful in
and of themselves for rapidly exploring data and doing reproducible science.
And not every app is improved by interacting with the notebook. In some
settings, such as collaborative research, education, and technical
presentations, going back and forth between the notebook view and app view
(which you can do from marimo edit
) can be useful!
How does marimo know what cells to run?
marimo reads each cell once to determine what global names it defines and what global names it reads. When a cell is run, marimo runs all other cells that read any of the global names it defines. A global name can refer to a variable, class, function, or import.
In other words, marimo uses static analysis to make a dataflow graph out of your cells. Each cell is a node in the graph across which global variables “flow”. Whenever a cell is run, either because you changed its code or interacted with a UI element it reads, all its descendants run in turn.
How do I prevent automatic execution from running expensive cells?
Reactive (automatic) execution ensures your code and outputs are always in sync, improving reproducibility by eliminating hidden state and out-of-order execution; marimo also takes care to run only the minimal set of cells needed to keep your notebook up to date. But when some cells take a long time to run, it’s understandable to be concerned that automatic execution will kick off expensive cells before you’re ready to run them.
Here are some tips to avoid accidental execution of expensive cells:
Disable expensive cells. When a cell is disabled, it and its descendants are blocked from running.
Use Python’s
functools.cache
to cache expensive intermediate computations (see our best practices guide).Wrap UI elements in a form.
Use
mo.stop
to conditionally stop execution of a cell and its descendants.
How do I use sliders and other interactive elements?
Interactive UI elements like sliders are available in marimo.ui
.
Assign the UI element to a global variable (
slider = mo.ui.slider(0, 100)
)Include it in the last expression of a cell to display it (
slider
ormo.md(f"Choose a value: {slider}")
)Read its current value in another cell via its
value
attribute (slider.value
)
When a UI element bound to a global variable is interacted with, all cells referencing the global variable are run automatically.
If you have many UI elements or don’t know the elements
you’ll create until runtime, use marimo.ui.array
and marimo.ui.dictionary
to create UI elements that wrap other UI elements (sliders = mo.ui.array([slider(1, 100) for _ in range(n_sliders)])
).
All this and more is explained in the UI tutorial. Run it with
marimo tutorial ui
at the command line.
How do I add a submit button to UI elements?
Use the form
method to add a submit button to a UI element. For
example,
form = marimo.ui.text_area().form()
When wrapped in a form, the
text area’s value will only be sent to Python when you click the submit button.
Access the last submitted value of the text area with form.value
.
Import marimo
(as mo
) in a notebook, and use the mo.md
function.
Include plots in the last expression of a cell to display them, just like all
other outputs. If you’re using matplotlib, you can display the Figure
object
(get the current figure with plt.gcf()
). For examples, run the plots tutorial:
marimo tutorial plots
Also see the plotting API reference.
How do I prevent matplotlib plots from being cut off?
If your legend or axes labels are cut off, try calling plt.tight_layout()
before outputting your plot:
import matplotlib.pyplot as plt
plt.plot([-8, 8])
plt.ylabel("my variable")
plt.tight_layout()
plt.gca()
How do I display interactive matplotlib plots?
fig, ax = plt.subplots()
ax.plot([1, 2])
mo.mpl.interactive(ax)
How do I display objects in rows and columns?
Use marimo.hstack
and marimo.vstack
. See the layout tutorial for details:
marimo tutorial layout
How do I create an output with a dynamic number of UI elements?
Use mo.ui.array
,
mo.ui.dictionary
, or
mo.ui.batch
to create a UI element
that wraps a dynamic number of other UI elements.
If you need custom
formatting, use mo.ui.batch
, otherwise
use mo.ui.array
or
mo.ui.dictionary
.
For usage examples, see the recipes for grouping UI elements together.
To reload modules, use
importlib.reload()
:
import mymodule
import importlib
importlib.reload(mymodule)
Running this cell will reload mymodule
with your new edits and automatically
re-run any cells using mymodule
.
Why aren’t my on_change
/on_click
handlers being called?
A UI Element’s on_change
(or for buttons, on_click
) handlers are only
called if the element is bound to a global variable. For example, this won’t work
mo.vstack([mo.ui.button(on_change=lambda _: print('I was called")) for _ in range(10)])
In such cases (when you want to output a dynamic number of UI elements),
you need to use
mo.ui.array
,
mo.ui.dictionary
, or
mo.ui.batch
.
See the recipes for grouping UI elements together for example code.
How does marimo treat type annotations?
Type annotations are registered as references of a cell, unless they are explicitly written as strings. This helps ensure correctness of code that depends on type annotations at runtime (e.g., Pydantic), while still providing a way to omit annotations from affecting dataflow graph.
For example, in
x: A = ...
A
is treated as a reference, used in determining the dataflow graph, but
in
x: "A" = ...
A
isn’t made a reference.
For Python 3.12+, marimo additionally implements annotation scoping.
You can use any Python package. marimo cells run arbitrary Python code.
Use the marimo CLI’s run
command to serve a notebook as an app:
marimo run notebook.py
Yes!