Why doesn't my callback in Dash take any output? - python

After many tries and research, I can't figure out why, but any target for this callback's output will return a key_error.
layout :
...
app = DjangoDash('liste_app', serve_locally=True)
app.layout = ...
...
...
html.Div(className='card-body',
children=[
dcc.Store(id='sorted_storage', data=''),
html.P(children=['filler text'],
id="sorted_liste", style={'overflow': 'scroll',
'height': '100px'})
])
...
callback :
#app.expanded_callback(
[Output('sorted_storage', 'data')],
[Input('insert', 'n_clicks')],
[State('tabs', 'value')]
)
def insertSortButton(n_clicks, value, **context):
if n_clicks is not None:
liste = get_int_liste(context['request'].session.session_key, int(value))
sorted_liste, time = insertSort(liste)
save_algo_result(sorted_liste, time, context['request'].session.session_key, int(value), 'insert')
else:
sorted_liste = 0
return sorted_liste
error :
File "D:\Projets\Python\Exercices\Algorithmique\venv\lib\site-packages\django_plotly_dash\dash_wrapper.py", line 620, in dispatch_with_args
for component_registration in self.callback_map[target_id]['inputs']:
KeyError: 'sorted_storage.data'

I finally found out what I did wrong : If there is only one Outpput, it must not be in a list.
This is my code, returning key_error :
#app.expanded_callback(
[Output('sorted_storage', 'data')],
[Input('insert', 'n_clicks')],
[State('tabs', 'value')]
)
This is correct code working fine :
#app.expanded_callback(
Output('sorted_storage', 'data'),
[Input('insert', 'n_clicks')],
[State('tabs', 'value')]
)
The missleading part is that Inputs and States work the opposite way :
#app.expanded_callback(
[Output('sorted_storage', 'data')],
Input('insert', 'n_clicks'),
[State('tabs', 'value')]
)
#app.expanded_callback(
[Output('sorted_storage', 'data')],
[Input('insert', 'n_clicks')],
State('tabs', 'value')
)
Those 2 blocks of code return the error "'Input' Object is not iterable"/"'State' object is not iterable".
Hope it can help someone someday

Related

Dash dropdown wont reset values once x clicked

I created 2 Dash dropdowns where one dropdown (the lower) is based on the selection in the first dropdown (the upper)
The selection and everything work fine.
However, when I click the X button to remove all the options from the area-dropdown, it does remove all the options but still, city-dropdown values are the same as when I clicked the X button.
why won't it reset?
This is the code I'm using:
#app.callback(
Output("city-dropdown", "options"),
Input("area-dropdown", "value"),
)
def update_city_dropdown(areas):
if areas is None or None in areas or areas == []:
return []
_area_codes = area_codes['area'][area_codes['name'].isin(areas)]
cities = city_codes['name'][city_codes['area'].isin(_area_codes)]
return [{'label': city, 'value': city} for city in cities]
where:
area_dropdown = dcc.Dropdown(
options=area_codes['name'],
placeholder="Select an area",
multi=True,
style=DROPDOWN_STYLE,
id='area-dropdown'
)
city_dropdown = dcc.Dropdown(
placeholder="Select a city",
options=[],
multi=True,
style=DROPDOWN_STYLE,
id='city-dropdown'
)
Thank you
The city_dropdown.value isn't updated, so upon re-selection of an area, the cities show-up again (since those values are now again in the refreshed options).
You can add the following callback:
#app.callback(
Output("city-dropdown", "value"),
Input("area-dropdown", "value")
)
def clear_city_dropdown(value):
return []
Note that the above will reset your cities when switching areas.

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)

How to save input from a dbc.Modal and write to mySql database in Python Dash app?

I have created a button when clicked will pop up a dash boostrap component, dbc.Modal with a couple input fields. Now I'm wondering how can I save this input information and write to a database like MySQL.
I know how to read/write to a DB in the context of a regular html button in Dash with a callback function that triggers when button clicked. But lost on how to use with a modal and callback. I couldn't find any examples online and documentations don't show how to use a modal to save input data and connect with external DB. Please advise. Below is a segment of my code:
Edited Code:
dbc.Modal(
[
dbc.ModalHeader("Add Favorite Faculty"),
dbc.ModalBody(
dbc.Form(
[
dbc.Row(
[
dbc.Label("Enter Name:", id="fav-name"),
dbc.Input(type="text", placeholder="name")
]
),
html.Br(),
dbc.Row(
[
dbc.Label("Enter Email:", id="fav-email"),
dbc.Input(type="email", placeholder="email")
],
),
html.Br(),
dbc.Row(
[
dbc.Label("Enter Comment:", id="fav-comment"),
dbc.Input(type="text", placeholder="comment")
],
),
html.Br(),
dbc.Button("Submit", id='fav-submit', color="primary"),
],
)
),
dbc.ModalFooter(
dbc.Button("Close", color="secondary", id="close-add-faculty", className="ml-auto")
),
],
id="fav-modal",
is_open=False,
And my basic callback function that just opens and closes the modal. Essentially I want to save the input fields when a submit button is clicked and write to a databse.
# prompt modal
#app.callback(
Output("fav-modal", "is_open"),
[
Input("add-faculty-button", "n_clicks"),
Input("close-add-faculty", "n_clicks")
],
[State("fav-modal", "is_open")]
)
def toggle_modal(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
# write to DB
#app.callback(
Output("written", "children"),
[
State("fav-name", "value"),
State("fav-email", "value"),
State("fav-comment", "value")
],
[
Input("fav-submit", "n_clicks")
]
)
def write_to_db(n_clicks, name, email, comment):
if n_clicks is not None:
....
An image of what it looks like:
The fact that these inputs are inside a modal doesn't matter in this case. You can still set up callbacks using those component IDs to get the value of each input, and then use that to pass along to your database.
You may want to consider adding a "submit" button or something like that, which would serve as the trigger for your callback, and take these inputs as State. Otherwise, your callback would fire every time the input updates, and you would likely send lots of unwanted values to your database.
Edit:
You need to add IDs to all the dbc.Input components and the submit button in order to hook them up to the callback. Here's an example.
# layout code
dbc.Input(type="text", placeholder="name", id='name-input')
# end of layout
#app.callback(
Output("some-notification-contaienr", "children"),
[
Input("submit-button", "n_clicks"),
],
[
State("name-input", "value"),
State("email-input", "value"),
State("comment-input", "value"),
]
)
def toggle_modal(submit_clicks, name, email, comment):
if not submit_clicks:
raise PreventUpdate
# some code here to send your stuff to the database
# ...
return 'Successfully submitted.'

Two filters in Dash Table using callback function

I am wanting to filter the table according to selected date filter or dropdown or both. But I'm not able to integrate the two components to interact with the table. Does anyone know where I'm going wrong?
I don't know exactly how to put two filters to work on a single table
app.layout = html.Div([
# Title
html.Div([
html.H1(children="test", id="title")
]),
# Range Date
html.Div(
id="container_range_date",
children=dcc.DatePickerRange(
id="date_range",
min_date_allowed=date(2016, 1 , 1),
max_date_allowed=date(2021, 12, 31),
initial_visible_month=date(2016, 1, 1),
start_date=date(2026, 1, 1),
end_date=date(2021, 12, 31)
)
),
# Menu Dropdown
html.Div(
id="container_col_select",
children=dcc.Dropdown(
id="col_select",
options=[{"label":i, "value":i} for i in df["customer"].unique()],
value=df["customer"][0:].unique(),
multi=True,
placeholder="customer"
)
),
# Data Table
dash_table.DataTable(
id="table",
columns=[{"name":x, "id":x} for x in df.columns],
data=df.to_dict("rows"),
fixed_rows={'headers':True},
export_format="xlsx",
filter_action="native"
)
])
# Callback
#app.callback(
Output("table", "data"),
[Input("col_select", "value"),
Input("date_range", "start_date"),
Input("date_range", "end_date")]
)
def outputUpdate(dropdownValue, startDate, endDate):
if type(dropdownValue) != str:
dfFiltered = df[(df["customer"].isin(dropdownValue)) & (df["date"] >= startDate) & (df["date"] <= endDate)]
else:
dfFiltered = df[df["customer"] == dropdownValue]
return dfFiltered.to_dict("rows")
feel free to use this example and adjust it according your data model:
#app.callback(
Output('table-container', 'data'),
[Input('Filter1_dropwdown', 'value'),
Input('Filter2_dropwdown', 'value')]
)
def filter_df(filter_01, filter_02):
if (not filter_01 and not filter_02):
# Return all the rows on initial load
return df.to_dict('records')
filtered = df.query('filter_1_field in #filter_01 or filter_2_field in #filter_02')
return filtered.to_dict('records')

Plotly: Dash button with live graph not working

i developed python dash based application for monitoring. as a part of the project i want to display live graph and change the live graph value based on user input. i am stuck in this part. the live graph getting update when i start typing in input box (eg:temp) the graph keep on updating for each letter like t,te,tem,temp. so i created a button to submit the input value. still the graph updating for each letter.
the code for the same:
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Input(id='input-value', value='example', type='text'),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
]
)
call back function is like below
#app.callback(Output('live-graph', 'figure'),
[Input('submit-button','n_clicks')],
state=[State(component_id='sentiment_term', component_property='value')],
events=[Event('graph-update', 'interval')])
def update_graph_scatter(n_clicks, input_value):
conn = sqlite3.connect('database.db')
c = conn.cursor()
df = pd.read_sql("SELECT * FROM table WHERE colume LIKE ? ORDER BY unix DESC LIMIT 1000", conn ,params=('%' + input_value+ '%',))
df.sort_values('unix', inplace=True)
df['date'] = pd.to_datetime(df['unix'],unit='ms')
df.set_index('date', inplace=True)
X = df.index
Y = df.column
data = plotly.graph_objs.Scatter(
x=X,
y=Y,
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],'layout' : go.Layout(xaxis=dict(range= [min(X),max(X)]),
yaxis=dict(range=[min(Y),max(Y)])}
Note: If i removed the interval the button start working.but i want to be live update as well as button
You could use an intermediate component like a div to save the input from the text field and update that div only on button click.
So you would have
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Input(id='input-value', value='example', type='text'),
html.Div(['example'], id='input-div', style={'display': 'none'}),
html.Button('Submit', id="submit-button"),
dcc.Graph(id='live-graph', animate=False),
dcc.Interval(
id='graph-update',
interval=1*1000
),
])
Now you update the div only on button click:
#app.callback(Output('input-div', 'children'),
[Input('submit-button', 'n_clicks')],
state=[State(component_id='input-value', component_property='value')])
def update_div(n_clicks, input_value):
return input_value
And the Graph always uses the the div content to query your database (either when the interval triggers or the div changes):
#app.callback(Output('live-graph', 'figure'),
[Input('graph-update', 'interval'),
Input('input-div', 'children')])
def update_graph_scatter(n, input_value):
...
Are you sure the updates on each letter are because of the input? Sounds like the interval updates the graph with the not finished input you are typing.
P.S.: I guess you have a name discrepancy between you Input and State id.

Categories

Resources