Interactive Scatter Plot with Dash: Dropdown Filtering Guide
Create a Plotly Dash app that lets users filter a scatter plot via a dropdown. Follow our step‑by‑step guide, checklists, and recovery tips to build, debug, and deploy the app.
15 Nov 2025, 07:47 UTC

Desired Outcome
Build a self‑contained Dash application where a user can pick a category from a dcc.Dropdown and the scatter plot updates to show only points from that category. The app should run locally on http://127.0.0.1:8050/ and be ready for simple deployment.
Prerequisites
- Python 3.10 or newer.
- Virtual environment (recommended):
python -m venv venv, thensource venv/bin/activate(Linux/macOS) orvenv\Scripts\activate(Windows). - Installed packages:
plotly>=5.0,dash>=2.0,pandas. Install withpip install plotly dash pandas. - A CSV file (or any source that can be read by
pandas.read_csv) containing at least one categorical column and two numeric columns for the x‑ and y‑axes.
Step‑by‑Step Procedure
-
Load Data
Read the data into a
pandas.DataFrame. ReplacePATH_TO_CSVwith your file path.import pandas as pd DATA_PATH = "PATH_TO_CSV" # e.g., "data/iris.csv" df = pd.read_csv(DATA_PATH) print(df.head()) # Verify columnsEnsure the categorical column (e.g.,
species) and numeric columns (e.g.,sepal_length,sepal_width) exist. -
Instantiate Dash App
import dash from dash import dcc, html app = dash.Dash(__name__) app.title = "Scatter Plot Filter" -
Build Dropdown
Create a dropdown whose options are the unique values of the categorical column. Convert to strings to avoid type mismatches.
category_col = "species" # replace with your column name options = [{"label": str(val), "value": str(val)} for val in sorted(df[category_col].unique())] dropdown = dcc.Dropdown( id="category-dropdown", options=options, value=options[0]["value"], # default selection clearable=False, style={"width": "200px"} ) -
Build Graph
Define a placeholder
dcc.Graphthat will be updated by the callback.graph = dcc.Graph(id="scatter-plot") -
Define Callback
Use
@app.callbackto link the dropdown selection to the graph figure. The callback runs on the server; heavy work should be avoided or offloaded.from dash.dependencies import Input, Output import plotly.express as px @app.callback( Output("scatter-plot", "figure"), Input("category-dropdown", "value") ) def update_figure(selected_category): filtered = df[df[category_col] == selected_category] if filtered.empty: # Avoid returning an empty figure; provide a placeholder message return { "data": [], "layout": { "title": f"No data for {selected_category}", "xaxis": {"visible": False}, "yaxis": {"visible": False} } } fig = px.scatter( filtered, x="sepal_length", # replace with your x column y="sepal_width", # replace with your y column title=f"{selected_category} samples", trendline="ols" ) return fig -
Layout and Server Run
Arrange the dropdown and graph in the app layout and start the server.
app.layout = html.Div([ html.H2("Scatter Plot Filter"), dropdown, graph ]) if __name__ == "__main__": app.run_server(debug=True)
Expected Checks
- Dropdown Options: Open the app and verify that the dropdown lists all unique values from the categorical column. The default value should match the first option.
- Callback Execution: Select each option and confirm that the console (terminal) shows no callback errors. In the browser, the graph title should update to reflect the chosen category.
- Graph Rendering: Axes labels should match the column names, and a trendline should appear if data points are sufficient. Inspect the network tab for 200 OK responses to
dash.jsanddash.css.
Recovery Options
-
Callback Errors
Common causes:
- Mismatch between component IDs in the callback and the layout. Ensure
id="category-dropdown"andid="scatter-plot"are consistent. - Missing
dash.dependenciesimports. Verifyfrom dash.dependencies import Input, Outputis present. - Data type mismatch in the filter. Convert the dropdown value and the DataFrame column to the same type (e.g., strings).
- Mismatch between component IDs in the callback and the layout. Ensure
-
Blank Graph
If the graph shows no points after a selection, print the shape of
filteredinside the callback to confirm that rows are returned. If the shape is (0, N), the filter condition is too strict or the category value is incorrect. -
App Crash on Start
Check that all required packages are installed and that you are running the script in the same virtual environment. Run
pip show plotly dash pandasto confirm versions. If a module is missing, reinstall it withpip install --upgrade package-name.
Performance Considerations
For datasets with millions of rows, client‑side filtering becomes slow. Options:
- Use server‑side pagination: store only the filtered subset in the callback and return a
go.Figurewith a limited number of points. - Cache the filtered DataFrames using
functools.lru_cacheor a dedicated caching library. - Offload heavy computations to background workers (e.g., Celery) and return a placeholder until results arrive.
Deployment Tips
- When moving to production, set
debug=Falseand consider usinggunicornoruvicornwithdash.Dash(server=True)for better performance. - Serve static assets from a CDN to reduce load times.
- Use environment variables to store secrets and data paths; avoid hard‑coding them in the script.
Final Code Example
#!/usr/bin/env python
# app.py
import pandas as pd
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px
# 1. Load data
DATA_PATH = "PATH_TO_CSV" # e.g., "data/iris.csv"
df = pd.read_csv(DATA_PATH)
# 2. Define column names
category_col = "species" # categorical column
x_col = "sepal_length"
y_col = "sepal_width"
# 3. Instantiate Dash
app = dash.Dash(__name__)
app.title = "Scatter Plot Filter"
# 4. Build components
options = [{"label": str(v), "value": str(v)} for v in sorted(df[category_col].unique())]
dropdown = dcc.Dropdown(
id="category-dropdown",
options=options,
value=options[0]["value"],
clearable=False,
style={"width": "200px"}
)
graph = dcc.Graph(id="scatter-plot")
# 5. Layout
app.layout = html.Div([
html.H2("Scatter Plot Filter"),
dropdown,
graph
])
# 6. Callback
@app.callback(
Output("scatter-plot", "figure"),
Input("category-dropdown", "value")
)
def update_figure(selected_category):
filtered = df[df[category_col] == selected_category]
if filtered.empty:
return {
"data": [],
"layout": {
"title": f"No data for {selected_category}",
"xaxis": {"visible": False},
"yaxis": {"visible": False}
}
}
fig = px.scatter(
filtered,
x=x_col,
y=y_col,
title=f"{selected_category} samples",
trendline="ols"
)
return fig
# 7. Run server
if __name__ == "__main__":
app.run_server(debug=True)
Summary
By following this guide, you can quickly create a responsive Dash application that lets users filter a scatter plot through a dropdown. The key steps are loading the data, constructing the dropdown and graph, wiring them together with a callback, and verifying that the UI updates correctly. Remember to keep performance in mind for large datasets, and test the app locally before deploying. Happy plotting!
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.