I'm making a webapp using Python and Dash, this webapp includes a choropleth map of the world with data based on the selected year. I want to be able to change the year and with that also update the map to match that year. I prefer to do this with the Dash slider, although any other way I would appreciate as well.
I've tried updating other graphs such as line charts with the text input, and that worked, but when i changed it to a choropleth map it stopped updating. It now only creates the map but updates on it don't show up. I've put some print text in the update function and it confirmed that it is actually called when I change the input, but the graph just doesn't update.
The layout:with the dcc.input i want to update the html.Div 'my-div'
app.layout = html.Div( children=[
html.H1(
children='UN Sustainable Development goal: Poverty',
style={
'textAlign': 'center',
'color': colors
}
),
dcc.Input(id='my-id',value='30', type='text'),
html.Div(id='my-div')
,
daq.Slider(
id='my-daq-slider',
min=1,
max=sliderlength,
step=1,
),
html.Div(id='slider-output')
], style={
'textAlign': 'center'
})
The update part
#app.callback(
Output('my-div', 'children'),
[Input('my-id', 'value')])
def update_output_div(input_value):
return dcc.Graph(
id='my-div',
figure={'data': [go.Choropleth(
locations = df_pov['Country Code'],
z = df_pov.iloc[:,int(input_value)],
text = df_pov['Country Name'],
autocolorscale = True,
reversescale = False,
marker = go.choropleth.Marker(
line = go.choropleth.marker.Line(
color = 'rgb(180,180,180)',
width = 0.5
)),
colorbar = go.choropleth.ColorBar(
tickprefix = '%',
title = '% below 1.90$ '),
)],
'layout': go.Layout(
title = go.layout.Title(
text = list(df_pov)[int(input_value)]
),
geo = go.layout.Geo(
showframe = False,
showcoastlines = False,
projection = go.layout.geo.Projection(
type = 'equirectangular'
)
),
annotations = [go.layout.Annotation(
x = 0.55,
y = 0.1,
xref = 'paper',
yref = 'paper',
text = 'Source: Kaggle',
showarrow = False
)]
)
}
)
What i expected: for the choropleth to update when changing the text input, or slider input.
Actual: the map gets created once ( with the same function that should update it), but doesn't update.
Dash doesn't like new components being loaded in like this. Try initializing your graph by adding an empty graph to the layout like this:
html.Div(id='my-div', children=[
dcc.Graph(
id='my-graph-id',
figure=dict(
data=[],
layout={},
),
)
])
With the graph already on the page, you would have to change the callback so that it updates the figure prop of the Graph instead of the children of the div.
Also, you have multiple IDs that are the same. Dash doesn't like that. Make sure every ID is unique. If all of this still does not work, I may need to ask you to post some more details so I can help further. Good luck!
Related
I am building a dash app. I want to viz a graph for crypto data (being extracted from APIs). The dash dropdowns contain different crypto ticker symbols & on that basis, I want to showcase different graphs. For e.g, if a user selects ETH in the dropdown, the API will extract the eth market price data & feeds it to the dash app so the user can see the graph, but I am struggling with using multiple datasets with the dropdowns.
So far, I think a dropdown is used to change the property of 1 dataset via changing rows, limits, etc. but unable to choose between multiple datasets.
I am looking for a method to show market price graphs for different cryptocurrencies through the dash app.
########################### Importing Libraries #############################################
import numpy as np
import pandas as pd
from dash import dcc,html,Dash
import plotly.express as px
import warnings
warnings.filterwarnings("ignore")
from api_to_df import open_df,high_df,low_df,close_df,volume_df,mkt_cap_df
###########################################################################################
# Defining app name
app = Dash(__name__)
colors = {
'background': '#231F20',
'text': '#ADD8E6'
}
############### Defining elements for dropdowns ####################################################
ticker_list = ['ETH', 'XRP','BTC','LTC','LRC','DOT','MANA','EGLD','SHIB','SOL','TFUEL','ICP','SAND','MATIC']
type_list = ['Open', 'High','Low','Close','Volume','Mkt cap']
currency_list = ['USD']
############################################################################################################
markdown_text = '''
Koin is a webapp focussed at providing crypto coin data to crypto newbies in a simple yet elegant fashion.
'''
def generate_table(dataframe, max_rows=15):
'''
generate_table function is used to parse pandas dataframes into html tables.
'''
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
#fig = px.bar(open_df, x="date", y="open",barmode = "group")
fig = px.line(open_df, x="date", y="open",markers = 1)
# Updating the layout of the figure
fig.update_layout(
plot_bgcolor=colors['background'],
paper_bgcolor=colors['background'],
font_color=colors['text']
)
#fig.update_traces(marker=dict(size=12,
# line=dict(width=2,
# color='Red')),
# selector=dict(mode='markers'))
# Div is used to create divisions in an html block
# children is a subbranch of an Division tree
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
# H1 is header 1 i.e Heading of the webapp
html.H1(
children='KOIN',
style={
'textAlign': 'center',
'color': colors['text']
}
),
# style is used to style a particular dash/html component
html.Div(children='Your Koin, Our Data', style={
'textAlign': 'center',
'color': colors['text']
}),
#dcc.markdown is used to add markdown/text info to the frontend
html.Div(children =[dcc.Markdown(children=markdown_text,style={
'textAlign': 'center',
'color': colors['text'] } )]),
#Inside children branch, a dcc dropdown component is created to add filters
html.Div(children =[html.Label('Ticker symbol'),
dcc.Dropdown(ticker_list,style={'color':'#000000'})
],
style={'color': colors['text'],'padding': 10, 'flex': 1}
),
html.Div(children =[html.Label('Data type'),
dcc.Dropdown(type_list,style={'color':'#000000'})
],
style={'color': colors['text'],'padding': 10, 'flex': 1}
),
html.Div(children = [html.Label('Currency'),
dcc.Dropdown(currency_list,style={'color':'#000000'})
],
style={'color': colors['text'],'padding': 10, 'flex': 1}
),
html.H2(children='ETH opening price',style={'color':colors['text']}),
# Adding generate_table function to html division
html.Div(generate_table(open_df),style={'color':colors['text']}),
#dcc.graph is used to parse plotly graphs to html
dcc.Graph(
id='open graph',
figure=fig
)
]
)
if __name__ =="__main__":
app.run_server(debug=True)enter code here
You need a callback that listens to the dropdown and builds a graph for each value selected. It should loop over the selected values, and append a graph to the output value for each one.
I am brand new to the world of Python and Plotly and have been working on a Capstone project with the following objective:
Create an interactive chart that allows the user to view US Vehicle Sales between 2019-2021
that allows the user to view the data by Body Type, Segment, Year, Make/Brand, and Individual Models.
I have learned how to add buttons using Plotly Express, though I have been having issues with making them toggle the way I want them to. Here is a snippet of my code:
segbar = px.bar(segments, x=segments.Month, y=segments.NumSold, color=segments.NumSold,
color_continuous_scale='inferno', custom_data=[segments.Segment, segments.PrimaryBodyType, segments.Month, segments.Year], barmode='group')
segbar.update_traces(hovertemplate='<b>Segment:</b> %{customdata[0]} %{customdata[1]}<br><b>Units Sold:</b> %{y:,.0f}<br>Date: %{customdata[2]} %{customdata[3]}')
segbar.update_layout(
updatemenus=[
dict(
type="dropdown",
direction="down",
bgcolor='Dark Blue',
buttons=list(
[
dict(
label="(All)",
method="update",
args=[{"y": segments.NumSold},
{"x": segments.Month}],
),
dict(
label="2021",
method="update",
args=[{"y": segments.loc[segments['Year'] == "2021", "NumSold]},
{"x": segments.loc[segments['Year] == "2021", "Month"]}]
)
]),
), dict(
type="dropdown",
direction="down"
)
], template='plotly_dark')
segbar.show()
The default view (first button) seems to be working fine, though when I select the other button to filter by rows with a "Year" value of 2021, this is the output:
You are pretty close – you just need to add another set of square brackets around the pd.Series you are passing to "y" and "x" in the args key of the dictionaries. To get the example to work, I had to modify your DataFrame slightly, but this should work with your DataFrame.
from io import StringIO
import pandas as pd
import plotly.express as px
segment_data = StringIO("""Segment|PrimaryBodyType|Month|Year|NumSold|MonthNum(Index)|Compact|
A|SUV|January|2021|254391|0|Compact|
B|SUV|January|2019|249913|0|Midsize|
C|SUV|January|2021|248762|0|Midsize|
D|SUV|January|2020|239102|0|Compact|
E|SUV|January|2020|233614|0|Compact|
""")
segments = pd.read_csv(segment_data, sep="|")
segments["Year"] = segments["Year"].astype(str)
segbar = px.bar(segments, x=segments.Month, y=segments.NumSold, color=segments.NumSold,
color_continuous_scale='inferno', custom_data=[segments.Segment, segments.PrimaryBodyType, segments.Month, segments.Year], barmode='group')
segbar.update_traces(hovertemplate='<b>Segment:</b> %{customdata[0]} %{customdata[1]}<br><b>Units Sold:</b> %{y:,.0f}<br>Date: %{customdata[2]} %{customdata[3]}')
segbar.update_layout(
updatemenus=[
dict(
type="dropdown",
direction="down",
bgcolor='Dark Blue',
buttons=list(
[
dict(
label="(All)",
method="update",
args=[{"y": [segments.NumSold]},
{"x": [segments.Month]}],
),
dict(
label="2021",
method="update",
args=[{"y": [segments.loc[segments['Year'] == "2021", "NumSold"]]},
{"x": [segments.loc[segments['Year'] == "2021", "Month"]]}]
)
]),
), dict(
type="dropdown",
direction="down"
)
], template='plotly_dark')
segbar.show()
Hi i am coding a Sunburst chart in python Plotly with Dash. Sunburst v1
when i go deeper in the leafs Sunburst v2 in first leaf and update the graph i get back to the top rootSunburst v3 after update.
can i start already in leaf? Or maybe simulate the clicks after the graph updates.
I already got the path, id with clickData. Thanks
Edit:clickData Output I can read the information when i click on Point in the Sunburstgraph. There has to be a way to start the sunburst again at this point right? Added some shortened code.
data_sunburst = pd.DataFrame.from_dict(namedict, orient='index',columns=['name','weight','Art', 'tp', 'impact', 'parent_key', 'child_list'])
app = dash.Dash(__name__) ##Starte Dash
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
app.layout = html.Div([
html.H4(id="title",
style={
'textAlign': 'left'}
),
html.Div([
html.H5("Focus CM"),
dcc.RadioItems(
id='focus_cm',
options=[
{'label': "True", 'value': "True"},
{'label': "False", 'value': "False"}],
value="False"
)]),
html.Div([
html.H5("Show T/B"), #color some areas
dcc.RadioItems(
id='show_tb',
options=[
{'label': "Show", 'value':"True"},
{'label': "Dont", 'value':"False" }],
value="False"
)]),
html.Br(),
dcc.Graph(id='sunburst'),
html.Div([
dcc.Markdown("""
**Click Data**
Click on points in the graph.
"""),
html.Pre(id='click-data', style=styles['pre']),
], className='three columns'),
])
#app.callback(
Output('click-data', 'children'),
Output('title', 'children'),
Input('sunburst', 'clickData'))
def display_click_data(clickData):
click_path = "test"
if clickData:
click_path = clickData["points"][0]["id"]
percentEntry = (clickData["points"][0]).get("percentEntry") ##Show all when returning to root
parent = (clickData["points"][0]).get("parent")
if percentEntry == 1 and parent == "test":
click_path = "test"
title = f"Selected from Sunburst Chart: {' '.join(click_path)}"
return json.dumps(clickData, indent=2), title
#app.callback(
Output('sunburst', 'figure'),
Input('show_tb', 'value'))
def update_graph(show_tb_input):
global focus_cm, show_tb, tp_dict
if show_tb_input == "True":
show_tb = True
else:
show_tb =False
tp_dict = {"bsp": C_BSP, "wm": C_WM}
colors = set_colors_for_sunburst(namedict) ## set color when Show T/B input True;False
fig = go.Figure(go.Sunburst( ## Build fig; Can i build already in Point from clickData?
ids=data_sunburst.index,
labels=data_sunburst.name,
parents=data_sunburst.parent_key,
values=data_sunburst.weight,
branchvalues="total",
marker=dict(colors=colors),
insidetextorientation="auto",
))
fig.update_layout(
grid=dict(columns=2, rows=1),
margin=dict(t=0, l=0, r=0, b=0))
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=True)
Easy solution:
Sunburst Object has paramenter level:
level – Sets the level from which this trace hierarchy is rendered. Set level to '' to start from the root node in the hierarchy. Must be an “id” if ids is filled in, otherwise plotly attempts to find a matching item in labels.
I am very new to Plotly Dash and I cannot get a hang of the #callback function with multiple inputs linked to two (scatter/bar) graphs.
Dashboard
Sample Data
For some reason, after selecting the inputs and clicking the “Run selection” button, the graphs do not update accordingly. Does anyone know what I am doing wrong? Been reading the documentation and browsing through online examples, but could not figure this one out... I believe something is wrong with the #callback function or the way I defined the data in my function.
Thank you in advance, would highly appreciate every bit of help! :slight_smile:
import pandas as pd
import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import plotly.express as px
# load the data
data = pd.read_excel('example_data.xlsx')
data.fillna(0, inplace=True)
data['Satellite'] = data['Satellite'].astype(int)
#initiate app and set theme
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# navigation bar
navbar = dbc.NavbarSimple(
children=[
dbc.NavItem(dbc.NavLink("Page 1", href="#")),
dbc.DropdownMenu(
children=[
dbc.DropdownMenuItem("Page 2", href="#"),
dbc.DropdownMenuItem("Page 3", href="#"),
],
nav=True,
in_navbar=True,
label="More",
),
],
brand="Sample Dash Application",
brand_href="#",
color="primary",
dark=True,
)
# Construct a dictionary of dropdown values for the days
day_options = []
for day in data['AsofDate'].unique():
# grab day_options and append to it
day_options.append({'label':str(day),'value':day})
# Construct a dictionary of dropdown values for the portfolios
portfolio_options = []
for portfolio in data['Satellite'].unique():
portfolio_options.append({'label':str(portfolio),'value':int(portfolio) or 0})
# Construct a dictionary of dropdown values for the region
region_options = []
for region in data['Region'].unique():
region_options.append({'label':str(region),'value':region})
###############################################################################
# Filter pane
# Check dash core components at https://dash.plotly.com/dash-core-components
###############################################################################
controls = [
html.Div(
[
'Select Day',
dcc.Dropdown(
id='day-dropdown',
options=day_options,
value=data['AsofDate'].min(),
clearable=False
),
]
),
html.Div(
[
'Select Portfolio',
dcc.Dropdown(
id='portfolio-dropdown',
options=portfolio_options,
value=data['Satellite'].min(),
clearable=False
),
]
),
html.Div(
[
'Select Region',
dcc.Dropdown(
id='region-dropdown',
options=region_options,
value=data['Region'].min(),
clearable=False
),
]
),
html.Br(),
dbc.Button("Run selection", color="primary", id="button-submit")
]
###############################################################################
# Add components here, e.g. graphs
###############################################################################
avp_graph = dcc.Graph(id="avp-graph", style={"height": "500px"})
bar_plot_graph = dcc.Graph(id='bar-plot-graph', style={"height": "500px"})
###############################################################################
# Container
# Check dash core components at https://dash.plotly.com/dash-core-components
###############################################################################
container = dbc.Container(
fluid=True,
children=[
html.Hr(),
html.H3('Dashboard'),
html.Hr(),
# Bootstrap Layout examples:
# https://getbootstrap.com/docs/4.0/examples/
# Bootstrap grid system: https://getbootstrap.com/docs/4.0/layout/grid/
# Under each column (2, 5, 5) you can add components.
# The left column has a width of 2 and contains the controls only.
# The middle column has a width of 5 and contains a table and a graph.
# The right column has a width of 5 and contains a table and a graph.
dbc.Row(
[
dbc.Col(
[
# See https://dash-bootstrap-components.opensource.faculty.ai/docs/components/card/
dbc.Card([
dbc.CardHeader("Filter Pane"),
dbc.CardBody(controls),
]
),
],
sm=2
),
dbc.Col(
[
html.H5('Column 1'),
avp_graph # middle column, graph 1
],
sm=5
),
dbc.Col(
[
html.H5('Column 2'),
bar_plot_graph # right column, graph 2
],
sm=5
)
]
)
]
)
# Define Layout
app.layout = html.Div([
navbar,
container
])
#app.callback(
[
Output("avp-graph", "figure"),
Output("bar-plot-graph", "figure")
],
[Input("button-submit", "n_clicks")],
[
State("day-dropdown", "value"),
State("portfolio-dropdown", "value"),
State("region-dropdown", "value"),
],
)
def run_submit(n_clicks, day, portfolio, region):
# Bar plot
mask = data["AsofDate"] == day
bar_plot_graph = px.bar(data[mask], x=data['Region'], y=data['Return'], title='Bar Plot') # barmode="group",
# Scatter Plot
avp_graph = px.scatter(
x=data['line_x'],
y=data['line_y'],
labels={"x": "x", "y": "y"},
title=f"Scatter Plot",
)
return [avp_graph, bar_plot_graph] # return the components in the order of Output Callbacks!!!
if __name__ == '__main__':
app.run_server(port=8051, debug=False)
I'm not sure how you want your plots to change, but what I can see is:
The variables portfolio and region are defined by the state of the dropdown menus, but they are not used in your callback function.
The plot avp_graph in the callback function doesn't depend on any input. Therefore, it makes sense that it remains constant independently of what you select in your dropdown menus.
The plot bar_plot_graph only depends on the variable day.
I have been banging my head off the wall all day and cannot find a way to fit a dash indicator inside of a dash_bootstrap_components card.
It seems that the body of the card and the graph do not live inside of the card. I am not very familiar with dash so it is difficult to find a way to solve the issue.
here is what I have been able to do so far in terms of plotting the indicator:
fig3 = go.Figure()
fig3.add_trace(go.Indicator(
mode = "number+delta",
number = {"font":{"size":40},'prefix': "$"},
value = 2045672,
delta = {'reference': 30000},
gauge = {'shape': "bullet"},
title = {"text": "On Hand<br><span style='font-size:0.9em;color:gray'></span>"},
#title='Stock On Hand',
domain = {'x': [0, 1], 'y': [0, 1]},
))
fig3.update_layout(paper_bgcolor = "rgba(0,0,0,0)",
plot_bgcolor = "rgba(0,0,0,0)",
autosize=False,
width = 200,
height=200,
)
fig3.update_traces(align="center", selector=dict(type='indicator'))
I am forced to specify width and height for the indicator otherwise it is way too big, however this cause issues because its size does not adjust in regards to the card.
here is the html dash code for the box and the plot:
html.Div(children=[
html.Div(children=[
html.Div(children=[
html.Div(children=[
dbc.Card(
[dbc.CardBody(
[dcc.Graph(figure=fig3)
]
)],className="card", style={"width": "15rem", "height":"8rem"}
),
], className='jumbotron', style={'background-color': '#fffffff'}),
])
],className="col-3 mx-auto"),
],className="row p-0 h-100", style={'background-color': '#f7f7f7', 'height':110}),
], className="full-width p-0 h-100", style={'background-color': '#fffffff'}),
and here is what the final output looks like:
I am not sure what else I can try to bring the graph inside of the box, any help would be appreciated
Remove the instances where you set the height in the style of dash components and the indicator doesn't get cut off.
So you can do something like this:
app.layout = html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
dbc.Card(
[
dbc.CardBody(
[dcc.Graph(figure=fig3)],
style={"width": "15rem"},
)
]
)
],
className="jumbotron",
style={"backgroundColor": "#fffffff"},
)
],
className="col-3 mx-auto",
)
],
className="row p-0 h-100",
style={"backgroundColor": "#f7f7f7"},
)
],
className="full-width p-0 h-100",
style={"backgroundColor": "#fffffff"},
)
I've also changed the casing of the style properties to camelCase as this is what React (which dash uses) likes.