Skip to content
Snippets Groups Projects
Commit 3e34b1c8 authored by David, Sebastian's avatar David, Sebastian
Browse files

Changed some variable names, removed some redundancies and expanded code documentation

parent e8cdb320
Branches
No related tags found
1 merge request!8UI Hinzufügen
......@@ -11,8 +11,14 @@ import input.publication
app = dash.Dash(__name__)
# List of options when inputting data and generating the graph
additional_options = ['Update Automatically','Smart Input']
# Reads the contents of info_box.txt. They can later be displayed by pressing the corresponding button.
f = open('info_box.txt', 'r')
boxcontent = f.read()
f.close()
app.layout = html.Div([
# Layer 0: For the Header and Help Function(s)
html.Div([
......@@ -22,15 +28,17 @@ app.layout = html.Div([
# Layer 1: For all mandatory Inputs
html.Div([
"Input: ",
# A simple box for inputting a string. Value is transmitted upon pressen return or clicking out of the box.
dcc.Input(id='input-string', value='', type='text',debounce=True),
# Forward recursion. Values between 1 and 10 can be entered.
dcc.Input(id='forward-depth',value='1',type='number',min='1',max='10'),
# Backward recursion. Values between 1 and 10 can be entered.
dcc.Input(id='backward-depth',value='1',type='number',min='1',max='10'),
# Upload box. Can be used via drag-and-drop or byclicking on it to open a file viewer.
dcc.Upload(
id="upload-data",
children=html.Div(
["Drag and drop or click to select a file to upload."]
),
["Drag and drop or click to select a file to upload."]),
style={
"width": "30%",
"height": "60px",
......@@ -44,15 +52,21 @@ app.layout = html.Div([
]),
# Layer 2: For the checklist, Remove-/Start-Buttons and input-error-message
html.Div([
# All input DOIs are collected in this checklist. It is initialized to avoid error messages.
dcc.Checklist(id='input-checklist',options=[],labelStyle = dict(display='block'),value=[]),
# Displays error message if 'Smart Input' is active.
html.Div(id='input-err',style={'color':'red'}),
# Clears the entire list.
html.Button(id='clear-all-button',children='Clear All'),
# Clear all selected elements.
html.Button(id='clear-selected-button',children='Clear Selected'),
# Starts the process that generates a graph.
html.Button(id='start-button',children='Generate Graph')
]),
# Layer 3: For additional Options (e.g. Topological Sort)
html.Div([
html.H4('Additional Options'),
# A checklist of all additional options that are listed above.
dcc.Checklist(id='additional-options',
options=[{'label':k,'value':k} for k in additional_options],
value=[])
......@@ -63,10 +77,6 @@ app.layout = html.Div([
])
])
'''
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'),
......@@ -82,49 +92,78 @@ input-string is required as Output to clear the input box after each input
)
def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,selected_inputs,additional_options):
'''
: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
Most important callback function. Updates the checklist that holds all inputs.
State of the checklist as input is needed so that previews entries are readded.
input-string is required as Output to clear the input box after each input.
Different actions are performed depending on which input triggered the callback.
The value-attribute of input-checklist must be updates so that the values
of deleted elements no longer appear in the list of selected elements.
:param input_value: given by dcc.Input
:type input_value: string
:param btn1: signals pressing of clear-all-button
:type btn1: int
:param btn2: signals pressing of clear-selected-button
:type btn2: int
:param filecontents: the contents of an uploaded file
:type filecontents: bit-string
: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 addtitional_options: all checked additional options
:type additional_options: list of strings
'''
# changed_id is used to determine which Input has triggered the callback
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 a new element is added via dcc.Input
if 'input-string' in changed_id:
options = all_inputs
currValues = [x['value'] for x in options]
# Creates a list of previously added inputs to make sure nothing is added twice
currValues = [x['value'] for x in all_inputs]
if input_value not in currValues:
# if 'Smart Input' is selected, the input will be checked for validity
# and a more readable string will be returned
if 'Smart Input' in additional_options:
try:
# Attempts to call get_publication. If unsuccesful,
# the DOI is not added and an error message is returned
i = InputInterface()
pub = i.get_publication(input_value)
except Exception as err:
return options,selected_inputs,'','{}'.format(err)
# Creates a more readable string to display in the checklist
rep_str = pub.contributors[0] + ',' + pub.journal + ',' + pub.publication_date
options.append({'label':rep_str, 'value':input_value})
all_inputs.append({'label':rep_str, 'value':input_value})
# if 'Smart Input' is not selected, the input value is added as is,
# without checking for validity.
else:
options.append({'label':input_value,'value':input_value})
return options,selected_inputs,'',''
all_inputs.append({'label':input_value,'value':input_value})
return all_inputs,selected_inputs,'',''
# when a txt-file is uploaded
if 'upload-data.contents' in changed_id:
if filecontents:
string = filecontents
found = base64.b64decode(re.search(',(.+?)$', string).group(1))
filecontents = found.decode('utf-8')
list_of_inputs = (filecontents.strip().split('\n'))
options = all_inputs
CurrValues = [x['value'] for x in options]
# Skips the info portion that is added when a file is uploaded
found = base64.b64decode(re.search(',(.+?)$', filecontents).group(1))
# Returns the binary string into a proper text
text = found.decode('utf-8')
# Creates a list of inputs by splitting the lines
list_of_inputs = (text.strip().split('\n'))
CurrValues = [x['value'] for x in all_inputs]
# For every line the same actions as for a single input are performed
for input_value in list_of_inputs:
if input_value not in CurrValues:
if 'Smart Input' in additional_options:
......@@ -132,36 +171,35 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,selecte
i = InputInterface()
pub = i.get_publication(input_value)
except Exception as err:
return options,selected_inputs,'','{}'.format(err)
return all_inputs,selected_inputs,'','{}'.format(err)
rep_str = pub.contributors[0] + ',' + pub.journal + ',' + pub.publication_date
options.append({'label':rep_str, 'value':input_value})
all_inputs.append({'label':rep_str, 'value':input_value})
else:
options.append({'label':input_value,'value':input_value})
return options,selected_inputs,'',''
all_inputs.append({'label':input_value,'value':input_value})
return all_inputs,selected_inputs,'',''
# when the programm is first started:
# if this is not done, the input_checklist will be generated
# with one element that contains an empty string
if input_value == '':
app.layout['input-checklist'].options.clear()
return list(),list(),'',''
'''
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):
'''
This callback shows and hides the (first) info-box by, checking how often
the button has been pressed. The text was loaded at the top.
:param n_clicks: number of times show-info has been clicked.
'type n_clicks: int
'''
if n_clicks % 2 == 0:
return ''
else:
f = open('Info Box.txt', 'r')
boxcontent = f.read()
return html.Div(boxcontent, style={'whiteSpace': 'pre-line'})
f.close()
'''
Basic structure for a callback that generates an output
'''
@app.callback(
Output('test-output','children'),
Input('start-button','n_clicks'),
......@@ -174,19 +212,22 @@ Basic structure for a callback that generates an output
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
Basic structure for a callback that generates an output. This is only a
proof of concept and has noting to do with the intended output yet.
: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:
......
......@@ -14,7 +14,7 @@ Clear Selected: clearing all selected inputs
Generate Graph: generates the graph
Update Automatically: updates Automatically the graph for every new input
Update Automatically: automatically updates the graph for every new input
Smart Input: checks the correctness of the entered DOI and shows a nicer depiction: Author, Journal, publication date.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment