How do I use Dash Loading with Dash Store? - python

I am writing a simple Dash page. I get data from external APIs etc. and put this in a dcc.Store. The Graphs then pull the data and plot in callbacks. I am trying to implement the dcc.Loading functionality as the pulling of the data can take some time. However I can't figure out how to trigger the Loading for the Graphs when the work is being done by Store.
Below is an example:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import plotly.express as px
import pandas as pd
import time
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(children=[
html.H1(children='Hello Dash'),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Dropdown(
id='demo-dropdown',
options=[
{'label': 'New York City', 'value': 'NYC'},
{'label': 'Montreal', 'value': 'MTL'},
{'label': 'San Francisco', 'value': 'SF'}
],
value='NYC'
),
dcc.Loading(
id='loading01',
children=html.Div(id='loading-output')),
# Store certain values
dcc.Store(
id='session',
storage_type='session'),
])
#app.callback(Output('loading-output', 'children'),
[Input('session', 'modified_timestamp')],
[State('session', 'data')])
def loading_graph(ts, store):
if store is None:
raise PreventUpdate
if 'NYC' in store['value']:
v = 1
elif 'SF' in store['value']:
v=2
else:
v=3
return dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': [1, 2, 3], 'y': [4*v, 1*v, 2*v], 'type': 'bar', 'name': 'SF'},
{'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
],
'layout': {
'title': 'Dash Data Visualization'
}
}
)
#app.callback(Output('session', 'data'),
[Input('demo-dropdown', 'value')],
[State('session', 'data')])
def storing(value, store):
store = store or {}
store['value'] = value
time.sleep(3)
return store
if __name__ == '__main__':
app.run_server(debug=True)
I guess I was hoping for the spinner to be present whilst Store was fetching things.
Thanks in advance for any help or pointers.

If you want to show a loader when the storing callback is called it also needs to have an output to a Loading components' children property.
You can't have duplicate callback outputs, so you could either combine the callbacks into a single callback. Then you could have a single spinner that is active for as long as the combined callback takes to execute.
Or you could have multiple Loading components: One for each callback function:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import time
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
children=[
html.H1(children="Hello Dash"),
html.Div(
children="""
Dash: A web application framework for Python.
"""
),
dcc.Dropdown(
id="demo-dropdown",
options=[
{"label": "New York City", "value": "NYC"},
{"label": "Montreal", "value": "MTL"},
{"label": "San Francisco", "value": "SF"},
],
value="NYC",
),
dcc.Loading(id="loading01", children=html.Div(id="loading-output1")),
dcc.Loading(id="loading02", children=html.Div(id="loading-output2")),
# Store certain values
dcc.Store(id="session", storage_type="session"),
]
)
#app.callback(
Output("loading-output2", "children"),
Input("session", "modified_timestamp"),
State("session", "data"),
prevent_initial_call=True,
)
def loading_graph(ts, store):
if store is None:
raise PreventUpdate
if "NYC" in store["value"]:
v = 1
elif "SF" in store["value"]:
v = 2
else:
v = 3
time.sleep(2)
return dcc.Graph(
id="example-graph",
figure={
"data": [
{
"x": [1, 2, 3],
"y": [4 * v, 1 * v, 2 * v],
"type": "bar",
"name": "SF",
},
{"x": [1, 2, 3], "y": [2, 4, 5], "type": "bar", "name": u"Montréal"},
],
"layout": {"title": "Dash Data Visualization"},
},
)
#app.callback(
Output("session", "data"),
Output("loading-output1", "children"),
Input("demo-dropdown", "value"),
State("session", "data"),
)
def storing(value, store):
time.sleep(2)
store = store or {}
store["value"] = value
return store, ""
if __name__ == "__main__":
app.run_server(debug=True)

Related

Dropdown menu isn't searchable with images as labels

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...

Dropdown and Datatable in dash

I have the datepicker component which filters the datatable (top 10 songs on that specific date).Also I would like to have the bar chart which shows the total number of streamed songs of that top 10 songs (10 bars accordingly) preferably with dropdown core component with the options of the titles of songs that where filtered based on the date (the ones that datatable shows). with the below codem, the dropdown component shows all unique song titles thate are in the df but as I already said I want only the ones which will be picked after filtering on date.
Viz: https://imgur.com/a/i2FY83V
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Output, Input
import plotly.express as px
import dash_bootstrap_components as dbc
from datetime import date
import pandas as pd
df = pd.read_csv('bel.csv')
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LITERA],
meta_tags=[{'name' : 'viewport',
'content': 'width=device-width, initial-scale=1.0' }]
)
# layout
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.H1('Top songs in Belgium',className='text-center text-primary,mb-4'),
html.P ('Analyze the Top streamed songs in a month of between March & April',
className='text-center'),
], width= 12)
]),
dbc.Row([
dbc.Col([
dcc.DatePickerSingle(
id = 'my-date-picker-single',
min_date_allowed=date(2022,3,1),
max_date_allowed= date(2022,5,1),
initial_visible_month=date(2022,3,1),
date= date(2022,3,1)
),
dash_table.DataTable(
id ='datatable-interactivity',
columns=[
{"name": i, "id": i, "deletable": False, "selectable": True, "hideable": True}
if i == "iso_alpha3" or i == "year" or i == "id"
else {"name": i, "id": i, "deletable": False, "selectable": True}
for i in df.loc[0:4,['Rank', 'Title']]
],
data =df.to_dict('records'),
editable= False,
style_as_list_view=True,
style_header={
'backgroundColor': 'white',
'fontWeight': 'bold',
},
style_data={
'whiteSpace': 'normal',
'height':'auto',
'backgroundColor': 'rgb(50, 50, 50)',
'color': 'white'},
),
], width=5),
dbc.Col([
dcc.Dropdown(id='my-dpdn', multi=True,
placeholder="Select a title",
options=[{'label': x, 'value': x}
for x in sorted(df['Title'].unique())]),
dcc.Graph(id='bar-fig', figure={}),
], width ={'size':5})
]),
dbc.Row([
]),
], fluid= True)
def date_string_to_date(date_string):
return pd.to_datetime(date_string, infer_datetime_format=True)
#app.callback(
dash.dependencies.Output('datatable-interactivity', 'data'),
dash.dependencies.Input('my-date-picker-single','date')
)
def update_data (date):
data = df.to_dict('records')
if date:
mask = (date_string_to_date(df['Chart Date']) == date_string_to_date(date))
data= df.loc[mask].head(10).to_dict('records')
return data
# -------------------------------------------------------------------------
if __name__ == '__main__':
app.run_server(debug=True)

Synchronize Slider with CurrentTime of Video Dash Plotly

I am building a Dash app that will have a video playing and be controlled by a play/pause button. Above the video, I have a slider which allows a user to skip to any part in the video (10 seconds long). I want to be able to have the slider move as the video plays.
Here is what I've tried so far:
import os
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_player as player
from flask import Flask, Response
from dash.dependencies import Input, Output, State
server = Flask(__name__)
app = dash.Dash(__name__, server=server)
app.layout = html.Div(
children=[
html.Div(
children=[
html.Div([
html.Button('Play/Pause', id='play-button', n_clicks=0),
],style={
'width':'10%',
'display':'inline-block'
}),
html.Div([
dcc.Slider(id='slider',
min=0,
max=10,
step=1,
value=0,
marks={0: {'label': '0s', 'style': {'color': 'black'}},
2: {'label': '2s', 'style': {'color': 'black'}},
4: {'label': '4s', 'style': {'color': 'black'}},
6: {'label': '6s', 'style': {'color': 'black'}},
8: {'label': '8s', 'style': {'color': 'black'}},
10: {'label': '10s', 'style': {'color': 'black'}}
}
),
],style={
'width':'90%',
'display':'inline-block'
})
]
),
html.Div(
children=[
player.DashPlayer(
id='video-player',
url='https://www.w3schools.com/html/mov_bbb.mp4',
controls=False,
width='100%'
)
]
)
]
)
#Use slider to skip to or "seekTo" different spots in video
#app.callback(Output('video-player', 'seekTo'),
Input('slider', 'value'))
def set_seekTo(value):
return value
#Press button to play/pause video 1
#app.callback(
Output("video-player", "playing"),
Output("slider","value"),
Input("play-button", "n_clicks"),
State("video-player", "playing"),
State('slider','value'),
State("video-player","currentTime")
)
def play_video(n_clicks, playing, value, currentTime):
value = currentTime
if n_clicks:
return not playing, value
return playing, value
if __name__ == "__main__":
app.run_server(debug=True, port=8050)
The play/pause button works just fine, but the functionality of syncing the slider bar to the currentTime of the video is ignored. No error messages. What am I missing here? Any help would be greatly appreciated!
Note: I initially wanted to make this a comment as I wasn't able to get the seekTo functionality to work in conjunction with synchronizing the time and the slider, but the explanation of my implementation was too long for a comment. Below is listed a way you could update the slider value based on the currentTime of the dash player component, but doesn't implement seekTo.
Implementation
import os
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_player as player
from flask import Flask, Response
from dash.dependencies import Input, Output, State
app = dash.Dash(__name__)
app.layout = html.Div(
children=[
html.Div(
children=[
html.Div(
[
html.Button("Play/Pause", id="play-button", n_clicks=0),
],
style={"width": "10%", "display": "inline-block"},
),
html.Div(
[
dcc.Slider(
id="slider",
min=0,
max=10,
step=1,
value=0,
marks={
0: {"label": "0s", "style": {"color": "black"}},
2: {"label": "2s", "style": {"color": "black"}},
4: {"label": "4s", "style": {"color": "black"}},
6: {"label": "6s", "style": {"color": "black"}},
8: {"label": "8s", "style": {"color": "black"}},
10: {"label": "10s", "style": {"color": "black"}},
},
),
],
style={"width": "90%", "display": "inline-block"},
),
]
),
html.Div(
children=[
player.DashPlayer(
id="video-player",
url="https://www.w3schools.com/html/mov_bbb.mp4",
controls=False,
width="100%",
)
]
),
]
)
#app.callback(Output("slider", "value"), Input("video-player", "currentTime"))
def update_slider(current_time):
return current_time
#app.callback(
Output("video-player", "playing"),
Input("play-button", "n_clicks"),
State("video-player", "playing"),
)
def play_video(n_clicks, playing):
if n_clicks:
return not playing
return playing
if __name__ == "__main__":
app.run_server(debug=True, port=8050)
Explanation
The idea of the above implementation is to create a callback for updating the slider value everytime the currentTime interval changes and to create a callback that handles playing and pausing the video when play-button is pressed.
Keep in mind here that I'm using currentTime as an input, so the callback will get called everytime this value changes. It seems to change every 40 ms by default. You can change this interval by setting the intervalCurrentTime prop on the DashPlayer.
Also keep in mind that the slider value will only change every second here, because step is set to 1. So change the step value in combination with intervalCurrentTime if you want different behavior.

How to use Callback to update Bar Graph in Dash

Since Dash is a fairly new framework for making interactive web-based graphs, there is not too many information that are specific or detailed for beginners. In my case I need to update a simple bar graph using a callback function.
The data does not render on the browser even though the server runs fine without prompting any errors.
Need help sorting out and understanding why data does not render.
import dash
from dash.dependencies import Output, Event
import dash_core_components as dcc
import dash_html_components as html
import plotly
import plotly.graph_objs as go
app = dash.Dash(__name__)
colors = {
'background': '#111111',
'background2': '#FF0',
'text': '#7FDBFF'
}
app.layout = html.Div( children = [
html.Div([
html.H5('ANNx'),
dcc.Graph(
id='cx1'
)
])
]
)
#app.callback(Output('cx1', 'figure'))
def update_figure( ):
return {
'data': [
{'x': ['APC'], 'y': [9], 'type': 'bar', 'name': 'APC'},
{'x': ['PDP'], 'y': [8], 'type': 'bar', 'name': 'PDP'},
],
'layout': {
'title': 'Basic Dash Example',
'plot_bgcolor': colors['background'],
'paper_bgcolor': colors['background']
}
}
if __name__ == '__main__':
app.run_server(debug=True)
You can use callback in a such way (I create dropdown menu for this):
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly
import plotly.graph_objs as go
import pandas as pd
app = dash.Dash(__name__)
df = pd.DataFrame({'x': ['APC', 'PDP'], 'y': [9, 8]})
colors = {
'background': '#111111',
'background2': '#FF0',
'text': '#7FDBFF'
}
app.layout = html.Div(children=[
html.Div([
html.H5('ANNx'),
html.Div(
id='cx1'
),
dcc.Dropdown(id='cx2',
options=[{'label': 'APC', 'value': 'APC'},
{'label': 'PDP', 'value': 'PDP'},
{'label': 'Clear', 'value': None}
]
)
])])
#app.callback(Output('cx1', 'children'),
[Input('cx2', 'value')])
def update_figure(value):
if value is None:
dff = df
else:
dff = df.loc[df["x"] == value]
return html.Div(
dcc.Graph(
id='bar chart',
figure={
"data": [
{
"x": dff["x"],
"y": dff["y"],
"type": "bar",
"marker": {"color": "#0074D9"},
}
],
"layout": {
'title': 'Basic Dash Example',
"xaxis": {"title": "Authors"},
"yaxis": {"title": "Counts"},
'plot_bgcolor': colors['background'],
'paper_bgcolor': colors['background']
},
},
)
)
if __name__ == '__main__':
app.run_server(debug=True)
If you write output in your calback function then you need to provide input as well, it can be, slider, date picker or dropdown menu and etc. but in your case you dont need any input and output as your graph is not dynamic in this case. check here https://dash.plot.ly/getting-started-part-2
so in your case it is enough just to put id and figure into dcc.Graph component:
import dash
import dash_core_components as dcc
import dash_html_components as html
app = dash.Dash(__name__)
colors = {
'background': '#111111',
'background2': '#FF0',
'text': '#7FDBFF'
}
app.layout = html.Div( children = [
html.Div([
html.H5('ANNx'),
dcc.Graph(
id='cx1', figure={
'data': [
{'x': ['APC'], 'y': [9], 'type': 'bar', 'name': 'APC'},
{'x': ['PDP'], 'y': [8], 'type': 'bar', 'name': 'PDP'},
],
'layout': {
'title': 'Basic Dash Example',
'plot_bgcolor': colors['background'],
'paper_bgcolor': colors['background']
}}
)
])
]
)
if __name__ == '__main__':
app.run_server(debug=True)

API defined dataframe (dynamically generated) into Table (Dash_Table_Experiments)

Does anyone know how to dynamically generate a TABLE of data based on the user input using Dash_Table_Experiments (Python code)?
This code is static, however, I would like to find a way to make it dynamic. Thus, when a user enters a ticker symbol the TABLE will automatically update with the pertinent data below the chart.
The dataframe will change because it is generated from an api (i.e. Alpha Vantage), thus it cannot be defined as a static table. See code below.
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dt
import json
import pandas as pd
from alpha_vantage.timeseries import TimeSeries
print(dcc.__version__) # 0.6.0 or above is required
app = dash.Dash()
ts = TimeSeries(key='', output_format='pandas')
data1, meta_data = ts.get_daily(symbol=inputsymbol, outputsize='full')
date=data1.reset_index(level=['date'])
df=(date.tail(10))
DF_SIMPLE = df
app.config.supress_callback_exceptions = True
app.scripts.config.serve_locally = True
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content'),
html.Div(dt.DataTable(rows=[{}]), style={'display': 'none'})
])
index_page = html.Div([
html.H1('Page Home'),
html.Br(),
dcc.Link('Go to Home', href='/'),
html.Br(),
dcc.Link('Go to Page 1', href='/page-1'),
])
page_1_layout = html.Div([
html.H1('Page 1'),
html.Br(),
dcc.Link('Go back to home', href='/'),
html.H4('DataTable'),
dt.DataTable(
rows=DF_SIMPLE.to_dict('records'),
# optional - sets the order of columns
#columns=sorted(DF_SIMPLE.columns),
editable=False,
id='editable-table'
),
html.Div([
html.Pre(id='output', className="two columns"),
html.Div(
dcc.Graph(
id='graph',
style={
'overflow-x': 'wordwrap'
}
),
className="ten columns"
)
], className="row"),
])
#app.callback(
dash.dependencies.Output('output', 'children'),
[dash.dependencies.Input('editable-table', 'rows')])
def update_selected_row_indices(rows):
return json.dumps(rows, indent=2)
#app.callback(
dash.dependencies.Output('graph', 'figure'),
[dash.dependencies.Input('editable-table', 'rows')])
def update_figure(rows):
dff = pd.DataFrame(rows)
return {
'data': [{
'x': dff['x'],
'y': dff['y'],
}],
'layout': {
'margin': {'l': 10, 'r': 0, 't': 10, 'b': 20}
}
}
# Update the index
#app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/page-1':
return page_1_layout
else:
return index_page
app.css.append_css({
'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'
})
if __name__ == '__main__':
app.run_server(debug=True)

Categories

Resources