Marimo Notebook Assistant
This skill provides specialized guidance for creating data science notebooks using marimo's reactive programming model. Focus on creating clear, efficient, and reproducible data analysis workflows.
Core Capabilities
- Data science and analytics using marimo notebooks
- Complete, runnable code that follows best practices
- Reproducibility and clear documentation
- Interactive data visualizations and analysis
- Understanding of marimo's reactive programming model
Marimo Fundamentals
Marimo is a reactive notebook that differs from traditional notebooks in key ways:
- Cells execute automatically when their dependencies change
- Variables cannot be redeclared across cells
- The notebook forms a directed acyclic graph (DAG)
- The last expression in a cell is automatically displayed
- UI elements are reactive and update the notebook automatically
Code Requirements
- All code must be complete and runnable
- Follow consistent coding style throughout
- Include descriptive variable names and helpful comments
- Import all modules in the first cell, always including
import marimo as mo
- Never redeclare variables across cells
- Ensure no cycles in notebook dependency graph
- The last expression in a cell is automatically displayed, just like in Jupyter notebooks
- Don't include comments in markdown cells
- Don't include comments in SQL cells
Reactivity
Marimo's reactivity means:
- When a variable changes, all cells that use that variable automatically re-execute
- UI elements trigger updates when their values change without explicit callbacks
- UI element values are accessed through
.value attribute
- Cannot access a UI element's value in the same cell where it's defined
Best Practices
Data Handling
- Use pandas for data manipulation
- Implement proper data validation
- Handle missing values appropriately
- Use efficient data structures
- A variable in the last expression of a cell is automatically displayed as a table
Visualization
- For matplotlib: use
plt.gca() as the last expression instead of plt.show()
- For plotly: return the figure object directly
- For altair: return the chart object directly
- Include proper labels, titles, and color schemes
- Make visualizations interactive where appropriate
UI Elements
- Access UI element values with
.value attribute (e.g., slider.value)
- Create UI elements in one cell and reference them in later cells
- Create intuitive layouts with
mo.hstack(), mo.vstack(), and mo.tabs()
- Prefer reactive updates over callbacks (marimo handles reactivity automatically)
- Group related UI elements for better organization
Data Sources
- Prefer GitHub-hosted datasets (e.g., raw.githubusercontent.com)
- Use CORS proxy for external URLs: https://corsproxy.marimo.app/
- Implement proper error handling for data loading
- Consider using
vega_datasets for common example datasets
SQL
- When writing duckdb, prefer using marimo's SQL cells, which start with
_df = mo.sql(query)
- See the SQL with duckdb example for an example on how to do this
- Don't add comments in cells that use
mo.sql()
- Consider using
vega_datasets for common example datasets
Troubleshooting
Common issues and solutions:
- Circular dependencies: Reorganize code to remove cycles in the dependency graph
- UI element value access: Move access to a separate cell from definition
- Visualization not showing: Ensure the visualization object is the last expression
Available UI Elements
mo.ui.altair_chart(altair_chart)
mo.ui.button(value=None, kind='primary')
mo.ui.run_button(label=None, tooltip=None, kind='primary')
mo.ui.checkbox(label='', value=False)
mo.ui.date(value=None, label=None, full_width=False)
mo.ui.dropdown(options, value=None, label=None, full_width=False)
mo.ui.file(label='', multiple=False, full_width=False)
mo.ui.number(value=None, label=None, full_width=False)
mo.ui.radio(options, value=None, label=None, full_width=False)
mo.ui.refresh(options: List[str], default_interval: str)
mo.ui.slider(start, stop, value=None, label=None, full_width=False, step=None)
mo.ui.range_slider(start, stop, value=None, label=None, full_width=False, step=None)
mo.ui.table(data, columns=None, sortable=True, filterable=True)
mo.ui.text(value='', label=None, full_width=False)
mo.ui.text_area(value='', label=None, full_width=False)
mo.ui.data_explorer(df)
mo.ui.dataframe(df)
mo.ui.plotly(plotly_figure)
mo.ui.tabs(elements: dict[str, mo.ui.Element])
mo.ui.array(elements: list[mo.ui.Element])
mo.ui.form(element: mo.ui.Element, label='', bordered=True)
Layout and Utility Functions
mo.md(text) - display markdown
mo.stop(predicate, output=None) - stop execution conditionally
mo.Html(html) - display HTML
mo.image(image) - display an image
mo.hstack(elements) - stack elements horizontally
mo.vstack(elements) - stack elements vertically
mo.tabs(elements) - create a tabbed interface
Examples
Basic UI with Reactivity
# Cell 1
import marimo as mo
import matplotlib.pyplot as plt
import numpy as np
# Cell 2
# Create a slider and display it
n_points = mo.ui.slider(10, 100, value=50, label="Number of points")
n_points # Display the slider
# Cell 3
# Generate random data based on slider value
# This cell automatically re-executes when n_points.value changes
x = np.random.rand(n_points.value)
y = np.random.rand(n_points.value)
plt.figure(figsize=(8, 6))
plt.scatter(x, y, alpha=0.7)
plt.title(f"Scatter plot with {n_points.value} points")
plt.xlabel("X axis")
plt.ylabel("Y axis")
plt.gca() # Return the current axes to display the plot
Data Explorer
# Cell 1
import marimo as mo
import pandas as pd
from vega_datasets import data
# Cell 2
# Load and display dataset with interactive explorer
cars_df = data.cars()
mo.ui.data_explorer(cars_df)
Multiple UI Elements
# Cell 1
import marimo as mo
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Cell 2
# Load dataset
iris = sns.load_dataset('iris')
# Cell 3
# Create UI elements
species_selector = mo.ui.dropdown(
options=["All"] + iris["species"].unique().tolist(),
value="All",
label="Species"
)
x_feature = mo.ui.dropdown(
options=iris.select_dtypes('number').columns.tolist(),
value="sepal_length",
label="X Feature"
)
y_feature = mo.ui.dropdown(
options=iris.select_dtypes('number').columns.tolist(),
value="sepal_width",
label="Y Feature"
)
# Display UI elements in a horizontal stack
mo.hstack([species_selector, x_feature, y_feature])
# Cell 4
# Filter data based on selection
filtered_data = iris if species_selector.value == "All" else iris[iris["species"] == species_selector.value]
# Create visualization based on UI selections
plt.figure(figsize=(10, 6))
sns.scatterplot(
data=filtered_data,
x=x_feature.value,
y=y_feature.value,
hue="species"
)
plt.title(f"{y_feature.value} vs {x_feature.value}")
plt.gca()
Interactive Chart with Altair
# Cell 1
import marimo as mo
import altair as alt
import pandas as pd
# Cell 2
# Load dataset
cars_df = pd.read_csv('https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json')
_chart = alt.Chart(cars_df).mark_point().encode(
x='Horsepower',
y='Miles_per_Gallon',
color='Origin',
)
chart = mo.ui.altair_chart(_chart)
chart
# Cell 3
# Display the selection
chart.value
Run Button Example
# Cell 1
import marimo as mo
# Cell 2
first_button = mo.ui.run_button(label="Option 1")
second_button = mo.ui.run_button(label="Option 2")
[first_button, second_button]
# Cell 3
if first_button.value:
print("You chose option 1!")
elif second_button.value:
print("You chose option 2!")
else:
print("Click a button!")
SQL with DuckDB
# Cell 1
import marimo as mo
# Cell 2
# Load dataset
cars_df = pd.read_csv('https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json')
# Cell 3
_df = mo.sql("SELECT * from cars_df WHERE Miles_per_Gallon > 20")
Writing LaTeX in Markdown
# Cell 1
import marimo as mo
# Cell 2
mo.md(r"""
The quadratic function $f$ is defined as
$$f(x) = x^2.$$
""")
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: dakesan-marimo-cc-marimo-editor3description: Marimo Notebook Assistant4---56# Marimo Notebook Assistant78This skill provides specialized guidance for creating data science notebooks using marimo's reactive programming model. Focus on creating clear, efficient, and reproducible data analysis workflows.910## Core Capabilities1112- Data science and analytics using marimo notebooks13- Complete, runnable code that follows best practices14- Reproducibility and clear documentation15- Interactive data visualizations and analysis16- Understanding of marimo's reactive programming model1718## Marimo Fundamentals1920Marimo is a reactive notebook that differs from traditional notebooks in key ways:21- Cells execute automatically when their dependencies change22- Variables cannot be redeclared across cells23- The notebook forms a directed acyclic graph (DAG)24- The last expression in a cell is automatically displayed25- UI elements are reactive and update the notebook automatically2627## Code Requirements28291. All code must be complete and runnable302. Follow consistent coding style throughout313. Include descriptive variable names and helpful comments324. Import all modules in the first cell, always including `import marimo as mo`335. Never redeclare variables across cells346. Ensure no cycles in notebook dependency graph357. The last expression in a cell is automatically displayed, just like in Jupyter notebooks368. Don't include comments in markdown cells379. Don't include comments in SQL cells3839## Reactivity4041Marimo's reactivity means:42- When a variable changes, all cells that use that variable automatically re-execute43- UI elements trigger updates when their values change without explicit callbacks44- UI element values are accessed through `.value` attribute45- Cannot access a UI element's value in the same cell where it's defined4647## Best Practices4849### Data Handling5051- Use pandas for data manipulation52- Implement proper data validation53- Handle missing values appropriately54- Use efficient data structures55- A variable in the last expression of a cell is automatically displayed as a table5657### Visualization5859- For matplotlib: use `plt.gca()` as the last expression instead of `plt.show()`60- For plotly: return the figure object directly61- For altair: return the chart object directly62- Include proper labels, titles, and color schemes63- Make visualizations interactive where appropriate6465### UI Elements6667- Access UI element values with `.value` attribute (e.g., `slider.value`)68- Create UI elements in one cell and reference them in later cells69- Create intuitive layouts with `mo.hstack()`, `mo.vstack()`, and `mo.tabs()`70- Prefer reactive updates over callbacks (marimo handles reactivity automatically)71- Group related UI elements for better organization7273### Data Sources7475- Prefer GitHub-hosted datasets (e.g., raw.githubusercontent.com)76- Use CORS proxy for external URLs: https://corsproxy.marimo.app/<url>77- Implement proper error handling for data loading78- Consider using `vega_datasets` for common example datasets7980### SQL8182- When writing duckdb, prefer using marimo's SQL cells, which start with `_df = mo.sql(query)`83- See the SQL with duckdb example for an example on how to do this84- Don't add comments in cells that use `mo.sql()`85- Consider using `vega_datasets` for common example datasets8687## Troubleshooting8889Common issues and solutions:90- Circular dependencies: Reorganize code to remove cycles in the dependency graph91- UI element value access: Move access to a separate cell from definition92- Visualization not showing: Ensure the visualization object is the last expression9394## Available UI Elements9596* `mo.ui.altair_chart(altair_chart)`97* `mo.ui.button(value=None, kind='primary')`98* `mo.ui.run_button(label=None, tooltip=None, kind='primary')`99* `mo.ui.checkbox(label='', value=False)`100* `mo.ui.date(value=None, label=None, full_width=False)`101* `mo.ui.dropdown(options, value=None, label=None, full_width=False)`102* `mo.ui.file(label='', multiple=False, full_width=False)`103* `mo.ui.number(value=None, label=None, full_width=False)`104* `mo.ui.radio(options, value=None, label=None, full_width=False)`105* `mo.ui.refresh(options: List[str], default_interval: str)`106* `mo.ui.slider(start, stop, value=None, label=None, full_width=False, step=None)`107* `mo.ui.range_slider(start, stop, value=None, label=None, full_width=False, step=None)`108* `mo.ui.table(data, columns=None, on_select=None, sortable=True, filterable=True)`109* `mo.ui.text(value='', label=None, full_width=False)`110* `mo.ui.text_area(value='', label=None, full_width=False)`111* `mo.ui.data_explorer(df)`112* `mo.ui.dataframe(df)`113* `mo.ui.plotly(plotly_figure)`114* `mo.ui.tabs(elements: dict[str, mo.ui.Element])`115* `mo.ui.array(elements: list[mo.ui.Element])`116* `mo.ui.form(element: mo.ui.Element, label='', bordered=True)`117118## Layout and Utility Functions119120* `mo.md(text)` - display markdown121* `mo.stop(predicate, output=None)` - stop execution conditionally122* `mo.Html(html)` - display HTML123* `mo.image(image)` - display an image124* `mo.hstack(elements)` - stack elements horizontally125* `mo.vstack(elements)` - stack elements vertically126* `mo.tabs(elements)` - create a tabbed interface127128## Examples129130### Basic UI with Reactivity131132```python133# Cell 1134import marimo as mo135import matplotlib.pyplot as plt136import numpy as np137138# Cell 2139# Create a slider and display it140n_points = mo.ui.slider(10, 100, value=50, label="Number of points")141n_points # Display the slider142143# Cell 3144# Generate random data based on slider value145# This cell automatically re-executes when n_points.value changes146x = np.random.rand(n_points.value)147y = np.random.rand(n_points.value)148149plt.figure(figsize=(8, 6))150plt.scatter(x, y, alpha=0.7)151plt.title(f"Scatter plot with {n_points.value} points")152plt.xlabel("X axis")153plt.ylabel("Y axis")154plt.gca() # Return the current axes to display the plot155```156157### Data Explorer158159```python160# Cell 1161import marimo as mo162import pandas as pd163from vega_datasets import data164165# Cell 2166# Load and display dataset with interactive explorer167cars_df = data.cars()168mo.ui.data_explorer(cars_df)169```170171### Multiple UI Elements172173```python174# Cell 1175import marimo as mo176import pandas as pd177import matplotlib.pyplot as plt178import seaborn as sns179180# Cell 2181# Load dataset182iris = sns.load_dataset('iris')183184# Cell 3185# Create UI elements186species_selector = mo.ui.dropdown(187 options=["All"] + iris["species"].unique().tolist(),188 value="All",189 label="Species"190)191x_feature = mo.ui.dropdown(192 options=iris.select_dtypes('number').columns.tolist(),193 value="sepal_length",194 label="X Feature"195)196y_feature = mo.ui.dropdown(197 options=iris.select_dtypes('number').columns.tolist(),198 value="sepal_width",199 label="Y Feature"200)201202# Display UI elements in a horizontal stack203mo.hstack([species_selector, x_feature, y_feature])204205# Cell 4206# Filter data based on selection207filtered_data = iris if species_selector.value == "All" else iris[iris["species"] == species_selector.value]208209# Create visualization based on UI selections210plt.figure(figsize=(10, 6))211sns.scatterplot(212 data=filtered_data,213 x=x_feature.value,214 y=y_feature.value,215 hue="species"216)217plt.title(f"{y_feature.value} vs {x_feature.value}")218plt.gca()219```220221### Interactive Chart with Altair222223```python224# Cell 1225import marimo as mo226import altair as alt227import pandas as pd228229# Cell 2230# Load dataset231cars_df = pd.read_csv('https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json')232_chart = alt.Chart(cars_df).mark_point().encode(233 x='Horsepower',234 y='Miles_per_Gallon',235 color='Origin',236)237238chart = mo.ui.altair_chart(_chart)239chart240241# Cell 3242# Display the selection243chart.value244```245246### Run Button Example247248```python249# Cell 1250import marimo as mo251252# Cell 2253first_button = mo.ui.run_button(label="Option 1")254second_button = mo.ui.run_button(label="Option 2")255[first_button, second_button]256257# Cell 3258if first_button.value:259 print("You chose option 1!")260elif second_button.value:261 print("You chose option 2!")262else:263 print("Click a button!")264```265266### SQL with DuckDB267268```python269# Cell 1270import marimo as mo271272# Cell 2273# Load dataset274cars_df = pd.read_csv('https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json')275276# Cell 3277_df = mo.sql("SELECT * from cars_df WHERE Miles_per_Gallon > 20")278```279280### Writing LaTeX in Markdown281282```python283# Cell 1284import marimo as mo285286# Cell 2287mo.md(r"""288289The quadratic function $f$ is defined as290291$$f(x) = x^2.$$292""")293```294295---296> Converted and distributed by [TomeVault](https://tomevault.io/claim/dakesan) — claim your Tome and manage your conversions.297<!-- tomevault:4.0:skill_md:2026-04-13 -->