DASH dropdowns and graph - python

I am having a problem in updating a map graph based on 3 dropdowns.
I have 3 dropdowns: one for country, one for district and one for category.
When I select 1 dropdown at a time I can see the results on the map.
But what I really want is to zoom in. So when I select country then district, I want to see the results in that particular district only.
Now, if I select a country from the dropdown and then select a category from the other dropdown, I see on the map the results of the whole country. It does not narrow down the search to just the category selected.
dbc.Col([
html.Label("Select Country: ", style={'font-family': 'arial', 'font-weight': 'bold', 'font-size': 15, 'color': 'white'}),
dcc.Dropdown(className='scrollable-element div-for-dropdown Select-control VirtualizedSelectOption',
id='country_dropdown',
options=[{'label': str(c), 'value': c} for c in sorted(df['Country'].unique())],
multi=True,
placeholder="Select",
value=['United Kingdom'],
clearable=True,
style={'width': '100%', 'font-family': 'arial', 'font-weight': 'bold', 'font-size': 13, 'color': 'black', 'background-color': '#31302F', 'border': '0px solid black'}
),
html.Br(),
html.Label("Select District: ", style={'font-family': 'arial', 'font-weight': 'bold', 'font-size': 15, 'color': 'white'}),
dcc.Dropdown(className='scrollable-element div-for-dropdown Select-control VirtualizedSelectOption',
id='district_dropdown',
multi=True,
value=[],
clearable=True,
options=[{'label': str(d), 'value': d} for d in sorted(df['MainLocation'].unique())],
placeholder="Select",
style={'width': '100%', 'font-family': 'arial', 'font-weight': 'bold', 'font-size': 13, 'color': 'black', 'background-color': '#31302F', 'border': '0px solid black'}
),
html.Br(),
html.Label("Select Category: ", style={'font-family': 'arial', 'font-weight': 'bold', 'font-size': 15, 'color': 'white'}),
dcc.Dropdown(className='div-for-dropdown Select-control VirtualizedSelectOption',
id='category_dropdown',
multi=True,
value=[],
clearable=True,
options=[{'label': '(Select All)', 'value': 'all'}] + [{'label': str(cat), 'value': cat} for cat in sorted(df['Category'].unique())],
placeholder="Select",
style={'width': '100%', 'font-family': 'arial', 'font-weight': 'bold', 'font-size': 13, 'color': 'black', 'background-color': '#31302F', 'border': '0px solid black'}
)
`#app.callback(Output('map_graph', 'figure'),
[Input('country_dropdown', 'value'),
Input('category_dropdown', 'value'),
Input('district_dropdown', 'value')])
def update_map_graph(chosen_country, chosen_category, chosen_district):
df_sub = df[(df['Country'].isin(chosen_country)) |
(df['Category'].isin(chosen_category)) |
(df['MainLocation'].isin(chosen_district))]
# Create figure
locations = [go.Scattermapbox(
lon=df_sub['Long'],
lat=df_sub['Lat'],
mode='markers',
marker={'color': df_sub['Color'], 'size': 13, 'opacity': 0.5},
unselected={'marker': {'opacity': 1}},
selected={'marker': {'opacity': 0.5, 'size': 18}},
hoverinfo='text',
hovertext=df_sub['Hover']
)]
# Return figure
return {
'data': locations,
'layout': go.Layout(
autosize=True,
margin=dict(l=0,
r=0,
t=0,
b=0),
uirevision='foo',
clickmode='event+select',
hovermode='closest',
hoverdistance=2,
mapbox=dict(
accesstoken=mapbox_access_token,
bearing=0,
style='mapbox://styles/mapbox/navigation-night-v1',
center=dict(
lat=50.1109,
lon=8.6821
),
pitch=0,
zoom=5
),
)
}`

you don't provide sample data, so I've used UK hospital data
create a geopandas data frame, so total_bounds can be used
straight forward build drop downs progressively. get centre of geometry of any selections
import json
import numpy as np
import dash
import plotly.graph_objects as go
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
import requests, io
import pandas as pd
import geopandas as gpd
import shapely
import plotly.express as px
# get some public addressess - hospitals. data that can be scattered
dfhos = pd.read_csv(
io.StringIO(
requests.get("http://media.nhschoices.nhs.uk/data/foi/Hospital.csv").text
),
sep="¬",
engine="python",
)
fig = px.scatter_mapbox(
dfhos, lat="Latitude", lon="Longitude", hover_data=["County", "City", "Address1"]
).update_layout(
mapbox={"style": "carto-positron"}, margin={"l": 0, "r": 0, "t": 0, "b": 0}
)
# create a geo dataframe of hospitals
gdfhos = gpd.GeoDataFrame(
data=dfhos,
geometry=dfhos.apply(
lambda r: shapely.geometry.Point(r["Longitude"], r["Latitude"]), axis=1
),
crs="EPSG:4326",
)
# Build App
app = JupyterDash(__name__)
app.layout = dash.html.Div(
[
dash.dcc.Dropdown(
id="County",
options=[
{"label": c, "value": c}
for c in dfhos["County"].dropna().sort_values().unique()
],
value=None,
),
dash.dcc.Dropdown(id="City", value=None),
dash.dcc.Dropdown(id="Address1", value=None),
dash.dcc.Graph(
id="map",
figure=fig,
),
],
)
#app.callback(
[
Output("map", "figure"),
Output("City", "options"),
Output("Address1", "options"),
],
Input("County", "value"),
Input("City", "value"),
Input("Address1", "value"),
State("map", "figure"),
)
def center_selection(county, city, address1, fig):
city_out = []
addr_out = []
bb = gdfhos.geometry.total_bounds
if county:
bb = gdfhos.loc[gdfhos["County"].eq(county)].geometry.total_bounds
city_out = [
{"label": c, "value": c}
for c in dfhos.loc[dfhos["County"].eq(county), "City"]
.dropna()
.sort_values()
.unique()
]
if county and city:
bb = gdfhos.loc[
gdfhos["County"].eq(county) & gdfhos["City"].eq(city)
].geometry.total_bounds
addr_out = [
{"label": c, "value": c}
for c in dfhos.loc[
dfhos["County"].eq(county) & dfhos["City"].eq(city), "OrganisationName"
]
.dropna()
.sort_values()
.unique()
]
return (
go.Figure(fig).update_layout(
mapbox={"center": {"lon": (bb[0] + bb[2]) / 2, "lat": (bb[1] + bb[3]) / 2}}
),
city_out,
addr_out,
)
# Run app and display result inline in the notebook
app.run_server(mode="inline")

Related

Python Dash app add download button in call back

I am trying to download the data frame using the download button in-dash app but I am unable to put logic where I can put this in my call back. I am generating the data frame based on user selection and using Dash_table.DataTable.
here is the full code:
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import datetime
import dash_table
from Dash_App.app import app
import pandas as pd
row1 = html.Div(
[
dbc.Row([
dbc.Col([
dbc.Input(id="ad_account_id",
type="text",
placeholder="Account ID",
style={'width': '150px'}),
]),
dbc.Col([
dbc.Input(id="app_id",
type="text",
placeholder="App ID",
style={'width': '150px'}),
]),
dbc.Col([
dbc.Input(id="access_token",
type="text",
style={'width': '150px'},
placeholder="Access Token")
]),
dbc.Col([
dbc.Input(id="app_secret",
type="text",
style={'width': '150px'},
placeholder="App Secret")
]),
dbc.Col([
dcc.Dropdown(
id='dimensions',
options=[{'label': i, 'value': i} for i in ['Campaign', 'Placement', 'Creative']],
multi=True,
style={'width': '150px'},
placeholder='Dimensions')
]),
dbc.Col([
dcc.Dropdown(
id='metrics',
options=[{'label': i, 'value': i} for i in ['Impressions', 'Clicks', 'Conversions']],
multi=True,
style={'width': '150px'},
placeholder='Metrics')
])
], align="center"),
], style={'margin-top': 20, 'margin-left': -100}
)
row2 = html.Div([
dbc.Row([
dbc.Col([
dcc.DatePickerSingle(
id='start-date',
placeholder="Start Date",
min_date_allowed=datetime.datetime.now().strftime('2018-01-01'),
max_date_allowed=datetime.datetime.today().date(),
display_format='YYYY-MM-DD',
style={'width': '150px', 'margin-left': 180}
),
], ),
dbc.Col([
# html.Br(),
dcc.DatePickerSingle(
id='end-date',
placeholder="End Date",
min_date_allowed=datetime.datetime.now().strftime('2018-01-01'),
max_date_allowed=datetime.datetime.today().date(),
display_format='YYYY-MM-DD',
style={'width': '150px', 'margin-left': 60}
)], align="center"),
])
])
row3 = html.Div([
dbc.Row([
dbc.Col([
html.Button(id='submit-button', type='submit', children='Submit', style={'width': '150px', 'margin-top': 5,
'margin-left': 370}),
], width={"order": "first"}),
dbc.Col([
html.Div(id='output_div'),
])
])
])
row4 = html.Div([
html.A(html.Button('Download Data', id='download-button'), id='download-link-facebook',
style={'width': '120px', 'margin-top': 10, 'margin-left': 345})
])
tab_1_layout = dbc.Container(children=[
row1,
html.Br(),
row2,
html.Br(),
row3,
row4
]
)
#app.callback(Output('output_div', 'children'),
[Input('submit-button', 'n_clicks')],
[State('ad_account_id', 'value'),
State('app_id', 'value'), State('access_token', 'value'),
State('app_secret', 'value'), State('dimensions', 'value'),
State('metrics', 'value'),
State('start-date', 'date'),
State('end-date', 'date'),
],
)
def update_output(clicks, ad_account_id, app_id, access_token, app_secret, dimensions, metrics, start_date, end_date):
if clicks is not None:
my_ad_account = ad_account_id
my_app_id = app_id
my_access_token = access_token
my_app_secret = app_secret
my_dimensions = dimensions
my_metrics = metrics
my_start_date = start_date
my_end_date = end_date
df = pd.read_csv('usa-agricultural-exports-2011.csv', encoding='ISO-8859-1')
new_df_col_list = my_dimensions + my_metrics
print(new_df_col_list)
dff = df[new_df_col_list]
return html.Div([
dash_table.DataTable(
css=[{'selector': '.row',
'rule': 'margin: 0; white-space: inherit; overflow: inherit; text-overflow: inherit;'}],
id='table',
columns=[{"name": i, "id": i} for i in dff.columns],
data=dff.to_dict("rows"),
style_cell={"fontFamily": "Arial", "size": 10, 'textAlign': 'left',
'width': '{}%'.format(len(dff.columns)), 'textOverflow': 'ellipsis', 'overflow': 'hidden'},
style_table={'maxHeight': '200px', 'overflowY': 'scroll', 'maxWidth': '1500px', 'overflowX': 'scroll'},
row_selectable="multi",
selected_rows=[],
editable=True,
style_header={'backgroundColor': '#ffd480', 'color': 'white', 'height': '10', 'width': '10',
'fontWeight': 'bold'},
style_data={'whiteSpace': 'auto', 'height': 'auto', 'width': 'auto'},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in dff.to_dict('rows')
],
tooltip_duration=None
),
], style={'margin-top': 30, 'display': 'inline-block', 'margin-left': 20, 'width': '100%'})
I never expected this is going to like this simple. I added the 'export' argument in my dash table and its solved.
return html.Div([
dash_table.DataTable(
css=[{'selector': '.row',
'rule': 'margin: 0; white-space: inherit; overflow: inherit; text-overflow: inherit;'}],
id='table',
export = "csv"
columns=[{"name": i, "id": i} for i in dff.columns],
data=dff.to_dict("rows"),
style_cell={"fontFamily": "Arial", "size": 10, 'textAlign': 'left',
'width': '{}%'.format(len(dff.columns)), 'textOverflow': 'ellipsis', 'overflow': 'hidden'},
style_table={'maxHeight': '200px', 'overflowY': 'scroll', 'maxWidth': '1500px', 'overflowX': 'scroll'},
row_selectable="multi",
selected_rows=[],
editable=True,
style_header={'backgroundColor': '#ffd480', 'color': 'white', 'height': '10', 'width': '10',
'fontWeight': 'bold'},
style_data={'whiteSpace': 'auto', 'height': 'auto', 'width': 'auto'},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in dff.to_dict('rows')
],
tooltip_duration=None
),
], style={'margin-top': 30, 'display': 'inline-block', 'margin-left': 20, 'width': '100%'})

Create a dash graph with dropdown menu

Hi I have an excel file that looks like this where there are three diferent servers (A, B, C).
I am trying to build a dash app that has a dropdown menu which will make it possible to select the desired server and display the graph for CPU Usage and Memory Usage for each server.
I have tried to modify the following code from the official Dash website. Data can be found on https://plotly.github.io/datasets/country_indicators.csv
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv('https://plotly.github.io/datasets/country_indicators.csv')
available_indicators = df['Indicator Name'].unique()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='xaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Fertility rate, total (births per woman)'
),
dcc.RadioItems(
id='xaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
],
style={'width': '48%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
id='yaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Life expectancy at birth, total (years)'
),
dcc.RadioItems(
id='yaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
],style={'width': '48%', 'float': 'right', 'display': 'inline-block'})
]),
dcc.Graph(id='indicator-graphic'),
dcc.Slider(
id='year--slider',
min=df['Year'].min(),
max=df['Year'].max(),
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()},
step=None
)
])
#app.callback(
Output('indicator-graphic', 'figure'),
[Input('xaxis-column', 'value'),
Input('yaxis-column', 'value'),
Input('xaxis-type', 'value'),
Input('yaxis-type', 'value'),
Input('year--slider', 'value')])
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
return {
'data': [dict(
x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
text=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],
mode='markers',
marker={
'size': 15,
'opacity': 0.5,
'line': {'width': 0.5, 'color': 'white'}
}
)],
'layout': dict(
xaxis={
'title': xaxis_column_name,
'type': 'linear' if xaxis_type == 'Linear' else 'log'
},
yaxis={
'title': yaxis_column_name,
'type': 'linear' if yaxis_type == 'Linear' else 'log'
},
margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
hovermode='closest'
)
}
if __name__ == '__main__':
app.run_server(debug=True)
The ouput of this code gives an output similar to mine except that the second drop down menu and the slicer would not be needed
I am struggling to understand how to modify the code to be able to apply to mine. Any help would be welcome. Thank you.
Your callback func will have a single Output and a single Input. The output will be the figure of the graph, and the input will be the value of the dropdown.
In your callback, you can filter the dataframe you build from the Excel file something like this:
df = pandas.read_excel('path/to/my/file.xlsx')
df = df[df['server'].eq(dropdown_value)]
From there just fit the data into the dict that represents the figure much like it's done in the Dash example and return it.

Python Dash: Function should not run when n_clicks < 0 and defined in a call back

I am working on plotly dash app. I have an almost working example. The only thing that is not working is that I am not able to restrict the functions defined in the callbacks not to run when the page loads.
I have tried add checks for the n_clicks inside the callback however it doesnt seem to be working. It runs the function without the clicks as well
Below is the code for the dash
from datetime import date
import base64
import dash
import plotly
import dash
from dash.dependencies import Input, Output, State
from plotly.graph_objs import *
from datetime import datetime as dt
import dash_html_components as html
import dash_core_components as dcc
import flask
import pandas as pd
server = flask.Flask('app')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash('app', server=server, external_stylesheets=external_stylesheets)
app.layout = html.Div(style={'backgroundColor': '#EFEAEA', 'margin': '0px', 'padding': '0px'}, children=[
html.Div([
html.Div([
html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()),
style={'width': '200px', 'height': '100px', 'display': 'inline-block', 'float': 'left', 'padding-left': '5px', 'padding-top': '5px'})
]),
html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='demographics',
options=[
{'label': 'All 18-49', 'value': '18_39'},
{'label': 'Female 25-54', 'value': '25_54 F'},
{'label': 'All 25-54', 'value': '25-54'},
],
placeholder="Select Demographics",
)
],
style={'width': '30.5%', 'display': 'inline-block', 'padding-right': '10px'}),
html.Div([
dcc.DatePickerRange(
id='my-date-picker-range',
start_date_placeholder_text="Select a Start Date",
end_date_placeholder_text="Select an End Date",
min_date_allowed=dt(2018, 1, 1),
max_date_allowed=dt(2050, 12, 31),
initial_visible_month=dt(2019, 1, 2),
style={'width': '600', 'display': 'inline-block', 'padding-right': '10px'}
),
html.Div(id='output-container-date-picker-range')
],
style={'width': '30.3%', 'display': 'inline-block', 'padding-right': '10px', 'position': 'relative'})
],
style={
'backgroundColor': '#EFEAEA',
'padding': '5px 10px'}),
html.Div([
html.Div([
dcc.Dropdown(
id='Horsepower',
options=[
{'label': '200', 'value': 'two_hundred'},
{'label': '250', 'value': 'two_hundred_fifty'},
{'label': '300', 'value': 'three_hundred'},
{'label': '350', 'value': 'three_hundred_fifty'},
{'label': '400', 'value': 'four_hundred'}
],
placeholder="Select TARP",
)
],
style={'width': '20%', 'display': 'inline-block', 'padding-right': '10px'}),
html.Div([
dcc.Dropdown(
id='Kilometers',
options=[
{'label': '250,000', 'value': 250000, 'type': 'number'},
{'label': '500,000', ''value': 500000, 'type': 'number'},
{'label': '750,000', 'value': 750000, 'type': 'number'},
{'label': '1,000,000', 'value': 1000000, 'type': 'number'},
],
placeholder="Select Impressions",
)
],
style={'width': '20%', 'display': 'inline-block', 'padding-right': '10px'}),
html.Div([
dcc.Dropdown(
id='Speed',
options=[
{'label': 'Low', 'value': 50, 'type': 'number'},
{'label': 'Average', 'value': 100, 'type': 'number'},
{'label': 'High', 'value': 150, 'type': 'number'},
],
placeholder="Select Frequency",
)
],
style={'width': '20%', 'display': 'inline-block', 'padding-right': '10px'}),
html.Div([
html.Button('Submit', id='submit_button', type='submit', n_clicks=1,
style={'width': '100px', 'height': '34.5px', 'margin-bottom': '8px',
'border-radius': '4px', 'display': 'inline-block', 'background-color': '#2D91C3', 'color': 'white'})
],
style={'display': 'inline-block', 'padding-bottom': '20px', 'verticalAlign': 'middle'}),
], style={
'backgroundColor': '#EFEAEA',
'padding': '5px'})
], style={'position': 'relative', 'left': '250px'})
]),
html.Div([
html.Div([
dcc.Graph(id='example-graph', config={'modeBarButtonsToRemove': ['pan2d', 'lasso2d', 'sendDataToCloud',
'select2d', 'autoScale2d', 'resetScale2d',
'toggleSpikelines',
'hoverClosestCartesian']})
],
style={'width': '49.3%', 'display': 'inline-block', 'border': 'thin grey solid', 'margin-left': '5px',
'margin-right': '2.5px', 'margin-top': '5px', 'margin-bottom': '2.5px'}),
html.Div([
dcc.Graph(id='example-graph1')
],
style={'width': '49.3%', 'display': 'inline-block', 'border': 'thin grey solid', 'margin-left': '2.5px',
'margin-right': '5px', 'margin-top': '5px', 'margin-bottom': '2.5px', 'backgroundColor': '#EFEAEA'})
], style={'backgroundColor': '#EFEAEA'}),
html.Div([
dcc.Graph(id='graph1')
],
style={'width': '99.2%', 'height': '120%', 'display': 'inline-block', 'border': 'thin grey solid', 'margin-left': '2.5px',
'margin-right': '5px', 'margin-top': '5px', 'margin-bottom': '2.5px', 'backgroundColor': '#EFEAEA'})
])
#app.callback(Output('example-graph1', 'figure'),
[Input('submit_button', 'n_clicks')],
[State('my-date-picker-range', 'start_date'),
State('my-date-picker-range', 'end_date')])
def update_graph(n_clicks, start_date, end_date):
if n_clicks > 0:
df = df_new
start_date_temp = dt.strptime(start_date, '%Y-%m-%d')
end_date_temp = dt.strptime(end_date, '%Y-%m-%d')
start_date_new = start_date_temp.replace(start_date_temp.year - 1)
end_date_new = end_date_temp.replace(end_date_temp.year - 1)
end_date_string = end_date_new.strftime('%Y-%m-%d')
start_date_string = start_date_new.strftime('%Y-%m-%d')
mask = (df['Date'] >= start_date_string) & (df['Date'] <= end_date_string)
filtered_df = df.loc[mask]
trace = Scatter(
y=filtered_df['Weights'],
x=filtered_df['Date'],
line=plotly.graph_objs.scatter.Line(
color='#42C4F7'
),
hoverinfo='skip',
error_y=plotly.graph_objs.scatter.ErrorY(
type='data',
array=filtered_df['Gender'],
thickness=1.5,
width=2,
color='#B4E8FC'
),
mode='lines'
)
layout1 = Layout(
height=450,
xaxis=dict(
showgrid=False,
showline=False,
zeroline=False,
fixedrange=True,
title='Time Elapsed (sec)'
),
yaxis=dict(
showline=False,
fixedrange=True,
zeroline=False,
),
margin=plotly.graph_objs.layout.Margin(
t=45,
l=50,
r=50
)
)
return Figure(data=[trace], layout=layout1)
else:
return {"I am the boss"}
The reason I presume the n_clicks checks is not working because I get the following error
TypeError: strptime() argument 1 must be str, not None
I believe the error is because of the below code inside the function as the first time the page loads start_date would be none type.
start_date_temp = dt.strptime(start_date, '%Y-%m-%d')
Can some one please help to resolve the issue. What I expect that when the page loads the call back function should not run.
Thanks a lot in advance !!
Here is your problem:
html.Button('Submit', id='submit_button', type='submit', n_clicks=1,
You've preset n_clicks to have a value. Just remove that n_clicks=1 part, and it will load the page as None. You will then need to check n_clicks like this (or similar):
if n_clicks is not None and n_clicks > 0:
It worked for me, and ran until it broke with my example df.

How to update xaxis and yaxis name on interval using Dash Plotly in python?

I copy the example from Dash-Plotly multiple inputs (https://dash.plot.ly/getting-started-part-2) and I changed it to be updated on intervals of 2 seconds. The graph is being updated but the title on the X and Y axis are not. The original example updates the X and Y titles on the graph. I am using python 3. I realized that this is happening only because I am using dcc.Graph(id='indicator-graphic', animate=True),. If I use dcc.Graph(id='indicator-graphic'), the xaxis and yaxis are updated but the graph itself no. Here is the code:
import dash
from dash.dependencies import Output, Input, Event
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv(
'https://gist.githubusercontent.com/chriddyp/'
'cb5392c35661370d95f300086accea51/raw/'
'8e0768211f6b747c0db42a9ce9a0937dafcbd8b2/'
'indicators.csv')
available_indicators = df['Indicator Name'].unique()
# load file with all RPi available
available_rpi = pd.read_csv('available_rpi.conf', header=None, dtype={0: str}).set_index(0).squeeze().to_dict()
print("Raspberry Pi's available:")
for key, value in available_rpi.items():
print('IP:{} name: {}'.format(key, value))
print()
app.layout = html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='xaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Fertility rate, total (births per woman)'
),
dcc.RadioItems(
id='xaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
],
style={'width': '30%', 'display': 'inline-block'}),
html.Div([
dcc.Dropdown(
id='yaxis-column',
options=[{'label': i, 'value': i} for i in available_indicators],
value='Life expectancy at birth, total (years)'
),
dcc.RadioItems(
id='yaxis-type',
options=[{'label': i, 'value': i} for i in ['Linear', 'Log']],
value='Linear',
labelStyle={'display': 'inline-block'}
)
],style={'width': '30%', 'float': 'right', 'display': 'inline-block'})
]),
dcc.Graph(id='indicator-graphic', animate=True),
dcc.Interval(id='graph-update',interval=2*1000),
dcc.Slider(
id='year--slider',
min=df['Year'].min(),
max=df['Year'].max(),
value=df['Year'].max(),
marks={str(year): str(year) for year in df['Year'].unique()}
)
])
#app.callback(
dash.dependencies.Output('indicator-graphic', 'figure'),
[dash.dependencies.Input('xaxis-column', 'value'),
dash.dependencies.Input('yaxis-column', 'value'),
dash.dependencies.Input('xaxis-type', 'value'),
dash.dependencies.Input('yaxis-type', 'value'),
dash.dependencies.Input('year--slider', 'value')],
events=[Event('graph-update', 'interval')])
def update_graph(xaxis_column_name, yaxis_column_name,
xaxis_type, yaxis_type,
year_value):
dff = df[df['Year'] == year_value]
return {
'data': [go.Scatter(
x=dff[dff['Indicator Name'] == xaxis_column_name]['Value'],
y=dff[dff['Indicator Name'] == yaxis_column_name]['Value'],
text=dff[dff['Indicator Name'] == yaxis_column_name]['Country Name'],
mode='markers',
marker={
'size': 15,
'opacity': 0.5,
'line': {'width': 0.5, 'color': 'white'}
}
)],
'layout': go.Layout(
xaxis={
'title': xaxis_column_name,
'type': 'linear' if xaxis_type == 'Linear' else 'log'
},
yaxis={
'title': yaxis_column_name,
'type': 'linear' if yaxis_type == 'Linear' else 'log'
},
margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
hovermode='closest'
)
}
if __name__ == '__main__':
app.run_server(debug=True)
according to https://community.plot.ly/t/my-callback-is-updating-only-the-lines-of-the-graph-but-not-the-legend/16208/3?u=felipe.o.gutierrez there is a lot of issues with animate=True and they are replacing for Exploring a "Transitions" API for dcc.Graph 2

Python-Dash dropdown display of multiple items with interactive callbacks

I am using Dash by Plotly with python to create a web application.
I have been struggling with having multiple values being displayed correctly on a dropdown element. Starting from a pandas dataframe I am extracting a column 1, then selecting values in another column 2 corresponding to values in column 1. Multiple values are to be displayed in the dropdown. Attached is a GIF of what the app is doing. I want the values on dropdown 2 to be independent values on separate lines, i.e distinct values and not concatenated together.
I think the problem is how I am returning the values in
def update_dropdown2(wdg):
wdgarray=df[ df['wdg'] == wdg ]['id'],
return [{'label':i,'value':i} for i in wdgarray]
Here is a gif file showing the problem of the
second dropdown element display on each line
Here is the code:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
from dash.dependencies import Input, Output
#create a dataframe with random data
df = pd.DataFrame(
{'wdg': [10,10,10,20,20,20,30,30,30,40],
'id': np.arange(0,100,10),
'b': np.random.rand(10)*100,
'c': np.random.rand(10)*100,
'd': np.random.rand(10)*100,
'e': np.random.rand(10)*100,
'f': np.random.rand(10)*100,
'g': np.random.rand(10)*100,
'h': np.random.rand(10)*100,
'k': np.random.rand(10)*100},
columns=['wdg','id','b','c','d','e','f','g','h','k'])
app = dash.Dash()
#html layout
app.layout = html.Div([
html.H1(
children='Perfomance database web app',
style={
'textAlign': 'center',
'color': colors['text']}
),
html.Div([
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in df.wdg.unique()],
value='10'
),
dcc.Dropdown(
id='dropdown2',
#options=[{'label': i, 'value': i} for i in mtrid_indicators],
#value='1'
),
],
style={'width': '49%', 'display': 'inline-block'}
),
html.Div(id='tablecontainer'),
html.Div(
dcc.Graph(
id='graph',
style={'width':'600','height':'500'}
),
style={'display':'inline-block'}
),
],
style={'width': '100%', 'display': 'inline-block'}
)
#callback to update dropdown 2
#app.callback(
Output(component_id='dropdown2',component_property='options'),
[Input(component_id='dropdown1',component_property='value')]
)
#function to that will update values in dropdown 2
def update_dropdown2(wdg):
wdgarray=df[ df['wdg'] == wdg ]['id'],
return [{'label':i,'value':i} for i in wdgarray]
#callback to update graph with values of dropdown 1 selecting pandas row
#app.callback(
Output('graph', 'figure'),
[Input('dropdown1', 'value')]
)
#graph plot and styling
def update_graph(row):
dff = df.iloc[int(row/10)].values # update with your own logic
return {
'data': [
go.Scatter(
x=np.arange(0,80,10),
y=dff,
mode='lines+markers',
line = dict(width = 5,color = 'rgb(200, 0, 0)'),
name='Torque curve',
marker = dict(
size = 10,
color = 'rgba(200, 0, 0, .9)',
line = dict(width = 2,color='rgb(0, 0, 0)')
)
),
],
'layout': go.Layout(
title='Torque Speed curve',
xaxis=dict(
# type='line',
title='Speed - (RPM)',
showgrid=True,
#zeroline=True,
showline=True,
gridcolor='#bdbdbd',
mirror="ticks",
ticks="inside",
tickwidth=1,
linewidth=2,
range=[0,100]
),
yaxis=dict(
title= 'Torque - (lb-ft)',
titlefont=dict( color='rgb(200, 0, 0)' ),
tickfont=dict( color='rgb(200, 0, 0)' ),
range=[0, 120],
showgrid=True,
#zeroline=True,
showline=True,
gridcolor='#bdbdbd',
mirror="ticks",
ticks="inside",
tickwidth=1,
linewidth=2
),
margin={'l': 60, 'b': 40, 't': 30, 'r': 60},
#legend={'x': 0.5, 'y': 1},
hovermode='closest',
showlegend=False,
)
}
if __name__ == '__main__':
app.run_server()
Solution coming from pdh in the amazing plotly community is to remove the comma which is turning what should be a pandas series into a tuple.
Link to solution from Plotly community
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
from dash.dependencies import Input, Output
#create a dataframe with random data
df = pd.DataFrame(
{'wdg': [10,10,10,20,20,20,30,30,30,40],
'id': np.arange(0,100,10),
'b': np.random.rand(10)*100,
'c': np.random.rand(10)*100,
'd': np.random.rand(10)*100,
'e': np.random.rand(10)*100,
'f': np.random.rand(10)*100,
'g': np.random.rand(10)*100,
'h': np.random.rand(10)*100,
'k': np.random.rand(10)*100},
columns=['wdg','id','b','c','d','e','f','g','h','k'])
app = dash.Dash()
#html layout
app.layout = html.Div([
html.H1(
children='Perfomance database web app',
style={
'textAlign': 'center',
'color': colors['text']}
),
html.Div([
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in df.wdg.unique()],
value='10'
),
dcc.Dropdown(
id='dropdown2',
#options=[{'label': i, 'value': i} for i in mtrid_indicators],
#value='1'
),
],
style={'width': '49%', 'display': 'inline-block'}
),
html.Div(id='tablecontainer'),
html.Div(
dcc.Graph(
id='graph',
style={'width':'600','height':'500'}
),
style={'display':'inline-block'}
),
],
style={'width': '100%', 'display': 'inline-block'}
)
#callback to update dropdown 2
#app.callback(
Output(component_id='dropdown2',component_property='options'),
[Input(component_id='dropdown1',component_property='value')]
)
#function to that will update values in dropdown 2
def update_dropdown2(wdg):
wdgarray=df[ df['wdg'] == wdg ]['id'] # removed problematic comma
return [{'label':i,'value':i} for i in wdgarray]
#callback to update graph with values of dropdown 1 selecting pandas row
#app.callback(
Output('graph', 'figure'),
[Input('dropdown1', 'value')]
)
#graph plot and styling
def update_graph(row):
dff = df.iloc[int(row/10)].values # update with your own logic
return {
'data': [
go.Scatter(
x=np.arange(0,80,10),
y=dff,
mode='lines+markers',
line = dict(width = 5,color = 'rgb(200, 0, 0)'),
name='Torque curve',
marker = dict(
size = 10,
color = 'rgba(200, 0, 0, .9)',
line = dict(width = 2,color='rgb(0, 0, 0)')
)
),
],
'layout': go.Layout(
title='Torque Speed curve',
xaxis=dict(
# type='line',
title='Speed - (RPM)',
showgrid=True,
#zeroline=True,
showline=True,
gridcolor='#bdbdbd',
mirror="ticks",
ticks="inside",
tickwidth=1,
linewidth=2,
range=[0,100]
),
yaxis=dict(
title= 'Torque - (lb-ft)',
titlefont=dict( color='rgb(200, 0, 0)' ),
tickfont=dict( color='rgb(200, 0, 0)' ),
range=[0, 120],
showgrid=True,
#zeroline=True,
showline=True,
gridcolor='#bdbdbd',
mirror="ticks",
ticks="inside",
tickwidth=1,
linewidth=2
),
margin={'l': 60, 'b': 40, 't': 30, 'r': 60},
#legend={'x': 0.5, 'y': 1},
hovermode='closest',
showlegend=False,
)
}
if __name__ == '__main__':
app.run_server()

Categories

Resources