marimo supports most major plotting libraries, including Matplotlib, Seaborn, Plotly, Altair, and HoloViews. Just import your plotting library of choice and use it as you normally would.

For Altair and Plotly plots, marimo does something special: use mo.ui.altair_chart or mo.ui.plotly to connect frontend selections to Python!

Reactive plots!

marimo supports reactive plots via mo.ui.altair_chart and mo.ui.plotly! Select and filter with your mouse, and marimo automatically makes the selected data available in Python as a Pandas dataframe!

Reactive plots! ⚡


Reactive plots currently require Altair or Plotly. Install with pip install altair or pip install plotly, depending on which library you are using.


Use mo.ui.altair_chart to easily create interactive, selectable plots: selections you make on the frontend are automatically made available as Pandas dataframes in Python.

Wrap an Altair chart in mo.ui.altair_chart to make it reactive: select data on the frontend, access it via the chart’s value attribute (chart.value).

Reactive plots are just one way that marimo makes your data tangible.


import marimo as mo
import altair as alt
import vega_datasets

# Load some data
cars =

# Create an Altair chart
chart = alt.Chart(cars).mark_point().encode(
    x='Horsepower', # Encoding along the x-axis
    y='Miles_per_Gallon', # Encoding along the y-axis
    color='Origin', # Category encoding by color

# Make it reactive ⚡
chart = mo.ui.altair_chart(chart)
# In a new cell, display the chart and its data filtered by the selection
mo.vstack([chart, chart.value.head()])

Learning Altair

If you’re new to Altair, we highly recommend exploring the Altair documentation. Altair provides a declarative, concise, and simple way to create highly interactive and sophisticated plots.

Altair is based on Vega-Lite, an exceptional tool for creating interactive charts that serves as the backbone for marimo’s reactive charting capabilities.


Learn by doing? Skip this section!

This section summarizes the main concepts used by Altair (and Vega-Lite). Feel free to skip this section and return later.

Our choice to use the Vega-Lite specification was driven by its robust data model, which is well-suited for data analysis. Some key concepts are summarized below. (For a more detailed explanation, with examples, we recommend the Basic Statistical Visualization tutorial from Altair.)

  • Data Source: This is the information that will be visualized in the chart. It can be provided in various formats such as a dataframe, a list of dictionaries, or a URL pointing to the data source.

  • Mark Type: This refers to the visual representation used for each data point on the chart. The options include ‘bar’, ‘dot’, ‘circle’, ‘area’, and ‘line’. Each mark type offers a different way to visualize and interpret the data.

  • Encoding: This is the process of mapping various aspects or dimensions of the data to visual characteristics of the marks. Encodings can be of different types:

    • Positional Encodings: These are encodings like ‘x’ and ‘y’ that determine the position of the marks in the chart.

    • Categorical Encodings: These are encodings like ‘color’ and ‘shape’ that categorize data points. They are typically represented in a legend for easy reference.

  • Transformations: These are operations that can be applied to the data before it is visualized, for example, filtering and aggregation. These transformations allow for more complex and nuanced visualizations.

Automatically interactive. marimo adds interactivity automatically, based on the mark used and the encodings. For example, if you use a mark_point and an x encoding, marimo will automatically add a brush selection to the chart. If you add a color encoding, marimo will add a legend and a click selection.

Automatic Selections

By default mo.ui.altair_chart will make the chart and legend selectable. Depending on the mark type, the chart will either have a point or interval (“brush”) selection. When using non-positional encodings (color, size, etc), mo.ui.altair_chart will also make the legend selectable.

Selection configurable through *_selection params in mo.ui.altair_chart. See the API docs for details.


You may still add your own selection parameters via Altair or Vega-Lite. marimo will not override your selections.

Altair transformations

Altair supports a variety of transformations, such as filtering, aggregation, and sorting. These transformations can be used to create more complex and nuanced visualizations. For example, you can use a filter to show only the points that meet a certain condition, or use an aggregation to show the average value of a variable.

In order for marimo’s reactive plots to work with transformations, you must install vegafusion, as this feature uses chart.transformed_data (which requires version 1.4.0 or greater of the vegafusion packages).

# These can be installed with pip using:
pip install "vegafusion[embed]>=1.4.0"
# Or with conda using:
conda install -c conda-forge "vegafusion-python-embed>=1.4.0" "vegafusion>=1.4.0"


Use mo.ui.plotly to create selectable Plotly plots whose values are sent back to Python on selection.

marimo.ui.plotly(figure: go.Figure, config: Dict[str, Any] | None = None, renderer_name: str | None = None, *, label: str = '', on_change: Callable[[JSONType], None] | None = None) None

Make reactive plots with Plotly.

Use mo.ui.plotly to make plotly plots reactive: select data with your cursor on the frontend, get them as a list of dicts in Python!


import as px
import marimo as mo
from vega_datasets import data

_plot = px.scatter(, x="Horsepower", y="Miles_per_Gallon", color="Origin"

plot = mo.ui.plotly(_plot)
# View the plot and selected data
mo.hstack([plot, plot.value])

Or with custom configuration:

plot = mo.ui.plotly(
    config={"staticPlot": True},


  • value: a dict of the plot data

  • ranges: the selection of the plot; this may be an interval along the name of an axis

Initialization Args.

  • figure: A plotly.graph_objects.Figure

  • config: optional configuration for the plot This is a dictionary that is passed directly to the plotly. See the plotly documentation for more information: This takes precedence over the default configuration of the renderer.

  • renderer_name: optional renderer to use for the plot. If this is not provided, the default renderer (pio.renderers.default) is used.

  • label: optional text label for the element

  • on_change: optional callback to run when this element’s value changes


To output a matplotlib plot in a cell’s output area, include its Axes or Figure object as the last expression in your notebook. For example:

plt.plot([1, 2])
# plt.gca() gets the current `Axes`


fig, ax = plt.subplots()

ax.plot([1, 2])

If you want to output the plot in the console area, use or

Interactive plots

To make matplotlib plots interactive, use mo.mpl.interactive. (Matplotlib plots are not yet reactive.)