For AI agents: the complete documentation index is at llms.txt. Remove the trailing slash from a page URL and append .md to read its Markdown version. For the docs home, use index.md.

Build a pandas data app

Use Reflex to turn pandas analysis into a shareable Python web app with a custom interface. This example uploads a CSV, filters its records, groups units by region, and downloads the filtered summary. Summary cards, an XY bar chart, and a table update together from the filtered data. The parsing and analysis functions remain ordinary Python functions.

Try the live sample below: select a region or search for a product, then apply the filters to update the cards, chart, and table. The complete app runs locally without a database or API key. CSV uploads run in your own app; the embedded preview uses sample data.

Set up the app

Create a blank app using the installation guide, then install pandas and XY with Python 3.11 or newer:

uv add pandas "xy[reflex]==0.0.7"

Register the XY plugin in rxconfig.py, keeping your app's existing name and other plugins:

import reflex as rx
import reflex_xy as rxy

config = rx.Config(
    app_name="pandas_data",
    plugins=[rxy.XYPlugin()],
)

The CSV must contain exactly region,product,units in that order. Regions are North, South, East, or West. Products are nonempty text up to 80 characters, and units are whole numbers from 0 to 1,000,000. Files must be UTF-8, at most 2 MiB, and contain 1–10,000 records.

Save this as orders.csv to try uploading:

region,product,units
North,Tea,12
South,Coffee,7
North,Coffee,5
West,Tea,9

Copy the complete example

Paste this code into your app module. It shows at most 50 matching records in the browser; the summary and download include all matching records within the upload limit.

Start Building Now!

Interactive preview loads as you scroll.

Register the page at the app root:

app = rx.App()
app.add_page(pandas_data_app, route="/")

Run uv run reflex run. Select Use sample data: the cards show four matching records and 33 units; the chart shows North 17, South 7, and West 9. Filter for North and Tea: one record totals 12 units. Download the summary to get North,12. A search with no matches shows the chart's empty state, clears the table, and disables download. Uploading an invalid CSV clears the previous dataset and shows an error; a valid upload or the sample button lets you recover.

Where pandas runs

read_orders parses and validates the upload on the backend. Parsing runs in a worker thread; the upload handler shows progress before awaiting it. analyze_orders uses a pandas DataFrame for literal text filtering and groupby aggregation. The filter form sends one event on submission, so typing does not repeatedly run the analysis.

The full validated dataset stays in _orders, a backend-only state variable. Only a preview of 50 matching rows, four possible region totals, and counts are sent as frontend state. The XY chart reads those complete regional totals through region_data; it never sums just the 50-row preview. cache=False keeps this tiny chart dataset current after filtering and hydration. The download contains those complete regional totals, not just totals from the preview. Each browser session has its own uploaded records; this is not shared durable storage.

Adapt it to your data

Replace the schema, validation, and analysis functions for your dataset. Keep the preview bounded and make clear whether a download contains raw records or aggregates. If you export user-controlled text to a spreadsheet, handle formula interpretation in your export policy.

This tutorial deliberately bounds the in-memory workload. For larger datasets, query and aggregate at the data source and use server-side pagination or a worker service. Set request-size limits at the server or proxy too: the handler's bounded read occurs after the upload reaches the endpoint. Original files are not written into the public upload directory.

To make a chart selection filter another chart and table, continue with linked XY charts. For saved records and access-controlled workflows, read dashboards and internal tools. Use performance and execution to measure parsing, filtering, and browser updates separately.