Reactive Data Analysis: Creating Interactive Dashboards with Marimo and Python
Traditional Python notebooks are excellent for data exploration, but they often become unwieldy as projects grow. Cells frequently execute in the wrong order, results fall out of sync, and transforming a static analysis into an interactive tool usually requires rebuilding the entire workflow in a separate framework.
Marimo offers a fundamentally different approach. As an open-source reactive Python notebook, it automatically updates cells whenever their dependencies change. Even more importantly, Marimo saves your work as a standard Python script rather than a complex JSON file. This architectural choice makes notebooks incredibly easy to version with Git, reproduce, and share without worrying about state mismatches.
In this guide, we will walk through building a complete interactive data analysis dashboard using Marimo, Pandas, and Altair. We will generate a dataset, add interactive filters, connect them to dynamic calculations, build a visualization, and finally deploy the same file as a read-only web application.
Getting Started with Installation
To begin, install Marimo alongside the libraries required for our analysis:
“`bash
pip install marimo pandas altair
“`
You can also use `uv` or `Conda` to set up your environment. Additionally, there is a `marimo[recommended]` installation bundle that includes useful data tools like DuckDB, Polars, and Altair.
Once installed, create your first notebook with the following command:
“`bash
python -m marimo edit analysis.py
“`
This launches the Marimo editor directly in your browser. One immediate benefit is that, unlike the `.ipynb` format used by older tools, Marimo stores your notebook as a normal `.py` file. This means your interactive workspace is also clean, executable Python code from the very start.
Building the Dataset
Let’s create a realistic sales dataset to use throughout the tutorial. We will generate records for various products across different regions and quarters, calculating units sold, unit pricing, and total revenue.
“`python
import altair as alt
import numpy as np
import pandas as pd
import marimo as mo
rng = np.random.default_rng(42)
products = [
(“Laptop”, “Tech”, 800, 1500),
(“Phone”, “Tech”, 500, 1200),
(“Tablet”, “Tech”, 250, 800),
(“Monitor”, “Tech”, 150, 600),
(“Keyboard”, “Accessories”, 30, 150),
(“Mouse”, “Accessories”, 15, 90),
(“Headphones”, “Accessories”, 50, 400),
(“Webcam”, “Accessories”, 40, 250),
]
regions = [“US”, “Europe”, “Asia”]
region_scale = {“US”: 1.0, “Europe”: 0.75, “Asia”: 0.55}
quarters = [“Q1”, “Q2”, “Q3”, “Q4”]
rows = []
for _quarter in quarters:
for _region in regions:
for _name, _category, _lo, _hi in products:
units_sold = int(
rng.integers(_lo, _hi) * region_scale[_region] * rng.uniform(0.7, 1.3)
)
unit_price = round(rng.uniform(_lo, _hi) / 8, 2)
rows.append(
{
“product”: _name,
“category”: _category,
“region”: _region,
“quarter”: _quarter,
“units_sold”: units_sold,
“unit_price”: unit_price,
“revenue”: round(units_sold * unit_price, 2),
}
)
df = pd.DataFrame(rows)
df
“`
A standout feature of Marimo is how effortlessly it handles data inspection. By simply placing the dataframe at the end of a cell, Marimo renders it as an interactive table complete with search, sort, and filter capabilities. Furthermore, this rendering works with both Pandas and Polars, allowing you to use your preferred DataFrame library without any extra configuration.
Implementing Interactive Controls
To make our dashboard dynamic, we need to introduce UI elements. Let us add a dropdown menu for selecting a specific region and a slider for setting a minimum sales threshold:
“`python
region = mo.ui.dropdown(
options=[“All”] + sorted(df[“region”].unique().tolist()),
value=”All”,
label=”Region”,
)
min_sales = mo.ui.slider(
start=0,
stop=int(df[“units_sold”].max()),
value=0,
label=”Minimum units sold”,
)
mo.hstack([region, min_sales])
“`
Marimo comes equipped with a variety of built-in UI components, including checkboxes, date pickers, file uploaders, and text inputs, making it simple to customize any interactive experience.
Reactive Data Filtering
Now we can connect our controls to the dataset. When the user adjusts the dropdown or slider, the data should automatically filter without any manual reruns:
“`python
filtered_df = df[df[“units_sold”] >= min_sales.value]
if region.value != “All”:
filtered_df = filtered_df[
filtered_df[“region”] == region.value
]
mo.ui.table(filtered_df)
“`
This is where Marimo’s reactive engine truly shines. You do not need to manually rerun the cell. Marimo understands that `filtered_df` depends on the `region` and `min_sales` components, so it automatically reruns the affected logic whenever those inputs change.
Visualizing the Data
With our filtered data ready, we can visualize the results using Altair:
“`python
chart = (
alt.Chart(filtered_df)
.mark_bar()
.encode(
x=”product:N”,
y=”units_sold:Q”,
color=”region:N”,
tooltip=[“product”, “region”, “quarter”, “units_sold”, “revenue”],
)
.properties(width=600, height=350)
)
chart
“`
As you adjust the controls, both the data table and the bar chart update simultaneously. Marimo integrates seamlessly with popular visualization libraries such as Matplotlib, Plotly, Seaborn, and HoloViews. It also supports passing selections from supported charts back into Python, enabling the creation of much more sophisticated, interactive analysis workflows.
Deploying the Notebook as an Application
One of the most powerful features of Marimo is the ability to transform the same notebook into an interactive application. From your terminal, simply run:
“`bash
python -m marimo run analysis.py
“`
Marimo launches the notebook in app mode, hiding the editable Python code and presenting a clean, read-only interface. This means you can use a single file for both exploring your data during development and sharing it as a polished dashboard or interactive application, completely bypassing the need to rebuild your analysis using a separate web framework.
Conclusion
Marimo successfully bridges the gap between exploratory data analysis and polished, shareable applications. By handling execution order automatically, storing work as plain Python scripts, and offering native interactive components, it eliminates the friction inherent in traditional notebook environments. You get a clean, local, and Git-friendly workflow that transforms raw data into interactive presentations without the overhead of managing multiple frameworks. For anyone looking to streamline their data science workflow, Marimo provides a remarkably simple, out-of-the-box solution.
FAQ
Q: How does Marimo handle execution order compared to traditional notebooks?
A: Unlike traditional notebooks where cells can be run out of sequence, Marimo is fully reactive. It maps dependencies between variables and automatically reruns any affected cells whenever an input or UI component changes, ensuring results are never out of sync.
Q: Can I use Polars instead of Pandas with Marimo?
A: Yes, Marimo natively supports both Pandas and Polars DataFrames. You can render interactive tables and perform analysis using either library without modifying your workflow.
Q: Do I need to install a separate web framework like Streamlit or Dash to create an app?
A: No. Marimo includes a built-in application runner (`marimo run`). It converts your notebook into a web-based, read-only dashboard automatically, removing the need for extra dependencies or separate dashboard frameworks.
Q: Which charting libraries are compatible with Marimo?
A: Marimo works with Altair, Matplotlib, Plotly, Seaborn, and HoloViews. It can also pass user selections from these charts back into Python code for deeper interactivity.
Q: Is Marimo suitable for team collaboration?
A: Absolutely. Because Marimo notebooks are standard `.py` files, they integrate seamlessly with Git and standard code review workflows. You can share the file directly, and teammates can run it locally without worrying about hidden cell states or execution orders.
Thank you for reading



