marimo provides powerful interactive dataframe components that let you explore, filter, sort, and transform your data directly in the UI.
Supported Libraries
marimo supports multiple dataframe libraries:
- pandas - The most popular Python data analysis library
- polars - High-performance DataFrame library
- pyarrow - Apache Arrow in Python
- ibis - Unified interface for SQL and dataframes
- DuckDB - In-process SQL database
All dataframe operations use narwhals under the hood for efficient, library-agnostic transformations.
Basic Usage
import marimo as mo
import pandas as pd
df = pd.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35],
"city": ["NYC", "SF", "LA"]
})
mo.ui.dataframe(df)
The mo.ui.dataframe component allows users to apply transformations through the UI:
Click the filter icon to add conditions:
Comparison operators: ==, !=, <, >, <=, >=
String operations: contains, starts_with, ends_with, regex
Null checks: is_null, is_not_null
Set operations: in, not_in
Click column headers to sort ascending or descending, with control over NA position.
Choose which columns to display using the column selector.
Group by columns and apply aggregations:
count, sum, mean, median, min, max
Rename columns - Change column names
Convert types - Change data types with error handling
Sample rows - Random sampling with or without replacement
Shuffle rows - Randomize row order
Remove duplicates - Keep first, last, or no duplicates
import marimo as mo
import pandas as pd
df = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
df_widget = mo.ui.dataframe(df)
In another cell:
# Access the transformed dataframe
transformed_df = df_widget.value
# The transformed data is in the same format as the input
type(transformed_df) # pandas.DataFrame
Configuration Options
mo.ui.dataframe(
df,
page_size=10, # Rows per page
show_download=True, # Show download button
lazy=False, # Apply transforms immediately
limit=10000, # Load limit for remote data
format_mapping={ # Format specific columns
"price": "${:.2f}".format,
"percentage": lambda x: f"{x*100:.1f}%"
}
)
Customize how values are displayed:
import marimo as mo
import pandas as pd
def format_name(name):
return name.upper()
df = pd.DataFrame({
"name": ["alice", "bob"],
"score": [95.5, 87.3]
})
mo.ui.dataframe(
df,
format_mapping={
"name": format_name,
"score": "{:.1f}".format
}
)
Lazy Evaluation
For large datasets or lazy dataframes (Polars LazyFrame, Ibis), marimo automatically enables lazy mode:
import polars as pl
import marimo as mo
# LazyFrame - transformations build a query plan
lazy_df = pl.scan_csv("large_file.csv")
# Lazy mode enabled automatically
mo.ui.dataframe(lazy_df)
With lazy mode, an “Apply” button appears - transformations are only executed when clicked.
Export Options
Users can download transformed data in multiple formats:
- CSV - With configurable encoding and separator
- JSON - With ASCII encoding option
- Parquet - Efficient columnar format
mo.ui.dataframe(
df,
download_csv_encoding="utf-8-sig", # Include BOM for Excel
download_csv_separator=";", # Use semicolon
download_json_ensure_ascii=True # Escape non-ASCII
)
Code Generation
marimo can generate Python code for the transformations applied in the UI:
df_widget = mo.ui.dataframe(df)
# After applying transformations in the UI
transformed = df_widget.value
# Get the equivalent Python code
# This is available internally and shown in the UI
Transformations are reactive - when you apply filters or sorts in the UI, df_widget.value automatically updates in dependent cells.
Selection and Tables
For row/cell selection without transformations, use mo.ui.table instead:
table = mo.ui.table(
df,
selection="multi", # or "single", "single-cell", "multi-cell"
pagination=True
)
# Access selected rows
selected = table.value
See the Tables guide for more details.
For DataFrames with more than 100,000 rows, lazy mode is automatically enabled to prevent loading all data into memory.
- Use
limit parameter for remote/lazy data sources
- Enable
lazy=True for expensive transformations
- Consider Polars LazyFrame for very large datasets
- Use
page_size to control initial rendering cost
Example: Complete Workflow
import marimo as mo
import pandas as pd
# Create sample data
df = pd.DataFrame({
"product": ["A", "B", "C", "A", "B"],
"sales": [100, 150, 200, 120, 180],
"region": ["North", "South", "North", "South", "North"],
"date": pd.date_range("2024-01-01", periods=5)
})
# Create interactive dataframe
df_widget = mo.ui.dataframe(
df,
page_size=5,
format_mapping={
"sales": "${:,.0f}".format
}
)
In another cell:
# Use transformed data for analysis
filtered_df = df_widget.value
# The dataframe reflects all UI transformations
mo.md(f"""
## Analysis Results
Total Sales: ${filtered_df['sales'].sum():,.0f}
Average: ${filtered_df['sales'].mean():,.2f}
""")