How to highlight active page with a className - Plotly Dash - plotly-dash

I have a classic multi page app made in Plotly Dash, but I can't figure out how to highlight a page in the navigation that is currently visited.
I managed to get the active pathname with a callback, but I still don't know how I can use this to add a className "active" to one of the links in the navigation.
#app.callback(Output("print", "children"), [Input("url", "pathname")])
def callback_func(pathname):
print(pathname)
return pathname
This is how I render my navigation:
html.Div(
className="items",
children=[
html.Div(
dcc.Link(
f"{page['name']}",
href=page["relative_path"],
)
)
for page in dash.page_registry.values()
],
),

Below is a working example that does what you're looking for!
from dash import Dash, dcc, html, Input, Output, ALL
import dash
app = Dash(__name__)
app.layout = html.Div([
dcc.Location(id="url"),
html.Div([
dcc.Link(f"LINK {val}", href="/" if val == 0 else f"/link{val}",
id={"type":"link-navbar",
"index": "/" if val == 0 else f"/link{val}"},
style={"marginRight":"16px"})
for val in range(3)]),
])
#app.callback(Output({"type":"link-navbar", "index":ALL}, "className"),
[Input("url", "pathname"),Input({"type":"link-navbar", "index":ALL}, "id")])
def callback_func(pathname, link_elements):
return ["active" if val["index"] == pathname else "not-active" for val in link_elements]
if __name__ == '__main__':
app.run_server(debug=True)
and in your style.css file:
.active {
background: red;
color:aqua
}
.not-active{
background: rgb(132, 0, 255);
color:rgb(255, 81, 0)
}
Hope it can solve your problem;
Regards,
Leonardo

Related

dash dcc.Uploader not working in multipage app

0
I have a multi-page dash app for generating custom dashboards based on user submission. I'm trying to create a secondary page for uploading files. The problem is that the dcc.Upload or the callback function does not produce the expected behavior, that is: a html.Div that shows the uploaded data.
This is my secondary page, organized in tabs:
import dash
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
import dash_mantine_components as dmc
from dash import dash_table
from dash.exceptions import PreventUpdate
import os
import unicodedata
import requests
from bs4 import BeautifulSoup
from urllib.request import urlopen
from urllib.parse import quote as urlquote
import sqlite3
from dash_iconify import DashIconify
from dash.dependencies import Input, Output, State
import pandas as pd
from app import app
def layout():
return [
dmc.Tabs(
[
dmc.TabsList(
[
dmc.Tab("Import", value="import"),
dmc.Tab("Connect BD", value="connectbd"),
dmc.Tab("Explore", value="explore"),
]
),
dmc.TabsPanel(
html.Div([
dcc.Upload(
id='upload-data',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '100%',
'height': '260px',
'lineHeight': '60px',
'borderWidth': '1px',
#'borderStyle': 'dashed',
'background' : '#f8f9fa',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
# Allow multiple files to be uploaded
multiple=True,
),
html.Div(id='output-data-upload'),
]),
value="import"),
dmc.TabsPanel("Settings tab content", value="connectbd"),
dmc.TabsPanel("Settings tab content", value="explore"),
],
#color="black",
orientation="horizontal",
)
]
def parse_contents(contents, filename, date):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# Assume that the user uploaded a CSV file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return html.Div([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
df.to_dict('records'),
[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(), # horizontal line
# For debugging, display the raw contents provided by the web browser
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
#app.callback(Output('output-data-upload', 'children'),
Input('upload-data', 'contents'),
State('upload-data', 'filename'),
State('upload-data', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
Solution attempts: the example of the dcc.Upload is in the documentation , but I use it inside a tab inside a secondary page that is called with the layout function in the app.py. The example is working correctly when is run as it is implemented in the documentation, but I can´t adapt it to my specific use case. I think the problem is near the callback or in the function that outputs the table.
I´m a newbie in dash. Thanks in advance for any help.
Expted: html.Div with uploaded data.

How can I dynamically change html.Button text in dash?

I have tried different attributes ( title, data, value, etc ) but they dont do the trick. Below is the sample code taken directly from the dash documentation. I simply would like to be able to push the button and have the button text change to something else besides "Submit", preferably the input text.
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(dcc.Input(id='input-on-submit', type='text')),
html.Button('Submit', id='submit-val', n_clicks=0),
html.Div(id='container-button-basic',
children='Enter a value and press submit')
])
#app.callback(
Output('container-button-basic', 'children'),
Input('submit-val', 'n_clicks'),
dash.dependencies.State('input-on-submit', 'value')
)
def update_output(n_clicks, value):
return ('The input value was "{}" and the button has been clicked {} times'.format(
value,
n_clicks
))
if __name__ == '__main__':
app.run_server(debug=True)
Well, I found that I needed to update the "children" property. Below is code that performs the function I was looking for:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = dash.Dash(__name__)
app.layout = html.Div([
html.Div(dcc.Input(id='input-on-submit', type='text')),
html.Button('Submit', id='submit-val', n_clicks=0),
html.Div(id='container-button-basic',
children='Enter a value and press submit')
])
#app.callback(
Output('container-button-basic', 'children'),
Output ('submit-val','children'),
Input('submit-val', 'n_clicks'),
dash.dependencies.State('input-on-submit', 'value')
)
def update_output(n_clicks, value):
if n_clicks==0:
return
else:
buttonText = value
return ('The input value was "{}" and the button has been clicked {} times'.format(
value,
n_clicks
), buttonText)
if __name__ == '__main__':
app.run_server(debug=True)

Plotly-dash - update graphs in tabs

I like to put plotly graph1 in tab1 and graph2 in tab 2, but there is no trace visible.
Why are traces not visible?
The graph in tab2 is also showing no traces.
It would be great to know whats wrong.
Simular example code would also be a big help.
Many thanks
''' import pandas as pd
import numpy as np
import plotly.express as px
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import requests
import dash_bootstrap_components as dbc
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
#fig1 = px.line(title='title1')
#fig2 = px.line(title='title2')
app.layout = dbc.Container(fluid=True, children=[
html.H1('Title',id="Titel",className='ml-1',style={'text-align': 'center', 'font-weight': 'bold', 'text-decoration': 'underline'}),
## Body
dbc.Row([
dbc.Col(md=6,children=[
html.Br(),html.Br(),
dbc.Col(md=9, children=[
dbc.Col(html.H4("graphs in tabs"), width={"size":6,"offset":3}),
dbc.Tabs(className="nav nav-pills", children=[
dbc.Tab(dcc.Graph(id="grafiek1"), label="tab1"),
dbc.Tab(dcc.Graph(id="grafiek2"), label="tab2")
])
])
#html.Div(id="tab-content", className="mx-auto"), #m=marge p=padding 0-5 of auto vb: P-4
]), # einde kolom 1
dbc.Col(md=6,children=[
]), # einde kolom 2
]), #einde rij
])
#,style={"background-image": 'url(image)'})
#app.callback(
Output("grafiek1", "figure"),
[Input("tabs", "active_tab")])
def tab_content(active_tab):
if active_tab is not None:
if active_tab == "tab1":
fig1 = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'], y=df['AAPL.Low'], mode='markers', name='data', line={"color":"black"}))
## add slider
fig.update_xaxes(rangeslider_visible=True)
## set background color
fig.update_layout(plot_bgcolor='white', autosize=False, width=1000, height=550)
return fig1
#app.callback(
Output("grafiek2", "figure"),
[Input("tabs", "active_tab")])
def tab_content(active_tab):
if active_tab is not None:
if active_tab == "tab2":
fig2 = go.Figure()
fig.add_trace(go.Scatter(x=df['Date'], y=df['AAPL.High'], mode='markers', name='data', line={"color":"black"}))
## add slider
fig.update_xaxes(rangeslider_visible=True)
## set background color
fig.update_layout(plot_bgcolor='white', autosize=False, width=1000, height=550)
return fig2
if __name__ == '__main__':
app.run_server(debug='True')
'''
The 'tabs' id you reference in your callbacks doesn't exist in your layout. Dash doesn't tell you about this because you do this
app.run_server(debug='True')
instead of
app.run_server(debug=True)
You also check if active_tab equals "tab1" in the first callback and "tab2" in the second, but the active_tab prop of your Tabs component isn't set to either of these values. The default active_tab value for the first tab is actually tab-0.
active_tab (string, optional): The tab_id of the currently active tab. If tab_id has not been specified for the active tab, this will default to tab-i, where i is the index (starting from 0) of the tab.
https://dash-bootstrap-components.opensource.faculty.ai/docs/components/tabs/
Since this if statement fails nothing is returned from either callback.
Also the callback function have the same function name, this is not allowed.
Lastly in both callbacks you create a figure, but you add the trace to another figure, so the trace also doesn't show up because you're returning an empty figure.
So instead you could do something like this:
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.graph_objects as go
df = pd.read_csv(
"https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv"
)
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
fluid=True,
children=[
html.H1(
"Title",
id="Titel",
className="ml-1",
style={
"text-align": "center",
"font-weight": "bold",
"text-decoration": "underline",
},
),
dbc.Row(
[
dbc.Col(
md=6,
children=[
html.Br(),
html.Br(),
dbc.Col(
md=9,
children=[
dbc.Col(
html.H4("graphs in tabs"),
width={"size": 6, "offset": 3},
),
dbc.Tabs(
id="tabs",
className="nav nav-pills",
children=[
dbc.Tab(
label="tab1",
children=[dcc.Graph(id="grafiek1")],
),
dbc.Tab(
label="tab2",
children=[dcc.Graph(id="grafiek2")],
),
],
),
],
),
],
),
dbc.Col(md=6, children=[]),
]
),
],
)
#app.callback(Output("grafiek1", "figure"), [Input("tabs", "active_tab")])
def tab_content1(active_tab):
if active_tab is not None:
if active_tab == "tab-0":
fig1 = go.Figure()
fig1.add_trace(
go.Scatter(
x=df["Date"],
y=df["AAPL.Low"],
mode="markers",
name="data",
line={"color": "black"},
)
)
return fig1
return go.Figure()
#app.callback(Output("grafiek2", "figure"), [Input("tabs", "active_tab")])
def tab_content2(active_tab):
if active_tab is not None:
if active_tab == "tab-1":
fig2 = go.Figure()
fig2.add_trace(
go.Scatter(
x=df["Date"],
y=df["AAPL.High"],
mode="markers",
name="data",
line={"color": "black"},
)
)
# add slider
fig2.update_xaxes(rangeslider_visible=True)
# set background color
fig2.update_layout(
plot_bgcolor="white", autosize=False, width=1000, height=550
)
return fig2
return go.Figure()
if __name__ == "__main__":
app.run_server(debug=True)

Dash Plotly: Highlighting point on the graph

I was googl'ing around trying to find solution for the following question (no luck so far). I am using Plotly Dash callback in order to build a graph:
#app.callback(
Output("graph", "figure"),
[Input("some-input", "value")],
[State("some-state", "value")])
def build_graph(input_value, state_value):
// computing data for graph_figure
return graph_figure
Now, I want to have another callback which will highlight a specific point on the graph (or add/remove a point) based on some input condition. I struggle to figure out what to use for Output in this case? Because I cannot output graph.figure again (Dash does not allow output to the same component from different callbacks). And re-drawing entire graph seems to be inefficient.
I will appreciate any suggestions.
It is possible to change the layout of your graph without redrawing the whole graph by using this library: https://github.com/jimmybow/mydcc
There is an example how to use it here: https://github.com/jimmybow/mydcc#3-mydccrelayout-
I have prepared a small example that adds an annotation on button click. Don't forget to pip install mydcc beforehand. I had to add a cache - in form of an invisible div - to preserve the old annotations when adding a new one.
import dash
import dash_core_components as dcc
import dash_html_components as html
import mydcc
import random
import json
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
initial_layout = {'title': 'Dash Data Visualization'}
app.layout = html.Div(children=[
html.H1(children='Hello Dash'),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Graph(
id='example-graph',
figure={
'data': [{'x': [1, 2, 3], 'y': [4, 1, 2], 'name': 'Test'}],
'layout': initial_layout
}
),
mydcc.Relayout(id="rrr", aim='example-graph'),
html.Button('Add random annotation', id='button'),
html.Div(id='user-cache', style={'display': 'none'},
children=json.dumps(initial_layout)),
])
#app.callback(
[dash.dependencies.Output('rrr', 'layout'),
dash.dependencies.Output('user-cache', 'children')],
[dash.dependencies.Input('button', 'n_clicks')],
[dash.dependencies.State('user-cache', 'children')])
def update_graph_annotations(n_clicks, layout):
if n_clicks is not None:
layout = json.loads(layout)
if not 'annotations' in layout:
layout['annotations'] = []
layout['annotations'].append(dict(
x=random.uniform(0, 1) * 2 + 1,
y=random.uniform(0, 1) * 2 + 1,
xref="x",
yref="y",
text="Annotation" + str(n_clicks),
showarrow=True
))
return layout, json.dumps(layout)
return dash.no_update, dash.no_update
if __name__ == '__main__':
app.run_server(debug=True)

How can I create tabs and subtabs in Dash?

I'm trying to create two tabs with two subtabs each in Dash but I'm having problems.
Here is my code:
import dash
import dash_html_components as html
import dash_core_components as dcc
app = dash.Dash()
# Create a Dash layout
app.layout = html.Div([
html.Div(
html.H1('My Dashboard')
),
dcc.Tabs(id="tabs", value='Tab1', children=[
dcc.Tab(label='Tab 1', id='tab1', value='Tab1', children =[
dcc.Tabs(id="subtabs1", value='Subtab1', children=[
dcc.Tab(label='Sutab 1', id='subtab1', value='Subtab1'),
dcc.Tab(label='Sutab 2', id='subtab2', value='Subtab2'),
]),
]),
dcc.Tab(label='Tab 2', id='tab2', value= 'Tab2', children=[
dcc.Tabs(id="subtabs2", value='Subtab4', children=[
dcc.Tab(label='Sutab 4', id='subtab4', value='Subtab4'),
dcc.Tab(label='Sutab 5', id='subtab5', value='Subtab5'),
]),
])
])
])
if __name__ == '__main__':
app.run_server(debug=True)
When I run this application the subtabs in the first tab work as expected. However, I can't navigate to any subtabs in the second tab. Why is this happening? Any help would be appreciated. Thank you.
As it stands, with Dash you would need to assign two separate callbacks and then check the values, and return the respective output when trying to do this.
It doesn't change the layout on the page whatsoever. That way you can check the values of the tabs and assign the desired callbacks (in this case traversing between tabs/subtabs).
The following code should achieve what you are looking to do :).
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
app = dash.Dash()
# Create a Dash layout
app.layout = html.Div([
html.Div(
html.H1('My Dashboard')
),
dcc.Tabs(id='tabs', value='Tab1', children=[
dcc.Tab(label='Tab 1', id='tab1', value='Tab1', children =[
]),
dcc.Tab(label='Tab 2', id='tab2', value='Tab2', children=[
])
])
])
#app.callback(Output('tab1', 'children'),
[Input('tabs', 'value')])
def update_tabs(value):
if value == 'Tab1':
return dcc.Tabs(id="subtabs1", value='Subtab1', children=[
dcc.Tab(label='Subtab 1', id='subtab1', value='Subtab1'),
dcc.Tab(label='Subtab 2', id='subtab2', value='Subtab2'),
]),
#app.callback(Output('tab2', 'children'),
[Input('tabs', 'value')])
def update_tabs(value):
if value == 'Tab2':
return dcc.Tabs(id="subtabs2", value='Subtab4', children=[
dcc.Tab(label='Subtab 4', id='subtab4', value='Subtab4'),
dcc.Tab(label='Subtab 5', id='subtab5', value='Subtab5')
]),
if __name__ == '__main__':
app.run_server(debug=True)