diff --git a/.citation_parser_ui.py.swp b/.citation_parser_ui.py.swp
deleted file mode 100644
index 38c0d61d4724d853b03e358ed4916b537560e72f..0000000000000000000000000000000000000000
Binary files a/.citation_parser_ui.py.swp and /dev/null differ
diff --git a/assets/json_text.json b/assets/json_text.json
index b2e4c5f1d417d21f23729da7e833989a82a9eeaf..b8177a35f64f22f16224949cf9e8c88ae7fdbe6b 100644
--- a/assets/json_text.json
+++ b/assets/json_text.json
@@ -1 +1 @@
-{"nodes": [{"doi": "https://doi.org/10.1021/acs.jcim.6b00709", "name": "Matched Molecular Series: Measuring SAR Similarity", "author": ["Emanuel S. R. Ehmki", "Christian Kramer"], "year": "May 1, 2017", "journal": "Journal of Chemical Information and Modeling", "group": "Input", "depth": 0, "citations": 5}, {"doi": "https://doi.org/10.1021/acs.jcim.0c00269", "name": "Matched Molecular Series Analysis for ADME Property Prediction", "author": ["Mahendra Awale", "Sereina Riniker", "Christian Kramer"], "year": "May 5, 2020", "journal": "Journal of Chemical Information and Modeling", "group": "Citedby", "depth": 1, "citations": 6}, {"doi": "https://doi.org/10.1021/acs.jcim.0c00290", "name": "Identification of Bioisosteric Substituents by a Deep Neural Network", "author": ["Peter Ertl"], "year": "June 15, 2020", "journal": "Journal of Chemical Information and Modeling", "group": "Citedby", "depth": 2, "citations": 2}], "links": [{"source": "https://doi.org/10.1021/acs.jcim.0c00269", "target": "https://doi.org/10.1021/acs.jcim.6b00709"}, {"source": "https://doi.org/10.1021/acs.jcim.0c00290", "target": "https://doi.org/10.1021/acs.jcim.0c00269"}]}
\ No newline at end of file
+{"nodes": [], "links": []}
\ No newline at end of file
diff --git a/citation_parser_ui.py b/citation_parser_ui.py
index 2dbd0be7bee696f3a62a68f38ff3a50f6fc5e80c..c2b119dce5075fb6f1e11226dbf866abccd1d4fe 100644
--- a/citation_parser_ui.py
+++ b/citation_parser_ui.py
@@ -42,31 +42,31 @@ app.layout = html.Div([
             is_open=False,
         ),
 
-    # Layer 1: For all mandatory Inputs
+    # Layer 1: For the string input
     html.Div([
         "Input: ",
         # A simple box for inputting a string. 
         # Value is transmitted upon pressing return or clicking out of the box.
-        dcc.Input(id='input-string', value='', type='text',debounce=True,
+        dcc.Input(id='string-input', value='', type='text',debounce=True,
         style={ "width": "400px"},
         ),
         
     ]),
-        # Layer 1,5: For test
+        # Layer 2: For file input and recursion depths
     html.Div([
-        "Forward recursion: ",
+        "Cited-by Depth: ",
         # Forward recursion. Values between 1 and 10 can be entered.
-        dcc.Input(id='forward-depth',value='1',type='number',min='1',max='10',
+        dcc.Input(id='forward-depth',value='1',type='number',min='0',max='5',
         style={ "width": "50px"},
         ),
-        "Backward recursion: ",
+        "References Depth: ",
         # Backward recursion. Values between 1 and 10 can be entered.
-        dcc.Input(id='backward-depth',value='1',type='number',min='1',max='10',
+        dcc.Input(id='backward-depth',value='1',type='number',min='0',max='5',
         style={"width": "50px"},
         ),
         # Upload box. Can be used via drag-and-drop or byclicking on it to open a file viewer.
         dcc.Upload(
-            id="upload-data",
+            id="file-input",
             children=html.Div(
             #Drag and drop or click to select a file to upload
                 ["Drag and drop"]),
@@ -82,7 +82,7 @@ app.layout = html.Div([
             })
     ]),
    
-    # Layer 2: For the checklist, Remove-/Start-Buttons and input-error-message
+    # Layer 3: For the checklist, Remove-/Start-Buttons and error message
     html.Div([
         # All input DOIs are collected in this checklist. 
         # It is initialized to avoid error messages.
@@ -97,7 +97,7 @@ app.layout = html.Div([
         # Starts the process that generates a graph.
         dbc.Button(id='start-button',children='Generate Graph', color="primary", className="me-1")
     ]),
-    # Layer 3: For additional Options (e.g. Topological Sort)
+    # Layer 4: For additional Options
     html.Div([
         html.H4('Additional Options'),
         # A checklist of all additional options that are listed above.
@@ -105,25 +105,25 @@ app.layout = html.Div([
             options=[{'label':k,'value':k} for k in additional_options],
             value=[])
         ]),
-    # Layer 4: For the Graph
-    html.Div(
-        [html.Iframe(
+    # Layer 5: For the Graph and corresponding error messages
+    html.Div([
+        html.Div(id='generate-graph-error',style={'color':'red'}),
+        html.Iframe(
             src="assets/index.html",
             style={"height": "600px", "width": "100%"},
         ),
-        html.Div(id='test-output')
     ])
 ])
 
 @app.callback(
     Output('input-checklist','options'),
     Output('input-checklist','value'),
-    Output('input-string','value'),
+    Output('string-input','value'),
     Output('input-err','children'),
-    Input('input-string','value'),
+    Input('string-input','value'),
     Input('clear-all-button','n_clicks'),
     Input('clear-selected-button','n_clicks'),
-    Input('upload-data','contents'),
+    Input('file-input','contents'),
     State('input-checklist','options'),
     State('input-checklist','value'),
     State('additional-options','value')
@@ -133,7 +133,7 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,
     '''
     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.
+    string-input 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.
@@ -168,7 +168,7 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,
         return all_inputs,list(),'',''
     
     # when a new element is added via dcc.Input
-    if 'input-string' in changed_id:
+    if 'string-input' in changed_id:
         # 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:
@@ -186,7 +186,10 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,
                 # Creates a more readable string to display in the checklist
                 rep_str = pub.contributors[0] + ',' + pub.journal + \
                         ',' + pub.publication_date
-                all_inputs.append({'label':rep_str, 'value':input_value})
+                # Makes sure not to add the same article with different links
+                currLabels = [x['label'] for x in all_inputs]
+                if rep_str not in currLabels:
+                    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.
@@ -195,7 +198,7 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,
         return all_inputs,selected_inputs,'',''
     
     # when a txt-file is uploaded
-    if 'upload-data.contents' in changed_id:
+    if 'file-input.contents' in changed_id:
         if filecontents:
             # Skips the info portion that is added when a file is uploaded
             found = base64.b64decode(re.search(',(.+?)$', filecontents).group(1))
@@ -215,7 +218,9 @@ def update_input_checklist(input_value,btn1,btn2,filecontents,all_inputs,
                             return all_inputs,selected_inputs,'','{}'.format(err)
                         rep_str = pub.contributors[0] + ',' + pub.journal + \
                                 ',' + pub.publication_date
-                        all_inputs.append({'label':rep_str, 'value':input_value})
+                        currLabels = [x['label'] for x in all_inputs]
+                        if rep_str not in currLabels:
+                            all_inputs.append({'label':rep_str, 'value':input_value})
                     else:
                         all_inputs.append({'label':input_value,'value':input_value})
         return all_inputs,selected_inputs,'',''
@@ -244,16 +249,14 @@ def toggle_collapse(n, is_open):
 
 
 @app.callback(
-    Output('test-output','children'),
+    Output('generate-graph-error','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):
+def generate_output(n_clicks,all_inputs,forward_depth,backward_depth,additional_options):
     '''
     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.
@@ -263,8 +266,6 @@ def generate_output(n_clicks,all_inputs,selected_inputs,
     :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
@@ -278,7 +279,15 @@ def generate_output(n_clicks,all_inputs,selected_inputs,
     elif 'Update Automatically' in additional_options \
             or 'start-button' in changed_id: 
         input_links = [x['value'] for x in all_inputs]
-        Processing(input_links,int(forward_depth),int(backward_depth),'assets/json_text.json')
+        errors = Processing(input_links,int(forward_depth),int(backward_depth),'assets/json_text.json')
+        if errors:
+            message = ['The following inputs are invalid and were not used:']
+            for error in errors:
+                message.append(html.Br())
+                message.append(error)
+            message = html.P(message)
+            #message = [html.P(error) for error in errors]
+            return message
 
 if __name__ == '__main__':
     app.run_server(debug=False)
diff --git a/input/get/__pycache__/__init__.cpython-38.pyc b/input/get/__pycache__/__init__.cpython-38.pyc
index f12fb9c33e874aa1c55d94725f867ac6503d407e..52f5d64aa3f72e25accf523fb850635617afbf5e 100644
Binary files a/input/get/__pycache__/__init__.cpython-38.pyc and b/input/get/__pycache__/__init__.cpython-38.pyc differ
diff --git a/input/get/__pycache__/acs.cpython-38.pyc b/input/get/__pycache__/acs.cpython-38.pyc
index 121d1856184f02775d5bb84d081dcd91a648ea67..78c1fb0c8b885e90285224e745b09af56faf9b01 100644
Binary files a/input/get/__pycache__/acs.cpython-38.pyc and b/input/get/__pycache__/acs.cpython-38.pyc differ
diff --git a/input/get/__pycache__/journal_fetcher.cpython-38.pyc b/input/get/__pycache__/journal_fetcher.cpython-38.pyc
index 72a774c45762b3d4cb37a7089f4d8275dab0e533..af9bd12b47a0bae4c1683adf78d92884b7e51193 100644
Binary files a/input/get/__pycache__/journal_fetcher.cpython-38.pyc and b/input/get/__pycache__/journal_fetcher.cpython-38.pyc differ
diff --git a/input/get/__pycache__/nature.cpython-38.pyc b/input/get/__pycache__/nature.cpython-38.pyc
index 3afb8454a05c8afe9b1f2aba3f534d66cbd8ae3a..ca8c9862b7234c55e49b676136ab64a62f91e58b 100644
Binary files a/input/get/__pycache__/nature.cpython-38.pyc and b/input/get/__pycache__/nature.cpython-38.pyc differ