Reputation: 3296
I have a bar chart and I would like to create a Modal when I click on them. Do you know how I can handle that? I tried something but nothing appears.
I knew how to do it with a datatable. But here I have a bar chart, I added a Modal object at the end of the design but I can't make it appear despite.
Here is a minimal reproducible example:
import dash
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
from dash.dependencies import Input, Output
df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)
trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined')
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')
app = dash.Dash()
app.layout = html.Div(children=[
html.H1(children='Sales Funnel Report'),
html.Div(children='''National Sales Funnel Report.'''),
dcc.Graph(
id='graph',
figure={
'data': [trace1, trace2, trace3, trace4],
'layout':
go.Layout(title='Order Status by Customer', barmode='stack')
}),
dbc.Modal(
[
dbc.ModalHeader("Header"),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button("Close", id="close", className="ml-auto")
),
],
size="xl",
id="modal",
)
])
@app.callback(
Output('modal', 'children'),
[Input('graph', 'clickData')])
def display_click_data(clickData):
print("clickData: ", clickData)
return [
dbc.ModalHeader("Test"),
dbc.ModalBody(
html.Div([
html.Div([
html.H6('Sales', style={'textAlign': 'center', 'padding': 10}),
html.P("Bitch", id="sales_stocks", style={'textAlign': 'center', 'padding': 10})
], className='pretty_container four columns'),
html.Div([
html.H5('Current ratio', style={'textAlign': 'center', 'padding': 10})
], className='pretty_container seven columns')
])),
dbc.ModalFooter(dbc.Button("Close", id="close"))
]
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
app.run_server(debug=True)
Upvotes: 0
Views: 3405
Reputation: 41
I encountered a similar question, but conceptually the same: click on something in a plotly/dash-object and then display a modal. Researching the issue, I also found this post on the plotly forum, which encounters very similar problems. The proposed solution there gave me the idea on how to solve.
There are 2 issues at hand if I copy your code.
app = dash.Dash()
with app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
open
should be set to True
. When the button, with id=close
is pressed, the open be altered to False
.I worked your code snipped out into something working. Hope this helps you out as well!
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
# added State to be used in callbacks
from dash.dependencies import Input, Output, State
# using #type: ignore to suppress warnings in my editor (vs code).
df = pd.read_excel("https://github.com/chris1610/pbpython/blob/master/data/salesfunnel.xlsx?raw=True")
pv = pd.pivot_table(df, index=['Name'], columns=["Status"], values=['Quantity'], aggfunc=sum, fill_value=0)#type: ignore
trace1 = go.Bar(x=pv.index, y=pv[('Quantity', 'declined')], name='Declined') #type: ignore
trace2 = go.Bar(x=pv.index, y=pv[('Quantity', 'pending')], name='Pending')#type: ignore
trace3 = go.Bar(x=pv.index, y=pv[('Quantity', 'presented')], name='Presented')#type: ignore
trace4 = go.Bar(x=pv.index, y=pv[('Quantity', 'won')], name='Won')#type: ignore
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(children=[
html.H1(children='Sales Funnel Report'),
html.Div(children='''National Sales Funnel Report.'''),
dcc.Graph(
id='graph',
figure={
'data': [trace1, trace2, trace3, trace4],
'layout':
go.Layout(title='Order Status by Customer', barmode='stack')#type: ignore
}),
dbc.Button("toggle", id="open"),
dbc.Modal(
[
dbc.ModalHeader("Header",id = 'modalheader'),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button("Close", id="close", className="ml-auto")
),
],
size="xl",
id="modal",
)
])
@app.callback([Output("modal", "children"),
Output("modal", "is_open")],
[Input("graph", "clickData"),
Input("close", "n_clicks")],
[State("modal", "is_open"),
State("modal", "children")])
def set_content(value,clicked,is_open,children):
ctx = dash.callback_context
if ctx.triggered[0]['prop_id'] == 'close.n_clicks':
# you pressed the closed button, keeping the modal children as is, and
# close the model itself.
return children, False
elif ctx.triggered[0]['prop_id'] == 'graph.clickData':
# you clicked in the graph, returning the modal children and opening it
return [dbc.ModalHeader("Test"),
dbc.ModalBody(
html.Div([
html.Div([
html.H6('Sales', style={'textAlign': 'center', 'padding': 10}),
html.P("Bitch", id="sales_stocks", style={'textAlign': 'center', 'padding': 10})
], className='pretty_container four columns'),
html.Div([
html.H5('Current ratio', style={'textAlign': 'center', 'padding': 10}),
html.P(str(value),style = {'fontFamily':'monospace'})
], className='pretty_container seven columns')
])),
dbc.ModalFooter(dbc.Button("Close", id="close"))
], True
else:
raise dash.exceptions.PreventUpdate
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
app.run_server(debug=True)
Upvotes: 2