From ba9f8f3ce1f192f8755b12e9e245a569b9e76974 Mon Sep 17 00:00:00 2001 From: Sebastian David <sebastian.david@uni-hamburg.de> Date: Fri, 12 Nov 2021 11:44:18 +0100 Subject: [PATCH] Code cleanup, added documentation, added start button, added recursion depth in both directions, added a basic example of an output function, fixed a bug where elements that where deleted and readded would still be selected --- ui_programm_fragmente/input_to_checklist.py | 104 ++++++++++++++++---- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/ui_programm_fragmente/input_to_checklist.py b/ui_programm_fragmente/input_to_checklist.py index 0f0ec61..740b51e 100644 --- a/ui_programm_fragmente/input_to_checklist.py +++ b/ui_programm_fragmente/input_to_checklist.py @@ -4,49 +4,82 @@ from dash import html from dash import callback_context from dash.dependencies import Input, Output, State from dash.exceptions import PreventUpdate +import plotly.express as px app = dash.Dash(__name__) list_of_inputs = dict() app.layout = html.Div([ - html.H4("Progressively add input strings to a list"), + # Layer 0: For the Header and Help Function(s) html.Div([ html.Button(id='show-info',children='Show Info',n_clicks=0), html.Div(id='info-box') ]), + # Layer 1: For all mandatory Inputs html.Div([ "Input: ", - dcc.Input(id='my-input', value='', type='text',debounce=True), - dcc.Checklist(id='list-of-inputs',labelStyle = dict(display='block')), + dcc.Input(id='input-string', value='', type='text',debounce=True), + dcc.Input(id='forward-depth',value='1',type='number',min='1',max='10'), + dcc.Input(id='backward-depth',value='1',type='number',min='1',max='10') + ]), + # Layer 2: For the checklist and Remove-/Start-Buttons + html.Div([ + dcc.Checklist(id='input-checklist',labelStyle = dict(display='block'),value=[]), html.Button(id='clear-all-button',children='Clear All'), - html.Button(id='clear-selected-button',children='Clear Selected') + html.Button(id='clear-selected-button',children='Clear Selected'), + html.Button(id='start-button',children='Generate Graph') ]), + # Layer 3: For additional Options (e.g. Topological Sort) + # Layer 4: For the Graph + html.Div([ + html.Div(id='test-output') + ]) ]) + +''' +Most important callback function. Updates the checklist that holds all inputs. +input-string is required as Output to clear the input box after each input +''' @app.callback( - Output('list-of-inputs','options'), - Output('my-input','value'), - Input('my-input','value'), + Output('input-checklist','options'), + Output('input-checklist','value'), + Output('input-string','value'), + Input('input-string','value'), Input('clear-all-button','n_clicks'), Input('clear-selected-button','n_clicks'), - State('list-of-inputs','value') + State('input-checklist','value') ) -def update_input_list(input_value,btn1,btn2,all_inputs): +def update_input_list(input_value,btn1,btn2,all_values): + ''' + :param input_value: given by dcc.Input + :type input_value: string + :param btn1: signals pressing of clear-all-button + :param btn2: signals pressing of clear-selected-button + :param all_values: values of all checked elements + :type all_values: list of strings + ''' changed_id = [p['prop_id'] for p in callback_context.triggered][0] + # if clear-all-button was pressed: if 'clear-all-button' in changed_id: list_of_inputs.clear() - return list(),'' + return list(),list(),'' + # if clear-selected-button was pressed: if 'clear-selected-button' in changed_id: - for key in range(len(all_inputs)): - if all_inputs[key]: - del list_of_inputs[all_inputs[key]] - return [{'label': i, 'value': i} for i in list_of_inputs], '' + for value in all_values: + del list_of_inputs[value] + return [{'label': i, 'value': i} for i in list_of_inputs],list(),'' + # when the programm is first started: if input_value == '': - return list(),'' + return list(),list(),'' + # when a new element is added via dcc.Input if input_value not in list_of_inputs: list_of_inputs[input_value] = input_value - return [{'label': i, 'value': i} for i in list_of_inputs], '' + return [{'label': i, 'value': i} for i in list_of_inputs],all_values,'' +''' +This callback shows and hides the (first) help-box +''' @app.callback( Output('info-box','children'), Input('show-info','n_clicks') @@ -55,9 +88,44 @@ def show_hide_info_box(n_clicks): if n_clicks % 2 == 0: return '' else: - return "Hier koennte Ihre Werbung stehen" - + return 'Hier koennte Ihre Werbung stehen' +''' +Basic structure for a callback that generates an output +''' +@app.callback( + Output('test-output','children'), + Input('start-button','n_clicks'), + State('input-checklist','options'), + State('input-checklist','value'), + State('forward-depth','value'), + State('backward-depth','value'), +) +def generate_output(n_clicks,all_options,all_values,forward_depth,backward_depth): + ''' + :param n_clicks: how often has Generate Graph been clicked + :type n_clicks: int + :param all_options: all labels and values from the checklist, + regardless if they have been checked or not + :type all_options: list of dictionaries with 2 entries each + :param all_values: values of all checked elements + :type all_values: list of strings + :param forward_depth: forward recursion depth + :type forward_depth: unsigned int + :param backward_depth: backward recursion depth + :type backward_depth: unsigned int + ''' + if n_clicks is None: + raise PreventUpdate + else: + s = '' + for i in range(len(all_options)): + x = all_options[i]['value'] + if x in all_values: + s += x*(abs(int(forward_depth)-int(backward_depth))) + else: + s += x*(int(forward_depth)+int(backward_depth)) + return s if __name__ == '__main__': app.run_server(debug=True) -- GitLab