I’ve been trying to find a way to put limits on the number of options the user can select, maximum and minimum, and I came up with a solution that is very simple which I’d like to share.
Basically, you only have to process the first n
of the selected items, and display helpful messages to the user.
Your callback function will simply look like this:
@app.callback(Output('output', 'children'),
[Input('dropdown', 'value')])
def process_selected(values):
do_something_with(values[:4]) # this is the solution
The function will only process the first n
(in this case four) items. Now we have to properly inform the user.
Here’s a full example:
from dash import Dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(id='dropdown',
options=[{'label': x, 'value': x} for x in range(10)],
value=[0],
multi=True),
html.Div(id='output')
])
@app.callback(Output('output', 'children'),
[Input('dropdown', 'value')])
def process_selected(values):
message = ''
if len(values) > 4:
message = 'A maximum of four items can be selected please de-select some '
output = 'You selected ' + ', '.join(str(v) for v in values[:4])
return html.Div([
message,
html.Br(),
output
])
if __name__ == '__main__':
app.run_server(debug=True)
Up to four items, everything runs normally with the callback displaying the selected values:
Beyond four, the output remains the same, simply because the callback is designed to only process values[:4]
.
A simple message informs the user about what they should do:
Note that the user can de-select in any order they want.
This is exactly like Twitter allowing you to go over the character limit while showing you how far you’ve gone:
Let’s make it more interesting (add a minimum number of values as well):
from dash import Dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output, Input
app = Dash(__name__)
app.layout = html.Div([
dcc.Dropdown(id='dropdown',
options=[{'label': x, 'value': x} for x in range(10)],
value=[0],
multi=True),
html.Div(id='output')
])
@app.callback(Output('output', 'children'),
[Input('dropdown', 'value')])
def process_selected(values):
message = ''
if len(values) < 2:
message = 'A minimum of two items need to be selected'
if len(values) > 4:
message = 'A maximum of four items can be selected please de-select some '
output = '' if len(values) < 2 else 'You selected ' + ', '.join(str(v) for v in values[:4])
return html.Div([
message,
html.Br(),
output
])
if __name__ == '__main__':
app.run_server(debug=True)
The output
is set to the emtpy string if the user selects < 2 items, otherwise, the previous logic is used:
Using the same logic, you can also ensure exactly n
options by setting the maximum and minimum to the same value (a scatter plot comparing any two of ten variables for example).
Hope this helps!
And please let me know if there are bugs/improvements. Thanks.