plotly-Dash - how to create 3 filters based on dataset columns (drop down list can be multi select) - plotly-dash

I am new to Dash, and I don't have knowledge for css and html.
I have a requirement that is to add 3 filters for the sankey chart based on dataCenter, customer and company ID columns with dash library ,type is multi selection dropdown. so I can filter the sankey chart.
The default value for all the 3 filters I need are 'Select All'.
I have refer to some materials on page https://dash.plotly.com/, but due to kind of reason, I am not able to successfully make it.
This is the code for dash part, and i don't know how to add call back for these 3 filters.
app.layout = html.Div([
dcc.Dropdown(
id='my-multi-dataCenter-dropdown',
options=[ {'label': i, 'value': i} for i in dataset['companyID'].unique()] + [{'label': 'Select all', 'value': 'allID'}],
multi=True, placeholder='Please select Data Center'),
dcc.Dropdown(
id='my-multi-customer-dropdown',
options=[{'label': i, 'value': i} for i in dataset['Customer'].unique()] + [{'label': 'Select all', 'value': 'allID'}],
multi=True, placeholder='Please select Customer'),
dcc.Dropdown(
id='my-multi-companyID-dropdown',
options=[{'label': i, 'value': i} for i in dataset['companyID'].unique()] + [{'label': 'Select all', 'value': 'allID'}],
multi=True, placeholder='Please select companyID'),
html.Div(id='dd-output-container'),
dcc.Graph(id='uxrPerfGoalSankey',figure=fig)
])
#app.callback(
Output('dd-output-container', 'children'),
Input('my-multi-dataCenter-dropdown', 'value'),
Input('my-multi-customer-dropdown', 'value'),
Input('my-multi-companyID-dropdown', 'value')
)
def update_output(value):
return 'You have selected "{}"'.format(value)
if __name__ == '__main__':
app.run_server(debug=True)

To add a 'select all' option, you can do something like this:
dcc.Dropdown(
id='my-multi-companyID-dropdown',
options=[
{'label': i, 'value': i} for i in dataset['companyID'].unique()
] + [{'label': 'Select all', 'value': 'allID'],
multi=True, placeholder='Please select companyID')
Then, in your callback, you can check for the 'allID' value, and know that means all values. You'd set a slightly different one for each callback, so you can tell them apart.
Edit: Fix for callback. You need to make sure the number of arguments the function takes matches the number of Input and State values you assign to the callback. The callback should look like this:
#app.callback(
Output('dd-output-container', 'children'),
Input('my-multi-dataCenter-dropdown', 'value'),
Input('my-multi-customer-dropdown', 'value'),
Input('my-multi-companyID-dropdown', 'value')
)
def update_output(data_value, customer_value, company_id_value):
# function body goes here

Related

How can I have my dash app comment list all the previously inputted comments?

I am trying to create a comment section in my dash app where the comments submitted will be updated as new comments are submitted.I tried different ways but it wasn't working.. this is the current code I have now which is able to return the most recent comment submitted.
layout = html.Div([
html.H3(children='Write Comments'),
dcc.Textarea(
id='textarea',
value='',
style={'width': '100%', 'height': 200},
),
html.Button('Submit', id='button', n_clicks=0),
html.Div(id='comment-output', style={'whiteSpace': 'pre-line'})
])
# Submit comment through pushing the 'submit' button
#callback(
Output('comment-output', 'children'),
Input('button', 'n_clicks'),
State('textarea', 'value')
)
def update_output(n_clicks, value):
if n_clicks > 0:
return 'Submitted Comment: {}'.format(value)
You have to include the history with the callback and then add to it, otherwise it will just overwrite with the latest. I've tried this locally and it works:
#callback(
Output('comment-output', 'children'),
Input('button', 'n_clicks'),
[
State('textarea', 'value'),
State('comment-output', 'children'),
],
)
def update_output(n_clicks, value, children):
if n_clicks > 0:
return f'{children}\n Submitted Comment: {value}'
else:
return ''

How to connect HTML elements with Dash Callback in Python

I'm using both html elements and dash bootstrap components in my code and wonder if I can connect an HTML component with a Dash component in callback. For example, I have a dash dropdown menu and want to update the html text based on the input of the dropdown menu.
#dropdown
html.Div =(
[
dcc.Dropdown(
id="dropdown",
options=[
{"label": "option1", "value": "option1"},
{"label": "option2", "value": "option2"},
],
multi=True,
)
]
)
# HTML Components
html.Div =(
[
html.H2("The selected option is")
html.P(id="text-holder", children =["text"])
]
)
#app.callback(
Output("text-holder", "children"),
Input("dropdown", "value)
)
def fill_text(value):
return value
Once a user selects a value from the dropdown menu, I want the selected value to appear on the text line created by html.P. For example, if "option1" is selected from the dropdown menu, the text that appears on the HTML part should be also "option1".
If I run the current script, I don't get any error message but the html part doesn't get updated at all. I think the callback is incorrect but am not sure how to fix it.
Using html.Div =( ... alters the value of html.Div. And it's really important to get the layout right.
Perhaps this is what you're looking for:
from dash import dcc, html, Dash, Output, Input
app = Dash(__name__)
app.layout = html.Div(
[
# dropdown
html.Div(
[
dcc.Dropdown(
id="dropdown",
options=[
{"label": f"option{idx}", "value": f"option{idx}"}
for idx in range(1, 5)
],
multi=True,
value="not specified",
)
]
),
# HTML Components
html.Div([html.H2("The selected option is"), html.P(id="text-holder")]),
]
)
#app.callback(Output("text-holder", "children"), Input("dropdown", "value"))
def fill_text(value):
return value
if __name__ == "__main__":
app.run_server()

adding a local html file into a Div in plotly/dash

I created a Dash app. On one tab I have a dropdown and a submit button. In a callback I generate an html file, saved locally, based on quantstats library (reports.html)
I am trying to producing this html within an html.Div but no success so far. All I managed to do is to print out an hyperlink to my local file but not the file itself.
Here is the layout part:
layout = html.Div([
dbc.Container([
dbc.Row([
dbc.Col(html.H1("Reports", className="text-center"), className="mb-5 mt-5")
]),
dbc.Row([
dbc.Col(dcc.Dropdown(id='reports_type',
options=[
{'label': 'YTD', 'value': 1},
{'label': 'ITD', 'value': 2},
],
value=1,
style={'display': 'block'},
)),
dbc.Col(html.Button('Run report', id='reports_submit')),
])
]),
html.Div(id='reports_holder')
])
Here is the callback:
#app.callback(
Output('reports_holder', 'children'),
[
Input('reports_submit', 'n_clicks')
],
[
State('reports_type', 'value')
],
prevent_initial_call=True
)
def produce_report(n_clicks, reports_type):
if n_clicks:
df = some dataframe
if reports_type == 1: #YTD
current_df = df[df.index.year == datetime.date.today().year]
my_pfo = pd.Series(current_df['Close'].values, name='Close', index=current_df.index)
qs.reports.html(my_pfo, "SPY", output='quantstats-tearsheet.html', title='YTD Tearsheet')
else: #ITD
my_pfo = pd.Series(df['Close'].values, name='Close', index=df.index)
qs.reports.html(my_pfo, "SPY", output='quantstats-tearsheet.html', title='ITD Tearsheet')
f = codecs.open('quantstats-tearsheet.html', 'r')
return f
Here is my latest try using the codecs library (this creates an error because the html documents cannot be JSON serializable). If I return f.read() instead then this is not html formated.
As said before I tried html.A instead of html.Div in my layout but this produces only an hyperlink (as expected with html.A). Should I use the property target with html.A but then how do I sepcify that the document should be opened in that same html.A? There must be a straightforward solution to this but I can't find it (most solutions involve opening a local html file into a new browser tab...)
Edit: here is an example of the html report generated via quantstats

Dash dropdown navigation

I'm trying to create an interactive menu in a Dash dashboard using a simple Dropdown element. The idea would simply to change the url pathname whenever the value in the Dropdown element changes. I've looked around how to manage that with a callback and couldn't find how to properly do that. Could you please help me on that? Cheers.
import dash_html_components as html
import dash_core_components as dcc
def Header(app):
return html.Div([get_header(app)])
def get_header(app):
logo = html.A(
html.Img(
src=app.get_asset_url("logo.jpeg"),
className="logo",
),
href="google.com",
)
dropdown = dcc.Dropdown(
options=[
{'label': 'Overview', 'value': 'Overview'},
{'label': 'Details', 'value': 'Iteration 1'},
{'label': 'Raw Data', 'value': 'Raw Data'},
],
value='Overview',
)
ddcontainer = html.Div(
[dropdown],
id="dd-container"
)
header = html.Div([logo, ddcontainer])
return header

dash Dropdown provides either string or list depending on number of selections

I'm currently working on a stock analysis tool utilizing dash. I have a dropdown populated with the NASDAQ 100 symbols and am attempting to get it to return a line graph with a line for each symbol selected.
With the dropdown, if I have one symbol selected the returned value is a string, if I select multiple it's then a list.
I'm trying to use a callback such as:
#app.callback(
Output(component_id='stock-graph-line', component_property='figure'),
Input(component_id='stock-input', component_property='value'),
suppress_callback_exceptions = True
)
def update_stock_symbol(input_value):
for i in input_value:
fig.append_trace({'x':df.index,'y':df[([i], 'close')], 'type':'scatter','name':'Price [Close]'},1,1)
fig['layout'].update(height=1000, title=input_value, template="plotly_dark")
return fig
However, the for loop does not work with only one symbol selected as it's getting a string, not a list. Is there an option in dash to specify the return type of the callbacks? (Can I force it to pass on the one symbol as a list item?) Or does this have to be handled with if statements testing the type?
I set up a dropdown and it is always returning either None or a list:
dcc.Dropdown(
id='dropdown-id',
options=[
{'label': 'a', 'value': 'a'},
{'label': 'b', 'value': 'b'},
{'label': 'c', 'value': 'c'},
{'label': 'd', 'value': 'd'},
{'label': 'e', 'value': 'e'},
],
multi=True
),
Perhaps yours is set up differently. If that won't work, then just check like this:
def update_stock_symbol(input_value):
if isinstance(input_value, str):
input_value = [input_value]
for i in input_value:
...