From e0cfa80efd00489fb8db8d19fed448881bab31c0 Mon Sep 17 00:00:00 2001
From: unknown <asoalexandros@gmail.com>
Date: Fri, 13 Jun 2025 16:42:40 +0200
Subject: [PATCH] Redefinement part 3 Plotting needs to become more efficient

---
 .../double_gate_ADU.py                        | 106 ++-------
 .../lib/help.py                               | 165 +++++---------
 .../lib/interface.py                          | 130 ++++++++++-
 .../lib/measurements.py                       | 208 +++++++++---------
 .../lib/transfer.py                           | 126 +++++++++++
 .../test_interface.ipynb                      |  96 +-------
 6 files changed, 437 insertions(+), 394 deletions(-)
 create mode 100644 hp4155/ADU for double gate devices_version_3/lib/transfer.py

diff --git a/hp4155/ADU for double gate devices_version_3/double_gate_ADU.py b/hp4155/ADU for double gate devices_version_3/double_gate_ADU.py
index 21987eb..3097116 100644
--- a/hp4155/ADU for double gate devices_version_3/double_gate_ADU.py	
+++ b/hp4155/ADU for double gate devices_version_3/double_gate_ADU.py	
@@ -8,111 +8,39 @@ from help import *
 from measurements import *
 import configparser
 
-style = {'description_width': 'initial'}
-sample = sample()
 
-transfer_check = measurement_check("Transfer")
-output_check = measurement_check("Output")
-gatediode_check = measurement_check("Gatediode")
-
-checkboxes = widgets.HBox([transfer_check,output_check,gatediode_check])
-display(checkboxes)
-
-#transfer
-
-integration_transfer = integration_time("MEDium")
-transfer_gates = gate_selection("VTG","VBG","BOTH SIMULTANEOUSLY","BOTH SEQUENTIALLY")
-
-Vds_transfer = secondary('VDS',0.05,0.95,1,1e-2)
-Vtg_transfer = primary('VTG',-5,0.01,5,1e-3)
-Vbg_transfer = primary('VBG',-15,0.1,15,1e-3)
-plot_transfer = plot_config(1)
-transfer_box = widgets.VBox([integration_transfer,transfer_gates,Vds_transfer.grid,Vtg_transfer.grid,Vbg_transfer.grid,plot_transfer.grid])
-
-
-#output
-integration_output = integration_time("SHORt")
-output_gates = gate_selection("VTG","VBG","BOTH")
-
-Vds_output = primary('VDS',0,0.01,5,1e-2)
-Vtg_output = secondary('VTG',-5,2,5,1e-3)
-Vbg_output = secondary('VBG',-15,5,15,1e-3)
-plot_output = plot_config(2)
-
-output_box = widgets.VBox([integration_output,output_gates,Vds_output.grid,Vtg_output.grid,Vbg_output.grid,plot_output.grid])
-
-integration_gatediode = integration_time("MEDium")
-gatediode_gates = gate_selection("VTG","VBG")
-
-Vg_gatediode=primary('VG',-5,0.05,5,1e-3)
-plot_gatediode = plot_config(3)
-gatediode_box = widgets.VBox([integration_gatediode,gatediode_gates,Vg_gatediode.grid,plot_gatediode.grid])
-
-#the tab widget
-children = [transfer_box,output_box,gatediode_box]
-titles = ["Transfer","Output","Gatediode"]
-tab = widgets.Tab()
-tab.children = children
-tab.titles = titles
-
-display(tab)
-
-button = widgets.Button(description ='Start Measurement')
-output = widgets.Output()
-
-export_ini_button = widgets.Button(description = 'Export as ini')
-import_ini_button = widgets.Button(description='Import from ini')
-
-all_widgets =[transfer_gates,output_gates,button,transfer_check,integration_transfer,output_check,integration_output,gatediode_check,integration_gatediode,gatediode_gates,export_ini_button,import_ini_button]
-add_widgets_to_list(sample,all_widgets)
-add_widgets_to_list(Vds_transfer,all_widgets)
-add_widgets_to_list(Vtg_transfer,all_widgets)
-add_widgets_to_list(Vbg_transfer,all_widgets)
-add_widgets_to_list(Vds_output,all_widgets)
-add_widgets_to_list(Vtg_output,all_widgets)
-add_widgets_to_list(Vbg_output,all_widgets)
-add_widgets_to_list(Vg_gatediode,all_widgets)
-add_widgets_to_list(plot_transfer,all_widgets)
-add_widgets_to_list(plot_output,all_widgets)
-add_widgets_to_list(plot_gatediode,all_widgets)
-
-
-line = widgets.HBox([button,import_ini_button,export_ini_button])
-display(line,output)
+#setup user interface
+ui = interface()
 device = hp4155a.HP4155a('GPIB0::17::INSTR')
 
 def on_start_clicked(b):
-    with output:
+    with ui.output:
         clear_output()
         #disable all widgets
-        disable_widgets(all_widgets)
+        change_state(all_widgets)
 
         #additional code to check smu configuration fast without modifing a lot of code
         try:
-            check_configuration(smu_map)
+            check_configuration(ui.sample)
         except Exception as e:
             error_box(e)
-            enable_widgets(all_widgets)
+            change_state(ui.all_widgets)
             return
 
-        Setup(device) #setup the device
+        #setup the devicr
+        device.reset()
 
-        #for all measurements the same (copy the interface with values for parameter setting)
-        map = smu_map.copy()
-        for key,value in map.items():
-            map[key]= value.value
+        #setup sweep measurement mode
+        device.measurement_mode('SWE')
+    
+        #disable all irrelevant units
+        device.disable_not_smu()
 
-        sample_copy = sample.copy()
-        for key,value in sample_copy.items():
-            sample_copy[key]=value.value
 
-        smu_s = device.smu_dict()
-        smu_s.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS') #Source smu is always grounded
         
-        if transfer_check.value == True:
-            plot = plot_transfer.copy()
-            for key,value in plot.items():
-                plot[key] = value.value
+        if ui.transfer_check.value == True:
+            if ui.transfer_gates.value == 'VTG':
+                
 
             points = number_of_points(Vds_transfer)
 
@@ -128,7 +56,7 @@ def on_start_clicked(b):
 
             # also drain smu is the same
             smu_d = device.smu_dict()
-            smu_d.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2')
+            smu_d.update()
             match transfer_gates.value:
                 case 'VTG' if check_values(Vtg_transfer,'primary') and check_values(Vds_transfer,'secondary'):
                     smu_t = device.smu_dict()
diff --git a/hp4155/ADU for double gate devices_version_3/lib/help.py b/hp4155/ADU for double gate devices_version_3/lib/help.py
index 8242fd1..91bf965 100644
--- a/hp4155/ADU for double gate devices_version_3/lib/help.py	
+++ b/hp4155/ADU for double gate devices_version_3/lib/help.py	
@@ -23,10 +23,11 @@ def get_dataframe_from_results(dictionary):
    
     df = pd.DataFrame(dictionary)
     return df
-def number_of_points(dict):
+
+def number_of_points(obj): # obj is interface object
     try:
-        diff = dict['stop'].value - dict['start'].value
-        ratio = abs(diff/dict['step'].value)
+        diff = obj.stop.value - obj.start.value
+        ratio = abs(diff/obj.step.value)
         points = int(ratio+1)
     
     except ZeroDivisionError:
@@ -38,68 +39,6 @@ def number_of_points(dict):
         points = 128
     return points
 
-def check_values(dictionary,function):
-    valid = True
-
-    root = tk.Tk()
-    root.withdraw()
-    root.lift() #show window above all other applications
-
-    root.attributes("-topmost", True)#window stays above all other applications
-
-    if function =='primary':
-        if abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting 
-            valid = False
-            tkinter.messagebox.showerror(message="Invalid parameter setting!")
-
-        if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity
-            dictionary['step'].value =(-1)*dictionary['step'].value
-
-        elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0:
-            dictionary['step'].value = (-1)*dictionary['step'].value
-
-        else:
-            pass
-    
-    if function == 'secondary':
-        if dictionary['start'].value == dictionary['stop'].value:
-            pass
-        elif abs(dictionary['step'].value) > abs(dictionary['stop'].value-dictionary['start'].value) or dictionary['step'].value==0:#invalid parameter setting 
-            valid = False
-            tkinter.messagebox.showerror(message="Invalid parameter setting!")
-        if dictionary['start'].value<dictionary['step'].value and dictionary['step'].value<0: #change polarity
-            dictionary['step'].value =(-1)*dictionary['step'].value
-
-        elif dictionary['start'].value>dictionary['stop'].value and dictionary['step'].value>0:
-            dictionary['step'].value = (-1)*dictionary['step'].value
-
-    if function == 'synchronous':
-        pass
-    
-    if valid == True:
-        #check compliance
-        comp = dictionary['comp'].value
-        start = dictionary['start'].value
-        stop = dictionary['stop'].value
-
-        if abs(comp)*max(abs(start),abs(stop))>2:
-            dictionary["comp"].value=np.sign(comp)*2/max(abs(start),abs(stop))
-        
-    root.destroy()
-    return valid 
-
-# No more dictionaries 
-def add_widgets_to_list(source_class,target_list):
-    for widget in (vars(source_class)).values():
-        target_list.append(widget)
-
-def change_state(widgets_list):
-    for widget in widgets_list:
-        try: 
-            widget.disabled = not widget.disabled
-        except:
-            pass # Perhaps other objects are there too
-
 
 def information_box(information):
     #open dialog and hide the main window
@@ -171,20 +110,18 @@ def load_ini():
     return file
 
 # function to return ratio and offset for synchronous sweep measurement
-def calculate_line(VTG,VBG):
-    ratio = (VBG['stop'].value-VBG['start'].value)/(VTG['stop'].value-VTG['start'].value)
-    offset = VBG['start'].value-ratio*VTG['start'].value    
+def calculate_line(VTG,VBG): # from now interface objects
+    ratio = (VBG.stop.value-VBG.start.value)/(VTG.stop.value-VTG.start.value)
+    offset = VBG.start.value-ratio*VTG.start.value    
     return ratio,offset
 
 
 
 #check if smu configuration has a double value
-def check_configuration(smu_map:dict):
+def check_configuration(sample): # the sample object from the interface
     #convert the dictionaries values to a list
     
-    map_list = []
-    for element in smu_map.values():
-        map_list.append(element.value)
+    map_list = [sample.source.value,sample.top_gate.value,sample.back_gate.value,sample.drain.value]
 
     #remove the duplicates by using a set
     map_set = set(map_list)
@@ -195,17 +132,14 @@ def check_configuration(smu_map:dict):
 
 
 # The function for graph in the tool
-def graph_tool(params,device):
+def graph_tool(plot_config,width,device): # the plot config object from the interface
     device.delete_axis("X")
     device.delete_axis("Y1")
     device.delete_axis("Y2")
-    device.del_user_functions()
-
-    device.clear_error_stack()
 
     # How to define user functions correctly and not multiple times
-    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
-    plot_set= set(plot_list)
+    plot_list = [plot_config.x.value,plot_config.y1.value,plot_config.y2.value]
+    plot_set = set(plot_list)
 
     
     #define the no values
@@ -213,7 +147,7 @@ def graph_tool(params,device):
         if element != "None":
             if element.endswith("mm"): #only I values
                 #define the respective user function
-                device.user_function(element,"mA/mm",f"{element[:-2]}*{normalization_factor(params['SAMPLE']['width'])}") #max 3
+                device.user_function(element,"mA/mm",f"{element[:-2]}*{normalization_factor(width)") #max 3
     
             #define the absolute(A to indicate absolute) always 3 (max 6!)
             if element.startswith('I') and element.endswith('mm'):
@@ -223,49 +157,38 @@ def graph_tool(params,device):
              
 
     # Now send the parameters in the tool
-    device.display_variable('X',params["PLOT"]["x"])
-    device.error_occured()
+    device.display_variable('X',plot_config.x.value)
     device.axis_scale('X','LIN')
-    device.error_occured()
-    device.display_variable_min_max('X','MIN',params["PLOT"]["x_min"])
-    device.error_occured()
-    device.display_variable_min_max('X','MAX',params["PLOT"]["x_max"])
-    device.error_occured()
+    device.display_variable_min_max('X','MIN',plot_config.x_min.value)
+    device.display_variable_min_max('X','MAX',plot_config.x_max.value)
 
 
-    if params["PLOT"]["y1_scale"]=='LOG':
-        device.display_variable('Y1',"A"+params["PLOT"]["y1"])
+    if plot_config.y1_scale.value=='LOG':
+        device.display_variable('Y1',"A"+plot_config.y1.value)
     else:
-        device.display_variable('Y1',params["PLOT"]["y1"])
-    device.error_occured()
-    device.axis_scale('Y1',params["PLOT"]["y1_scale"])
-    device.error_occured()
-    device.display_variable_min_max('Y1','MIN',params["PLOT"]["y1_min"])
-    device.error_occured()
-    device.display_variable_min_max('Y1','MAX',params["PLOT"]["y1_max"])
-    device.error_occured()
-
-    if params["PLOT"]["y2"]!= "None":
+        device.display_variable('Y1',plot_config.y1.value)
+    device.axis_scale('Y1',plot_config.y1.value)
+    device.display_variable_min_max('Y1','MIN',plot_config.y1_min.value)
+    device.display_variable_min_max('Y1','MAX',plot_config.y1_max.value)
+
+    if plot_config.y2.value!= "None":
         if params["PLOT"]["y2_scale"]=='LOG':
-            device.display_variable('Y2',"A"+params["PLOT"]["y2"])
+            device.display_variable('Y2',"A"+plot_config.y2.value)
         else:
-            device.display_variable('Y2',params["PLOT"]["y2"])
-        device.error_occured()
-        device.axis_scale('Y2',params["PLOT"]["y2_scale"])
-        device.error_occured()
-        device.display_variable_min_max('Y2','MIN',params["PLOT"]["y2_min"])
-        device.display_variable_min_max('Y2','MAX',params["PLOT"]["y2_max"])
-        device.error_occured()
+            device.display_variable('Y2',plot_config.y2.value)
+        device.axis_scale('Y2',plot_config.y2_scale.value)
+        device.display_variable_min_max('Y2','MIN',plot_config.y2_min.value)
+        device.display_variable_min_max('Y2','MAX',plot_config.y2_max.value)
 
 
 
 #plot software functions
-def values_to_plot(params,device):
+def values_to_plot(plot_config,device):
     #plotted variables as they are named in the tool
     #return the plotted data for easier configuration
     plotted_variables = {'X':device.get_axis_variable('X'),'Y1': device.get_axis_variable('Y1')}
 
-    if params["PLOT"]["y2"]!= "None":
+    if plot_config.y2.value!= "None":
         plotted_variables['Y2']= device.get_axis_variable('Y2')
 
     plot_values ={}
@@ -290,11 +213,27 @@ def set_axes_labels(plot_list):
     
     return axes_labels
 
-    
-    
+def create_file(filename):
+    root = tk.Tk()
+    root.withdraw()
+    root.lift() #show window above all other applications
 
-    
+    root.attributes("-topmost", True)#window stays above all other applications
 
-    
+    file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =filename)
+
+    #check if the file path is correct(.txt)
+    while file.endswith(".txt") == False:
+        #open again filedialog with error message box
+        tk.messagebox.showerror(message='invalid filename!')
+        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
+
+    root.destroy()
 
-   
\ No newline at end of file
+def write_sample_information(sample,file):
+    file.write(f"Series:{sample.processing_number.value}"+"\n")
+    file.write(f"Sample:{sample.sample.value}"+"\n")
+    file.write(f"Field:{sample.field.value}"+"\n")
+    file.write(f"Device:{sample.device.value}"+"\n")
+    file.write(f"Device Width/um:{sample.width.value}"+"\n")
+    
\ No newline at end of file
diff --git a/hp4155/ADU for double gate devices_version_3/lib/interface.py b/hp4155/ADU for double gate devices_version_3/lib/interface.py
index 00641ab..6fa954f 100644
--- a/hp4155/ADU for double gate devices_version_3/lib/interface.py	
+++ b/hp4155/ADU for double gate devices_version_3/lib/interface.py	
@@ -9,6 +9,20 @@ height = 'auto'
 style = {'description_width': 'initial'}
 floatbox_width = "80%"
 
+
+# functionallities for the widgets
+# No more dictionaries 
+def add_widgets_to_list(source_class,target_list):
+    for widget in (vars(source_class)).values():
+        target_list.append(widget)
+
+def change_state(widgets_list):
+    for widget in widgets_list:
+        try: 
+            widget.disabled = not widget.disabled
+        except:
+            pass # Perhaps other objects are there too
+
 # here are the custom widgets
 def measurement_check(name):
     check=widgets.Checkbox(
@@ -257,8 +271,118 @@ class plot_config: #meas = 1,2,3 for transfer,output,gatediode
         self.x_max = self.grid[5,1]
         self.y1_max = self.grid[5,2]
         self.y2_max = self.grid[5,3]
-    
-    
-    
+
+
+# The whole interface
+class interface:
+    def __init__(self):
+        self.sample = sample()
+        
+        self.transfer_check = measurement_check("Transfer")
+        self.output_check = measurement_check("Output")
+        self.gatediode_check = measurement_check("Gatediode")
+        
+        checkboxes = widgets.HBox([self.transfer_check,self.output_check,self.gatediode_check])
+        display(checkboxes)
+        
+        #transfer
+        
+        self.integration_transfer = integration_time("MEDium")
+        self.transfer_gates = gate_selection("VTG","VBG","BOTH SIMULTANEOUSLY","BOTH SEQUENTIALLY")
+        
+        self.Vds_transfer = secondary('VDS',0.05,0.95,1,1e-2)
+        self.Vtg_transfer = primary('VTG',-5,0.01,5,1e-3)
+        self.Vbg_transfer = primary('VBG',-15,0.1,15,1e-3)
+        self.plot_transfer = plot_config(1)
+        transfer_box = widgets.VBox(
+            [
+                self.integration_transfer,
+                self.transfer_gates,
+                self.Vds_transfer.grid,
+                self.Vtg_transfer.grid,
+                self.Vbg_transfer.grid,
+                self.plot_transfer.grid
+            ]
+        )
+        
+        
+        #output
+        self.integration_output = integration_time("SHORt")
+        self.output_gates = gate_selection("VTG","VBG","BOTH")
+        
+        self.Vds_output = primary('VDS',0,0.01,5,1e-2)
+        self.Vtg_output = secondary('VTG',-5,2,5,1e-3)
+        self.Vbg_output = secondary('VBG',-15,5,15,1e-3)
+        self.plot_output = plot_config(2)
+        
+        output_box = widgets.VBox(
+            [
+                self.integration_output,self.output_gates,
+                self.Vds_output.grid,
+                self.Vtg_output.grid,
+                self.Vbg_output.grid,
+                self.plot_output.grid
+            ]
+        )
+        
+        self.integration_gatediode = integration_time("MEDium")
+        self.gatediode_gates = gate_selection("VTG","VBG")
+        
+        self.Vg_gatediode=primary('VG',-5,0.05,5,1e-3)
+        self.plot_gatediode = plot_config(3)
+        gatediode_box = widgets.VBox(
+            [
+                self.integration_gatediode,
+                self.gatediode_gates,
+                self.Vg_gatediode.grid,
+                self.plot_gatediode.grid
+            ]
+        )
+        
+        #the tab widget
+        children = [transfer_box,output_box,gatediode_box]
+        titles = ["Transfer","Output","Gatediode"]
+        tab = widgets.Tab()
+        tab.children = children
+        tab.titles = titles
+        
+        display(tab)
+
+        # Now the buttons
+        self.start = widgets.Button(description ='Start Measurement')
+        self.output = widgets.Output()
+
+        self.export_ini = widgets.Button(description = 'Export as ini')
+        self.import_ini = widgets.Button(description ='Import from ini')
+
+        # capture all widgets
+        self.all_widgets=[
+            self.transfer_gates,
+            self.output_gates,
+            self.start,         
+            self.transfer_check,
+            self.integration_transfer,
+            self.output_check,
+            self.integration_output,
+            self.gatediode_check,
+            self.integration_gatediode,
+            self.gatediode_gates,
+            self.export_ini,
+            self.import_ini
+        ]
+        add_widgets_to_list(self.sample,self.all_widgets)
+        add_widgets_to_list(self.Vds_transfer,self.all_widgets)
+        add_widgets_to_list(self.Vtg_transfer,self.all_widgets)
+        add_widgets_to_list(self.Vbg_transfer,self.all_widgets)
+        add_widgets_to_list(self.Vds_output,self.all_widgets)
+        add_widgets_to_list(self.Vtg_output,self.all_widgets)
+        add_widgets_to_list(self.Vbg_output,self.all_widgets)
+        add_widgets_to_list(self.Vg_gatediode,self.all_widgets)
+        add_widgets_to_list(self.plot_transfer,self.all_widgets)
+        add_widgets_to_list(self.plot_output,self.all_widgets)
+        add_widgets_to_list(self.plot_gatediode,self.all_widgets)
+
+        line = widgets.HBox([self.start,self.import_ini,self.export_ini])
+        display(line,self.output)
 
     
\ No newline at end of file
diff --git a/hp4155/ADU for double gate devices_version_3/lib/measurements.py b/hp4155/ADU for double gate devices_version_3/lib/measurements.py
index 74e7d38..71d4914 100644
--- a/hp4155/ADU for double gate devices_version_3/lib/measurements.py	
+++ b/hp4155/ADU for double gate devices_version_3/lib/measurements.py	
@@ -11,47 +11,71 @@ from decimal import Decimal
 
 import os
 
-def Setup(device):
-    device.reset()
-
-    #setup sweep measurement mode
-    device.measurement_mode('SWE')
-
-    #disable all irrelevant units
-    device.disable_not_smu()
-
 # Transfer only VTG 
-def Transfer_VTG(device,params):
-    # calculate normalization factor
-    
-    norm = normalization_factor(params["SAMPLE"]["width"])
-    points = params["VAR2"]["points"]
+def Transfer_VTG(device,ui): # ui interface
+    device.del_user_functions() # delete all user functions 
+    device.clear_error_stack() # clear error stack
+    # setup the smus
+
+    norm = normalization_factor(ui.sample.width.value)
+    points = number_of_points(ui.Vds_transfer)
+
+    smu_source = device.smu_dict()
+    smu_source.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS')
+
+    smu_top_gate = device.smu_dict()
+    smu_top_gate.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1')
+
+    smu_back_gate = device.smu_dict()
+    smu_back_gate.update(vname = 'VBG',iname='IBG',mode = 'COMM',func = 'CONS')
+
+    smu_drain = device.smu_dict()
+    smu_drain = device.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2')
+
+    # setup VAR1
+    var1 = device.var1_dict()
+    var1.update(
+        mode = ui.Vtg_transfer.hyst.value,
+        start = ui.Vtg_transfer.start.value,
+        stop = ui.Vtg_transfer.stop.value,
+        step = ui.Vtg_transfer.step.value,
+        comp = ui.Vtg_transfer.comp.value,
+        pcomp = ui.Vtg_transfer.pcomp.value
+    )
+
+    var2=device.var2_dict() #Vds_output is always used in tranfer curve with the same config
+    var2.update(
+        start=ui.Vds_transfer.start.value,
+        step=ui.Vds_transfer.step.value,
+        points=points,
+        comp=ui.Vds_transfer.comp.value,
+        pcomp=ui.Vds_transfer.pcomp.value,
+    )
+   
     try:
-        device.setup_smu(params["MAP"]['TG'],params["SMU_T"])
-        device.setup_smu(params["MAP"]['D'],params["SMU_D"])
-        device.setup_smu(params["MAP"]['BG'],params["SMU_B"])
-        device.setup_smu(params["MAP"]['S'],params["SMU_S"])
+        device.setup_smu(ui.sample.top_gate.value,smu_top_gate)
+        device.setup_smu(ui.sample.drain.value,smu_drain)
+        device.setup_smu(ui.sample.back_gate.value,smu_back_gate)
+        device.setup_smu(ui.sample.source.value,smu_source)
     
-        device.setup_var1(params["VAR1"])
-        device.setup_var2(params["VAR2"])
+        device.setup_var1(var1)
+        device.setup_var2(var2)
     
-        device.integration_time(params["INTEGRATION"])
+        device.integration_time(ui.integration_transfer.value)
     
         variables_list =["VTG","ITG","VDS","ID"]
         device.variables_to_save(variables_list)
     
-        try:
-            plotted_variables = graph_tool(params,device)
-        except Exception as e:
-            error_box(e)
-            return
-    
+        
+        plotted_variables = graph_tool(ui.plot_transfer,ui.sample.width.value,device)
     
+
         device.single_measurement()
         while device.operation_completed()==False:
             pass
-    
-        device.autoscaling()
+
+        if ui.sample.quick.value == False:
+            device.autoscaling()
         device.error_occured()
     
         values = dict([(variable,device.return_values(variable)) for variable in variables_list])
@@ -65,98 +89,58 @@ def Transfer_VTG(device,params):
     df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
 
     # Save the results
-    default_filename = f"{params['SAMPLE']['sample']}_{params['SAMPLE']['field']}_{params['SAMPLE']['device']}_TOP_GATE_U.txt"
-
-    root = tk.Tk()
-    root.withdraw()
-    root.lift() #show window above all other applications
-
-    root.attributes("-topmost", True)#window stays above all other applications
-
-    file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
-
-    #check if the file path is correct(.txt)
-    while file.endswith(".txt") == False:
-        #open again filedialog with error message box
-        tk.messagebox.showerror(message='invalid filename!')
-        file = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text files","*.txt")],title = "save results path",initialfile =default_filename)
-
-    root.destroy()
+    default_filename = f"{ui.sample.sample.value}_{ui.sample.field.value}_{ui.sample.device.value}_TOP_GATE_U.txt"
+    file = create_file(default_filename)
+    
 
     with open(file,'w') as f:
         date = str(datetime.today().replace(microsecond=0))
         f.write(f"Transfer Curve at {date}"+"\n")
-        f.write(f"Series:{params['SAMPLE']['processing_number']}"+"\n")
-        f.write(f"Sample:{params['SAMPLE']['sample']}"+"\n")
-        f.write(f"Field:{params['SAMPLE']['field']}"+"\n")
-        f.write(f"Device:{params['SAMPLE']['device']}"+"\n")
-        f.write(f"Device Width/um:{params['SAMPLE']['width']}"+"\n")
+        
         f.write("Sweeping Gate:VTG"+"\n\n")
 
         f.write('Parameters\n')
-        f.write(f"VTG from {params['VAR1']['start']}V to {params['VAR1']['stop']}V with step {params['VAR1']['step']}V"+"\n")
-        f.write(f"VDS from {params['VAR2']['start']}V to {params['VAR2']['stop']}V with step {params['VAR2']['step']}V"+"\n")
+        f.write(f"VTG from {ui.Vtg_transfer.start.value}V to {ui.Vtg_transfer.stop.value}V with step {ui.Vtg_transfer.step.value}V"+"\n")
+        f.write(f"VDS from {ui.Vds_transfer.start.value}V to {ui.Vds_transfer.stop.value}V with step {ui.Vds_transfer.step.value}V"+"\n")
         
-        if params['VAR1']['pcomp']==0:
-            f.write(f"Top Gate Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        if ui.Vtg_transfer.pcomp.value==0:
+            f.write(f"Top Gate Current Compliance/A:{ui.Vtg_transfer.comp.value}"+"\n")
         else:
-            f.write(f"Top Gate Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
+            f.write(f"Top Gate Power Compliance/A:{ui.Vtg_transfer.pcomp.value}"+"\n")
 
-        if params['VAR2']['pcomp'] == 0:
-            f.write(f"Drain Current Compliance/A:{params['VAR1']['comp']}"+"\n")
+        if ui.Vds_transfer.pcomp.value == 0:
+            f.write(f"Drain Current Compliance/A:{ui.Vds_transfer.comp.value}"+"\n")
         else:
-             f.write(f"Drain Power Compliance/A:{params['VAR1']['pcomp']}"+"\n")
-        f.write(f"Integration Time:{params['INTEGRATION']}"+"\n")
+             f.write(f"Drain Power Compliance/A:{ui.Vds_transfer.pcomp.value}"+"\n")
+        f.write(f"Integration Time:{ui.integration_transfer.value}"+"\n")
         f.write("\nResults\n")
 
     df.to_csv(file,sep=" ",mode='a')
 
-    plot_values = values_to_plot(params,device)
-
-    # Plot user specified results
-    fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
-
-    plot_list = [params["PLOT"]["x"],params["PLOT"]["y1"],params["PLOT"]["y2"]]
-    scale_list =['LIN',params["PLOT"]["y1_scale"],params["PLOT"]["y2_scale"]]
-    axes_labels = set_axes_labels(plot_list)
-
-    if scale_list[1]=='LOG':
-        ax1.set_yscale('log')
+    if ui.sample.quick.value == False:
+        plot_values = values_to_plot(ui.plot_transfer,device)
+    
+        # Plot user specified results
+        fig,ax1= plt.subplots(figsize=(10,6),layout='constrained')
 
-    #now set the labels
-    ax1.set_xlabel(axes_labels[0])
-    ax1.set_ylabel(axes_labels[1])
 
-    x = np.split(plot_values['X'],points)
-    y1 = np.split(plot_values['Y1'],points)
-    labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels
+        plot_list = [ui.plot_transfer.x.value]
+        scale_list =['LIN',ui.plot_transfer.y1_scale.value,ui.plot_transfer.y2_scale.value]
+        axes_labels = set_axes_labels(plot_list)
     
-    for i in range(points):
-        ax1.plot(x[i],y1[i],label = f"VDS:{round(labels[i],3)} (V)")
+        if scale_list[1]=='LOG':
+            ax1.set_yscale('log')
     
-    # Adding title
-    fig.suptitle('Transfer Curve', fontweight ="bold")
-    fig.legend(loc='outside right upper')
-
-    display(fig)
-    #save plot if checked
-    if params["SAMPLE"]['save_fig'] == True:
-        filename= os.path.splitext(file)[0]
-        fig.savefig(filename+'_Y1.png')
+        #now set the labels
+        ax1.set_xlabel(axes_labels[0])
+        ax1.set_ylabel(axes_labels[1])
     
-    #add the second axis if applicable
-    if plot_list[2]!= "None":
-        fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
-        y2 = np.split(plot_values['Y2'],points)
+        x = np.split(plot_values['X'],points)
+        y1 = np.split(plot_values['Y1'],points)
+        labels =np.mean(np.array_split(df["VDS/V"],points),axis = 1) # VDS values for labels
         
-        if scale_list[2]=='LOG':
-            ax2.set_yscale('log')
-
-        ax2.set_xlabel(axes_labels[0])
-         
-        ax2.set_ylabel(axes_labels[2])
         for i in range(points):
-            ax2.plot(x[i],y2[i],label = f"VDS:{round(labels[i],3)} (V)")
+            ax1.plot(x[i],y1[i],label = f"VDS:{round(labels[i],3)} (V)")
         
         # Adding title
         fig.suptitle('Transfer Curve', fontweight ="bold")
@@ -166,7 +150,31 @@ def Transfer_VTG(device,params):
         #save plot if checked
         if params["SAMPLE"]['save_fig'] == True:
             filename= os.path.splitext(file)[0]
-            fig.savefig(filename+'_Y2.png')
+            fig.savefig(filename+'_Y1.png')
+        
+        #add the second axis if applicable
+        if plot_list[2]!= "None":
+            fig,ax2=plt.subplots(figsize=(10,6),layout='constrained')
+            y2 = np.split(plot_values['Y2'],points)
+            
+            if scale_list[2]=='LOG':
+                ax2.set_yscale('log')
+    
+            ax2.set_xlabel(axes_labels[0])
+             
+            ax2.set_ylabel(axes_labels[2])
+            for i in range(points):
+                ax2.plot(x[i],y2[i],label = f"VDS:{round(labels[i],3)} (V)")
+            
+            # Adding title
+            fig.suptitle('Transfer Curve', fontweight ="bold")
+            fig.legend(loc='outside right upper')
+        
+            display(fig)
+            #save plot if checked
+            if params["SAMPLE"]['save_fig'] == True:
+                filename= os.path.splitext(file)[0]
+                fig.savefig(filename+'_Y2.png')
 
 
 # Transfer only VBG
diff --git a/hp4155/ADU for double gate devices_version_3/lib/transfer.py b/hp4155/ADU for double gate devices_version_3/lib/transfer.py
new file mode 100644
index 0000000..556e690
--- /dev/null
+++ b/hp4155/ADU for double gate devices_version_3/lib/transfer.py	
@@ -0,0 +1,126 @@
+# This file contains the transfer measurements
+
+import sys
+sys.path.insert(0, '..') #append parent directory
+
+import hp4155a
+from help import *
+from decimal import Decimal
+
+import os
+
+def VTG(ui,device):
+    device.del_user_functions() # delete all user functions 
+    device.clear_error_stack() # clear error stack
+    # setup the smus
+
+    norm = normalization_factor(ui.sample.width.value)
+    points = number_of_points(ui.Vds_transfer)
+
+    smu_source = device.smu_dict()
+    smu_source.update(vname ='VS',iname = 'IS',mode = 'COMM',func='CONS')
+
+    smu_top_gate = device.smu_dict()
+    smu_top_gate.update(vname = 'VTG',iname='ITG',mode = 'V',func='VAR1')
+
+    smu_back_gate = device.smu_dict()
+    smu_back_gate.update(vname = 'VBG',iname='IBG',mode = 'COMM',func = 'CONS')
+
+    smu_drain = device.smu_dict()
+    smu_drain = device.update(vname='VDS',iname='ID',mode = 'V',func = 'VAR2')
+
+    # setup VAR1
+    var1 = device.var1_dict()
+    var1.update(
+        mode = ui.Vtg_transfer.hyst.value,
+        start = ui.Vtg_transfer.start.value,
+        stop = ui.Vtg_transfer.stop.value,
+        step = ui.Vtg_transfer.step.value,
+        comp = ui.Vtg_transfer.comp.value,
+        pcomp = ui.Vtg_transfer.pcomp.value
+    )
+
+    var2=device.var2_dict() #Vds_output is always used in tranfer curve with the same config
+    var2.update(
+        start=ui.Vds_transfer.start.value,
+        step=ui.Vds_transfer.step.value,
+        points=points,
+        comp=ui.Vds_transfer.comp.value,
+        pcomp=ui.Vds_transfer.pcomp.value,
+    )
+   
+    try:
+        device.setup_smu(ui.sample.top_gate.value,smu_top_gate)
+        device.setup_smu(ui.sample.drain.value,smu_drain)
+        device.setup_smu(ui.sample.back_gate.value,smu_back_gate)
+        device.setup_smu(ui.sample.source.value,smu_source)
+    
+        device.setup_var1(var1)
+        device.setup_var2(var2)
+    
+        device.integration_time(ui.integration_transfer.value)
+    
+        variables_list =["VTG","ITG","VDS","ID"]
+        device.variables_to_save(variables_list)
+    
+        
+        plotted_variables = graph_tool(ui.plot_transfer,ui.sample.width.value,device)
+    
+
+        device.single_measurement()
+        while device.operation_completed()==False:
+            pass
+
+        device.error_occured()
+
+        if ui.sample.quick.value == False:
+            device.autoscaling()
+       
+    
+        values = dict([(variable,device.return_values(variable)) for variable in variables_list])
+        df = get_dataframe_from_results(values)
+    except Exception as e:
+        error_box(e)
+        return
+
+    # Append the normalized current 
+    df["IDmm/uA/um"]= (df["ID/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+    df["ITGmm/uA/um"]= (df["ITG/A"].apply(lambda x: Decimal(str(x))*Decimal(str(norm)))).astype('float')
+
+    # Save the results
+    default_filename = f"{ui.sample.sample.value}_{ui.sample.field.value}_{ui.sample.device.value}_TOP_GATE_U.txt"
+    file = create_file(default_filename)
+
+    
+    with open(file,'w') as f:
+        date = str(datetime.today().replace(microsecond=0))
+        f.write(f"Transfer Curve at {date}"+"\n")
+        write_sample_information(ui.sample,f)
+        f.write("Sweeping Gate:VTG"+"\n\n")
+        f.write('Parameters\n')
+        f.write(f"VTG from {ui.Vtg_transfer.start.value}V to {ui.Vtg_transfer.stop.value}V with step {ui.Vtg_transfer.step.value}V"+"\n")
+        f.write(f"VDS from {ui.Vds_transfer.start.value}V to {ui.Vds_transfer.stop.value}V with step {ui.Vds_transfer.step.value}V"+"\n")
+        
+        if ui.Vtg_transfer.pcomp.value==0:
+            f.write(f"Top Gate Current Compliance/A:{ui.Vtg_transfer.comp.value}"+"\n")
+        else:
+            f.write(f"Top Gate Power Compliance/A:{ui.Vtg_transfer.pcomp.value}"+"\n")
+
+        if ui.Vds_transfer.pcomp.value == 0:
+            f.write(f"Drain Current Compliance/A:{ui.Vds_transfer.comp.value}"+"\n")
+        else:
+             f.write(f"Drain Power Compliance/A:{ui.Vds_transfer.pcomp.value}"+"\n")
+        f.write(f"Integration Time:{ui.integration_transfer.value}"+"\n")
+        f.write("\nResults\n")
+
+    df.to_csv(file,sep=" ",mode='a')
+
+    # here we stop! We need efficient plotting
+
+        
+        
+
+
+
+    
+
diff --git a/hp4155/ADU for double gate devices_version_3/test_interface.ipynb b/hp4155/ADU for double gate devices_version_3/test_interface.ipynb
index ade47b6..279486a 100644
--- a/hp4155/ADU for double gate devices_version_3/test_interface.ipynb	
+++ b/hp4155/ADU for double gate devices_version_3/test_interface.ipynb	
@@ -9,7 +9,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "b78a708f357341328ff31a4eb7d6aa48",
+       "model_id": "cf15158f4515448c98bcbbf8631ced8d",
        "version_major": 2,
        "version_minor": 0
       },
@@ -23,7 +23,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "6d684dc17c4d4b63bd5d84b8b70816ff",
+       "model_id": "e0c47c8a58e5402287a451cdcf89ce66",
        "version_major": 2,
        "version_minor": 0
       },
@@ -37,7 +37,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "3d56de01c1354f04be53908afea44b97",
+       "model_id": "943d1489c4ca464aab01a2e4b801c073",
        "version_major": 2,
        "version_minor": 0
       },
@@ -51,7 +51,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "31e7dd9a0c7e47e7b75c7cf5f444ad95",
+       "model_id": "b338fddab9694a2e89f38d43a426f7c1",
        "version_major": 2,
        "version_minor": 0
       },
@@ -65,7 +65,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "d47a7dad9691423ba72db805d019cde9",
+       "model_id": "4113f2f58c554acdb2064fb8cb331e9e",
        "version_major": 2,
        "version_minor": 0
       },
@@ -86,95 +86,13 @@
     "from interface import *\n",
     "from help import *\n",
     "\n",
-    "# Create the grids\n",
-    "#create the information grid\n",
-    "style = {'description_width': 'initial'}\n",
-    "sample = sample()\n",
-    "\n",
-    "transfer_check = measurement_check(\"Transfer\")\n",
-    "output_check = measurement_check(\"Output\")\n",
-    "gatediode_check = measurement_check(\"Gatediode\")\n",
-    "\n",
-    "checkboxes = widgets.HBox([transfer_check,output_check,gatediode_check])\n",
-    "display(checkboxes)\n",
-    "\n",
-    "#transfer\n",
-    "\n",
-    "integration_transfer = integration_time(\"MEDium\")\n",
-    "transfer_gates = gate_selection(\"VTG\",\"VBG\",\"BOTH SIMULTANEOUSLY\",\"BOTH SEQUENTIALLY\")\n",
-    "\n",
-    "Vds_transfer = secondary('VDS',0.05,0.95,1,1e-2)\n",
-    "Vtg_transfer = primary('VTG',-5,0.01,5,1e-3)\n",
-    "Vbg_transfer = primary('VBG',-15,0.1,15,1e-3)\n",
-    "plot_transfer = plot_config(1)\n",
-    "transfer_box = widgets.VBox([integration_transfer,transfer_gates,Vds_transfer.grid,Vtg_transfer.grid,Vbg_transfer.grid,plot_transfer.grid])\n",
-    "\n",
-    "\n",
-    "#output\n",
-    "integration_output = integration_time(\"SHORt\")\n",
-    "output_gates = gate_selection(\"VTG\",\"VBG\",\"BOTH\")\n",
-    "\n",
-    "Vds_output = primary('VDS',0,0.01,5,1e-2)\n",
-    "Vtg_output = secondary('VTG',-5,2,5,1e-3)\n",
-    "Vbg_output = secondary('VBG',-15,5,15,1e-3)\n",
-    "plot_output = plot_config(2)\n",
-    "\n",
-    "output_box = widgets.VBox([integration_output,output_gates,Vds_output.grid,Vtg_output.grid,Vbg_output.grid,plot_output.grid])\n",
-    "\n",
-    "integration_gatediode = integration_time(\"MEDium\")\n",
-    "gatediode_gates = gate_selection(\"VTG\",\"VBG\")\n",
-    "\n",
-    "Vg_gatediode=primary('VG',-5,0.05,5,1e-3)\n",
-    "plot_gatediode = plot_config(3)\n",
-    "gatediode_box = widgets.VBox([integration_gatediode,gatediode_gates,Vg_gatediode.grid,plot_gatediode.grid])\n",
-    "\n",
-    "#the tab widget\n",
-    "children = [transfer_box,output_box,gatediode_box]\n",
-    "titles = [\"Transfer\",\"Output\",\"Gatediode\"]\n",
-    "tab = widgets.Tab()\n",
-    "tab.children = children\n",
-    "tab.titles = titles\n",
-    "\n",
-    "display(tab)\n",
-    "\n",
-    "button = widgets.Button(description ='Start Measurement')\n",
-    "output = widgets.Output()\n",
-    "\n",
-    "export_ini_button = widgets.Button(description = 'Export as ini')\n",
-    "import_ini_button = widgets.Button(description='Import from ini')\n",
-    "\n",
-    "all_widgets =[transfer_gates,output_gates,button,transfer_check,integration_transfer,output_check,integration_output,gatediode_check,integration_gatediode,gatediode_gates,export_ini_button,import_ini_button]\n",
-    "add_widgets_to_list(sample,all_widgets)\n",
-    "add_widgets_to_list(Vds_transfer,all_widgets)\n",
-    "add_widgets_to_list(Vtg_transfer,all_widgets)\n",
-    "add_widgets_to_list(Vbg_transfer,all_widgets)\n",
-    "add_widgets_to_list(Vds_output,all_widgets)\n",
-    "add_widgets_to_list(Vtg_output,all_widgets)\n",
-    "add_widgets_to_list(Vbg_output,all_widgets)\n",
-    "add_widgets_to_list(Vg_gatediode,all_widgets)\n",
-    "add_widgets_to_list(plot_transfer,all_widgets)\n",
-    "add_widgets_to_list(plot_output,all_widgets)\n",
-    "add_widgets_to_list(plot_gatediode,all_widgets)\n",
-    "\n",
-    "\n",
-    "line = widgets.HBox([button,import_ini_button,export_ini_button])\n",
-    "display(line,output)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "563c17ae-e2b1-4f45-96cc-f7c86f93cc08",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "change_state(all_widgets)"
+    "interface = interface()"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "84efb313-b320-41a8-9e0b-64a18673a3cf",
+   "id": "65639b77-8c22-4132-a2cf-754276d08b72",
    "metadata": {},
    "outputs": [],
    "source": []
-- 
GitLab