How to keep the dropdown value after button click in Dash? - python

I have an application in which I want to update the dropdown values when the user inputs some text into the dropdown. So far, I managed to get the text from an Input text that the user inputs, but not from the dropdown. The dropdown keeps reseting after clicking in any part of the screen or on the button.
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
app = dash.Dash(
external_stylesheets=[
dbc.themes.BOOTSTRAP])
app.layout = html.Div(
[
dcc.Input(id='helper'),
dcc.Dropdown(id="my-dynamic-dropdown", options=[]),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
html.Br(),
dbc.Button('Add to Dropdown', id='dropdown_button', n_clicks=0, color="info",
className="mr-1")
],
)
options = []
#app.callback(
Output("my-dynamic-dropdown", "options"),
Input('dropdown_button', 'n_clicks'),
[State('my-dynamic-dropdown', 'options'),
# State('helper', 'value')
State('my-dynamic-dropdown', 'search_value')
]
)
def update_options(n_clicks,existing_options,helper_value):
if helper_value is None:
print("none value")
return options
else:
print("helper value ",helper_value)
options.append({'label': helper_value, 'value': helper_value})
return options
if __name__ == "__main__":
app.run_server(debug=True)

The dropdown allows a user to search through the existing options, but what you're trying to do is not what the dropdown was designed for. You would either need to write a custom component, use some combination of dropdown and input components, or find a different solution to whatever problem you're trying to solve.

Related

plotly dash chained callback

This is my code
app = Dash(__name__)
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
dcc.Dropdown(options=['bar', 'pie'], id='dropdown', multi=False, value='bar', placeholder='Select graph type'),
html.Div(id='page-content'),
])
#app.callback(
Output('see1', 'options'),
Input('url', 'search')
)
def ex_projecKey(search):
return re.search('project_key=(.*)', search).group(1)
#app.callback(
Output('page-content', 'children'),
Input('see1', 'options'),
Input('dropdown', 'value')
)
def update_page(options, value):
return f'{options}.{value}'
if __name__ == '__main__':
app.run_server(debug=True, port=4444)
I receive something URL and search project_key
after choice dropdown menu like bar or pie
Then i receive two object (project_key, graph_type )
But two error occur
Property "options" was used with component ID:
"see1"
in one of the Input items of a callback.
This ID is assigned to a dash_html_components.Div component
in the layout, which does not support this property.
This ID was used in the callback(s) for Output(s):
page-content.children
Property "options" was used with component ID:
"see1"
in one of the Output items of a callback.
This ID is assigned to a dash_html_components.Div component
in the layout, which does not support this property.
This ID was used in the callback(s) for Output(s):
see1.options
first callback Output see1, options
Than second callback Input receive that options inst it?
You get an error because you did not define see1 in the layout. I don't know which type of object you want see1 to be, but I think if it is juste to pass data bewteen callback, you should use dcc.Store. So you would call it with Output('see1', 'data') instead of Output('see1', 'options').
Full code :
from dash import dcc, html, Dash, Input, Output
import re
app = Dash(__name__)
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
dcc.Dropdown(options=['bar', 'pie'], id='dropdown', multi=False, value='bar', placeholder='Select graph type'),
html.Div(id='page-content'),
dcc.Store(id="see1", storage_type='memory'), # define see1 in layout as dcc.Store component
])
#app.callback(
Output('see1', 'data'), # use 'data' property
Input('url', 'search')
)
def ex_projecKey(search):
return re.search('project_key=(.*)', search).group(1)
#app.callback(
Output('page-content', 'children'),
Input('see1', 'data'),
Input('dropdown', 'value')
)
def update_page(options, value):
return f'{options}.{value}'
if __name__ == '__main__':
app.run_server(debug=True, port=4444)

Display "5 items chosen" instead of "Red", "Blue", "Yellow" .... in a dropdown Dash Python?

I want to create a table in Dash where it is possible to choose multiple values in a specific column. My goal is to do it with a regular table and then add dropdowns for filtering.
However, when a dropdown is added and the size of the choices is bigger than the dropdown it adds "rows". Is it possible to let the choices that been made to be translated into number of choices made instead?
I wonder is it is possible to do something similiar to the Basic example in
https://mdbootstrap.com/docs/standard/extended/multiselect/
I have tried something like this
from dash import Dash, dcc, html, Input, Output
from plotly.express import data
import pandas as pd
df = data.medals_long()
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(df.columns, id='pandas-dropdown-1', multi=True),
html.Div(id='pandas-output-container-1')
])
#app.callback(
Output('pandas-output-container-1', 'children'),
Output('pandas-dropdown-1', 'search_value'),
Input('pandas-dropdown-1', 'value')
)
def update_output(value):
return f'You have selected {value}', f'{len(value)} values have been chosen'
if __name__ == '__main__':
app.run_server(debug=True)

Define Dependent Dictionaries in Python

I am working on an NLP project analyzing the words spoken by characters in The Office. Part of this project involves making a network diagram of which characters talk to each other for a given episode.
This will be shown in a Dash app by allowing a user to select dropdowns for 4 parameters: season, episode, character1, and character2.
Here is a relevant snippet of my code so far:
#Import libraries
import pandas as pd
import numpy as np
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, State
#Load data
sheet_url = 'https://docs.google.com/spreadsheets/d/18wS5AAwOh8QO95RwHLS95POmSNKA2jjzdt0phrxeAE0/edit#gid=747974534'
url = sheet_url.replace('/edit#gid=', '/export?format=csv&gid=')
df = pd.read_csv(url)
#Set parameters
choose_season = df['season'].unique()
choose_episode = df['episode'].unique()
choose_character = ['Andy','Angela', 'Darryl', 'Dwight', 'Jan', 'Jim','Kelly','Kevin','Meredith','Michael','Oscar','Pam','Phyllis','Roy','Ryan','Stanley','Toby']
#Define app layout
app = dash.Dash()
server = app.server
app.layout = html.Div([
dbc.Row([
dbc.Col(
dcc.Dropdown(
id='dropdown1',
options=[{'label': i, 'value': i} for i in choose_season],
value=choose_season[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown2',
options=[{'label': i, 'value': i} for i in choose_episode],
value=choose_episode[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown3',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[0]
), width=3
),
dbc.Col(
dcc.Dropdown(
id='dropdown4',
options=[{'label': i, 'value': i} for i in choose_character],
value=choose_character[1]
), width=3
)
])
])
if __name__=='__main__':
app.run_server()
In order to have this work efficiently, I would like to have the following dependencies in the dropdown menus:
1.) The selection of the first dropdown menu updates the dropdown menu
ie: Season updates possible episodes
2.) The selection of the first two dropdown menus updates the 3rd and 4th dropdown menus
ie: Season, Episode updates possible characters (if a character was not in that episode, they will not appear)
3.) The selection of the third dropdown menu updates the fourth dropdown menu
ie: If a character is selected in the third dropdown menu, they can not be selected in the fourth (can't select the same character twice)
I understand one way to do this is to make a massive season to episode dictionary and then an even larger season to episode to character dictionary.
I've already made the code to process the season to episode dictionary:
#app.callback(
Output('dropdown2', 'options'), #--> filter episodes
Output('dropdown2', 'value'),
Input('dropdown1', 'value') #--> choose season
)
def set_episode_options(selected_season):
return [{'label': i, 'value': i} for i in season_episode_dict[selected_season]], season_episode_dict[selected_season][0]
I can definitely build these dictionaries, but this seems like a really inefficient use of time. Does anyone know of a way to build these dictionaries with just a few lines of code? Not sure how to approach building these in the easiest way possible. Also, if you have an idea for a better way to approach this problem, please let me know that too.
Any help would be appreciated! Thank you!
I think I see what you're asking about now. Something like this should get you a basic dictionary, which you could then modify for the options param for the dropdowns.
df = pd.read_csv(url)
season_episode_character_dictionary = {}
for season in df['season'].unique.tolist():
df_season = df[df['season'].eq(season)]
season_episode_character_dictionary[season] = {}
for episode in df_season['episode'].unique.tolist():
df_episode = df_season[df_season['episode'].eq(episode)]
characters = df_episode['characters'].unique.tolist()
season_episode_character_dictionary[season][episode] = characters

Persistence problem for dependent dropdowns in Plotly Dash

I have two dependent dropdowns that I want to persist in user session. I noticed that the persistence doesn't work for the second dropdown. It get reset with no possible value.
Here is a code sample :
from dash import Dash, dcc, html
from dash.dependencies import Input, Output
app = Dash(
prevent_initial_callbacks=True,
suppress_callback_exceptions=True,
)
#app.callback(
Output("dd-client-code", "options"),
Input("dd-clients-seg-1", "value")
)
def dd_client_code(client_seg_1):
#any function would do for generate_options
return generate_options(selected_segment=client_seg_1)
dd1 = dcc.Dropdown(
id="dd-clients-seg-1",
options=["record_1", "record_2", "record_3"],
persistence="true",
persistence_type="session",
)
dd2 = dcc.Dropdown(
id="dd-client-code",
persistence="true",
persistence_type="session",
)
app.layout = html.Div(children=[dd1, dd2])
app.run_server(debug=True)
Can anyone help me ?
The persistent values for both dropdowns are stored as expected...
but the value for dd2 is updated to null when the page is reloaded because dd2 has no options at that time.
The callback to update dd2 is not called when the page is reloaded. Even if the callback was called it would be too late because of the first issue.
The following modified code uses dcc.Store to store the value of dd1 each time it is changed. dcc.Interval is used to ensure that the callback is called after the page reload. dd2 is turned into a function that takes the value of dd1 and is called by a new callback that triggers on the interval to update the layout.
import dash.exceptions
from dash import Dash, dcc, html
from dash.dependencies import Input, Output, State
app = Dash(
prevent_initial_callbacks=True,
suppress_callback_exceptions=True,
)
def generate_options(selected_segment):
if selected_segment == "record_1":
return ["A", "B", "C"]
elif selected_segment == "record_2":
return ["One", "Two", "Three"]
else:
return ["Small", "Medium", "Large"]
dd1 = dcc.Dropdown(
id="dd-clients-seg-1",
options=["record_1", "record_2", "record_3"],
persistence="true",
persistence_type="session",
)
def dd2(dd1_value):
"""Return a dd2 dropdown with the appropriate options based on dd1 value"""
options = [] if not dd1_value else generate_options(dd1_value)
return dcc.Dropdown(
id="dd-client-code",
options=options,
persistence="true",
persistence_type="session",
)
#app.callback(
Output("dd-client-code", "options"),
# Store the value of dd1 dropdown when it changes
Output("dd-clients-seg-1-value", "data"),
Input("dd-clients-seg-1", "value")
)
def dd_client_code(client_seg_1):
if not client_seg_1:
raise dash.exceptions.PreventUpdate
return generate_options(client_seg_1), client_seg_1
#app.callback(
Output("dd2-div", "children"),
Input("interval-timer", "n_intervals"),
State("dd-clients-seg-1-value", "data"),
)
def dd2_div_handler(unused, dd1_value):
"""Update the dd2 menu when triggered by dcc.Interval"""
return dd2(dd1_value)
app.layout = html.Div([
# store the latest value of dd-clients-seg-1 dropdown
dcc.Store("dd-clients-seg-1-value", storage_type="session"),
# fires 1ms after page load
dcc.Interval(id="interval-timer", interval=1, max_intervals=1),
# static menu
dd1,
# dynamic menu: don't put dd2 here to avoid persistent value going null
html.Div(id="dd2-div")
])
app.run_server(debug=True)
This was tested with Dash 2.4.1

Plotly Dash: Display a variable inside Markdown text

I'm new to the Dash and Plotly ecosystem and began building a web-based dashboard a few days ago.
Here is a snippet of code:
import dash
import dash_html_components as html
import dash_core_components as dcc
# initialize the application
app = dash.Dash()
# define the layout of the app
app.layout = html.Div([
# add a date range selector
dcc.DatePickerRange(
id = 'my-date-picker-range',
min_date_allowed = dt(2010,1,4),
max_date_allowed = dt(2020, 12, 31),
initial_visible_month = dt(2020, 5, 23)
),
html.Div(id = 'output-container-date-picker-range'),
# add some markdown text
dcc.Markdown(f'''
This report covers the time period spanning {start_date} to {end_date}.
'''),
])
#app.callback(
dash.dependencies.Output('output-container-date-picker-range', 'children'),
[dash.dependencies.Input('my-date-picker-range', 'start_date'),
dash.dependencies.Input('my-date-picker-range', 'end_date')])
app.run_server(debug = True)
I'm attempting to display the start_date and end_date variables inside the markdown text (using an f string). Unfortunately, I'm getting the following error message:
NameError: name 'start_date' is not defined
Is it possible to include variable output in Markdown text? Thanks!
You are using a decorator (#app.callback) but you did not attach it to a function to be executed. You need to attach the decorator to the function that is responsible for updating the right div.
I think your best bet is to stick to the documentation.
This gives a similar result as what you want:
import dash
import dash_html_components as html
import dash_core_components as dcc
from datetime import datetime as dt
# initialize the application
app = dash.Dash()
# define the layout of the app
app.layout = html.Div([
# add a date range selector
dcc.DatePickerRange(
id = 'my-date-picker-range',
min_date_allowed = dt(2010,1,4),
max_date_allowed = dt(2020, 12, 31),
initial_visible_month = dt(2020, 5, 23)
),
html.Div(id = 'output-container-date-picker-range'),
])
#app.callback(
dash.dependencies.Output('output-container-date-picker-range', 'children'),
[dash.dependencies.Input('my-date-picker-range', 'start_date'),
dash.dependencies.Input('my-date-picker-range', 'end_date')])
def update_output_div(start_date, end_date):
return f"This report covers the time period spanning {start_date} to {end_date}"
app.run_server(debug = True)

Categories

Resources