I'm new to Dash and I'm trying to figure out how to set Callback inputs.
My Dash app has graphs that I want to dynamically update with new data on every page load (or refresh.)
I don't want to do it through user interaction such as dropdown, radio button...
To do so I have created hidden divs as callback inputs, but I'm not sure this is the proper way.
Is there any other approach that would be more suitable (or elegant) in this situation?
Please let me know if there’s something else in my code that needs to be changed.
This is my code:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
import json
import plotly.express as px
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions'] = True
data = [['Blue', 30], ['Red ', 20], ['Green', 60]]
df = pd.DataFrame(data, columns=['Color', 'Number'])
data1 = [['A', 10, 88], ['B ', 50, 45], ['C', 25, 120]]
df1 = pd.DataFrame(data1, columns=['Letter', 'Column1', 'Column2'])
def serve_layout():
slayout = html.Div(children=[
html.H1(children='Colors and Letters', style={'text-align': 'center'}),
html.Div([
html.Div(id='input-value', style={'display': 'none'}),
html.Div(id='intermediate-value', style={'display': 'none'}),
]),
html.Div([dcc.Graph(id='graph', style={'width': 1200,
"margin-left": "auto",
"margin-right": "auto",
}),
dcc.Graph(id='graph1', style={'width': 1200,
"margin-left": "auto",
"margin-right": "auto",
})]),
])
return slayout
#app.callback(Output('intermediate-value', 'children'),
[Input('input-value', 'value')])
def clean_data(value):
df_1 = df
df_2 = df1
datasets = {
'df_1': df_1.to_json(orient='split', date_format='iso'),
'df_2': df_2.to_json(orient='split', date_format='iso')
}
return json.dumps(datasets)
#app.callback(
Output('graph', 'figure'),
[Input('intermediate-value', 'children')])
def update_graph(cleaned_data):
datasets = json.loads(cleaned_data)
dff = pd.read_json(datasets['df_1'], orient='split')
fig = go.Figure(data=[go.Bar(x=dff['Color'], y=dff['Number'], text=dff['Number'], textposition='auto')],
layout=go.Layout())
return fig
#app.callback(
Output('graph1', 'figure'),
[Input('intermediate-value', 'children')])
def update_graph(cleaned_data):
datasets = json.loads(cleaned_data)
dff1 = pd.read_json(datasets['df_2'], orient='split')
fig1 = px.line(x=dff1['Letter'], y=dff1['Column1'], color=px.Constant('Column1'),
labels=dict(x='Letter', y='Column1', color='Letter'))
fig1.add_bar(x=dff1['Letter'], y=dff1['Column2'], name='Column2')
return fig1
app.layout = serve_layout
if __name__ == '__main__':
app.run_server(debug=True)
Thanks for any help on this matter.
If you only want to update the plots on page load / refresh, I would advise against any callbacks and instead directly load the figures.
This way, you can leave out all the hidden and intermediate values.
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
import plotly.graph_objs as go
import json
import plotly.express as px
import numpy as np
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions'] = True
def refresh_data():
data = [['Blue', 30], ['Red ', np.random.random(1)[0] * 10], ['Green', 60]]
df = pd.DataFrame(data, columns=['Color', 'Number'])
data1 = [['A', 10, 88], ['B ', 50, 45], ['C', 25, 120]]
df1 = pd.DataFrame(data1, columns=['Letter', 'Column1', 'Column2'])
return df, df1
def serve_layout():
plot_style = {'width': 1200,
"margin-left": "auto",
"margin-right": "auto",
}
slayout = html.Div(children=[
html.H1(children='Colors and Letters', style={'text-align': 'center'}),
html.Div(
[dcc.Graph(figure=get_graph(), id='graph', style=plot_style),
dcc.Graph(figure=get_graph1(), id='graph1', style=plot_style)]),
])
return slayout
def get_clean_data():
df_1, df_2 = refresh_data()
datasets = {
'df_1': df_1.to_json(orient='split', date_format='iso'),
'df_2': df_2.to_json(orient='split', date_format='iso')
}
return json.dumps(datasets)
def get_graph():
datasets = json.loads(get_clean_data())
dff = pd.read_json(datasets['df_1'], orient='split')
fig = go.Figure(data=[
go.Bar(x=dff['Color'], y=dff['Number'], text=dff['Number'],
textposition='auto')],
layout=go.Layout())
return fig
def get_graph1():
datasets = json.loads(get_clean_data())
dff1 = pd.read_json(datasets['df_2'], orient='split')
fig1 = px.line(x=dff1['Letter'], y=dff1['Column1'],
color=px.Constant('Column1'),
labels=dict(x='Letter', y='Column1', color='Letter'))
fig1.add_bar(x=dff1['Letter'], y=dff1['Column2'], name='Column2')
return fig1
app.layout = serve_layout
if __name__ == '__main__':
app.run_server(debug=True)
Related
Adding images to dropdown labels as described in paragraph Components as Option Labels in
https://dash.plotly.com/dash-core-components/dropdown
makes labels not searchable even though searchable=True is set.
Is there workaround to make labels searchable as usual?
Minimal working code:
import pandas as pd
import plotly
import plotly.express as px
import json
import dash_bootstrap_components as dbc
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
df = pd.read_csv('data_bdo.csv', index_col=0)
temp=[
{
"label": html.Div(
[
html.Img(src="/assets/1.png", height=20),
html.Div("Python", style={'font-size': 15, 'padding-left': 10}),
], style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'}
),
"value": "Python",
},
{
"label": html.Div(
[
html.Img(src="/assets/2.png", height=20),
html.Div("Julia", style={'font-size': 15, 'padding-left': 10}),
], style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'}
),
"value": "Julia",
},]
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.DARKLY],update_title = None )
app.layout = html.Div([
html.Div([
dcc.Dropdown(id='my_dropdown',
options=temp,
searchable=True #allow user-searching of dropdown values
)],className='three columns')])
#app.callback(
Output(component_id='the_graph', component_property='figure'),
[Input(component_id='my_dropdown', component_property='value')]
)
def update_bar_chart(my_dropdown):
df = pd.read_csv('data_bdo.csv', index_col=0)
fig = px.bar(df[["name", my_dropdown]].dropna().sort_values(by=my_dropdown,ascending=False),
x="name",
y=my_dropdown,
template = 'plotly_dark',
text=my_dropdown,
labels={my_dropdown:"Amount of "+ str(my_dropdown)}
)
fig.update_traces(textfont_size=13, textposition="outside", cliponaxis=False)
return fig
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
Dropdown with options of the form [{'label': 'Python', 'value': 'Python'}] is searchable though...
I am creating an app where the first page should take only 'text input' and results(graph) must show on second page or new tab. I do not want text input and charts on the same page. It means, if I write the input as 'USA' in text input bar, the graph of USA should populate on second tab. Following is the working code that I have written so far in dropdown format. In this code, dropdown and graphs are on the same page which I do not want. Please suggest.
import pandas as pd
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
import numpy as np
import plotly.io as pio
pio.renderers.default='browser'
app = dash.Dash(__name__)
app.layout = html.Div([
html.H1("Economy Analysis"),
dcc.Dropdown(id='Country_select',
options=[{'label': x, 'value': x}
for x in df.Country.unique()],
value = 'USA'
),
dcc.Graph(id ='my-graph', figure = {})
])
#app.callback(
Output(component_id = 'my-graph', component_property = 'figure'),
Input(component_id = 'Country_select', component_property = 'value'))
def interactive_graphing(value_country):
print(value_country)
s = 100
cat_g = ["developing","develop"]
sample_cat = [cat_g[np.random.randint(0,2)]for i in range(100)]
df = pd.DataFrame({"Country": np.random.choice(["USA", "JPY", "MEX", "IND", "AUS"], s),
"Net": np.random.randint(5, 75, s),
})
df["sample_cat"] = sample_cat
df = df[df.Country==value_country]
df2 = df.pivot_table(index='Country',columns='sample_cat',values='Net',aggfunc='sum')
df2.reset_index(inplace=True)
fig = px.bar(df2, x="Country",
y=['develop','developing'])
return fig
if __name__=='__main__':
app.run_server()
You can use dcc.Tabs and dcc.Tab containers in your layout, and put the input/graph in separate tabs. Dash bootstrap components tabs would also work for this. The ids will still work as inputs/outputs with your callback.
Sample layout:
app.layout = html.Div([
html.H1("Economy Analysis"),
dcc.Tabs([
dcc.Tab(
label='Dropdown',
children=[
dcc.Dropdown(id='Country_select',
options=[{'label': x, 'value': x}
for x in df.Country.unique()],
value = 'USA')
]
),
dcc.Tab(
label='Graph',
children=[
dcc.Graph(id ='my-graph')
]
)
])
])
I have created this very simplified example in which I would like to dynamically update the title of a chart as a dropdown label changes.
Here's the code:
data = {'Stock': ['F', 'NFLX', 'AMZN'], 'Number': [10, 15, 7]}
df = pd.DataFrame(data, columns=['Stock', 'Number'])
stock_options = df['Stock']
app = dash.Dash(__name__)
app.layout = html.Div(children=[
html.H1(children='Example Bar Chart'),
html.Div([
dcc.Dropdown(
id='dropdown',
options=[{'label': i, 'value': i} for i in stock_options],
value='F',
),
html.Div(dcc.Graph(id='graph')),
]),
])
#app.callback(
Output(component_id='graph', component_property='figure'),
Input(component_id='dropdown', component_property='value')
)
def update_graph(stock):
msk = df.Stock.isin([stock])
figure = px.bar(df[msk], x='Stock', y='Number', title=f"{stock} open price")
return figure
if __name__ == '__main__':
app.run_server(debug=True)
So, while keeping the same label in dropdown instead of 'F open price' in the title I would like to get 'Facebook open price'... and so on.
I've tried to solve this with map but I couldn't get it working. Can someone point me in the direction on how to resolve this?
Thanks in advance.
As I wrote in my comment, not sure how you want to store the mapping between symbol name and the displayed title in the graph. Here is one solution that works using a dictionary stock_name_mapping that contains the symbols als keys and the displayed names as values:
import pandas as pd
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
data = {'Stock': ['F', 'NFLX', 'AMZN'], 'Number': [10, 15, 7]}
df = pd.DataFrame(data, columns=['Stock', 'Number'])
stock_options = df['Stock']
stock_name_mapping = {'F': 'Facebook',
'NFLX': 'Netflix',
'AMZN': 'Amazon'}
app = dash.Dash(__name__)
app.layout = html.Div(children=[
html.H1(children='Example Bar Chart'),
html.Div([
dcc.Dropdown(
id='dropdown',
options=[{'label': i, 'value': i} for i in stock_options],
value='F',
),
html.Div(dcc.Graph(id='graph')),
]),
])
#app.callback(
Output(component_id='graph', component_property='figure'),
Input(component_id='dropdown', component_property='value')
)
def update_graph(stock):
msk = df.Stock.isin([stock])
stock_name = stock_name_mapping[stock]
figure = px.bar(df[msk], x='Stock', y='Number', title=f"{stock_name} open price")
return figure
if __name__ == '__main__':
app.run_server(debug=True)
I am trying capture mouse hover events using Dash. I capture the position of the mouse using hoverData.
The problem appears when I filter the time series using the range selector or the range slider. The plot correctly reduces to the selected time, but when I hover it with the mouse it resets to the main view (whole main series).
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
app.layout = html.Div([
dcc.Graph(
id='stock-plot'
),
], className="container")
#app.callback(
Output('stock-plot', 'figure'),
[Input('stock-plot', 'hoverData')])
def drawStockPrice(hoverData):
traces = [go.Scatter(
x=df.Date,
y=df['AAPL.High'],
mode='lines',
opacity=0.7,
connectgaps=True),
]
return {'data': traces,
'layout': go.Layout(colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'],
height=600,
title=f"Closing prices",
xaxis={"title": "Date",
'rangeselector': {'buttons': list([{'count': 1, 'label': '1M',
'step': 'month',
'stepmode': 'backward'},
{'count': 6, 'label': '6M',
'step': 'month',
'stepmode': 'backward'},
{'step': 'all'}])},
'rangeslider': {'visible': True}, 'type': 'date'},
yaxis={"title": "Price (USD)"},
)}
if __name__ == '__main__':
app.run_server(debug=True)
I am sure there should be a better solution but this is what I got (Dash v1.6.0):
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
layout = go.Layout( colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'],
height=600,
title=f"Closing prices",
xaxis={"title": "Date",
'rangeselector': {'buttons': list([{'count': 1, 'label': '1M',
'step': 'month',
'stepmode': 'backward'},
{'count': 6, 'label': '6M',
'step': 'month',
'stepmode': 'backward'},
{'step': 'all'}]
),
},
'rangeslider': {'visible': True},
'type': 'date',
},
yaxis={"title": "Price (USD)"},
)
traces = [go.Scatter( x=df.Date,
y=df['AAPL.High'],
mode='lines',
opacity=0.7,
connectgaps=True
)]
app.layout = html.Div([
dcc.Graph(
id='stock-plot',
figure={
'data': traces,
'layout': layout
}
),
], className="container")
#app.callback(
Output('stock-plot', 'figure'),
[Input('stock-plot', 'hoverData'),
Input('stock-plot', 'relayoutData')],
[State('stock-plot', 'figure')]
)
def drawStockPrice(hoverData, selected, figure):
data = figure['data']
layout = figure['layout']
if selected is not None and 'xaxis.range' in selected:
layout['xaxis']['range'] = selected['xaxis.range']
return {'data': data,
'layout': layout
}
if __name__ == '__main__':
app.run_server(debug=True)
I am trying to update a graph in dash using an excel with data. I have 2 drop down and an excel document with different sheets for each drop down. I couldn't manage yet to select a value from drop down and to charge that data into the table (I have also a table before the graph) and plot values into the graph.
import dash
import dash_auth
import dash_core_components as dcc
import dash_html_components as html
import plotly
import dash_daq as daq
import os
import random
import pandas as pd
import plotly.graph_objs as go
from collections import deque
import psycopg2
from dash.dependencies import Output, Input
DB_NAME = "LicentaTest"
DB_USER = "postgres"
DB_PASS = "admin"
DB_HOST = "localhost"
DB_PORT = "5433"
VALID_USERNAME_PASSWORD_PAIRS = [
['admin1', 'admin']
]
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(_name_, external_stylesheets=external_stylesheets)
auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)
df = pd.read_excel('UploadData.xlsx', sheet_name='Total')
def generate_table(dataframe, max_rows=13):
return html.Table(
# Header
[html.Tr([html.Th(col) for col in dataframe.columns])] +
# Body
[html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))]
)
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(_name_, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.H1('Electrica SDEE Transilvania SUD SA'),
html.H4('Select the branch:'),
dcc.Dropdown(
id='dropdown',
options=[{'label': i, 'value': i} for i in ['ALBA', 'BRASOV',
'COVASNA', 'HARGHITA', 'MURES', 'SIBIU', 'TOTAL']],
value='',
placeholder = 'Select branch'
#multi = True
),
html.H4('Select the year:'),
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in ['2012', '2013',
'2014', '2015', '2016', '2017', '2018', 'ALL']],
value='',
placeholder = 'Select year'
),
html.Br(),
html.Button('OK', id='submit-form'),
html.Br(),
html.Div(children=[
html.H4(children='Own Technological Consumption'),
generate_table(df),
]),
html.Br(),
html.Br(),
html.Br(),
dcc.Graph(id='graph')],
className='container')
#app.callback(
dash.dependencies.Output('graph', 'figure'),
[dash.dependencies.Input('dropdown', 'value')])
def update_graph1(dropdown_value):
df = pd.read_excel('UploadData.xlsx', sheet_name='Total')
X1 = df.Date.values
Y1 = df.CPT.values
data = plotly.graph_objs.Scatter(
x=X1,
y=Y1,
name='Graph',
mode='lines+markers'
)
return {
'data': [data], 'layout' : go.Layout(xaxis=dict(range[min(X1),max(X1)]),
yaxis=dict(range=[min(Y1),max(Y1)]),
)
}
if _name_ == '_main_':
app.run_server(debug=True)
I expect, when select the value Alba from drop down and year 2015 to show me on table all the values related to this and to plot the CPT function of data.