Dash, how to callback depending on which button is being clicked? - python

I have a function that dynamically creates a set of buttons:
def generate_team_button(team_shortName):
return dbc.Button(
str(team_shortName),
className="btn btn-primary",
id=str(team_shortName),
style={
"margin-right": "10px",
"margin-bottom": '10px',
},
n_clicks=0,
)
These buttons are displayed by looping through a set of items
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input
from dash.dependencies import Output
from dash.dependencies import State
import pandas as pd
data = {'teams': ['team1', 'team2', 'team3', 'team4']}
df_teams = pd.DataFrame(data)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(
[
dbc.Row([
dbc.Col(
children=[generate_team_button(i) for i in df_teams['teams']]
),
]),
dbc.Row([
dbc.Col(
id='section',
#WANT TO UPDATE THIS SECTION BASED ON WHICH BUTTON IS BEEING CLICKED
),
]),
]
),
What I want to do is to update id=section based on which button is being pressed. To do that I need a #app.callback like below. But what I get is a tuple with how many times each button has been pressed.
#app.callback(
[
Output('league-table', 'value'),
],
[
Input(str(i), 'n_clicks') for i in df_teams['teams']
]
)
def update_league_table(*args):
print(args)
return f'{args}'
How can I update a section based on which button has been clicked?

This information is available via the callback_context object. Here is a small example,
import dash
import dash_html_components as html
from dash.dependencies import Output, Input
from dash import callback_context
n_buttons = 5
# Create example app.
app = dash.Dash(prevent_initial_callbacks=True)
app.layout = html.Div([html.Button("Button {}".format(i), id=str(i)) for i in range(n_buttons)] + [html.Div(id="log")])
#app.callback(Output("log", "children"), [Input(str(i), "n_clicks") for i in range(n_buttons)])
def func(*args):
trigger = callback_context.triggered[0]
return "You clicked button {}".format(trigger["prop_id"].split(".")[0])
if __name__ == '__main__':
app.run_server()
For additional details, see the documentation on advanced callbacks.

Related

Dash model with separate button callbacks

In Python I am working with Dash and Dash bootstrap components. I am having trouble with the bootstrap Modal component. My most basic implementation of the modal, using the first example here, works fine. However, If I try to replace their single callback with two separate callbacks for the buttons, it stops working. Can anybody explain to me why this is and help me get it working? The callbacks don't seem difficult at all.
Most basic implementation of their code (this works for me):
from dash import Dash, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from dash_bootstrap_components.themes import LUMEN
app = Dash(external_stylesheets=[LUMEN])
app.title = "Test"
app.layout = html.Div(
[
dbc.Button("Open modal", id="open", n_clicks=0),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("Header")),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button(
"Close", id="close", className="ms-auto", n_clicks=0
)
),
],
id="modal",
is_open=False,
),
]
)
#app.callback(
Output("modal", "is_open"),
[Input("open", "n_clicks"), Input("close", "n_clicks")],
[State("modal", "is_open")],
)
def toggle_modal(n1, n2, is_open):
print(is_open)
print(type(is_open))
if n1 or n2:
return not is_open
return is_open
app.run()
Code with their callbacks replaced by two separate callbacks for the buttons (not working):
from dash import Dash, html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from dash_bootstrap_components.themes import LUMEN
app = Dash(external_stylesheets=[LUMEN])
app.title = "Test"
app.layout = html.Div(
[
dbc.Button("Open modal", id="open", n_clicks=0),
dbc.Modal(
[
dbc.ModalHeader(dbc.ModalTitle("Header")),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(
dbc.Button(
"Close", id="close", className="ms-auto", n_clicks=0
)
),
],
id="modal",
is_open=False,
),
]
)
#app.callback(
Output("modal", "is_open"),
Input("open", "n_clicks")
)
def toggle_modal_open(n1):
if n1:
return True
#app.callback(
Output("modal", "is_open"),
Input("close", "n_clicks")
)
def toggle_modal_close(n1):
if n1:
return False
app.run()

There is a Horizontal Scrollbar dasboard plotly

I am building a dashboard with multi-Page Apps plotly and bootstrap. There is a horizontal scrollbar overflow on my website. I am looking to remove a scroll bar, and remove this blank space after imagen, thank you.
Here is the code:
App:
import pandas as pd
from dash_auth import BasicAuth
from dash import Dash, dcc, html, Input, Output, callback
from dash_extensions.enrich import ServersideOutput, DashProxy, ServersideOutputTransform
import dash_bootstrap_components as dbc
from pages import test, error_404
df = pd.read_parquet('dataset.parquet.gzip')
external_stylesheets = [
dbc.themes.BOOTSTRAP,
dbc.icons.BOOTSTRAP,
]
app = Dash(__name__, title = 'Test',
external_stylesheets=external_stylesheets,
suppress_callback_exceptions=True,
)
server = app.server
app.layout = html.Div([
dcc.Location(id="url", pathname="", refresh=False),
# Header
dbc.Row([
dbc.Col(html.A(
html.Img(src=app.get_asset_url("leters.jpg"), className="img-fluid brand-other"),
id="logo",
href="https://www.leters.com/", target="blank"
), width='12', class_name='justify-content-end d-flex'),
]),
html.Div(id='page-content'),
], className='col-12 col-lg-12')
#callback(
Output(component_id='page-content', component_property='children'),
Input(component_id='url', component_property='pathname')
)
def routing(path):
print(path)
if path == "":
return test.test
else:
return error_404
if __name__ == "__main__":
app.run_server(debug=True)
test:
from dash import html
test = html.Div([
html.H3("test", className="sub_title"),
])
I think you should change from html.Div to dbc.Container as below:
app.layout = dbc.Container([
dcc.Location(id="url", pathname="", refresh=False),
# Header
dbc.Row([
dbc.Col(html.A(
html.Img(src=app.get_asset_url("leters.jpg"), className="img-fluid brand-other"),
id="logo",
href="https://www.leters.com/", target="blank"
), width='12', class_name='justify-content-end d-flex'),
]),
html.Div(id='page-content'),
], fluid=True)
Hope this help.

How to fix Python dash app.callback returning error? app.callback returning error: Cannot read properties of null (reading 'data')

import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.express as px
nasdaq = pd.read_csv("CFTC-209742_FO_L_ALL.csv")
app = dash.Dash()
app.layout = html.Div(
[
html.H1("NASDAQ Dashboard"),
html.P(
[
"This dashboard shows NASDAQ info:",
html.Br(),
html.A(
"Nasdaq data scource",
href="https://data.nasdaq.com/data/CFTC/209742_FO_L_ALL-commitment-of-traders-nasdaq-mini-cme-futures-and-options-legacy-format-209742",
target="_blank",
),
]
),
dcc.Dropdown(id="my_dropdown", options=nasdaq.columns, value="Open Interest"),
dcc.Graph(id="my_graph"),
]
)
#app.callback(
Output(component_id="my_graph", component_property="figure"),
Input(component_id="my_dropdown", component_property="value"),
)
def update_graph(selected_value):
line_fig = px.line(
x=nasdaq["Date"],
y=nasdaq[f"{selected_value}"],
labels={"y": f"{selected_value}", "x": "Dates"},
)
if __name__ == "__main__":
app.run_server(debug=True)
Above you can see my Python code that I am having troubles with.
For some reason I cannot seem to get "selected_value" to update my chart dynamically. When I hard code the different possible values from my CSV file then it does work perfectly fine.
The github repo

Updating dbc.Card with hoverData

I have the following skeleton code
# ------------------------------
# IMPORT LIBRARIES
# ------------------------------
# Import Dash and Dash Bootstrap Components
import dash
import dash_bootstrap_components as dbc
from dash import Input, Output, dcc, html, dash_table, State
import dash_leaflet as dl
# Import Core Libraries
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from dash import Input, Output, dcc, html, dash_table
token='my_token'
FONT_AWESOME = "https://use.fontawesome.com/releases/v5.10.2/css/all.css"
# Import data
data_url = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vSGcAFoXyMXk7lj3KJrpzKd5XiBufm2xa7M39QNZxw5ma0TZhP35q-mf2ybyf9cZQdEwsoWkHiQWfjC/pub?gid=0&single=true&output=csv'
df = pd.read_csv(data_url)
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP,FONT_AWESOME], title='CONFIRM - SK4U', update_title=None,
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=0.7, minimum-scale=0.4"}],
)
server = app.server
fig_map = px.scatter_mapbox(df,lat='latitude',lon='longitude',
mapbox_style='mapbox://styles/vostpt/cl1w0k6uf000415nt86nk7uv2',
#color='Kategória / Category',
width=1400,height=700,
hover_name='name',
#center=[48.799330977271445,19.338585158029197],
center=dict(lon=20.0068, lat=48.8264),
zoom=7,
custom_data=['name']
)
fig_map.update_layout(
hoverlabel=dict(
bgcolor="white",
font_size=16,
font_family="sans-serif"
)
)
fig_map.update_layout(mapbox = dict(accesstoken = token, style ='mapbox://styles/vostpt/cl1w0k6uf000415nt86nk7uv2'))
app.layout = html.Div(
[
dbc.Row(
[
dbc.Col(
dbc.Card(
dbc.CardBody(
[
html.H4("Title", className="card-title"),
html.H6("Card subtitle", className="card-subtitle"),
html.P(id="card_data"),
dbc.CardLink("Card link", href="#"),
dbc.CardLink("External link", href="https://google.com"),
]
),
),
),
dbc.Col(
dcc.Graph(id="my_map",figure=fig_map),
xs=12,
),
],
),
],
)
#app.callback(
Output(component_id="card_data", component_property="children"),
Input(component_id="my_map", component_property="hoverData")
)
def upgrade_card(hoverData):
title = hoverData['name'][0]
return title
if __name__ == "__main__":
app.run_server(host='0.0.0.0', debug=True)
My objective is to update the text in the card, with the data from the dataframe, on mouse hover.
The app receives the input from the hoverData but returns the error message
TypeError: 'NoneType' object is not subscriptable
Any help would be much appreciated.
Disclaimer: The solution will be used in a non-for-profit NGO's project. No commercial use will be made of the solution
These errors usually come up when you did not properly initialize. The children of the p-tag are non-existent in your example, so they cannot be updated.
So, replace html.P(id="card_data") with html.P("", id="card_data").

Plotly Dash: How to generate html components with a for loop?

I'm want to create multiple dbc.Button by passing a list of strings to a constructor that generates these buttons, in the following way:
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import plotly.express as px
from functools import lru_cache
import dash_bootstrap_components as dbc
from dash.dependencies import Input
from dash.dependencies import Output
from dash.dependencies import State
import pandas as pd
data = {'teams': ['team1', 'team2', 'team3', 'team4']}
df_teams = pd.DataFrame(data)
def generate_team_button(team_shortName):
return dbc.Button(
str(team_shortName),
color="primary",
className="mr-1",
id=str(team_shortName),
),
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
colors = {
'background': '#111111',
'text': '#7FDBFF'
}
app.layout = html.Div(
[
dbc.Row([
dbc.Col(
[generate_team_button(i) for i in df_teams.iterrows()]
)
]),
],
)
if __name__ == '__main__':
app.run_server(debug=True)
But I'm getting the following error for all the generated buttons when trying to do above:
The children property of a component is a list of lists,
instead of just a list. Check the component that has the
following contents, and remove one of the levels of nesting:
[
{
"props": {
"children": "(0, 0 team1\nName: 0, dtype: object)",
"id": "(0, 0 team1\nName: 0, dtype: object)",
"className": "mr-1",
"color": "primary"
},
"type": "Button",
"namespace": "dash_bootstrap_components"
}
]
What do I have to do to generate the buttons?
There is a small bug in your code, if you delete the comma after the generate_team_button() function you will not get the error anymore. You may also want to replace df_teams.iterrows() with df_teams['teams'], see the example below.
import dash
import dash_html_components as html
import dash_bootstrap_components as dbc
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
data = {'teams': ['team1', 'team2', 'team3', 'team4']}
df_teams = pd.DataFrame(data)
def generate_team_button(team_shortName):
return dbc.Button(children=str(team_shortName),
color="primary",
className="mr-1",
id=str(team_shortName))
app.layout = html.Div([
dbc.Row([
dbc.Col(children=[generate_team_button(i) for i in df_teams['teams']])
])
])
if __name__ == '__main__':
app.run_server(debug=True)

Categories

Resources