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.
Related
Quite some posts have discussed the matter, but nothing to solve my problem. The problem is the 'error loading layout' in the browser when running the multi-page dash app. In the terminal I have no error.
my app is based on the 'towards data science'article: https://towardsdatascience.com/callbacks-layouts-bootstrap-how-to-create-dashboards-in-plotly-dash-1d233ff63e30
I already have re-installed the different modules and have started all over again, all without a satisfying result.
my code is:
app.py
import dash
app = dash.Dash(__name__, suppress_callback_exceptions=True)
server = app.server
index.py
from dash import dcc
from dash import html
from dash import Output, Input
from app import app
from layouts import navbar
from layouts import layout_overview, layout_comparison, layout_analysis
app.config.suppress_callback_exceptions = True
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
navbar(),
html.Div(id='page-content')
])
#app.callback(Output('page-content', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/':
return layout_overview
elif pathname == '/overview':
return layout_overview
elif pathname == '/comparison':
return layout_comparison
elif pathname == '/analysis':
return layout_analysis
else:
return '404'
if __name__ == '__main__':
app.run_server(port='5000', host='127.0.0.1', debug=True)
layouts.py (is under construction)
from dash import dcc
from dash import html
import pandas as pd
########################################
# Add Data
########################################
df = pd.read_csv('C:\\Users\\StefanSijbesmaDAAT\\Documents\\Scripting\\Test\\assets\\Life expectancy.csv')
years = df['Year'].unique()
country=df['Entity'].unique()
########################################
# Create Auxiliary Components Here
########################################
def navbar():
html.Nav([ # navbar on top of the dashboard using html components
dcc.Link(
html.H4('Overview'),
href='/overview',
style={
'display': 'inline-block',
'margin-right': '30px'
}
),
dcc.Link(
html.H4('Comparison'),
href='/comparison',
style={
'display': 'inline-block',
'margin-right': '30px'
}
),
dcc.Link(
html.H4('Analysis'),
href='/analysis',
style={
'display': 'inline-block',
'margin-right': '230px'
}
),
], className='navbar'),
return navbar
########################################
# Create Page Layouts Here
########################################
### Layout Overview
layout_overview = html.Div('overview'
)
### Layout Comparison
layout_comparison = html.Div('comparison'
)
### Layout Analysis
layout_analysis = html.Div('analysis'
)
callbacks.py
still empty
Can anyone please point me in the right direction?
Thanks in advance.
The problem is in the navbar() function. It should return one element, currently you are returning a function (since you forgot to assign the html.Nav element to the variable and return it).
Fixed code:
def navbar():
navbar_element = html.Nav(
[ # navbar on top of the dashboard using html components
dcc.Link(
html.H4("Overview"),
href="/overview",
style={"display": "inline-block", "margin-right": "30px"},
),
dcc.Link(
html.H4("Comparison"),
href="/comparison",
style={"display": "inline-block", "margin-right": "30px"},
),
dcc.Link(
html.H4("Analysis"),
href="/analysis",
style={"display": "inline-block", "margin-right": "230px"},
),
],
className="navbar",
)
return navbar_element
Also be careful, you have comma after html.Nav() definition, that can cause the function navbar to return tuple instead of one element.
After this fix you won't see the layout when accessing http://127.0.0.1:5000 since your display_page callback require to access http://127.0.0.1:5000/. So that is also part which you can improve.
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've recently started a Dash application that shows up pre-registered HTML files that I show via HTML.iFrame :
html.Iframe(id = 'my-output', src = "assets/ABCD.html",
style={"height": "495px", "width": "100%",})
and I've got a function/app callback, like the following:
#app.callback(
Output(component_id='my-output', component_property='children'),
Input(component_id='my-input', component_property='value'),
)
def update_output_div(input_value):
return XYZ
Now I need that output value in my src, like this
html.Iframe(id = 'my-output', src = "assets/XYZ.html",
style={"height": "495px", "width": "100%",})
But i don't know how to get back that output value and change my src parameters.
You can make the src property an Output in your callback.
Example that uses a Dropdown as Input:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input
app = dash.Dash()
app.layout = html.Div(
[
html.Iframe(
id="my-output",
src="assets/ABCD.html",
style={"height": "495px", "width": "100%"},
),
dcc.Dropdown(
id="input",
options=[
{"label": "ABCD", "value": "ABCD.html"},
{"label": "XYZ", "value": "XYZ.html"},
],
value="ABCD.html",
),
]
)
#app.callback(
Output("my-output", "src"), Input("input", "value"), prevent_initial_call=True
)
def update_output_div(input_value):
return f"assets/{input_value}"
if __name__ == "__main__":
app.run_server()
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.
I am trying to add multiple navigations for the same URL path.
my code..
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
app = dash.Dash()
index_layout = html.Div([
# represents the URL bar, doesn't render anything
dcc.Location(id='url', refresh=False),
html.Br(),
dcc.Link(dbc.Button('Page1',
color="secondary",
className="mr-1",
outline=True,
style={"width":400,
"vertical-align": "middle",
}
), href='/page1'),
html.Br(),html.Br(),html.Br(),html.Br(),html.Br(),
dcc.Link(dbc.Button("Page2",
style={"width":400,
"vertical-align": "middle"},
color="secondary",
className="mr-1",
outline=True
), href='/page2'),
])
page1_layout = html.H1("Page1")
page2_layout = html.H1("Page2")
app.layout = html.Div([
dcc.Location(id='url-nav', refresh=True),
html.Span(dbc.Nav(
[
dbc.NavLink(dbc.NavLink("Page1", href="/page1")),
dbc.NavLink(dbc.NavLink("Page2", href="/page2")),
],
pills=True,),
className="ml-auto"
),
dcc.Location(id='url', refresh=True),
html.Center([
html.H3('DEMO AP',id='title'),
# content will be rendered in this element
html.Div(id='page-content'),
],),
])
### CALLBACKS
#app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname="/"):
ctx = dash.callback_context
triggered_by = ctx.triggered[0].get("prop_id")
if pathname == "/page1":
return page1_layout
elif pathname == "/page2":
return page2_layout
else:
return index_layout
if __name__ == "__main__":
app.run_server()
Button navigations are working fine, but html.Nav only works on the very first click, not consistent and not working on the following clicks.
Kindly help.
From testing this out the problem seems to be with this line in index_layout:
dcc.Location(id='url', refresh=False),
If you look in the console you will see that a lot of requests are sent constantly when you're on the main page (when index_layout is rendered).
When this line is removed your code works as expected.
Working solution:
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
import dash_table
app = dash.Dash()
index_layout = html.Div(
[
html.Br(),
dcc.Link(
dbc.Button(
"Page1",
color="secondary",
className="mr-1",
outline=True,
style={
"width": 400,
"vertical-align": "middle",
},
),
href="/page1",
),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
dcc.Link(
dbc.Button(
"Page2",
style={"width": 400, "vertical-align": "middle"},
color="secondary",
className="mr-1",
outline=True,
),
href="/page2",
),
]
)
page1_layout = html.H1("Page1")
page2_layout = html.H1("Page2")
app.layout = html.Div(
[
dcc.Location(id="url-nav", refresh=True),
html.Span(
dbc.Nav(
[
dbc.NavLink(dbc.NavLink("Page1", href="/page1")),
dbc.NavLink(dbc.NavLink("Page2", href="/page2")),
],
pills=True,
),
className="ml-auto",
),
dcc.Location(id="url", refresh=True),
html.Center(
[
html.H3("DEMO AP", id="title"),
# content will be rendered in this element
html.Div(id="page-content"),
],
),
]
)
### CALLBACKS
#app.callback(
dash.dependencies.Output("page-content", "children"),
[dash.dependencies.Input("url", "pathname")],
)
def display_page(pathname="/"):
ctx = dash.callback_context
triggered_by = ctx.triggered[0].get("prop_id")
if pathname == "/page1":
return page1_layout
elif pathname == "/page2":
return page2_layout
else:
return index_layout
if __name__ == "__main__":
app.run_server()
The problem here I think is that there are two Location components rendered at the same time with the same id (url). This apparently causes the callback to be called constantly and causes inconsistent link behavior.