Plotting API Reference
marimo integrates with major plotting libraries and provides reactive chart components for interactive data selection.
Supported Libraries
marimo renders output from these libraries automatically:
- Matplotlib
- Plotly
- Altair
- Seaborn
- Bokeh
- HoloViews
- hvPlot
- Leafmap
- Pygwalker
Simply return a figure/chart as the last expression in a cell.
Reactive Charts
Interactive charts that return selected data.
Altair Charts
import marimo as mo
import altair as alt
# Create reactive Altair chart
chart = mo.ui.altair_chart(
alt.Chart(df).mark_point().encode(
x="x:Q",
y="y:Q",
color="category:N"
)
)
# Display chart
chart
# In another cell - access selected data
selected_df = chart.value # Returns filtered DataFrame
Options:
chart = mo.ui.altair_chart(
alt_chart,
chart_selection="point", # "point", "interval", True, False
legend_selection=True, # Enable legend filtering
label="Select data points"
)
# Apply selection to external DataFrame
filtered = chart.apply_selection(other_df)
Selection types:
- Point selection: Click individual points
- Interval selection: Drag to select region
- Legend selection: Click legend items to filter
Performance note: marimo's CSV transformer handles up to 400,000+ rows efficiently.
Plotly Charts
import marimo as mo
import plotly.express as px
fig = px.scatter(df, x="x", y="y", color="category")
# Create reactive Plotly chart
chart = mo.ui.plotly(fig)
# Display
chart
# Access selection data
chart.value # Complete selection info
chart.indices # Selected point indices
chart.points # Selected point data as dicts
chart.ranges # Axis range selections
Matplotlib Interactive
import marimo as mo
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x, y)
# Create interactive viewer with pan/zoom
mo.mpl.interactive(fig)
Features:
- Pan and zoom
- Coordinate hover
- Requires WebSocket (not available in WASM)
Static Plots
Matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
ax.set_xlabel("X")
ax.set_ylabel("Y")
fig # Display
Seaborn
import seaborn as sns
fig = sns.scatterplot(data=df, x="x", y="y", hue="category")
fig.figure # Display
Plotly (non-reactive)
import plotly.express as px
fig = px.line(df, x="date", y="value")
fig # Display
Altair (non-reactive)
import altair as alt
chart = alt.Chart(df).mark_bar().encode(
x="category:N",
y="count:Q"
)
chart # Display
Embedding Plots in Markdown
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
mo.md(f"""
## Analysis Results
{mo.as_html(fig)}
The plot shows a quadratic relationship.
""")
Custom Selection Behavior
Disable automatic selections and use custom Altair selections:
import altair as alt
# Create custom selection
brush = alt.selection_interval()
chart = alt.Chart(df).mark_point().encode(
x="x:Q",
y="y:Q",
color=alt.condition(brush, "category:N", alt.value("lightgray"))
).add_params(brush)
# Wrap without automatic selection
mo.ui.altair_chart(
chart,
chart_selection=False,
legend_selection=False
)
Multiple Linked Charts
# Brush selection shared between charts
brush = alt.selection_interval()
chart1 = alt.Chart(df).mark_point().encode(
x="x:Q",
y="y:Q"
).add_params(brush)
chart2 = alt.Chart(df).mark_bar().encode(
x="category:N",
y="count()"
).transform_filter(brush)
mo.hstack([
mo.ui.altair_chart(chart1),
chart2
])
Faceted Charts
chart = alt.Chart(df).mark_point().encode(
x="x:Q",
y="y:Q"
).facet(
column="category:N"
)
mo.ui.altair_chart(chart)
Large Datasets
For large datasets, consider:
- Sampling: Plot a representative sample
- Aggregation: Use binning or grouping
- Canvas rendering: Use Plotly with
render_mode="webgl" - Lazy loading: Load data on demand
# Plotly WebGL for large datasets
import plotly.express as px
fig = px.scatter(
large_df,
x="x", y="y",
render_mode="webgl" # GPU acceleration
)
Reactive Plot Updates
Charts automatically update when dependent variables change:
# Cell 1
n_points = mo.ui.slider(10, 1000, value=100, label="Points")
# Cell 2
import numpy as np
x = np.random.randn(n_points.value)
y = np.random.randn(n_points.value)
# Cell 3
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.scatter(x, y, alpha=0.5)
ax.set_title(f"{n_points.value} Points")
fig # Updates when slider changes