import dash
import json
from dash import dcc, html, ctx
from dash.dependencies import Input, Output, State
import plotly.express as px
import pandas as pd
# Sample data
df = px.data.iris()
# Initialize the app
app = dash.Dash(__name__, suppress_callback_exceptions=True)
# Define the layout of the app
app.layout = html.Div(children=[
html.H1(children='Dash App with a Graph and Filter'),
# Dropdown filter
dcc.Dropdown(
id='variable-dropdown',
options=["setosa", "virginica", "versicolor"],
multi=False,
value="setosa"
),
html.Div([
# Source interaction
html.Div([
dcc.Store(id="store_1", data=0),
dcc.Graph(
id="graph_1",
figure=px.scatter(df, x="sepal_length", y="petal_length", color="species", custom_data="species", title="Source interaction refreshed 0 times"),
),
], style={"flex": "2"}),
# JSON output container
html.Div([
html.H4("clickData Output"),
html.Pre(id="json_clickData_output", style={
"whiteSpace": "pre-wrap",
"wordBreak": "break-word",
"background": "#f8f8f8",
"padding": "10px",
"border": "1px solid #ccc",
"borderRadius": "5px",
"height": "300px",
"overflowY": "scroll"
})
], style={"flex": "1", "paddingLeft": "20px"}),
html.Div([
html.H4("selectedData Output"),
html.Pre(id="json_selectedData_output", style={
"whiteSpace": "pre-wrap",
"wordBreak": "break-word",
"background": "#f8f8f8",
"padding": "10px",
"border": "1px solid #ccc",
"borderRadius": "5px",
"height": "300px",
"overflowY": "scroll"
})
], style={"flex": "1", "paddingLeft": "20px"}),
], style={
"display": "flex",
"flexDirection": "row",
"alignItems": "flex-start",
"marginBottom": "30px"
}),
html.Div([
# clickData target
dcc.Store(id="store_2", data=0),
dcc.Graph(
id="graph_2",
figure=px.scatter(df, x="sepal_length", y="petal_length", color="species", title="clickData target refreshed 0 times"),
),
# selectedData target
dcc.Store(id="store_3", data=0),
dcc.Graph(
id="graph_3",
figure=px.scatter(df, x="sepal_length", y="petal_length", color="species", title="selectedData targetc refreshed 0 times"),
)
],
style={
"display": "flex",
"flexDirection": "row",
"justifyContent": "space-between",
"alignItems": "center"
})
])
@app.callback(
Output('graph_1', 'figure'),
Output('store_1', 'data'),
Input('variable-dropdown', 'value'),
State('store_1', 'data'),
prevent_callback_call=True,
)
def update_graph_1(selected_variable, store):
if not ctx.triggered_id:
raise dash.exceptions.PreventUpdate
filtered_df = df[df['species'] == selected_variable]
fig = px.scatter(filtered_df, x="sepal_length", y="petal_length", color="species", custom_data="species", title=f"Source interaction refreshed {store + 1} times")
return fig, store + 1
@app.callback(
Output('json_clickData_output', 'children'),
Output('json_selectedData_output', 'children'),
Input('graph_1', 'clickData'),
Input('graph_1', 'selectedData'),
)
def display_click_selected_data(click_data, selected_data):
return json.dumps(click_data, indent=2), json.dumps(selected_data, indent=2)
@app.callback(
Output('graph_2', 'figure'),
Output('store_2', 'data'),
Input('graph_1', 'clickData'),
State('store_2', 'data'),
prevent_callback_call=True,
)
def update_graph_2(click_data, store):
if not ctx.triggered_id:
raise dash.exceptions.PreventUpdate
if click_data:
clicked_point = click_data['points'][0]['customdata'][0]
filtered_df = df[df['species'].isin([clicked_point])]
else:
filtered_df = df
fig = px.scatter(filtered_df, x="sepal_width", y="petal_width", color="species", title=f"clickData target refreshed {store + 1} times")
return fig, store + 1
@app.callback(
Output('graph_3', 'figure'),
Output('store_3', 'data'),
Input('graph_1', 'selectedData'),
State('store_3', 'data'),
prevent_callback_call=True,
)
def update_graph_2(selected_data, store):
if not ctx.triggered_id:
raise dash.exceptions.PreventUpdate
if selected_data:
selected_points = [point['customdata'][0] for point in selected_data['points']]
filtered_df = df[df['species'].isin(selected_points)]
else:
filtered_df = df
fig = px.scatter(filtered_df, x="sepal_width", y="petal_width", color="species", title=f"selectedData target refreshed {store + 1} times")
return fig, store + 1
# Run the app
app.run(debug=True)