docs: def btn_clicked(self):
          """
          slot to which connect buttons
          """
          sender = self.sender()
          self.probe_to_plot = None
  
          def start_button():
              """
              starts the selected script
              """
              item = self.tree_scripts.currentItem()
  
              # BROKEN 20170109: repeatedly erases updates to gui
              # self.expanded_items = []
              # for index in range(self.tree_scripts.topLevelItemCount()):
              #     someitem = self.tree_scripts.topLevelItem(index)
              #     if someitem.isExpanded():
              #         self.expanded_items.append(someitem.name)
              self.script_start_time = datetime.datetime.now()
  
  
              if item is not None:
                  # get script and update settings from tree
                  self.running_item = item
                  script, path_to_script, script_item = item.get_script()
  
                  self.update_script_from_item(script_item)
  
                  self.log('starting {:s}'.format(script.name))
  
                  # put script onto script thread
                  print('================================================')
                  print(('===== starting {:s}'.format(script.name)))
                  print('================================================')
                  script_thread = self.script_thread
  
                  def move_to_worker_thread(script):
  
                      script.moveToThread(script_thread)
  
                      # move also the subscript to the worker thread
                      for subscript in list(script.scripts.values()):
                          move_to_worker_thread(subscript)
  
                  move_to_worker_thread(script)
  
                  script.updateProgress.connect(self.update_status) # connect update signal of script to update slot of gui
                  script_thread.started.connect(script.run) # causes the script to start upon starting the thread
                  script.finished.connect(script_thread.quit)  # clean up. quit thread after script is finished
                  script.finished.connect(self.script_finished) # connect finished signal of script to finished slot of gui
  
                  # start thread, i.e. script
                  script_thread.start()
  
                  self.current_script = script
                  self.btn_start_script.setEnabled(False)
                  # self.tabWidget.setEnabled(False)
  
                  if isinstance(self.current_script, ScriptIterator):
                      self.btn_skip_subscript.setEnabled(True)
  
  
              else:
                  self.log('User tried to run a script without one selected.')
  
          def stop_button():
              """
              stops the current script
              """
              if self.current_script is not None and self.current_script.is_running:
                  self.current_script.stop()
              else:
                  self.log('User clicked stop, but there isn\'t anything running...this is awkward. Re-enabling start button anyway.')
              self.btn_start_script.setEnabled(True)
  
          def skip_button():
              """
              Skips to the next script if the current script is a Iterator script
              """
              if self.current_script is not None and self.current_script.is_running and isinstance(self.current_script,
                                                                                                   ScriptIterator):
                  self.current_script.skip_next()
              else:
                  self.log('User clicked skip, but there isn\'t a iterator script running...this is awkward.')
  
          def validate_button():
              """
              validates the selected script
              """
              item = self.tree_scripts.currentItem()
  
              if item is not None:
                  script, path_to_script, script_item = item.get_script()
                  self.update_script_from_item(script_item)
                  script.is_valid()
                  script.plot_validate([self.matplotlibwidget_1.figure, self.matplotlibwidget_2.figure])
                  self.matplotlibwidget_1.draw()
                  self.matplotlibwidget_2.draw()
  
          def store_script_data():
              """
              updates the internal self.data_sets with selected script and updates tree self.fill_dataset_tree
              """
              item = self.tree_scripts.currentItem()
              if item is not None:
                  script, path_to_script, _ = item.get_script()
                  script_copy = script.duplicate()
                  time_tag = script.start_time.strftime('%y%m%d-%H_%M_%S')
  
                  self.data_sets.update({time_tag : script_copy})
  
                  self.fill_dataset_tree(self.tree_dataset, self.data_sets)
  
          def save_data():
              """"
              saves the selected script (where is contained in the script itself)
              """
              indecies = self.tree_dataset.selectedIndexes()
              model = indecies[0].model()
              rows = list(set([index.row()for index in indecies]))
  
              for row in rows:
                  time_tag = str(model.itemFromIndex(model.index(row, 0)).text())
                  name_tag = str(model.itemFromIndex(model.index(row, 1)).text())
                  path = self.gui_settings['data_folder']
                  script = self.data_sets[time_tag]
                  script.update({'tag' : name_tag, 'path': path})
                  script.save_data()
                  script.save_image_to_disk()
                  script.save_b26()
                  script.save_log()
  
          def delete_data():
              """
              deletes the data from the dataset
              Returns:
              """
              indecies = self.tree_dataset.selectedIndexes()
              model = indecies[0].model()
              rows = list(set([index.row()for index in indecies]))
  
              for row in rows:
                  time_tag = str(model.itemFromIndex(model.index(row, 0)).text())
                  del self.data_sets[time_tag]
  
                  model.removeRows(row,1)
  
          def load_probes():
              """
              opens file dialog to load probes into gui
              """
  
              # if the probe has never been started it can not be disconnected so we catch that error
              try:
                  self.read_probes.updateProgress.disconnect()
                  self.read_probes.quit()
                  # self.read_probes.stop()
              except RuntimeError:
                  pass
              dialog = LoadDialogProbes(probes_old=self.probes, filename=self.gui_settings['probes_folder'])
              if dialog.exec_():
                  self.gui_settings['probes_folder'] = str(dialog.txt_probe_log_path.text())
                  probes = dialog.get_values()
                  added_instruments = list(set(probes.keys()) - set(self.probes.keys()))
                  removed_instruments = list(set(self.probes.keys()) - set(probes.keys()))
                  # create instances of new probes
                  self.probes, loaded_failed, self.instruments = Probe.load_and_append(
                      probe_dict=probes,
                      probes={},
                      instruments=self.instruments)
                  if not loaded_failed:
                      print(('WARNING following probes could not be loaded', loaded_failed, len(loaded_failed)))
  
  
                  # restart the readprobes thread
                  del self.read_probes
                  self.read_probes = ReadProbes(self.probes)
                  self.read_probes.start()
                  self.tree_probes.clear() # clear tree because the probe might have changed
                  self.read_probes.updateProgress.connect(self.update_probes)
                  self.tree_probes.expandAll()
  
          def load_instruments():
              """
              opens file dialog to load instruments into gui
              """
              if 'instrument_folder' in self.gui_settings:
                  dialog = LoadDialog(elements_type="instruments", elements_old=self.instruments,
                                      filename=self.gui_settings['instrument_folder'])
  
              else:
                  dialog = LoadDialog(elements_type="instruments", elements_old=self.instruments)
  
              if dialog.exec_():
                  self.gui_settings['instrument_folder'] = str(dialog.txt_probe_log_path.text())
                  instruments = dialog.get_values()
                  added_instruments = set(instruments.keys()) - set(self.instruments.keys())
                  removed_instruments = set(self.instruments.keys()) - set(instruments.keys())
                  # print('added_instruments', {name: instruments[name] for name in added_instruments})
  
                  # create instances of new instruments
                  self.instruments, loaded_failed = Instrument.load_and_append(
                      {name: instruments[name] for name in added_instruments}, self.instruments)
                  if len(loaded_failed)>0:
                      print(('WARNING following instrument could not be loaded', loaded_failed))
                  # delete instances of new instruments/scripts that have been deselected
                  for name in removed_instruments:
                      del self.instruments[name]
  
          def plot_data(sender):
              """
              plots the data of the selected script
              """
              if sender == self.tree_dataset:
                  index = self.tree_dataset.selectedIndexes()[0]
                  model = index.model()
                  time_tag = str(model.itemFromIndex(model.index(index.row(), 0)).text())
                  script = self.data_sets[time_tag]
                  self.plot_script(script)
              elif sender == self.tree_scripts:
                  item = self.tree_scripts.currentItem()
                  if item is not None:
                      script, path_to_script, _ = item.get_script()
                  # only plot if script has been selected but not if a parameter has been selected
                  if path_to_script == []:
                      self.plot_script(script)
  
          def save():
              self.save_config(self.gui_settings['gui_settings'])
          if sender is self.btn_start_script:
              start_button()
          elif sender is self.btn_stop_script:
              stop_button()
          elif sender is self.btn_skip_subscript:
              skip_button()
          elif sender is self.btn_validate_script:
              validate_button()
          elif sender in (self.tree_dataset, self.tree_scripts):
              plot_data(sender)
          elif sender is self.btn_store_script_data:
              store_script_data()
          elif sender is self.btn_save_data:
              save_data()
          elif sender is self.btn_delete_data:
              delete_data()
          # elif sender is self.btn_plot_probe:
          elif sender is self.chk_probe_plot:
              if self.chk_probe_plot.isChecked():
                  item = self.tree_probes.currentItem()
                  if item is not None:
                      if item.name in self.probes:
                          #selected item is an instrument not a probe, maybe plot all the probes...
                          self.log('Can\'t plot, No probe selected. Select probe and try again!')
                      else:
                          instrument = item.parent().name
                          self.probe_to_plot = self.probes[instrument][item.name]
                  else:
                      self.log('Can\'t plot, No probe selected. Select probe and try again!')
              else:
                  self.probe_to_plot = None
          elif sender is self.btn_save_gui:
              # get filename
              filepath, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save gui settings to file', self.config_filepath, filter = '*.b26')
  
              #in case the user cancels during the prompt, check that the filepath is not an empty string
              if filepath:
                  filename, file_extension = os.path.splitext(filepath)
                  if file_extension != '.b26':
                      filepath = filename + ".b26"
                  filepath = os.path.normpath(filepath)
                  self.save_config(filepath)
                  self.gui_settings['gui_settings'] = filepath
                  self.refresh_tree(self.tree_gui_settings, self.gui_settings)
          elif sender is self.btn_load_gui:
              # get filename
              fname = QtWidgets.QFileDialog.getOpenFileName(self, 'Load gui settings from file',  self.gui_settings['data_folder'], filter = '*.b26')
              self.load_config(fname[0])
          elif sender is self.btn_about:
              msg = QtWidgets.QMessageBox()
              msg.setIcon(QtWidgets.QMessageBox.Information)
              msg.setText("pylabcontrol: Laboratory Equipment Control for Scientific Experiments")
              msg.setInformativeText("This software was developed by Arthur Safira, Jan Gieseler, and Aaron Kabcenell at"
                                     "Harvard University. It is licensed under the LPGL licence. For more information,"
                                     "visit the GitHub page at github.com/LISE-B26/pylabcontrol .")
              msg.setWindowTitle("About")
              # msg.setDetailedText("some stuff")
              msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
              # msg.buttonClicked.connect(msgbtn)
              retval = msg.exec_()
          # elif (sender is self.btn_load_instruments) or (sender is self.btn_load_scripts):
          elif sender in (self.btn_load_instruments, self.btn_load_scripts, self.btn_load_probes):
              if sender is self.btn_load_instruments:
                  load_instruments()
              elif sender is self.btn_load_scripts:
                  self.load_scripts()
              elif sender is self.btn_load_probes:
                  load_probes()
              # refresh trees
              self.refresh_tree(self.tree_scripts, self.scripts)
              self.refresh_tree(self.tree_settings, self.instruments)
          elif sender is self.actionSave:
              self.save_config(self.gui_settings['gui_settings'])
          elif sender is self.actionGo_to_pylabcontrol_GitHub_page:
              webbrowser.open('https://github.com/LISE-B26/pylabcontrol')
          elif sender is self.actionExport:
              export_dialog = ExportDialog()
              export_dialog.target_path.setText(self.gui_settings['scripts_folder'])
              if self.gui_settings_hidden['scripts_source_folder']:
                  export_dialog.source_path.setText(self.gui_settings_hidden['scripts_source_folder'])
              if export_dialog.source_path.text():
                  export_dialog.reset_avaliable(export_dialog.source_path.text())
              #exec_() blocks while export dialog is used, subsequent code will run on dialog closing
              export_dialog.exec_()
              self.gui_settings.update({'scripts_folder': export_dialog.target_path.text()})
              self.fill_treeview(self.tree_gui_settings, self.gui_settings)
              self.gui_settings_hidden.update({'scripts_source_folder': export_dialog.source_path.text()})