I try to learn Python Dash to visualize some data. I worked on the Plotly Example with multiple Buttons:
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Button('Button 1', id='btn-nclicks-1', n_clicks=0),
html.Button('Button 2', id='btn-nclicks-2', n_clicks=0),
html.Button('Button 3', id='btn-nclicks-3', n_clicks=0),
html.Div(id='container-button-timestamp')
])
#app.callback(Output('container-button-timestamp', 'children'),
Input('btn-nclicks-1', 'n_clicks'),
Input('btn-nclicks-2', 'n_clicks'),
Input('btn-nclicks-3', 'n_clicks'))
def displayClick(btn1, btn2, btn3):
changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
if 'btn-nclicks-1' in changed_id:
msg = 'Button 1 was most recently clicked'
elif 'btn-nclicks-2' in changed_id:
msg = 'Button 2 was most recently clicked'
elif 'btn-nclicks-3' in changed_id:
msg = 'Button 3 was most recently clicked'
else:
msg = 'None of the buttons have been clicked yet'
return html.Div(msg)
if __name__ == '__main__':
app.run_server(debug=True)
The code displays which button was clicked recently. I want to ask if it is possible to put this in a loop, so that I can loop over i numbers of buttons, because it is pretty much work if I want to use 50 buttons or so.
Instead of
html.Button('Button 1', id='btn-nclicks-1', n_clicks=0),
html.Button('Button 2', id='btn-nclicks-2', n_clicks=0),
html.Button('Button 3', id='btn-nclicks-3', n_clicks=0),
something like:
for i in range(number_buttons):
html.Button('Button i', id='btn-nclicks-i', n_clicks=0)
#app.callback(
Input('btn-nclicks-i', 'n_clicks')
)
I'd appreciate some links to tutorials or examples with Dash Callbacks.
The trickiest part about this is adding all of the buttons created in your loop as Input to your callback, but you can do that using pattern matching callbacks (see dash docs). Here is a small example, using the code you provided as basis but using 10 buttons via a loop:
from dash.dependencies import Input, Output, ALL
import dash_html_components as html
app = dash.Dash(__name__)
btnlst = [html.Button(
'Button {}'.format(i),
id={
'type' : 'mybuttons',
'index' : i,
}
)
for i in range(10)]
app.layout = html.Div(btnlst + [
html.Div(id='btn-out-container'),
])
#app.callback(Output('btn-out-container', 'children'),
Input({'type':'mybuttons', 'index':ALL}, 'n_clicks'))
def display_click(nclicks):
changed_id = [p['prop_id'] for p in dash.callback_context.triggered][0]
if changed_id == '.':
msg = 'None of the buttons have been clicked yet'
else:
# do additional parsing of changed_id here as necessary
msg = 'Changed property: {}'.format(changed_id)
return html.Div(msg)
if __name__ == '__main__':
app.run_server(debug=True)
Important things to note:
I created the list of buttons btnlst beforehand and added it to the first argument of the other html.Div component. That technique is universal and does not only work with pattern matching callbacks.
Note the form of the id property of each button, which is needed to use them in a pattern matching callback. The type of the id can be any string, but if you are going to use multiple groups like this, it's advisable to not mix their names.
The changed_id used in display_clicks has a pretty custom format, as you can see when looking at the output. You'll propably need to do some extra parsing on it, especially if you have any other Input besides just the list of buttons.
Related
I would like to include a component in my Dash App, that automatically goes through all of the values of a slider. Basically a ‘play button’. As the consequence the callback with the slider value as input should fire and update the output element.
Does anyone know how to do it?
Here is some sample code from the official docs:
from dash import Dash, dcc, html, Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Slider(0, 20, 5,
value=10,
id='my-slider'
),
html.Div(id='slider-output-container')
])
#app.callback(
Output('slider-output-container', 'children'),
Input('my-slider', 'value'))
def update_output(value):
return 'You have selected "{}"'.format(value)
if __name__ == '__main__':
app.run_server(debug=True)
I am inexperienced in Dash, so I looked into it and found a case study answer on the plotly communication site. I have modified it to meet your requirements. As far as I understand it, you need two callbacks, one to start and stop the button click and one to return the value obtained from the animation and the new slider value. Note that it does not have a function to automatically stop when the maximum value is reached.
from dash import Dash, dcc, html, Input, Output, State
from jupyter_dash import JupyterDash # Add for my environment
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
#app = Dash(__name__, external_stylesheets=external_stylesheets)
app = JupyterDash(__name__, external_stylesheets=external_stylesheets) # Add for my environment
step_num = 5
app.layout = html.Div([
dcc.Interval(id="animate", disabled=True),
dcc.Slider(min=0,
max=50,
step=5,
value=0,
id='my-slider'
),
html.Button("Play/Stop", id="play"),
html.Div(id='slider-output-container')
])
#app.callback(
Output('slider-output-container', 'children'),
Output("my-slider", "value"),
Input('animate', 'n_intervals'),
State('my-slider', 'value'),
prevent_initial_call=True,
)
def update_output(n, selected_value):
selected_value = (n%11)*step_num
return 'You have selected "{}"'.format(selected_value), selected_value
#app.callback(
Output("animate", "disabled"),
Input("play", "n_clicks"),
State("animate", "disabled"),
)
def toggle(n, playing):
if n:
return not playing
return playing
if __name__ == '__main__':
app.run_server(debug=True, port=8051, mode='inline') #Add for my environment
i'm trying to learn dash i'm at the third tutorial but it raise this error whenever i run the file(python app.py)
dash.exceptions.IncorrectTypeException: The input argument input.value must be a list or tuple of dash.dependencies.Inputs.
this is the code i'm running :
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.H6("Change the value in the text box to see callbacks in action!"),
html.Div(["Input: ",
dcc.Input(id='input', value='initial value', type='text')]),
html.Br(),
html.Div(id='output'),
])
#app.callback(
Output(component_id='output', component_property='children'),
Input(component_id='input', component_property='value')
)
def update_output_div(input_value):
return 'Output: {}'.format(input_value)
if __name__ == '__main__':
app.run_server(debug=True)
please what is wrong with the code?! even i tried to copy and paste the code still raise the same error
thank you ..
versions
python = 3.6
dash=1.7.0
dash-core-components=1.6.0
dash-html-components=1.0.2
You need to wrap your inputs in a list, like this:
#app.callback(
Output(component_id='output', component_property='children'),
[Input(component_id='input', component_property='value')]
)
def update_output_div(input_value):
return 'Output: {}'.format(input_value)
I wrote a Dash app whose source code is shared below:
import dash
from dash 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
import time
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP], url_base_pathname='/self_serve/')
server = app.server
reset_flag = False
counter = 0
app.title = 'jammed dash app'
app.layout = html.Div([
# buttons
dcc.Input(id='main',placeholder='Main Value'),
dcc.Input(id='filter1',placeholder='filter 1'),
dcc.Input(id='filter2',placeholder='filter 2'),
dcc.Input(id='filter3',placeholder='filter 3'),
dcc.Input(id='filter4',placeholder='filter 4'),
html.Div(id='output',children='')
])
#metric list
#app.callback(
Output(component_id='filter1',component_property='value'),
Output(component_id='filter2',component_property='value'),
Output(component_id='filter3',component_property='value'),
Output(component_id='filter4',component_property='value'),
[
Input(component_id='main',component_property='value')
]
)
def update_filter(main):
# clear up all filters if main is provided
global reset_flag
reset_flag = True
return '','','',''
#app.callback(
Output(component_id='output',component_property='children'),
[
Input(component_id='main',component_property='value'),
Input(component_id='filter1',component_property='value'),
Input(component_id='filter2',component_property='value'),
Input(component_id='filter3',component_property='value'),
Input(component_id='filter4',component_property='value'),
]
)
def calculate(*args):
# do some intensive calculation based on the inputs, but I do not want the clearing action to trigger this callback undesirably
ctx = dash.callback_context
print('\n')
print('************ inside calculate *************')
print('triggered:', ctx.triggered)
print('inputs:', ctx.inputs)
# my idea for solving this problem
global reset_flag, counter
if reset_flag:
counter += 1
if counter <= 4:
print('counter:',counter)
print('reset_flag:',reset_flag)
return ''
else:
reset_flag = False
counter = 0
print('we passed into the correct flow!')
pass
# below is some intensive calculation using pandas.read_sql(), substituted by time.sleep()
print('Wait 10 seconds here')
time.sleep(10)
output = ''
for item in args:
if item:
output += item
print('output:',output)
return output
if __name__ == '__main__':
app.run_server(debug=True)
I need to perform some intensive calculations (e.g. sql code) in the 2nd callback ("calculate"). I would also like to clear up all filter elements whenever value in "main" changes, which is implemented in the 1st callback ("update_filter").
The issue is that, when each filter is cleared in the 1st callback, dash is making call to the 2nd callback in quick succession and the program is jammed.
My question is: how to avoid firing the 2nd callback when the 1st callback is called?
My idea is to track the number of times the 2nd callback is called "redundantly" and letting the "correct" call to pass while returning empty output for "redundant" calls. I tried to implement using a global counter, but this is to no avail.
And in general, what is the best/common practice for avoiding these undesirable, chained callback firing?
Thanks a lot in advance!
Here is my rather crude implementation of the lock on your calculate function using a file. Global variables, I think, are problematic given various threading issues etc. The idea is when calculate does its heavy calculations it puts a '1' into a file, and when it is done it puts '0' there. If in the meantime the function is called again, it checks the lockfile and if there is '1' there it exists without triggering recalculation.
import dash
from dash 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
import time
app = Dash(__name__, external_stylesheets=[
dbc.themes.BOOTSTRAP], url_base_pathname='/self_serve/')
server = app.server
reset_flag = False
counter = 0
lockfilename = 'lockfile.txt' # this is where we keep the lock
with open(lockfilename, 'w') as fw:
fw.write('0') # unlock when we start
app.title = 'jammed dash app'
app.layout = html.Div([
# buttons
dcc.Input(id='main', placeholder='Main Value'),
dcc.Input(id='filter1', placeholder='filter 1'),
dcc.Input(id='filter2', placeholder='filter 2'),
dcc.Input(id='filter3', placeholder='filter 3'),
dcc.Input(id='filter4', placeholder='filter 4'),
html.Div(id='output', children='')
])
# metric list
#app.callback(
Output(component_id='filter1', component_property='value'),
Output(component_id='filter2', component_property='value'),
Output(component_id='filter3', component_property='value'),
Output(component_id='filter4', component_property='value'),
[
Input(component_id='main', component_property='value')
]
)
def update_filter(main):
# clear up all filters if main is provided
global reset_flag
reset_flag = True
return '', '', '', ''
#app.callback(
Output(component_id='output', component_property='children'),
[
Input(component_id='main', component_property='value'),
Input(component_id='filter1', component_property='value'),
Input(component_id='filter2', component_property='value'),
Input(component_id='filter3', component_property='value'),
Input(component_id='filter4', component_property='value'),
]
)
def calculate(*args):
# do some intensive calculation based on the inputs, but I do not want the clearing action to trigger this callback undesirably
ctx = dash.callback_context
print('\n')
print('************ inside calculate *************')
print('triggered:', ctx.triggered)
print('inputs:', ctx.inputs)
with open(lockfilename, 'r') as fr:
line = next(fr)
if(line[0] == '1'):
print('Calc is locked, early exit')
return dash.no_update
# below is some intensive calculation using pandas.read_sql(), substituted by time.sleep()
print('Starting heavy calc, locking the file')
with open(lockfilename, 'w') as fw:
fw.write('1')
print('Wait 10 seconds here')
for n in range(10):
print('.', end='')
time.sleep(1)
output = ''
for item in args:
if item:
output += item
print('output:', output)
print('Done with heavy calc, unlocking the file')
with open(lockfilename, 'w') as fw:
fw.write('0')
return output
if __name__ == '__main__':
app.run_server(debug=True)
In your case, what you might want to do is:
Input(main) -> Output(filter) # reset filter
# when filter changes, take main's state and use it to update output
Input(filter), State(main) -> Output(output)
This doesn't block because it is a chained callback: changing main clears filter, and changing filter triggers the second callback which takes main's state and updates output.
For time-intensive operations, you might want to cache those results. There is an entry in the doc showing this: https://dash.plotly.com/performance
In dash, how do I update the values of one dropdown into another checklist or slider?
In the below code, I am selecting one value from a dropdown which should update checklist values based on the selected value from the dropdown. Here I am partially successful in taking value from the dropdown but it's accumulating with older selected values in the checklist.
Please find below part of the code.
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import pandas as pd
from dash.exceptions import PreventUpdate
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.config['suppress_callback_exceptions'] = True
app.layout = html.Div([
dash_table.DataTable(
id='datatable-upload-container',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict('records'),
),
html.Div(dcc.Dropdown(
id='data_selector1',
options=[
{'label': '', 'value': ''}
],
value=[]
)
),
html.Br(),
html.Div([
html.Div(id='numerical-slider'),
# this is a hack: include a hidden dcc component so that
# dash registers and serve's this component's JS and CSS
# libraries
dcc.Input(style={'display': 'none'})
])
])
#app.callback(Output('data_selector1', 'options'),
[Input('datatable-upload-container', 'data')])
def update_dropdown(rows):
print('updating menus')
numerical_col = [i for i in df.columns if df[i].dtypes != "object"]
col_labels=[{'label' :k, 'value' :k} for k in numerical_col]
return col_labels
#app.callback(Output('numerical-slider','children'),
[Input('data_selector1', 'value'),
Input('datatable-upload-container', 'data')])
def explanatory_cat_slider(value, rows):
if value:
categories, intervals = pd.cut(df[value], 3, retbins=True)
return html.Div(html.Label([value,
dcc.RangeSlider(id='numerical-slider',
min=min(intervals),
max=max(intervals),
step=None,
marks={str(val): str(round(val,2)) for val in intervals},
value = [intervals[0],intervals[-1]]
)
],style={'width': '50%', 'display': 'inline-block', 'textAlign': 'left'})
)
else:
return []
if __name__ == '__main__':
app.run_server(debug=False)
updated code...
I am getting an issue with explanatory_cat_slider, it's not getting updated with new selected values.
In the first image I can select one value of dropdown which automatically shows slider of that value
In the second image sliders getting accumulated on upon other. How do I rectify this issue?
In the last image, how it becomes slider overlapped
The code you posted is incomplete, because you have the Input ID data_selector and the ID datatable-upload-container in your callback, but they do not exist in your layout. I can see that the callback will have a problem with its Output as well, because it's trying to update the children of categorical-checklist with an element that contains an ID of the same. This would result in non-unique IDs in your layout, which will break.
I may be able to help more with the complete code but, essentially, you have the right idea to check if value: and run your code inside that block. Make sure you do not let the callback silently end, because that will return None and cause trouble for you. You should include a return [] or return '' at the end, or inside an else: block to protect against that, and keep the children component valid, even if only with an empty value.
You should also include the dcc.Checklist in your initial layout. Give it options=[] to start with and have your callback update its options prop. That should work but, if there are still problems, update your posted code and I'll take another look.
I would like to get inputs x and y from a user's input to a text box.
if x + 2*y 3*x*y > 100:
print('Blurb 1')
else:
print('Blurb 2')
This seems to be convoluted in dash with callbacks, etc, even though it could be self-contained and quite simple. Is there a simple way to do this within a web app? Other resources I found seem to assume a much more complex goal, so I am curious as to how much the code can be pared.
I don't think you can accomplish your task without defining a callback, but the code to get the work done is very short and simple. A possible solution could be the following:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = dash.Dash()
app.layout = html.Div([
html.H1("Simple input example"),
dcc.Input(
id='input-x',
placeholder='Insert x value',
type='number',
value='',
),
dcc.Input(
id='input-y',
placeholder='Insert y value',
type='number',
value='',
),
html.Br(),
html.Br(),
html.Div(id='result')
])
#app.callback(
Output('result', 'children'),
[Input('input-x', 'value'),
Input('input-y', 'value')]
)
def update_result(x, y):
return "The sum is: {}".format(x + y)
if __name__ == '__main__':
app.run_server(host='0.0.0.0', debug=True, port=50800)
This is what you get:
The value of the sum is updated every time one of the two input boxes changes its values.