Skip to content
Snippets Groups Projects
input_to_checklist.py 5.93 KiB
Newer Older
David, Sebastian's avatar
David, Sebastian committed
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)