docs: def _function(self):
          '''
          Runs either a loop or a parameter sweep over the subscripts in the order defined by the parameter_list 'script_order'
          '''
          def get_sweep_parameters():
              """
              Returns: the paramter values over which to sweep
              """
              #in both cases, param values have tolist to make sure that they are python types (ex float) rather than numpy
              #types (ex np.float64), the latter of which can cause typing issues
              sweep_range = self.settings['sweep_range']
              if self.settings['stepping_mode'] == 'N':
                  param_values = np.linspace(sweep_range['min_value'], sweep_range['max_value'],
                                             int(sweep_range['N/value_step']), endpoint=True).tolist()
              elif self.settings['stepping_mode'] == 'value_step':
                  param_values = np.linspace(sweep_range['min_value'], sweep_range['max_value'],
                                             (sweep_range['max_value'] - sweep_range['min_value']) / sweep_range[
                                                 'N/value_step'] + 1, endpoint=True).tolist()
              return param_values
  
          script_names = list(self.settings['script_order'].keys())
          script_indices = [self.settings['script_order'][name] for name in script_names]
          _, sorted_script_names = list(zip(*sorted(zip(script_indices, script_names))))
  
          if self.iterator_type == 'sweep':
  
  
              def get_script_and_settings_from_str(sweep_param):
                  """
                  Args:
                      sweep_param: astring with the path to the sweep parameter
                          e.g. script.param.subparam or script->subscript.parameter
  
                  Returns:
                      script_list: a list with the scripts, e.g. [script] or [script, subscript]
                      parameter_list: a list with the paraemeters, e.g. [param, subparam] or [parameter] for the cases above
                  """
                  split_trace = sweep_param.split('.')
                  script_list = split_trace[0].split('->')
                  parameter_list = split_trace[1:]
  
                  return script_list, parameter_list
  
              param_values = get_sweep_parameters()
  
              print('JG parametes before', param_values)
              if self.settings['sweep_range']['randomize'] == True:
                  random.shuffle(param_values)
              print('JG parametes after', param_values)
  
              for i, value in enumerate(param_values):
                  self.iterator_progress = float(i) / len(param_values)
  
                  script_list, parameter_list = get_script_and_settings_from_str(self.settings['sweep_param'])
                  script = self
                  while len(script_list)>0:
                      script = script.scripts[script_list[0]]
                      script_list = script_list[1:]
  
                  curr_type = type(reduce(lambda x,y: x[y], parameter_list, script.settings)) #traverse nested dict to get type of variable
  
                  update_dict = reduce(lambda y, x: {x: y}, reversed(parameter_list), curr_type(value)) #creates nested dictionary from list
  
                  script.settings.update(update_dict)
                  parameter_name = parameter_list[-1]
                  if np.abs(value) < 1000:
                      self.log('setting parameter {:s} to {:.3g}'.format(self.settings['sweep_param'], value))
                  else:
                      self.log('setting parameter {:s} to {:0.2e}'.format(self.settings['sweep_param'], value))
  
                  for script_name in sorted_script_names:
                      if self._abort:
                          break
                      j = i if self.settings['run_all_first'] else (i+1)
  
                      curr_script_exec_freq = self.settings['script_execution_freq'][script_name]
                      if curr_script_exec_freq != 0 and (j % curr_script_exec_freq == 0):
                          # i+1 so first execution is mth loop, not first
                          self.log('starting {:s}'.format(script_name))
                          tag = self.scripts[script_name].settings['tag']
                          self.scripts[script_name].settings['tag'] = '{:s}_{:s}_{:0.3e}'.format(tag, parameter_name, value)
                          self.scripts[script_name].run()
                          self.scripts[script_name].settings['tag'] = tag
  
          elif self.iterator_type == 'loop':
  
              num_loops = self.settings['num_loops']
              if num_loops == 0:
                  self.log('Loop set to run 0 times')
                  return
  
              self.data = {}
              for i in range(num_loops):
                  self.iterator_progress = float(i) / num_loops
  
                  for script_name in sorted_script_names:
                      if self._abort:
                          break
                      j = i if self.settings['run_all_first'] else (i+1)
  
                      curr_script_execution_freq = self.settings['script_execution_freq'][script_name]
  
                      if curr_script_execution_freq != 0 and (j % curr_script_execution_freq == 0):
                          # i+1 so first execution is mth loop, not first
                          self.log('starting {:s} \t iteration {:d} of {:d}'.format(script_name, i + 1, num_loops))
                          tag = self.scripts[script_name].settings['tag']
                          tmp = tag + '_{' + ':0{:d}'.format(len(str(num_loops))) + '}'
                          self.scripts[script_name].settings['tag'] = tmp.format(i)
                          self.scripts[script_name].run()
                          self.scripts[script_name].settings['tag'] = tag
  
                  # from the last script we take the average of the data as the data of the iterator script
                  if isinstance(self.scripts[script_name].data, dict):
                      data = self.scripts[script_name].data
                  elif isinstance(self.scripts[script_name].data, deque):
                      data = self.scripts[script_name].data[-1]
                  if i == 0:
                      self.data.update(data)
                  else:
                      if self._abort:
                          break
  
                      for key in list(data.keys()):
  
                          # can't add None values
                          if not data[key] is None:
                              # if subscript data have differnet length, e.g. fitparameters can be differet, depending on if there is one or two peaks
                              if len(self.data[key]) != len(data[key]):
                                  print(('warning subscript data {:s} have different lengths'.format(key)))
                                  continue
  
                              if isinstance(self.data[key], list):
                                  self.data[key] += np.array(data[key])
                              elif isinstance(self.data[key], dict):
                                  self.data[key] = {x: self.data[key].get(x, 0) + data[key].get(x, 0) for x in list(self.data[key].keys())}
                              else:
                                  self.data[key] += data[key]
  
              if not self._abort and num_loops > 0:
                  # normalize data because we just kept adding the values
                  for key in list(data.keys()):
                      if isinstance(self.data[key], list):
                          self.data[key] = np.array(self.data[key]) / num_loops
                      elif isinstance(self.data[key], dict):
                          self.data[key] = {k:v/num_loops for k, v in self.data[key].items()}
                      elif self.data[key] is None:
                          self.log('None type in data! check code')
                          pass
                      elif isinstance(self.data[key], int):
                          self.data[key] = float(self.data[key]) / num_loops # if int we can not devide. Thus we convert explicitely to float
                      else:
                          self.data[key] = self.data[key] / num_loops
  
          else:
              raise TypeError('wrong iterator type')