Skip to content

Plotting

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

For more information about plotting, see the plotting guide.

Reactive charts with Altair

Disabling automatic selection

marimo automatically adds a default selection based on the mark type, however, you may want to customize the selection behavior of your Altair chart. You can do this by setting chart_selection and legend_selection to False, and using .add_params directly on your Altair chart.

# Create an interval selection
brush = alt.selection_interval(encodings=["x"])

_chart = (
    alt.Chart(traces, height=150)
    .mark_line()
    .encode(x="index:Q", y="value:Q", color="traces:N")
    .add_params(brush) # add the selection to the chart
)

chart = mo.ui.altair_chart(
    _chart,
    # disable automatic selection
    chart_selection=False,
    legend_selection=False
)
chart # You can now access chart.value to get the selected data

marimo.ui.altair_chart

altair_chart(
    chart: Chart,
    chart_selection: Literal["point"]
    | Literal["interval"]
    | bool = True,
    legend_selection: list[str] | bool = True,
    *,
    label: str = "",
    on_change: Optional[
        Callable[[ChartDataType], None]
    ] = None
)

Bases: UIElement[ChartSelection, ChartDataType]

Make reactive charts with Altair.

Use mo.ui.altair_chart to make Altair charts reactive: select chart data with your cursor on the frontend, get them as a dataframe in Python!

Supports polars, pandas, and arrow DataFrames.

Examples:

import altair as alt
import marimo as mo
from vega_datasets import data

chart = (
    alt.Chart(data.cars())
    .mark_point()
    .encode(
        x="Horsepower",
        y="Miles_per_Gallon",
        color="Origin",
    )
)

chart = mo.ui.altair_chart(chart)
# View the chart and selected data as a dataframe
mo.hstack([chart, chart.value])
ATTRIBUTE DESCRIPTION
value

A dataframe of the plot data filtered by the selections.

TYPE: ChartDataType

dataframe

A dataframe of the unfiltered chart data.

TYPE: ChartDataType

selections

The selection of the chart; this may be an interval along the name of an axis or a selection of points.

TYPE: ChartSelection

PARAMETER DESCRIPTION
chart

An Altair Chart object.

TYPE: Chart

chart_selection

Selection type, "point", "interval", or a bool. Defaults to True which will automatically detect the best selection type. This is ignored if the chart already has a point/interval selection param.

TYPE: Union[Literal['point'], Literal['interval'], bool] DEFAULT: True

legend_selection

List of legend fields (columns) for which to enable selection, True to enable selection for all fields, or False to disable selection entirely. This is ignored if the chart already has a legend selection param. Defaults to True.

TYPE: Union[list[str], bool] DEFAULT: True

label

Markdown label for the element. Defaults to "".

TYPE: str DEFAULT: ''

on_change

Optional callback to run when this element's value changes. Defaults to None.

TYPE: Optional[Callable[[ChartDataType], None]] DEFAULT: None

dataframe instance-attribute

dataframe: Optional[
    ChartDataType
] = _get_dataframe_from_chart(chart)

name class-attribute instance-attribute

name: Final[str] = 'marimo-vega'

selections property

selections: ChartSelection

text property

text: str

A string of HTML representing this element.

value property writable

value: ChartDataType

apply_selection

apply_selection(df: ChartDataType) -> ChartDataType

Apply the selection to a DataFrame.

This method is useful when you have a layered chart and you want to apply the selection to a DataFrame.

PARAMETER DESCRIPTION
df

A DataFrame to apply the selection to.

TYPE: ChartDataType

RETURNS DESCRIPTION
ChartDataType

A DataFrame of the plot data filtered by the selections.

TYPE: ChartDataType

Examples:

import altair as alt
import marimo as mo
from vega_datasets import data

cars = data.cars()

_chart = (
    alt.Chart(cars)
    .mark_point()
    .encode(
        x="Horsepower",
        y="Miles_per_Gallon",
        color="Origin",
    )
)

chart = mo.ui.altair_chart(_chart)
chart

# In another cell
selected_df = chart.apply_selection(cars)

batch

batch(**elements: UIElement[JSONType, object]) -> batch

Convert an HTML object with templated text into a UI element.

This method lets you create custom UI elements that are represented by arbitrary HTML.

Example
user_info = mo.md(
    '''
    - What's your name?: {name}
    - When were you born?: {birthday}
    '''
).batch(name=mo.ui.text(), birthday=mo.ui.date())

In this example, user_info is a UI Element whose output is markdown and whose value is a dict with keys 'name' and 'birthday' (and values equal to the values of their corresponding elements).

PARAMETER DESCRIPTION
elements

the UI elements to interpolate into the HTML template.

TYPE: UIElement[JSONType, object] DEFAULT: {}

callout

callout(
    kind: Literal[
        "neutral", "danger", "warn", "success", "info"
    ] = "neutral"
) -> Html

Create a callout containing this HTML element.

A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the kind argument.

Examples:

mo.md("Hooray, you did it!").callout(kind="success")
mo.md("It's dangerous to go alone!").callout(kind="warn")

center

center() -> Html

Center an item.

Example
mo.md("# Hello, world").center()
RETURNS DESCRIPTION
Html

An Html object.

form

form(
    label: str = "",
    *,
    bordered: bool = True,
    loading: bool = False,
    submit_button_label: str = "Submit",
    submit_button_tooltip: Optional[str] = None,
    submit_button_disabled: bool = False,
    clear_on_submit: bool = False,
    show_clear_button: bool = False,
    clear_button_label: str = "Clear",
    clear_button_tooltip: Optional[str] = None,
    validate: Optional[
        Callable[[Optional[JSONType]], Optional[str]]
    ] = None,
    on_change: Optional[
        Callable[[Optional[T]], None]
    ] = None
) -> form[S, T]

Create a submittable form out of this UIElement.

Creates a form that gates submission of a UIElement's value until a submit button is clicked. The form's value is the value of the underlying element from the last submission.

Examples:

Convert any UIElement into a form:

prompt = mo.ui.text_area().form()

Combine with HTML.batch to create a form made out of multiple UIElements:

form = (
    mo.ui.md(
        '''
    **Enter your prompt.**

    {prompt}

    **Choose a random seed.**

    {seed}
    '''
    )
    .batch(
        prompt=mo.ui.text_area(),
        seed=mo.ui.number(),
    )
    .form()
)

PARAMETER DESCRIPTION
label

A text label for the form.

TYPE: str DEFAULT: ''

bordered

Whether the form should have a border.

TYPE: bool DEFAULT: True

loading

Whether the form should be in a loading state.

TYPE: bool DEFAULT: False

submit_button_label

The label of the submit button.

TYPE: str DEFAULT: 'Submit'

submit_button_tooltip

The tooltip of the submit button.

TYPE: Optional[str] DEFAULT: None

submit_button_disabled

Whether the submit button should be disabled.

TYPE: bool DEFAULT: False

clear_on_submit

Whether the form should clear its contents after submitting.

TYPE: bool DEFAULT: False

show_clear_button

Whether the form should show a clear button.

TYPE: bool DEFAULT: False

clear_button_label

The label of the clear button.

TYPE: str DEFAULT: 'Clear'

clear_button_tooltip

The tooltip of the clear button.

TYPE: Optional[str] DEFAULT: None

validate

A function that takes the form's value and returns an error message if invalid, or None if valid.

TYPE: Optional[Callable[[Optional[JSONType]], Optional[str]]] DEFAULT: None

on_change

A callback that takes the form's value and returns an error message if invalid, or None if valid.

TYPE: Optional[Callable[[Optional[T]], None]] DEFAULT: None

left

left() -> Html

Left-justify.

Example
mo.md("# Hello, world").left()
RETURNS DESCRIPTION
Html

An Html object.

right

right() -> Html

Right-justify.

Example
mo.md("# Hello, world").right()
RETURNS DESCRIPTION
Html

An Html object.

send_message

send_message(
    message: Dict[str, object],
    buffers: Optional[Sequence[bytes]],
) -> None

Send a message to the element rendered on the frontend from the backend.

style

style(
    style: Optional[dict[str, Any]] = None, **kwargs: Any
) -> Html

Wrap an object in a styled container.

Example
mo.md("...").style({"max-height": "300px", "overflow": "auto"})
mo.md("...").style(max_height="300px", overflow="auto")
PARAMETER DESCRIPTION
style

an optional dict of CSS styles, keyed by property name

TYPE: Optional[dict[str, Any]] DEFAULT: None

**kwargs

CSS styles as keyword arguments

TYPE: Any DEFAULT: {}

Performance and Data Transformers

Altair has a concept of data transformers, which can be used to improve performance.

Such examples are:

  • pandas Dataframe has to be sanitized and serialized to JSON.
  • The rows of a Dataframe might need to be sampled or limited to a maximum number.
  • The Dataframe might be written to a .csv or .json file for performance reasons.

By default, Altair uses the default data transformer, which is the slowest in marimo. It is limited to 5000 rows (although we increase this to 20_000 rows as marimo can handle this). This includes the data inside the HTML that is being sent over the network, which can also be limited by marimo's maximum message size.

It is recommended to use the marimo_csv data transformer, which is the most performant and can handle the largest datasets: it converts the data to a CSV file which is smaller and can be sent over the network. This can handle up to +400,000 rows with no issues.

When using mo.ui.altair_chart, we automatically set the data transformer to marimo_csv for you. If you are using Altair directly, you can set the data transformer using the following code:

import altair as alt
alt.data_transformers.enable('marimo_csv')

Reactive plots with Plotly

mo.ui.plotly only supports scatter plots, treemaps charts, and sunbursts charts.

marimo can render any Plotly plot, but mo.ui.plotly only supports reactive selections for scatter plots, treemaps charts, and sunbursts charts. If you require other kinds of selection, consider using mo.ui.altair_chart.

marimo.ui.plotly

plotly(
    figure: Figure,
    config: Optional[Dict[str, Any]] = None,
    renderer_name: Optional[str] = None,
    *,
    label: str = "",
    on_change: Optional[Callable[[JSONType], None]] = None
)

Bases: UIElement[PlotlySelection, List[Dict[str, Any]]]

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!

This function currently only supports scatter plots, treemaps charts, and sunbursts charts.

Examples:

import plotly.express as px
import marimo as mo
from vega_datasets import data

_plot = px.scatter(
    data.cars(), 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(
    _plot,
    config={"staticPlot": True},
)
ATTRIBUTE DESCRIPTION
value

A dict of the plot data.

TYPE: Dict[str, Any]

ranges

The selection of the plot; this may be an interval along the name of an axis.

TYPE: Dict[str, List[float]]

points

The selected points data.

TYPE: List[Dict[str, Any]]

indices

The indices of selected points.

TYPE: List[int]

PARAMETER DESCRIPTION
figure

A plotly Figure object.

TYPE: Figure

config

Configuration for the plot. This is a dictionary that is passed directly to plotly. See the plotly documentation for more information: https://plotly.com/javascript/configuration-options/ This takes precedence over the default configuration of the renderer. Defaults to None.

TYPE: Optional[Dict[str, Any]] DEFAULT: None

renderer_name

Renderer to use for the plot. If this is not provided, the default renderer (pio.renderers.default) is used. Defaults to None.

TYPE: Optional[str] DEFAULT: None

label

Markdown label for the element. Defaults to "".

TYPE: str DEFAULT: ''

on_change

Callback to run when this element's value changes. Defaults to None.

TYPE: Optional[Callable[[JSONType], None]] DEFAULT: None

indices property

indices: List[int]

Get the indices of selected points in the plot.

RETURNS DESCRIPTION
List[int]

List[int]: A list of indices corresponding to the selected points. Returns an empty list if no points are selected.

name class-attribute instance-attribute

name: Final[str] = 'marimo-plotly'

points property

points: List[Dict[str, Any]]

Get the selected points data from the plot.

RETURNS DESCRIPTION
List[Dict[str, Any]]

List[Dict[str, Any]]: A list of dictionaries containing the data for each selected point. Returns an empty list if no points are selected.

ranges property

ranges: Dict[str, List[float]]

Get the range selection of the plot.

RETURNS DESCRIPTION
Dict[str, List[float]]

Dict[str, List[float]]: A dictionary mapping field names to their selected ranges, where each range is a list of [min, max] values. Returns an empty dict if no range selection exists.

text property

text: str

A string of HTML representing this element.

value property writable

value: T

The element's current value.

batch

batch(**elements: UIElement[JSONType, object]) -> batch

Convert an HTML object with templated text into a UI element.

This method lets you create custom UI elements that are represented by arbitrary HTML.

Example
user_info = mo.md(
    '''
    - What's your name?: {name}
    - When were you born?: {birthday}
    '''
).batch(name=mo.ui.text(), birthday=mo.ui.date())

In this example, user_info is a UI Element whose output is markdown and whose value is a dict with keys 'name' and 'birthday' (and values equal to the values of their corresponding elements).

PARAMETER DESCRIPTION
elements

the UI elements to interpolate into the HTML template.

TYPE: UIElement[JSONType, object] DEFAULT: {}

callout

callout(
    kind: Literal[
        "neutral", "danger", "warn", "success", "info"
    ] = "neutral"
) -> Html

Create a callout containing this HTML element.

A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the kind argument.

Examples:

mo.md("Hooray, you did it!").callout(kind="success")
mo.md("It's dangerous to go alone!").callout(kind="warn")

center

center() -> Html

Center an item.

Example
mo.md("# Hello, world").center()
RETURNS DESCRIPTION
Html

An Html object.

form

form(
    label: str = "",
    *,
    bordered: bool = True,
    loading: bool = False,
    submit_button_label: str = "Submit",
    submit_button_tooltip: Optional[str] = None,
    submit_button_disabled: bool = False,
    clear_on_submit: bool = False,
    show_clear_button: bool = False,
    clear_button_label: str = "Clear",
    clear_button_tooltip: Optional[str] = None,
    validate: Optional[
        Callable[[Optional[JSONType]], Optional[str]]
    ] = None,
    on_change: Optional[
        Callable[[Optional[T]], None]
    ] = None
) -> form[S, T]

Create a submittable form out of this UIElement.

Creates a form that gates submission of a UIElement's value until a submit button is clicked. The form's value is the value of the underlying element from the last submission.

Examples:

Convert any UIElement into a form:

prompt = mo.ui.text_area().form()

Combine with HTML.batch to create a form made out of multiple UIElements:

form = (
    mo.ui.md(
        '''
    **Enter your prompt.**

    {prompt}

    **Choose a random seed.**

    {seed}
    '''
    )
    .batch(
        prompt=mo.ui.text_area(),
        seed=mo.ui.number(),
    )
    .form()
)

PARAMETER DESCRIPTION
label

A text label for the form.

TYPE: str DEFAULT: ''

bordered

Whether the form should have a border.

TYPE: bool DEFAULT: True

loading

Whether the form should be in a loading state.

TYPE: bool DEFAULT: False

submit_button_label

The label of the submit button.

TYPE: str DEFAULT: 'Submit'

submit_button_tooltip

The tooltip of the submit button.

TYPE: Optional[str] DEFAULT: None

submit_button_disabled

Whether the submit button should be disabled.

TYPE: bool DEFAULT: False

clear_on_submit

Whether the form should clear its contents after submitting.

TYPE: bool DEFAULT: False

show_clear_button

Whether the form should show a clear button.

TYPE: bool DEFAULT: False

clear_button_label

The label of the clear button.

TYPE: str DEFAULT: 'Clear'

clear_button_tooltip

The tooltip of the clear button.

TYPE: Optional[str] DEFAULT: None

validate

A function that takes the form's value and returns an error message if invalid, or None if valid.

TYPE: Optional[Callable[[Optional[JSONType]], Optional[str]]] DEFAULT: None

on_change

A callback that takes the form's value and returns an error message if invalid, or None if valid.

TYPE: Optional[Callable[[Optional[T]], None]] DEFAULT: None

left

left() -> Html

Left-justify.

Example
mo.md("# Hello, world").left()
RETURNS DESCRIPTION
Html

An Html object.

right

right() -> Html

Right-justify.

Example
mo.md("# Hello, world").right()
RETURNS DESCRIPTION
Html

An Html object.

send_message

send_message(
    message: Dict[str, object],
    buffers: Optional[Sequence[bytes]],
) -> None

Send a message to the element rendered on the frontend from the backend.

style

style(
    style: Optional[dict[str, Any]] = None, **kwargs: Any
) -> Html

Wrap an object in a styled container.

Example
mo.md("...").style({"max-height": "300px", "overflow": "auto"})
mo.md("...").style(max_height="300px", overflow="auto")
PARAMETER DESCRIPTION
style

an optional dict of CSS styles, keyed by property name

TYPE: Optional[dict[str, Any]] DEFAULT: None

**kwargs

CSS styles as keyword arguments

TYPE: Any DEFAULT: {}

Interactive matplotlib

marimo.mpl.interactive

interactive(figure: Union[Figure, SubFigure, Axes]) -> Html

Render a matplotlib figure using an interactive viewer.

The interactive viewer allows you to pan, zoom, and see plot coordinates on mouse hover.

Example
plt.plot([1, 2])
# plt.gcf() gets the current figure
mo.mpl.interactive(plt.gcf())
PARAMETER DESCRIPTION
figure

A matplotlib Figure or Axes object.

TYPE: matplotlib Figure or Axes

RETURNS DESCRIPTION
Html

An interactive matplotlib figure as an Html object.

TYPE: Html

Source code in marimo/_plugins/stateless/mpl/_mpl.py
@mddoc
def interactive(figure: Union[Figure, SubFigure, Axes]) -> Html:
    """Render a matplotlib figure using an interactive viewer.

    The interactive viewer allows you to pan, zoom, and see plot coordinates
    on mouse hover.

    Example:
        ```python
        plt.plot([1, 2])
        # plt.gcf() gets the current figure
        mo.mpl.interactive(plt.gcf())
        ```

    Args:
        figure (matplotlib Figure or Axes): A matplotlib `Figure` or `Axes` object.

    Returns:
        Html: An interactive matplotlib figure as an `Html` object.
    """
    # We can't support interactive plots in Pyodide
    # since they require a WebSocket connection
    if is_pyodide():
        LOGGER.error(
            "Interactive plots are not supported in Pyodide/WebAssembly"
        )
        return as_html(figure)

    # No top-level imports of matplotlib, since it isn't a required
    # dependency
    from matplotlib.axes import Axes

    if isinstance(figure, Axes):
        maybe_figure = figure.get_figure()
        assert maybe_figure is not None, "Axes object does not have a Figure"
        figure = maybe_figure

    ctx = get_context()
    if not isinstance(ctx, KernelRuntimeContext):
        return as_html(figure)

    # Figure Manager, Any type because matplotlib doesn't have typings
    figure_manager = new_figure_manager_given_figure(id(figure), figure)

    # TODO(akshayka): Proxy this server through the marimo server to help with
    # deployment.
    app = get_or_create_application()
    port = app.state.port

    class CleanupHandle(CellLifecycleItem):
        def create(self, context: RuntimeContext) -> None:
            del context

        def dispose(self, context: RuntimeContext, deletion: bool) -> bool:
            del context
            del deletion
            figure_managers.remove(figure_manager)
            return True

    figure_managers.add(figure_manager)
    assert ctx.execution_context is not None
    ctx.cell_lifecycle_registry.add(CleanupHandle())
    ctx.stream.cell_id = ctx.execution_context.cell_id

    content = _template(str(figure_manager.num), port)

    return Html(
        h.iframe(
            srcdoc=html.escape(content),
            width="100%",
            height="550px",
            onload="__resizeIframe(this)",
        )
    )

Leafmap support

marimo supports rendering Leafmap maps using the folium and plotly backends.

Other plotting libraries

You can use all the popular plotting libraries with marimo. Such as: