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.
Related
I know this question might be asked, but I couldn't find a solution that fits my problem.
I'm trying to build a multi layout dash app.
I would like to to change the layout (which contains dcc.Graphs and dbc.Card) everytime I click on a different Tab ( I have 3 of those). The problem is that I have this exception when I run my code:
"dash.exceptions.InvalidCallbackReturnValue: The callback for <Output content.children>
returned a value having type Dash
which is not JSON serializable. "
Below is my code:
import dash_bootstrap_components as dbc
import base64
import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from DashFriends import friends_layout
from DashUser import user_layout
from FriendsUserApp import userfriends_layout
app = dash.Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.MINTY],
meta_tags=[{'name': 'viewport',
'content': 'width=device-width, initial-scale=1.0'}]
)
colors = {
'background': '#ffffff',
'text': '#4d94ff',
'plot': '#D1D0CE',
'textfig': '#000000'
}
app_tabs = html.Div(
[
dbc.Tabs(
[
dbc.Tab(label="My friends", tab_id="tab-friends", labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger"),
dbc.Tab(label="Just me", tab_id="tab-user", labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger"),
dbc.Tab(label="My Friends and I", tab_id="tab-userfriends",
labelClassName="text-success font-weight-bold",
activeLabelClassName="text-danger")
],
id="tabs",
active_tab="tab-user",
),
], className="mt-3"
)
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
html.H1(
children='Twitter User Analysis',
style={
'textAlign': 'center',
'font-family': 'Garamond',
'font-weight': 'bold',
'color': colors['text']
}
),
html.Div(children='Get an analysis of a user', style={
'textAlign': 'center',
'font-family': 'Garamond',
'font-weight': 'bold',
'color': colors['text']
}),
html.Br(),
html.Hr(),
dbc.Row(dbc.Col(app_tabs, width=12), className="mb-3"),
html.Br(),
html.Div(id='content', children=[])
])
#app.callback(
Output(component_id="content", component_property="children"),
[Input(component_id="tabs", component_property="active_tab")]
)
def switch_tab(tab_chosen):
if tab_chosen == "tab-friends":
return friends_layout
elif tab_chosen == "tab-user":
return user_layout
elif tab_chosen == "tab-userfriends":
return userfriends_layout
return html.P("This shouldn't be displayed for now...")
if __name__ == '__main__':
app.run_server(debug=True)
The problem is in code you haven't shared, but based on the error
dash.exceptions.InvalidCallbackReturnValue: The callback for <Output content.children>
returned a value having type Dash
which is not JSON serializable.
one of the layouts you return in your switch_tab callback returns an instance of a Dash app.
You can't do this:
In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.
I am trying to get into using Plotly Dash and I am getting stuck on this one piece where I would like to dynamically add a user-defined number of dropdowns. Here is what I tried:
# Import required libraries
import dash
import math
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
# App Begins
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = "Tool"
server = app.server
# Create global chart template
mapbox_access_token = "pk.eyJ1IjoicGxvdGx5bWFwYm94IiwiYSI6ImNrOWJqb2F4djBnMjEzbG50amg0dnJieG4ifQ.Zme1-Uzoi75IaFbieBDl3A"
layout = dict(
autosize=True,
automargin=True,
margin=dict(l=30, r=30, b=20, t=40),
hovermode="closest",
plot_bgcolor="#F9F9F9",
paper_bgcolor="#F9F9F9",
legend=dict(font=dict(size=10), orientation="h"),
title="Satellite Overview",
mapbox=dict(
accesstoken=mapbox_access_token,
style="light",
center=dict(lon=-78.05, lat=42.54),
zoom=7,
),
)
# Create app layout
app.layout = html.Div(
[
dcc.Store(id="aggregate_data"),
# empty Div to trigger javascript file for graph resizing
html.Div(id="output-clientside"),
html.Div(
[
html.Div(
[
html.Img(
src=app.get_asset_url("dash-logo.png"),
id="plotly-image",
style={
"height": "60px",
"width": "auto",
"margin-bottom": "25px",
},
)
],
className="one-third column",
),
html.Div(
[
html.Div(
[
html.H3(
"Dash Tool",
style={"margin-bottom": "0px"},
),
]
)
],
className="one-half column",
id="title",
),
],
id="header",
className="row flex-display",
style={"margin-bottom": "25px"},
),
html.Div(
[
html.Div(
[
html.P("Quantity 1:", className="control_label"),
dcc.Input(
id="quantity_1",
type="number",
placeholder=33.
),
html.P("Quantity 2:", className="control_label"),
dcc.Input(
id="quantity_2",
type="number",
placeholder=-115.
),
html.P("Number of Drop Downs:", className="control_label"),
dcc.Slider(
id="drop_downs",
min=2,
max=10,
value=2,
step=1.0,
className="dcc_control",
),
html.P("Load Inputs:", className="control_label"),
dcc.Checklist(
id='sources_flag',
options=[
{'label': 'Yes', 'value': 'Y'},
],
value=['Y'],
labelStyle={'display': 'inline-block'}
),
html.Div(id='source_dropdown_container', children=[]),
html.Div(id='source_dropdown_container_output'),
html.Div(id='source_file_container', children=[]),
html.Div(id='source_file_container_output'),
],
className="pretty_container four columns",
id="cross-filter-options",
),
],
className="row flex-display",
),
],
id="mainContainer",
style={"display": "flex", "flex-direction": "column"},
)
# Create callbacks
#app.callback(
[
Output(component_id='source_dropdown_container_output', component_property='children'),
],
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
if value_1 == 'Y':
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=['GOOG', 'FB', 'TDOC', 'FANG']
)
children.append(new_dropdown)
print(children)
print(type(children))
return children
I keep running into a callback error. The drop down is constructed properly, so I am kind of confused as to why that error is being invoked.
dash.exceptions.InvalidCallbackReturnValue: The callback ..source_dropdown_container_output.children.. is a multi-output.
Expected the output type to be a list or tuple but got:
None.
Any guidance or help is appreciated. All I am trying to do is add based on user input a dynamic number of drop downs to the layout.
you have three errors in your callback
there is only one return, hence do not define Output as a list
conditional check is wrong, should be if value_1 == ['Y']:
doc.Dropdown() options argument needs to define list of dict
# Create callbacks
#app.callback(
Output(component_id='source_dropdown_container_output', component_property='children'),
[
Input(component_id='drop_downs', component_property='value'),
Input(component_id='sources_flag', component_property='value'),
]
)
def update_source_dropdowns(value, value_1):
"""Controls the number of drop-downs available to choose sources"""
print("cb", value, value_1)
if value_1 == ['Y']:
children = []
for i in range(0, value):
new_dropdown = dcc.Dropdown(
id=f'''source_dropdown_{str(i)}''',
options=[{"label":v, "value":v } for v in ['GOOG', 'FB', 'TDOC', 'FANG']],
)
children.append(new_dropdown)
print(children)
print(type(children))
return children
I'm trying to organize my Plotly Dash dashboard into sections of columns, but I can't understand what I'm doing wrong here. I've included my components in separate dbc.Cols within one dbc.Row and specified the width of the column I'd like for them to take up, but everything is just stacked. Ideally, I'd have the cards in a column all by themselves on the left, then I would have the questions next to them on the right. Can someone please help me diagnose what I'm doing that's causing all my components to stack?
#Import packages
import dash
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output, State
app = dash.Dash()
#App Layout
app.layout = html.Div([
dbc.Row(children=[
dbc.Col(id="card_col",width = 6),
dbc.Col(id="form", width=6, children=[
html.Div([
dbc.FormGroup(children=[
dbc.Label("Question 1"),
dbc.Col(
dcc.Input(type="text", id="q1", placeholder="Enter your info"),
width=6
)
],row=True)
]),
html.Br(),
html.Div(children=[
dbc.FormGroup(children=[
dbc.Label("Question 2?"),
dbc.Col(
dbc.Input(type="text",id="q2",placeholder="Enter your info"),
width=6
)
],row=True)
]),
html.Br(),
html.Div([
dbc.FormGroup(children=[
dbc.Label("Yes/No?"),
dbc.Col(
dbc.RadioItems(id="q3",options=[{"label": "Yes", "value": 1},
{"label": "No", "value": 2}
]
),width=6
)
],row=True)
]),
html.Br(),
html.Div([
html.Button(id='submit-button',
n_clicks=0,
children='Submit Query',
style={'fontSize':24})
])
]) #End of second column
]), #End of row,
dbc.Row(
html.Div([
dcc.Graph(id='graph1')
])
)
])
#app.callback(
Output('card_col','children'),
Input('submit-button','n_clicks'),
State('q1','value'),
State('q2','value'),
State('q3','value'))
def update_cards(n_clicks,input1,input2,input3):
card1 = dbc.Card([
dbc.CardBody([
html.H4(f"{input1}", className="card-title"),
html.P(f"{input1} was submitted.")
],style={'display': 'inline-block',
'width': '33.3%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'border': "2px solid white"})
])
card2 = dbc.Card([
dbc.CardBody([
html.H4(f"{input2}", className="card-title"),
html.P(f"{input2} was submitted.")
],style={'display': 'inline-block',
'width': '33.3%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'border': "2px solid white"})
])
card3 = dbc.Card([
dbc.CardBody([
html.H4(f"{input3}", className="card-title"),
html.P(f"{input3} was submitted.")
],style={'display': 'inline-block',
'width': '33.3%',
'text-align': 'center',
'background-color': 'rgba(37, 150, 190)',
'color':'white',
'border': "2px solid white"})
])
return (card1, card2, card3)
if __name__ == "__main__":
app.run_server()
You haven't included the bootstrap styles:
Linking a stylesheet
dash-bootstrap-components doesn't come with CSS included. This is to give you the freedom to use any Bootstrap v4 stylesheet of your choice. This means however that in order for the components to be styled properly, you must link to a stylesheet yourself.
In Python, each CDN link is available within the dbc.themes submodule and can be used when instantiating the app object.
https://dash-bootstrap-components.opensource.faculty.ai/docs/quickstart/
So instead of this:
app = dash.Dash()
do this:
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
I am trying to build a webpage with dash plotly. I want it to be interactive so whenever I insert values and click on the button.
Therefore, I use request on the API to get the results.
However, for some reason in terminal I can only see :
"ERROR in app: Exception on /_dash-update-component [POST]"
before inserting the values then it starts giving me success code
"POST /_dash-update-component HTTP/1.1" 200
Can anyone tell me how to solve the initial error?
Here is my code:
import json
import base64
import datetime
import requests
import pathlib
import math
import pandas as pd
import flask
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import dash_bootstrap_components as dbc
import plotly.express as px
from dash.dependencies import Input, Output, State
from plotly import tools
def fig1(data):
colors = {
'background': '#000220',
'text': '#FFFFFF'
}
today=datetime.datetime.today().strftime("%Y -%m -%d")
df_nested=data
df = df_nested.loc[df_nested['timestamp']>=today].groupby(['contract_name','contract_ticker_symbol']).mean('close.quote').reset_index()
fig = px.pie(df, values='close.quote', names='contract_name',labels={ "contract_name":'Contract Name',
"close.quote": "USD Value"} , title='Asset Allocation', color_discrete_sequence=px.colors.sequential.Plasma)
fig.update_traces(textposition='inside')
# fig.update_layout(uniformtext_minsize=12, uniformtext_mode='hide')
fig.update_layout(plot_bgcolor=colors['background'], paper_bgcolor=colors['background'],font_color=colors['text']
)
return fig
def fig2(data):
colors = {
'background': '#000220',
'text': '#FFFFFF'
}
df_nested=data
fig2=px.line(df_nested, x="timestamp", y="close.quote", color="contract_name",line_group="contract_ticker_symbol",labels={
"contract_name":'Contract Name',
"timestamp": "Date",
"close.quote": "USD Value",
"contract_ticker_symbol": "Ticker"
}, title='Asset Value Over Time', hover_name="contract_ticker_symbol",)
fig2.update_layout(plot_bgcolor=colors['background'], paper_bgcolor=colors['background'],font_color=colors['text'])
return fig2
app = dash.Dash(
__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}],
)
app.title = ""
server = app.server
PATH = pathlib.Path(__file__).parent
# API Requests for news div
news_requests = requests.get(
"https://newsapi.org/v2/top-headlines?sources=bbc-news&apiKey=API_KEY"
)
# API Call to update news
def update_news():
json_data = news_requests.json()["articles"]
df = pd.DataFrame(json_data)
df = pd.DataFrame(df[["title", "url"]])
max_rows = 10
return html.Div(
children=[
html.P(className="p-news", children="Headlines"),
html.P(
className="p-news float-right",
children="Last update : "
+ datetime.datetime.now().strftime("%H:%M:%S"),
),
html.Table(
className="table-news",
children=[
html.Tr(
children=[
html.Td(
children=[
html.A(
className="td-link",
children=df.iloc[i]["title"],
href=df.iloc[i]["url"],
target="_blank",
)
]
)
]
)
for i in range(min(len(df), max_rows))
],
),
]
)
# Dash App Layout
app.layout = html.Div(
className="row",
children=[
# Interval component for live clock
dcc.Interval(id="interval", interval=1 * 1000, n_intervals=0),
# Interval component for ask bid updates
dcc.Interval(id="i_bis", interval=1 * 2000, n_intervals=0),
# Interval component for graph updates
dcc.Interval(id="i_tris", interval=1 * 5000, n_intervals=0),
# Interval component for graph updates
dcc.Interval(id="i_news", interval=1 * 60000, n_intervals=0),
# Left Panel Div
html.Div(
className="three columns div-left-panel",
children=[
# Div for Left Panel App Info
html.Div(
className="div-info",
children=[
html.Img(
className="logo", src=app.get_asset_url("covalent.png")
),
html.H6(className="title-header", children="Covalent Analytics"),
html.P(
"""
Covalent Analytics provide portfolio tracking services across chains
"""
),
],
),
# Div for News Headlines
html.Div(
className="div-news",
children=[html.Div(id="news", children=update_news())],
),
],
),
# Right Panel Div
html.Div(
className="nine columns div-right-panel",
children=[
# Panel for orders
html.Div(
id="bottom_panel",
className="row div-bottom-panel",
children=[
html.Div(
className="display-inlineblock",
children=[
dcc.Input(id="address", placeholder="Enter wallet address...", type="text"),
dcc.Dropdown(id='chain_id',placeholder="Select Chain", options = [
{"label": "Ethereum", "value": "1"},
{"label": "Matic", "value": "137"},
{"label": "Binance Smart Chain", "value": "56"},
{"label": "Avalanche", "value": "43114"},
{"label": "Fantom", "value": "250"}
],
value=[],
),
],
),
html.Div(
className="display-inlineblock float-right",
children=[
html.Button('Add Wallet', id='btn-1', n_clicks=0)
],
), html.Div(id='container')
],
),
],
),
],
)
#JSON NORMALIZE
def normalize(data):
df=data['items']
df=pd.json_normalize(df,record_path=['holdings'],meta=['contract_ticker_symbol','contract_name',"contract_address"])
df=df[['contract_ticker_symbol','contract_name',"contract_address",'timestamp','close.quote']]
return df
#SET TIME FORMAT
def set_time(data):
return pd.to_datetime(data['timestamp'])
#app.callback(Output('container', 'children'),
Input("chain_id", "value"),
Input("address", "value"),)
def display(value,address):
ctx = dash.callback_context
api_key= "####"
if not ctx.triggered:
pass
else:
response = requests.get(f"https://api.covalenthq.com/v1/{value}/address/{address}/portfolio_v2/?format=format%3Dcsv&key={api_key}")
data=normalize(response.json())
data['timestamp']=set_time(data)
return [
dcc.Graph(
id='graph1',
figure=fig1(data)
),
dcc.Graph(
id='graph2',
figure=fig2(data)
)
]
# Dynamic Callbacks
# Function to open or close STYLE or STUDIES menu
def generate_open_close_menu_callback():
def open_close_menu(n, className):
if n == 0:
return "not_visible"
if className == "visible":
return "not_visible"
else:
return "visible"
return open_close_menu
# Function for hidden div that stores the last clicked menu tab
# Also updates style and studies menu headers
def generate_active_menu_tab_callback():
def update_current_tab_name(n_style, n_studies):
if n_style >= n_studies:
return "Style", "span-menu selected", "span-menu"
return "Studies", "span-menu", "span-menu selected"
return update_current_tab_name
# Function show or hide studies menu for chart
def generate_studies_content_tab_callback():
def studies_tab(current_tab):
if current_tab == "Studies":
return {"display": "block", "textAlign": "left", "marginTop": "30"}
return {"display": "none"}
return studies_tab
# Function show or hide style menu for chart
def generate_style_content_tab_callback():
def style_tab(current_tab):
if current_tab == "Style":
return {"display": "block", "textAlign": "left", "marginTop": "30"}
return {"display": "none"}
return style_tab
# Callback to update news
#app.callback(Output("news", "children"), [Input("i_news", "n_intervals")])
def update_news_div(n):
return update_news()
if __name__ == "__main__":
app.run_server(debug=False)
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)