Is there any way that two separate browser window can show the same graph and be connected if we change the data ? Like if, in the code below, we change the value of the dropdown on the main window, then the graph in the popup window must change its data accordingly. I would have thought that with a dcc.Interval
component it would work and a shared dcc.Store
in the session memory, but it doesn’t seem to. Maybe this isn’t possible ?
import dash
from dash import dcc, html, Input, Output, State
import plotly.express as px
import plotly.graph_objects as go
df_iris = px.data.iris()
df_tips = px.data.tips()
datasets = {
"iris": df_iris,
"tips": df_tips,
}
def get_figure(dataset):
"""
Returns the Plotly figure for the chosen dataset
"""
df = datasets.get(dataset, df_iris)
if dataset == "iris":
fig = go.Figure()
for specie in df["species"].unique():
df_specie = df[df["species"] == specie]
fig.add_trace(
go.Scatter(
x=df_specie["sepal_length"],
y=df_specie["sepal_width"],
mode="markers",
name=specie,
)
)
fig.update_layout(
title="Iris data",
xaxis_title="Sepal lenght",
yaxis_title="Sepal width",
)
elif dataset == "tips":
fig = go.Figure()
for sex in df["sex"].unique():
df_sex = df[df["sex"] == sex]
fig.add_trace(
go.Scatter(
x=df_sex["total_bill"],
y=df_sex["tip"],
mode="markers",
name=sex,
)
)
fig.update_layout(
title="Tips data",
xaxis_title="Total bill",
yaxis_title="Tip",
)
else:
fig = go.Figure(
go.Scatter(
x=df.iloc[:, 0],
y=df.iloc[:, 1],
mode="markers",
)
)
fig.update_layout(title="Default graph")
return fig
app = dash.Dash(__name__)
app.config['suppress_callback_exceptions'] = True
app.update_title = "Loading..."
app.layout = html.Div(
[
dcc.Location(id='url', refresh=False),
dcc.Store(id='current-dataset', data='iris', storage_type='session'),
html.Div(id='page-content')
]
)
main_layout = html.Div(
[
html.H1("App test"),
dcc.Dropdown(
id='dataset-dropdown',
options=[
{'label': 'Iris', 'value': 'iris'},
{'label': 'Tips', 'value': 'tips'},
],
value='iris'
),
html.Br(),
html.Button("Open graph window", id="popup-button"),
html.Div(id="dummy-output"),
dcc.Graph(id="graph"),
]
)
popup_layout = html.Div(
[
html.H1("Popup graph"),
dcc.Interval(id="interval-popup", interval=1000, disabled=False),
dcc.Graph(id="graph-popup"),
]
)
@app.callback(
Output('page-content', 'children'),
Input('url', 'pathname'),
)
def display_page(pathname):
if pathname == '/popup':
return popup_layout
else:
return main_layout
@app.callback(
Output('graph', 'figure'),
Output('current-dataset', 'data'),
Input('dataset-dropdown', 'value'),
)
def update_graph_main(selected_dataset):
return get_figure(selected_dataset), selected_dataset
@app.callback(
Output('graph-popup', 'figure'),
Input('interval-popup', 'n_intervals'),
State('current-dataset', 'data'),
)
def update_graph_popup(n, current_dataset):
print("Updating...")
return get_figure(current_dataset)
app.clientside_callback(
"""
function(n_clicks) {
if (n_clicks) {
window.open("/popup", "PopupGraph", "width=600,height=400");
}
return "";
}
""",
Output("dummy-output", "children"),
Input("popup-button", "n_clicks"),
)
if __name__ == '__main__':
app.run_server(debug=True)