import dash from dash import dcc from dash import html from dash import callback_context from dash.dependencies import Input, Output, State from dash.exceptions import PreventUpdate from input.interface import InputInterface import input.publication app = dash.Dash(__name__) additional_options = ['Update Automatically'] app.layout = html.Div([ # 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='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, Remove-/Start-Buttons and input-error-message html.Div([ dcc.Checklist(id='input-checklist',options=[],labelStyle = dict(display='block'),value=[]), html.Div(id='input-err',style={'color':'red'}), html.Button(id='clear-all-button',children='Clear All'), 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) html.Div([ html.H4('Additional Options'), dcc.Checklist(id='additional-options', options=[{'label':k,'value':k} for k in additional_options], value=[]) ]), # 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('input-checklist','options'), Output('input-checklist','value'), Output('input-string','value'), Output('input-err','children'), Input('input-string','value'), Input('clear-all-button','n_clicks'), Input('clear-selected-button','n_clicks'), State('input-checklist','options'), State('input-checklist','value') ) def update_input_checklist(input_value,btn1,btn2,all_inputs,selected_inputs): ''' :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_inputs: all labels and values from the checklist, regardless if they have been checked or not :type all_inputs: list of dictionaries with 2 entries each :param selected_inputs: values of all checked elements :type selected_inputs: 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: return list(),list(),'','' # if clear-selected-button was pressed: if 'clear-selected-button' in changed_id: all_inputs = [i for i in all_inputs if i['value'] not in selected_inputs] return all_inputs,list(),'','' # when the programm is first started: if input_value == '': app.layout['input-checklist'].options.clear() return list(),list(),'','' # when a new element is added via dcc.Input if 'input-string' in changed_id: options = all_inputs currValues = [x['value'] for x in options] if input_value not in currValues: try: i = InputInterface() pub = i.get_pub_light(input_value) except Exception as err: return options,selected_inputs,'','{}'.format(err) rep_str = pub.contributors[0] + ',' + pub.journal + ',' + pub.publication_date options.append({'label':rep_str, 'value':input_value}) return options,selected_inputs,'','' ''' This callback shows and hides the (first) help-box ''' @app.callback( Output('info-box','children'), Input('show-info','n_clicks') ) def show_hide_info_box(n_clicks): if n_clicks % 2 == 0: return '' else: 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'), Input('input-checklist','options'), Input('input-checklist','value'), Input('forward-depth','value'), Input('backward-depth','value'), State('additional-options','value') ) def generate_output(n_clicks,all_inputs,selected_inputs, forward_depth,backward_depth,additional_options): ''' :param n_clicks: how often has Generate Graph been clicked :type n_clicks: int :param all_inputs: all labels and values from the checklist, regardless if they have been checked or not :type all_inputs: list of dictionaries with 2 entries each :param selected_inputs: values of all checked elements :type selected_inputs: 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 :param additional_options: value of all selected additional options :type additional_options: list of strings ''' changed_id = [p['prop_id'] for p in callback_context.triggered][0] if n_clicks is None: raise PreventUpdate elif 'Update Automatically' in additional_options \ or 'start-button' in changed_id: s = '' for i in range(len(all_inputs)): x = all_inputs[i]['value'] if x in selected_inputs: s += x*(abs(int(forward_depth)-int(backward_depth))) else: s += x*(int(forward_depth)+int(backward_depth)) return s else: raise PreventUpdate if __name__ == '__main__': app.run_server(debug=True)