Route in Dash without creating inefficient, hidden items - python

I am inheriting a plotly Dash app which currently has an app.layout as follows:
def serve_layout():
return html.Div(
className="app",
children=[
dcc.Location(id="url", refresh=False),
build_navbar(),
html.Div(
id="app-container",
className="main-content",
children=[
dcc.Store(id="usecase-store", storage_type="session", data=LiveGraph.use_case_library),
dcc.Store(id="gen-config-store", storage_type="session", data=LiveGraph.gen_config),
dcc.Store(id="control-config-store", storage_type="session", data=LiveGraph.control_config),
dcc.Store(id="data-config-store", storage_type="session", data=LiveGraph.data_config),
dcc.Store(id="data-store", storage_type="session"),
dcc.Store(id="liveplot-store", storage_type="session"),
build_settings_tab(),
build_simulation_tab(),
build_network_tab(),
dcc.Interval(id='graph-update', interval=1000, max_intervals=1000, n_intervals=0,
disabled=True)
],
),
],
)
where there are 3 separate routes for each of the build_* functions; with a callback setting {display: none} on the divs returned by the non-selected functions. I propose the following code:
def serve_layout():
return html.Div(
className="app",
children=[
dcc.Location(id="url", refresh=False),
build_navbar(),
html.Div(
id="app-container",
className="main-content",
children=[
dcc.Store(id="usecase-store", storage_type="session", data=LiveGraph.use_case_library),
dcc.Store(id="gen-config-store", storage_type="session", data=LiveGraph.gen_config),
dcc.Store(id="control-config-store", storage_type="session", data=LiveGraph.control_config),
dcc.Store(id="data-config-store", storage_type="session", data=LiveGraph.data_config),
dcc.Store(id="data-store", storage_type="session"),
dcc.Store(id="liveplot-store", storage_type="session"),
dcc.Interval(id='graph-update', interval=1000, max_intervals=1000, n_intervals=0,
disabled=True),
html.Div(id="main-content")
],
),
],
)
#app.callback(Output("main-content", "children"), [Input("url", "pathname")])
def route(path):
if path == "/":
return build_settings_tab()
# ...only return the individual function necessary for the path
Note that I have removed the three function calls from serve_layout() and added a div#main-content. The issue I'm running into is that I have callbacks set up to watch various inputs across the three pages, so I get an Error loading dependencies if I try to use the second code block. Is there a way around this, or do I really have to put everything in app.layout that I want to access later on? This would be really inefficient, as one of my pages creates charts and I don't want to render the charts and then set {display: none}, seems backwards and certainly sets off a lot of warning bells in my head... Are there any other solutions?

Related

how can I resolve the error Dash can not load data in browser (error loading layout)

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.

Additional elements inline with Dash's dcc.Tabs?

For my Dash app, I want to create a navigation bar that has links to the different pages but also additional stuff, e.g. the currently logged in user, and logos and stuff.
However, I unfortunately cannot use pages (Like in the "Navbar" example in dbc) since the WebApp has to be hosted as a single-url app inside another tool. My only option is to got with dcc.Tabs.
However, it looks to me like dcc.Tabs forces a newline behind the Tabs. I tried different things to prevent that, but nothing seems to be working. The best I got so far is the example below. How do I make it so that the text is in the same row as the Tabs element?
tabs_styles = {
'height': '44px', "width": "49%", "display":"inline-block"
}
app.layout = html.Div(children=[
html.Div(children=[
dcc.Tabs(id="tabs-styled-with-inline", value='tab-1', children=[
dcc.Tab(label='Page1', value='tab-1', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Page2', value='tab-2', style=tab_style, selected_style=tab_selected_style),
], style=tabs_styles)]),
html.Span(children=[
" Logged in as ",
html.Strong(id="username")
], style = tabs_styles),
html.Div(children=[
# Distance to header:
html.Hr(),
html.Div(id='tabs-content-inline')
])
])
Your inline style should be applied to the parent div of your Tabs component. I made some small modifications here (look at tabs_container_styles):
tabs_styles = {"height": "44px"}
tabs_container_styles = {"width": "49%", "display": "inline-block"}
app.layout = html.Div(
children=[
html.Div(
children=[
dcc.Tabs(
id="tabs-styled-with-inline",
value="tab-1",
children=[
dcc.Tab(label="Page1", value="tab-1"),
dcc.Tab(label="Page2", value="tab-2"),
],
style=tabs_styles,
)
],
style=tabs_container_styles,
),
html.Span(
children=[" Logged in as ", html.Strong(id="username")], style=tabs_styles
),
html.Div(
children=[
# Distance to header:
html.Hr(),
html.Div(id="tabs-content-inline"),
]
),
]
)
Set the parent_style property of your Tabs component instead of the style property and move your Span component to be a child of the div containing your Tabs component.
parent_style (dict; optional): Appends (inline) styles to the top-level parent container holding both the Tabs container and the content container.
style (dict; optional): Appends (inline) styles to the Tabs container holding the individual Tab components.
https://dash.plotly.com/dash-core-components/tabs
MRE
from dash import Dash, html, dcc
tabs_styles = {"height": "44px", "width": "49%", "display": "inline-block"}
app = Dash()
app.layout = html.Div(
children=[
html.Div(
children=[
dcc.Tabs(
id="tabs-styled-with-inline",
value="tab-1",
children=[
dcc.Tab(
label="Page1", value="tab-1", style={}, selected_style={}
),
dcc.Tab(
label="Page2", value="tab-2", style={}, selected_style={}
),
],
parent_style=tabs_styles,
),
html.Span(
children=[" Logged in as ", html.Strong(id="username")], style=tabs_styles
),
]
),
html.Div(
children=[
# Distance to header:
html.Hr(),
html.Div(id="tabs-content-inline"),
]
),
]
)
if __name__ == "__main__":
app.run_server()

How to show completion percentage in a bootstrap card in python dash?

I am building a dash application and have calculated a completion_percentage for the project completion. I am using dash_bootstrap_components and want to show that percentage inside the card. Is there any way to do so or is there any other way to graphically show the completion percentage on the application page?
Below is the code which I am using as part of the layout
completion_percentage = str((closed_tickets / total_tickets) * 100)
app.layout = html.Div(
children=[
html.H1(children="Project Analytics",),
html.P(
children="Get the status!",
),
dcc.Graph(
figure=fig,
),
dcc.Graph(
figure=pie_chart
),
dbc.Card(
dbc.CardBody(
[
html.H4("Completion Percentage", className="card-title"),
dbc.CardText(completion_percentage)
]
)
)
]
)
The above is giving me error as cardtext excpets P or Div. Can someone help with the following.
As the error says:
AttributeError: CardText has been removed from dash-bootstrap-components. Set className='card-text' on a html component such as Div, or P instead. CardText originally used P.
So you can use html.P or html.Div where you're now using dbc.CardText.
Example:
from dash import Dash
import dash_html_components as html
import dash_bootstrap_components as dbc
closed_tickets = 10
total_tickets = 80
completion_percentage = str((closed_tickets / total_tickets) * 100)
app = Dash(
external_stylesheets=[dbc.themes.BOOTSTRAP]
)
app.layout = html.Div(
children=[
html.H1(children="Project Analytics",),
html.P(
children="Get the status!",
),
dbc.Card(
dbc.CardBody(
[
html.H4("Completion Percentage", className="card-title"),
html.P(completion_percentage)
]
)
)
]
)
if __name__ == "__main__":
app.run_server()
https://dash-bootstrap-components.opensource.faculty.ai/docs/components/card/

plotly-dash: embed indicator graph inside of a dbc card

I have been banging my head off the wall all day and cannot find a way to fit a dash indicator inside of a dash_bootstrap_components card.
It seems that the body of the card and the graph do not live inside of the card. I am not very familiar with dash so it is difficult to find a way to solve the issue.
here is what I have been able to do so far in terms of plotting the indicator:
fig3 = go.Figure()
fig3.add_trace(go.Indicator(
mode = "number+delta",
number = {"font":{"size":40},'prefix': "$"},
value = 2045672,
delta = {'reference': 30000},
gauge = {'shape': "bullet"},
title = {"text": "On Hand<br><span style='font-size:0.9em;color:gray'></span>"},
#title='Stock On Hand',
domain = {'x': [0, 1], 'y': [0, 1]},
))
fig3.update_layout(paper_bgcolor = "rgba(0,0,0,0)",
plot_bgcolor = "rgba(0,0,0,0)",
autosize=False,
width = 200,
height=200,
)
fig3.update_traces(align="center", selector=dict(type='indicator'))
I am forced to specify width and height for the indicator otherwise it is way too big, however this cause issues because its size does not adjust in regards to the card.
here is the html dash code for the box and the plot:
html.Div(children=[
html.Div(children=[
html.Div(children=[
html.Div(children=[
dbc.Card(
[dbc.CardBody(
[dcc.Graph(figure=fig3)
]
)],className="card", style={"width": "15rem", "height":"8rem"}
),
], className='jumbotron', style={'background-color': '#fffffff'}),
])
],className="col-3 mx-auto"),
],className="row p-0 h-100", style={'background-color': '#f7f7f7', 'height':110}),
], className="full-width p-0 h-100", style={'background-color': '#fffffff'}),
and here is what the final output looks like:
I am not sure what else I can try to bring the graph inside of the box, any help would be appreciated
Remove the instances where you set the height in the style of dash components and the indicator doesn't get cut off.
So you can do something like this:
app.layout = html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
html.Div(
children=[
dbc.Card(
[
dbc.CardBody(
[dcc.Graph(figure=fig3)],
style={"width": "15rem"},
)
]
)
],
className="jumbotron",
style={"backgroundColor": "#fffffff"},
)
],
className="col-3 mx-auto",
)
],
className="row p-0 h-100",
style={"backgroundColor": "#f7f7f7"},
)
],
className="full-width p-0 h-100",
style={"backgroundColor": "#fffffff"},
)
I've also changed the casing of the style properties to camelCase as this is what React (which dash uses) likes.

Dynamically changing content of html div using callbacks

I am trying to create a drop down menu with 2 options : Village Amenities and Town Amenities. If the user selects one of these options, I want the selected option to appear in the html div I have created below.
For this, I tried to use callbacks, but it doesn't seem to work.
My code is as follows :
app.layout = html.Div(
html.Div([
html.Div(children=[
dcc.Dropdown(
id='input',
options=[{'label': label, 'value': value} for label, value in zip(
['Town Amenities', 'Village Amenties'], ['Town', 'Village'])],
value="Town Amenties"
),
html.Div(id='ouput'),
], style={'width': '20%', 'display': 'inline-block'}),
.......
And the callback code is as follows :
#app.callback(
Output(component_id='output', component_property='children'),
[Input(component_id='input', component_property='value')]
)
def update_value(input_data):
return input_data
Any help or suggestions would be really appreciated. Thanks a lot !!
The output div in the layout has no set children prop. Dash struggles with unset default values, so you can fix this by setting it explicitly like this:
html.Div(id='ouput', children=[]),
The callback should work after that.

Categories

Resources