Hi,
I’m new to dash and developing web layouts, but not to python.
My goal is to have a list of clickable elements which all have basically the same callback, namely to display further info and to execute some data driven code.
I’ve tried to do it with pattern-matching callbacks, since the list is not fixed and might change, but I find it hard to believe that I’m doing it efficiently. Here’s some of my code:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, MATCH, ALL
import datasets
import html_generators
import re
app = dash.Dash(__name__)
sentences, embeddings = datasets.dataset_from_csv('sentences')
categories = set(sentence['category'] for sentence in sentences if sentence['category'])
app.layout = html.Div([
html.Div(
className="app-header",
children=[
html.Div('Plotly Dash', className="app-header--title")
]
),
html.Div(
className="arg-list-pane",
children=[
html.Div(className="arg-list-box", children=[
html.Div('Header', className="arg-list-header"),
html.Ul(children=[
html.Div(
sentence['sentence'],
id={'type': 'argument-container', 'index': sentence['id']},
className="arg-container") for sentence in sentences]
)]
),
html.Div('Argument Details', id="argument-detail-box")
]
),
html.Div(
className="category-pane",
children=[
html.Div(className="category-box", children=[
html.Div(
className="category-header",
children=[
dcc.Input(id='cat-input', value='Add Category..', type='text'),
html.Button(id='submit-cat-button', n_clicks=0, children='Add')
]),
html.Ul(
id='cat_list',
children=[
html.Div(category, {'type': 'category-item', 'index': index},
className="category-container")
for index, category in enumerate(categories)
])
]
),
html.Div("algorithm or something, idk, I'm not a web designer", id='algo-box')
]
)
])
@app.callback(
Output('cat_list', 'children'),
Input('submit-cat-button', 'n_clicks'),
State('cat-input', 'value'),
State('cat_list', 'children')
)
def add_category(n_clicks, cat_input,children):
if n_clicks > 0:
new_cat = html.Div(cat_input,
id={'type': 'category-item', 'index': len(children)},
className="category-container")
children.append(new_cat)
return children
@app.callback(
Output('argument-detail-box', 'children'),
Output('algo-box', 'children'),
Input({'type': 'argument-container', 'index': ALL}, 'n_clicks')
)
def handle_arg_click(n_clicks):
"""handle click on a list item.
When a list item is clicked, the n_clicks property will update, the callback
will be triggered and the responsible list element will be stored in
`dash.callable_context.triggered`. From that, the index/id of the sentence
is known. With that information, the algorithm can be fed and the info box
can be changed.
"""
if not dash.callback_context.triggered[0]['value']:
raise dash.exceptions.PreventUpdate
sentence_id = int(re.findall('(\d+)',dash.callback_context.triggered[0]['prop_id'])[0])
print(dash.callback_context.triggered)
sentence_data = sentences[sentence_id]
details_table = html_generators.create_details_table(sentence_data, header='argument details')
return details_table, 'Algorithm output here'
if __name__ == '__main__':
app.run_server(debug=True)
This is very slow, I assume due tot the fact that I dynamically create a callback for each output and match them all. I tried to just match the one input that was actually changed with Input({'type': 'argument-container', 'index': MATCH}, 'n_clicks')
, however, since the output is not generated for a generic ID, that didn’t work.
Also, getting the correct ID by regexing for the number in the stringified dict in [‘prop_id’] seems pretty fishy.
So here’s my question:
How do I make clickable list elements which are dynamically created after loading some data. Basically, I want to have a list of sentences and by clicking these list elements, I want the details box to display details in a table, and the algorithm box to display the results of a chosen algorithm as a list of sentences (which also should be clickable).
Any help would be greatly appreciated, I suspect the answer to be relatively simple, I just can’t find it.
Kind Regards,
ZBN