Exemple #1
0
	def __init__(self):
		"""
		Initialize the graphical user interface
		"""
		QMainWindow.__init__(self)
		# Set up the user interface from Designer.
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)

		# Setup the ploting widgets
		self.canvas=self.ui.mpl.canvas
		self.fig = self.ui.mpl.canvas.fig
		self.canvas.mpl_connect('pick_event', self.on_pick)
		
		self.save=False 

		# Setup the plotting layout
		self.initPlotLayout()

		# Ask for the directory containing the matrix files
		if len(sys.argv)<2:
			self.path=QFileDialog.getExistingDirectory()
		else:
			# If an argument is sent to the script, the first argument will be used as a Path. Very usefull for debugging the script without having to selectr the folder each time with window dialog
			self.path=sys.argv[1]
		
		# Read the Matrix file
		self.M=pyO.Matrix(self.path)

		# Looking for a Table of Content file (called toc.txt or ToC.txt)
		self.ToC=None
		f=False
		if os.path.exists(self.path+"/toc.txt"):
			f=open(self.path+"/toc.txt","r")
		elif os.path.exists(self.path+"/ToC.txt"):
			f=open(self.path+"/ToC.txt","r")
		if f:
			self.ToC={int(z[0]):z[1] for z in [x.split() for x in f.readlines()]}
			f.close()
		val=200 # value used for the colors
		# colors used for the plot lines
		self.colors=[(0,0,val),(0,val,0),(val,0,0),(val,val,0),(val,0,val),(0,val,val)]
		
		# Add the found data to the combo box
		self.populateUI()


		# QT: SIGNALS -> SLOTS
		# This set which function is called when buttons, checkboxes, etc. are clicked
		self.ui.comboBox.currentIndexChanged.connect(self.updateSTSid)
		self.ui.listWidget.itemChanged.connect(self.plotUpdate)
		self.ui.DV.valueChanged.connect(self.plotUpdate)
		self.ui.statCB.stateChanged.connect(self.plotUpdate)
		self.ui.normCB.stateChanged.connect(self.plotUpdate)
		self.ui.pushButton.clicked.connect(self.InfoShowHideToggle)
		self.ui.saveBT.clicked.connect(self.export)
		self.InfoShowHideToggle('Hide')
		
		self.updateSTSid()
		
		if len(sys.argv)>2:
			ID=sys.argv[2]
			self.ui.comboBox.setCurrentIndex(self.ui.comboBox.findText(ID,QtCore.Qt.MatchStartsWith))

		self.plotUpdate()
Exemple #2
0
    def __init__(self, DIext='Aux2'):
        """
        Initialize the graphical user interface
        """
        QMainWindow.__init__(self)
        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Setup the ploting widgets
        self.canvas = self.ui.mpl.canvas
        self.fig = self.ui.mpl.canvas.fig
        self.canvas.mpl_connect('pick_event', self.on_pick)
        
        self.save = False

        self.DIext = DIext

        # Setup the plotting layout
        self.initPlotLayout()

        # Ask for the directory containing the matrix files
        if len(sys.argv) < 2:
            self.path = QFileDialog.getExistingDirectory()
        else:
            # If an argument is sent to the script, the first argument will be used as a Path. Very usefull for debugging the script without having to selectr the folder each time with window dialog
            self.path = sys.argv[1]
        
        # Read the Matrix file
        self.M = pyO.Matrix(self.path)

        # Looking for a Table of Content file (called toc.txt or ToC.txt)
        self.ToC = None
        f = False
        if os.path.exists(self.path+"/toc.txt"):
            f = open(self.path+"/toc.txt", "r")
        elif os.path.exists(self.path+"/ToC.txt"):
            f = open(self.path+"/ToC.txt", "r")
        if f:
            self.ToC = {int(z[0]):z[1] for z in [x.split() for x in f.readlines()]}
            f.close()
        val = 200 # value used for the colors
        # colors used for the plot lines
        self.colors = [(0, 0, val), (0, val, 0), (val, 0, 0),\
            (val, val, 0), (val, 0, val), (0, val, val)]
        
        # Add the found data to the combo box
        self.populateUI()


        # QT: SIGNALS -> SLOTS
        # This set which function is called when buttons, checkboxes, etc. are clicked
        self.ui.comboBox.currentIndexChanged.connect(self.updateSTSid)
        self.ui.listWidget.itemChanged.connect(self.plotUpdate)
        self.ui.DV.valueChanged.connect(self.plotUpdate)
        self.ui.statCB.stateChanged.connect(self.plotUpdate)
        self.ui.normCB.stateChanged.connect(self.plotUpdate)
        self.ui.pushButton.clicked.connect(self.InfoShowHideToggle)
        self.ui.saveBT.clicked.connect(self.export)
        self.InfoShowHideToggle('Hide')
        
        self.updateSTSid()
        
        if len(sys.argv) > 2:
            ID = sys.argv[2]
            self.ui.comboBox.setCurrentIndex(\
                self.ui.comboBox.findText(ID,QtCore.Qt.MatchStartsWith))

        self.plotUpdate()
Exemple #3
0
class STSviewer(QMainWindow):
	def plot_err1(self, ax,X,Y,DY,col):
		"""
		Function to plot the mean and the statistical error (1*sigma and 2*sigma as a filled area)
		ax: The axis object
		X: the vector containing the X-data
		Y: the vector containing the mean data
		DY: the vector containing the standard-deviation data
		X,Y and DY should have the same length
		"""
		ax.plot(X,Y,color=col)
		ax.fill_between(X,Y-DY,Y+DY,facecolor=col,alpha=0.3)
		ax.fill_between(X,Y-2*DY,Y+2*DY,facecolor=col,alpha=0.2)

	def on_pick(self): # Do nothing important
		pass
	
	def initPlotLayout(self):
		"""
		Setup the plotting layout.
		"""
		gs=gridspec.GridSpec(2, 2)
		sp1=gs.new_subplotspec((0,0))
		sp2=gs.new_subplotspec((1,0))
		sp3=gs.new_subplotspec((0,1),2)
		self.ax1 = self.fig.add_subplot(sp1)
		self.ax2  = self.fig.add_subplot(sp2)
		self.ax3  = self.fig.add_subplot(sp3)
		self.ax1b = self.ax1.twinx()
		self.ax3b = self.ax3.twinx()
		self.fig.tight_layout()

	def __init__(self):
		"""
		Initialize the graphical user interface
		"""
		QMainWindow.__init__(self)
		# Set up the user interface from Designer.
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)

		# Setup the ploting widgets
		self.canvas=self.ui.mpl.canvas
		self.fig = self.ui.mpl.canvas.fig
		self.canvas.mpl_connect('pick_event', self.on_pick)
		
		self.save=False 

		# Setup the plotting layout
		self.initPlotLayout()

		# Ask for the directory containing the matrix files
		if len(sys.argv)<2:
			self.path=QFileDialog.getExistingDirectory()
		else:
			# If an argument is sent to the script, the first argument will be used as a Path. Very usefull for debugging the script without having to selectr the folder each time with window dialog
			self.path=sys.argv[1]
		
		# Read the Matrix file
		self.M=pyO.Matrix(self.path)

		# Looking for a Table of Content file (called toc.txt or ToC.txt)
		self.ToC=None
		f=False
		if os.path.exists(self.path+"/toc.txt"):
			f=open(self.path+"/toc.txt","r")
		elif os.path.exists(self.path+"/ToC.txt"):
			f=open(self.path+"/ToC.txt","r")
		if f:
			self.ToC={int(z[0]):z[1] for z in [x.split() for x in f.readlines()]}
			f.close()
		val=200 # value used for the colors
		# colors used for the plot lines
		self.colors=[(0,0,val),(0,val,0),(val,0,0),(val,val,0),(val,0,val),(0,val,val)]
		
		# Add the found data to the combo box
		self.populateUI()


		# QT: SIGNALS -> SLOTS
		# This set which function is called when buttons, checkboxes, etc. are clicked
		self.ui.comboBox.currentIndexChanged.connect(self.updateSTSid)
		self.ui.listWidget.itemChanged.connect(self.plotUpdate)
		self.ui.DV.valueChanged.connect(self.plotUpdate)
		self.ui.statCB.stateChanged.connect(self.plotUpdate)
		self.ui.normCB.stateChanged.connect(self.plotUpdate)
		self.ui.pushButton.clicked.connect(self.InfoShowHideToggle)
		self.ui.saveBT.clicked.connect(self.export)
		self.InfoShowHideToggle('Hide')
		
		self.updateSTSid()
		
		if len(sys.argv)>2:
			ID=sys.argv[2]
			self.ui.comboBox.setCurrentIndex(self.ui.comboBox.findText(ID,QtCore.Qt.MatchStartsWith))

		self.plotUpdate()

	def InfoShowHideToggle(self,action='Toggle'):
		"""
		Show a TreeWidget containing the details of a STS scan.
		"""
		if action=='Hide' or self.ui.treeWidget.isVisible():
			self.ui.treeWidget.hide()
			self.ui.pushButton.setText("<<")
		else:
			self.ui.treeWidget.show()
			self.ui.pushButton.setText(">>")

	def populateUI(self):
		"""
		Look for I(V) measurements and add them to the combobox list
		"""
		self.STS={}
		self.hasDIDV=[]
		for i in self.M.images:
			r=re.search(r"--([0-9]+)_([0-9]+).I\(V\)_mtrx",i)
			if r and os.path.exists(self.path+"/"+i):
				j=int(r.group(1))
				if j in self.STS: self.STS[j]+=1
				else: self.STS[j]=1
				if i[:-9]+'Aux2(V)_mtrx' in self.M.images: self.hasDIDV.append(j)
		for i in self.STS:
			if self.ToC!=None and i in self.ToC:
				self.ui.comboBox.addItem(str(i)+" (%s)"%(self.ToC[i]))
			else:
				self.ui.comboBox.addItem(str(i))

	def updateSTSid(self):
		"""
		If and ID is chosen, the listWidget will be populated with the correct num and selected
		"""
		if self.ui.comboBox.currentIndex()==-1: raise ValueError("No Data found!")
		self.ui.listWidget.itemChanged.disconnect()
		self.ui.listWidget.clear()
		ID=int(self.ui.comboBox.currentText().split(' ')[0])
		for i in range(self.STS[ID]):
			item = QtGui.QListWidgetItem()
			item.setText(str(i+1)+" -----")
			item.setTextColor(QtGui.QColor(*self.colors[i%len(self.colors)]))
			item.setFlags(item.flags()|QtCore.Qt.ItemIsUserCheckable)
			self.ui.listWidget.addItem( item )
			item.setCheckState(QtCore.Qt.Checked)
		self.ui.listWidget.itemChanged.connect(self.plotUpdate)
		self.plotUpdate()

	def updateModel(self, value, item=None):
		"""
		Gather information about the STS measurement and populate the treeWidget (the one hidden on the right of the screen)
		"""
		if item==None:
			self.ui.treeWidget.clear()
			item=self.ui.treeWidget.invisibleRootItem()
		if type(value) is dict:
			if 'value' in value and 'unit' in value:
				child=QtGui.QTreeWidgetItem()	
				if value['unit']=='--':
					child.setText(0,str(value['value']))
				else:
					child.setText(0,str(value['value'])+" "+str(value['unit']))
				item.addChild(child)
			else:
				for key, val in sorted(value.items()):
					child=QtGui.QTreeWidgetItem()
					child.setText(0,key)
					item.addChild(child)
					self.updateModel(val, child)
		elif type(value) is list:
			for val in value:
				child=QtGui.QTreeWidgetItem()
				item.addChild(child)
				if type(val) is dict:
					child.setText(0, '[dict]')
					self.updateModel(val,child)
				elif type(val) is list:
					child.setText(0, '[list]')
					self.updateModel(val,child)
				else:
					child.setText(0, str(val))
				child.setExpanded(True)
		else:
			child=QtGui.QTreeWidgetItem()
			child.setText(0,str(value))
			item.addChild(child)
	def export(self):
		"""
		Toggle the flag to save the data
		"""
		self.save=True
		self.plotUpdate()
		self.save=False		
	
	def plotUpdate(self):
		"""
		Most important function which is retrieving and plotting the data
		"""
		# Clear the plot
		self.ax1.clear()
		self.ax1b.clear()
		self.ax2.clear()
		self.ax3.clear()
		self.ax3b.clear()

		# Setting labels and axis
		self.ax1.hold(True)
		self.ax1.set_xlabel("Bias [V]",fontsize=FontSize)
		self.ax2.set_xlabel("Bias [V]",fontsize=FontSize)
		self.ax1.set_ylabel("Current [pA]",fontsize=FontSize)
		self.ax1b.set_ylabel("dI/dV [pA/V]",fontsize=FontSize)
		self.ax2.set_ylabel(r'$\frac{dI/dV}{\overline{I/V}}$',fontsize=FontSize)
		self.ax3.set_xlabel("Bias [V]",fontsize=FontSize)
		self.ax3.set_ylabel("I/V [$\mu$A/V]",fontsize=FontSize)
		self.ax3b.yaxis.label.set_color("green")
		self.ax3b.tick_params(axis='y',colors="green")

		# plot the selected curves
		ID=int(self.ui.comboBox.currentText().split(' ')[0])
		paramsShowed=False
		stat=False
		norm=False
		
		# If checkbox "statistics" is checked, then variable stat=True
		if self.ui.statCB.isChecked(): stat=True 
		if self.ui.normCB.isChecked(): norm=True
		counter=0
		NumShown=[]

		for i in range(self.STS[ID]): # Scan over all STS having the same ID
			if self.ui.listWidget.item(i).checkState()==QtCore.Qt.Checked: # Is the curve selected by the user to be plotted?
				NumShown.append(i+1) # Store in a list which num will be displayed

				# Retrieve the STS data for the ID and num=i+1
				V,I,IM=self.M.getSTS(ID,i+1,params=True)
				NPTS=int(IM['Spectroscopy']['Device_1_Points']['value']) # Number of points in the V range
				DV=self.ui.DV.value()
				Vstep=(IM['Spectroscopy']['Device_1_End']['value']-IM['Spectroscopy']['Device_1_Start']['value'])/float(NPTS)
				skip=int(np.ceil(DV/Vstep))
				if not paramsShowed:
					paramsShowed=True
					p=self.M.getSTSparams(ID,i+1)
					self.updateModel(p)
					N=(0,NPTS)

					# The follwing variables store matrices of the various signals as a list. The first element of the list is for the Up scans and the second for Down scans
					Im=[np.empty(N),np.empty(N)] # Current: I
					dIm=[np.empty(N),np.empty(N)] # dI/dV
					IVm=[np.empty((0,NPTS+2*skip)),np.empty((0,NPTS+2*skip))] # I/V
					BIVm=[np.empty(N),np.empty(N)] # Broadened I/V (BIV)
					dIdVIVm=[np.empty(N),np.empty(N)] # (dI/dV)/BIV

				# reconstruct the voltage array
				sV=np.linspace(min(V),max(V),NPTS) # Voltage values in increading order

				if len(I)<NPTS: # Missing data
					I=np.pad(I,NPTS,'constant',constant_values=np.nan)
				elif len(I)>NPTS: # Forward & Backward scan
					if V[1]<V[0]: # Start with Downward scan
						IUp=I[NPTS:]
						IDown=I[NPTS-1::-1] # flip first part of the data
					else:
						IUp=I[:NPTS]
						IDown=I[-1:NPTS-1:-1] # Flip second part of the data
					if len(IDown)<NPTS: # Missing data
						IDown=np.pad(IDown,NPTS,'constant',constant_values=np.nan)
					Im[0]=np.vstack((Im[0],IUp))   # Im[0] contains the Up scans
					Im[1]=np.vstack((Im[1],IDown)) # Im[1] contains the Down scans
					if not stat:
						self.ax1.plot(sV,IUp*1e-6,
							color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),
							label="I%i (->)"%(i))
					if not stat:
						self.ax1.plot(sV,IDown*1e-6,'--',
							color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),
							label="I%i (<-)"%(i))
				else:
					if V[0]==min(V):
						Im[0]=np.vstack((Im[0],I))
					else:
						Im[1]=np.vstack((Im[1],I))
					if not stat: self.ax1.plot(V,I*1e-6,
						color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),
						label="I%i"%(i))
					
				if ID in self.hasDIDV:
					V2,dI=self.M.getDIDV(ID,i+1)
					if norm: dI-=dI.min()
					if len(I)>NPTS: # Forward & Backward scan
						if V[1]<V[0]: # Start with Downward scan
							dIUp=dI[NPTS:]
							dIDown=dI[NPTS-1::-1]
						else:
							dIUp=dI[:NPTS]
							dIDown=dI[-1:NPTS-1:-1]
						dIm[0]=np.vstack((dIm[0],dIUp))
						dIm[1]=np.vstack((dIm[1],dIDown))
						Is=[IUp,IDown]
						dIs=[dIUp,dIDown]
					else:
						Is=[I]
						dIs=[dI]
						if V[0]==min(V):
							dIm[0]=np.vstack((dIm[0],dI))
						else:
							dIm[1]=np.vstack((dIm[1],dI))

					for ud in range(len(Is)):
						if len(dIs[ud])<NPTS: dIs[ud]=np.pad(dIs[ud],NPTS,'constant',constant_values=np.nan)
						if not stat: self.ax1b.plot(sV,dIs[ud]*1e-6,[':','-.'][ud],
							color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),
							label="dI%i (%s)"%(i,['->','<-'][ud]))
						delta=NPTS-len(Is[ud])
						if delta>0:
							if V[1]>V[0]: # problem on the downscan
								sV=sV[delta:]
							else:
								sV=sV[:-delta]
						S=STS(sV,Is[ud],DV)
						IV=S.getIV()
						BIV=S.getBIV()
						W=S.getW()
						nV=S.getnV()
						IVm[ud]=np.vstack((IVm[ud],IV))
						BIVm[ud]=np.vstack((BIVm[ud],BIV))
						dIdVIVm[ud]=np.vstack((dIdVIVm[ud],dIs[ud]/BIV))
						if not stat: self.ax3.plot(nV,1e-12*IV,['b','--b'][ud],
							label="I/V (%s)"%(["->","<-"][ud]))
						if not stat: self.ax3.plot(sV,1e-12*BIV,['r','--r'][ud],
							label="$\overline{I/V}$ (%s)"%(["->","<-"][ud]))
						if ud==0: self.ax3b.plot(nV,W,'g',label="conv. func.")
						if not stat: self.ax2.plot(sV,dIs[ud]/BIV,['-','--'][ud],
							color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),
							label="(%s)"%(['->','<-'][ud]))
					# end for ud (up/down)
				# end if STS is shown
			# end for i in IDs
##			self.ax3.legend(prop={'size':6}) quite slow. comment it for now
##			self.ax1.legend(loc=2,prop={'size':6})
##		 	self.ax1b.legend(loc=1,prop={'size':6})

		if self.save:
			# Saving the data
			X=np.vstack((sV,Im[0],dIm[0],Im[1],dIm[1],dIdVIVm[0],dIdVIVm[1]))
			header="DV=%.3fV\nV\t"%(DV)
			header+="\t".join(["I{}_Up(V)".format(i) for i in NumShown])
			header+="\t"+"\t".join(["dI{}/dV_Up".format(i) for i in NumShown])
			header+="\t"+"\t".join(["I{}_Down(V)".format(i) for i in NumShown])
			header+="\t"+"\t".join(["dI{}/dV_Down".format(i) for i in NumShown])
			header+="\t"+"\t".join(["(dI{}_Up/dV)/(I/V)".format(i) for i in NumShown])
			header+="\t"+"\t".join(["(dI{}_Down/dV)/(I/V)".format(i) for i in NumShown])
			np.savetxt("STS_%i.dat"%(ID),X.transpose(),header=header)
		if stat: # If statistic checkbox is enabled
			for ud in range(2):
				if Im[ud].shape[0]==0: continue
				fmt=['-','--'][ud]
				col1=['blue','purple'][ud]
				col2=['red','orange'][ud]
				col3=['green','green'][ud]
				Imm=Im[ud].mean(axis=0)
				Ims=Im[ud].std(axis=0)
				
				dImm=dIm[ud].mean(axis=0)
				dIms=dIm[ud].std(axis=0)

				dIVm=dIdVIVm[ud].mean(axis=0)
				dIVs=dIdVIVm[ud].std(axis=0)
				IVmm=IVm[ud].mean(axis=0)
				IVms=IVm[ud].std(axis=0)
				BIVmm=BIVm[ud].mean(axis=0)
				BIVms=BIVm[ud].std(axis=0)
				self.plot_err1(self.ax1,sV,Imm,Ims,col1)
				self.plot_err1(self.ax1b,sV,dImm,dIms,col2)
				self.plot_err1(self.ax2,sV,dIVm,dIVs,col1)
				self.plot_err1(self.ax3,nV,IVmm,IVms,col1)
				self.ax3.plot(sV,BIVmm,color=col2)
				self.ax3.fill_between(sV,BIVmm-BIVms,BIVmm+BIVms,facecolor=col2,alpha=0.3)
				self.ax3.fill_between(sV,BIVmm-2*BIVms,BIVmm+2*BIVms,facecolor=col2,alpha=0.2)
		for x in [self.ax1,self.ax1b,self.ax2,self.ax3,self.ax3b]:
			x.tick_params(axis='both', labelsize=FontSize)
		self.canvas.draw()
Exemple #4
0
class STSviewer(QMainWindow):
    def plot_err1(self, ax, X, Y, DY, col):
        """
        Function to plot the mean and the statistical error (1*sigma and 2*sigma as a filled area)
        ax: The axis object
        X: the vector containing the X-data
        Y: the vector containing the mean data
        DY: the vector containing the standard-deviation data
        X,Y and DY should have the same length
        """
        ax.plot(X, Y, color=col)
        ax.fill_between(X, Y-DY, Y+DY, facecolor=col, alpha=0.3)
        ax.fill_between(X, Y-2*DY, Y+2*DY, facecolor=col, alpha=0.2)

    def on_pick(self): # Do nothing important
        pass
    
    def initPlotLayout(self):
        """
        Setup the plotting layout.
        """
        gs = gridspec.GridSpec(2, 2)
        sp1 = gs.new_subplotspec((0, 0))
        sp2 = gs.new_subplotspec((1, 0))
        sp3 = gs.new_subplotspec((0, 1), 2)
        self.ax1 = self.fig.add_subplot(sp1)
        self.ax2 = self.fig.add_subplot(sp2)
        self.ax3 = self.fig.add_subplot(sp3)
        self.ax1b = self.ax1.twinx()
        self.ax3b = self.ax3.twinx()
        self.fig.tight_layout()

    def __init__(self, DIext='Aux2'):
        """
        Initialize the graphical user interface
        """
        QMainWindow.__init__(self)
        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Setup the ploting widgets
        self.canvas = self.ui.mpl.canvas
        self.fig = self.ui.mpl.canvas.fig
        self.canvas.mpl_connect('pick_event', self.on_pick)
        
        self.save = False

        self.DIext = DIext

        # Setup the plotting layout
        self.initPlotLayout()

        # Ask for the directory containing the matrix files
        if len(sys.argv) < 2:
            self.path = QFileDialog.getExistingDirectory()
        else:
            # If an argument is sent to the script, the first argument will be used as a Path. Very usefull for debugging the script without having to selectr the folder each time with window dialog
            self.path = sys.argv[1]
        
        # Read the Matrix file
        self.M = pyO.Matrix(self.path)

        # Looking for a Table of Content file (called toc.txt or ToC.txt)
        self.ToC = None
        f = False
        if os.path.exists(self.path+"/toc.txt"):
            f = open(self.path+"/toc.txt", "r")
        elif os.path.exists(self.path+"/ToC.txt"):
            f = open(self.path+"/ToC.txt", "r")
        if f:
            self.ToC = {int(z[0]):z[1] for z in [x.split() for x in f.readlines()]}
            f.close()
        val = 200 # value used for the colors
        # colors used for the plot lines
        self.colors = [(0, 0, val), (0, val, 0), (val, 0, 0),\
            (val, val, 0), (val, 0, val), (0, val, val)]
        
        # Add the found data to the combo box
        self.populateUI()


        # QT: SIGNALS -> SLOTS
        # This set which function is called when buttons, checkboxes, etc. are clicked
        self.ui.comboBox.currentIndexChanged.connect(self.updateSTSid)
        self.ui.listWidget.itemChanged.connect(self.plotUpdate)
        self.ui.DV.valueChanged.connect(self.plotUpdate)
        self.ui.statCB.stateChanged.connect(self.plotUpdate)
        self.ui.normCB.stateChanged.connect(self.plotUpdate)
        self.ui.pushButton.clicked.connect(self.InfoShowHideToggle)
        self.ui.saveBT.clicked.connect(self.export)
        self.InfoShowHideToggle('Hide')
        
        self.updateSTSid()
        
        if len(sys.argv) > 2:
            ID = sys.argv[2]
            self.ui.comboBox.setCurrentIndex(\
                self.ui.comboBox.findText(ID,QtCore.Qt.MatchStartsWith))

        self.plotUpdate()

    def InfoShowHideToggle(self, action='Toggle'):
        """
        Show a TreeWidget containing the details of a STS scan.
        """
        if action == 'Hide' or self.ui.treeWidget.isVisible():
            self.ui.treeWidget.hide()
            self.ui.pushButton.setText("<<")
        else:
            self.ui.treeWidget.show()
            self.ui.pushButton.setText(">>")

    def populateUI(self):
        """
        Look for I(V) measurements and add them to the combobox list
        """
        self.STS = {}
        self.hasDIDV = []
        for i in self.M.images:
            r = re.search(r"--([0-9]+)_([0-9]+).I\(V\)_mtrx", i)
            if r and os.path.exists(self.path+"/"+i):
                j = int(r.group(1))
                if j in self.STS:
                    self.STS[j] += 1
                else:
                    self.STS[j] = 1
                if i[:-9]+self.DIext+'(V)_mtrx' in self.M.images:
                    self.hasDIDV.append(j)
        for i in self.STS:
            if self.ToC != None and i in self.ToC:
                self.ui.comboBox.addItem(str(i)+" (%s)"%(self.ToC[i]))
            else:
                self.ui.comboBox.addItem(str(i))

    def updateSTSid(self):
        """
        If and ID is chosen, the listWidget will be populated with the correct num and selected
        """
        if self.ui.comboBox.currentIndex() == -1:
            raise ValueError("No Data found!")
        self.ui.listWidget.itemChanged.disconnect()
        self.ui.listWidget.clear()
        ID = int(self.ui.comboBox.currentText().split(' ')[0])
        for i in range(self.STS[ID]):
            item = QtGui.QListWidgetItem()
            item.setText(str(i+1)+" -----")
            item.setTextColor(QtGui.QColor(*self.colors[i%len(self.colors)]))
            item.setFlags(item.flags()|QtCore.Qt.ItemIsUserCheckable)
            self.ui.listWidget.addItem( item )
            item.setCheckState(QtCore.Qt.Checked)
        self.ui.listWidget.itemChanged.connect(self.plotUpdate)
        self.plotUpdate()

    def updateModel(self, value, item=None):
        """
        Gather information about the STS measurement and populate the treeWidget (the one hidden on the right of the screen)
        """
        if item == None:
            self.ui.treeWidget.clear()
            item = self.ui.treeWidget.invisibleRootItem()
        if type(value) is dict:
            if 'value' in value and 'unit' in value:
                child = QtGui.QTreeWidgetItem() 
                if value['unit'] == '--':
                    child.setText(0,str(value['value']))
                else:
                    child.setText(0,str(value['value'])+" "+str(value['unit']))
                item.addChild(child)
            else:
                for key, val in sorted(value.items()):
                    child = QtGui.QTreeWidgetItem()
                    child.setText(0, key)
                    item.addChild(child)
                    self.updateModel(val, child)
        elif type(value) is list:
            for val in value:
                child = QtGui.QTreeWidgetItem()
                item.addChild(child)
                if type(val) is dict:
                    child.setText(0, '[dict]')
                    self.updateModel(val, child)
                elif type(val) is list:
                    child.setText(0, '[list]')
                    self.updateModel(val, child)
                else:
                    child.setText(0, str(val))
                child.setExpanded(True)
        else:
            child = QtGui.QTreeWidgetItem()
            child.setText(0, str(value))
            item.addChild(child)
            
    def export(self):
        """
        Toggle the flag to save the data
        """
        self.save = True
        self.plotUpdate()
        self.save = False       
    
    def plotUpdate(self):
        """
        Most important function which is retrieving and plotting the data
        """
        # Clear the plot
        self.ax1.clear()
        self.ax1b.clear()
        self.ax2.clear()
        self.ax3.clear()
        self.ax3b.clear()

        # Setting labels and axis
        self.ax1.set_xlabel("Bias [V]", fontsize=FontSize)
        self.ax2.set_xlabel("Bias [V]", fontsize=FontSize)
        self.ax1.set_ylabel("Current [pA]", fontsize=FontSize)
        self.ax1b.set_ylabel("dI/dV [pA/V]", fontsize=FontSize)
        self.ax2.set_ylabel(r'$\frac{dI/dV}{\overline{I/V}}$', fontsize=FontSize)
        self.ax3.set_xlabel("Bias [V]", fontsize=FontSize)
        self.ax3.set_ylabel("I/V [$\mu$A/V]", fontsize=FontSize)
        self.ax3b.yaxis.label.set_color("green")
        self.ax3b.tick_params(axis='y', colors="green")

        # plot the selected curves
        ID = int(self.ui.comboBox.currentText().split(' ')[0])
        paramsShowed = False
        stat = False
        norm = False
        
        # If checkbox "statistics" is checked, then variable stat=True
        if self.ui.statCB.isChecked():
            stat = True
        if self.ui.normCB.isChecked():
            norm = True
        counter = 0
        NumShown = []

        for i in range(self.STS[ID]): # Scan over all STS having the same ID
            if self.ui.listWidget.item(i).checkState() == QtCore.Qt.Checked: # Is the curve selected by the user to be plotted?
                NumShown.append(i+1) # Store in a list which num will be displayed

                # Retrieve the STS data for the ID and num=i+1
                V, I, IM = self.M.getSTS(ID, i+1, params=True)
                NPTS = int(IM['Spectroscopy']['Device_1_Points']['value']) # Number of points in the V range
                DV = self.ui.DV.value()
                Vstep = (IM['Spectroscopy']['Device_1_End']['value']-IM['Spectroscopy']['Device_1_Start']['value'])/float(NPTS)
                skip = int(np.ceil(DV/Vstep))
                if not paramsShowed:
                    paramsShowed = True
                    p = self.M.getSTSparams(ID, i+1)
                    self.updateModel(p)
                    N = (0, NPTS)

                    # The follwing variables store matrices of the various signals as a list. The first element of the list is for the Up scans and the second for Down scans
                    Im = [np.empty(N), np.empty(N)] # Current: I
                    dIm = [np.empty(N), np.empty(N)] # dI/dV
                    IVm = [np.empty((0, NPTS+2*skip)), np.empty((0, NPTS+2*skip))] # I/V
                    BIVm = [np.empty(N), np.empty(N)] # Broadened I/V (BIV)
                    dIdVIVm = [np.empty(N), np.empty(N)] # (dI/dV)/BIV

                # reconstruct the voltage array
                sV = np.linspace(min(V), max(V), NPTS) # Voltage values in increading order

                if len(I) < NPTS: # Missing data
                    I = np.pad(I, NPTS, 'constant', constant_values=np.nan)
                elif len(I) > NPTS: # Forward & Backward scan
                    if V[1] < V[0]: # Start with Downward scan
                        IUp = I[NPTS:]
                        IDown = I[NPTS-1::-1] # flip first part of the data
                    else:
                        IUp = I[:NPTS]
                        IDown = I[-1:NPTS-1:-1] # Flip second part of the data
                    if len(IDown) < NPTS: # Missing data
                        IDown = np.pad(IDown, NPTS, 'constant', constant_values=np.nan)
                    Im[0] = np.vstack((Im[0], IUp))   # Im[0] contains the Up scans
                    Im[1] = np.vstack((Im[1], IDown)) # Im[1] contains the Down scans
                    if not stat:
                        self.ax1.plot(sV, IUp*1e-6,\
                            color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),\
                            label="I%i (->)"%(i))
                    if not stat:
                        self.ax1.plot(sV, IDown*1e-6, '--',\
                            color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),\
                            label="I%i (<-)"%(i))
                else:
                    if V[0] == min(V):
                        Im[0] = np.vstack((Im[0], I))
                    else:
                        Im[1] = np.vstack((Im[1], I))
                    if not stat:
                        self.ax1.plot(V, I*1e-6,\
                        color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),\
                        label="I%i"%(i))
                    
                if ID in self.hasDIDV:
                    V2, dI = self.M.getSTS(ID, i+1, self.DIext)
                    if norm:
                        dI -= dI.min()
                    if len(I) > NPTS: # Forward & Backward scan
                        if V[1] < V[0]: # Start with Downward scan
                            dIUp = dI[NPTS:]
                            dIDown = dI[NPTS-1::-1]
                        else:
                            dIUp = dI[:NPTS]
                            dIDown = dI[-1:NPTS-1:-1]
                        dIm[0] = np.vstack((dIm[0], dIUp))
                        dIm[1] = np.vstack((dIm[1], dIDown))
                        Is = [IUp, IDown]
                        dIs = [dIUp, dIDown]
                    else:
                        Is = [I]
                        dIs = [dI]
                        if V[0] == min(V):
                            dIm[0] = np.vstack((dIm[0], dI))
                        else:
                            dIm[1] = np.vstack((dIm[1], dI))

                    for ud in range(len(Is)):
                        if len(dIs[ud]) < NPTS:
                            dIs[ud] = np.pad(dIs[ud], NPTS, 'constant', constant_values=np.nan)
                        if not stat:
                            self.ax1b.plot(sV, dIs[ud]*1e-6, [':','-.'][ud],\
                             color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),\
                             label="dI%i (%s)"%(i,['->', '<-'][ud]))
                        delta = NPTS-len(Is[ud])
                        if delta > 0:
                            if V[1] > V[0]: # problem on the downscan
                                sV = sV[delta:]
                            else:
                                sV = sV[:-delta]
                        S = STS(sV, Is[ud], DV)
                        IV = S.getIV()
                        BIV = S.getBIV()
                        W = S.getW()
                        nV = S.getnV()
                        IVm[ud] = np.vstack((IVm[ud], IV))
                        BIVm[ud] = np.vstack((BIVm[ud], BIV))
                        dIdVIVm[ud] = np.vstack((dIdVIVm[ud], dIs[ud]/BIV))
                        if not stat:
                            self.ax3.plot(nV, 1e-12*IV, ['b', '--b'][ud],\
                                label="I/V (%s)"%(["->", "<-"][ud]))
                        if not stat:
                            self.ax3.plot(sV, 1e-12*BIV, ['r','--r'][ud],\
                                label="$\overline{I/V}$ (%s)"%(["->", "<-"][ud]))
                        if ud==0:
                            self.ax3b.plot(nV, W, 'g', label="conv. func.")
                        if not stat:
                            self.ax2.plot(sV, dIs[ud]/BIV, ['-', '--'][ud],\
                                color="#{0:02x}{1:02x}{2:02x}".format(*self.colors[i%len(self.colors)]),\
                                label="(%s)"%(['->', '<-'][ud]))

        if self.save:
            # Saving the data
            X = np.vstack((sV, Im[0], dIm[0], Im[1], dIm[1], dIdVIVm[0], dIdVIVm[1]))
            header = "DV=%.3fV\nV\t"%(DV)
            header += "\t".join(["I{}_Up(V)".format(i) for i in NumShown])
            header += "\t"+"\t".join(["dI{}/dV_Up".format(i) for i in NumShown])
            header += "\t"+"\t".join(["I{}_Down(V)".format(i) for i in NumShown])
            header += "\t"+"\t".join(["dI{}/dV_Down".format(i) for i in NumShown])
            header += "\t"+"\t".join(["(dI{}_Up/dV)/(I/V)".format(i) for i in NumShown])
            header += "\t"+"\t".join(["(dI{}_Down/dV)/(I/V)".format(i) for i in NumShown])
            np.savetxt("STS_%i.dat"%(ID), X.transpose(), header=header)
        if stat: # If statistic checkbox is enabled
            for ud in range(2):
                if Im[ud].shape[0] == 0:
                    continue
                fmt = ['-', '--'][ud]
                col1 = ['blue', 'purple'][ud]
                col2 = ['red', 'orange'][ud]
                col3 = ['green', 'green'][ud]
                Imm = Im[ud].mean(axis=0)
                Ims = Im[ud].std(axis=0)
                
                dImm = dIm[ud].mean(axis=0)
                dIms = dIm[ud].std(axis=0)

                dIVm = dIdVIVm[ud].mean(axis=0)
                dIVs = dIdVIVm[ud].std(axis=0)
                IVmm = IVm[ud].mean(axis=0)
                IVms = IVm[ud].std(axis=0)
                BIVmm = BIVm[ud].mean(axis=0)
                BIVms = BIVm[ud].std(axis=0)
                self.plot_err1(self.ax1, sV, Imm, Ims, col1)
                try:
                    self.plot_err1(self.ax1b, sV, dImm, dIms, col2)
                    self.plot_err1(self.ax2, sV, dIVm, dIVs, col1)
                    self.plot_err1(self.ax3, nV, IVmm, IVms, col1)
                except:
                    pass # No DI signal
                self.ax3.plot(sV, BIVmm, color=col2)
                self.ax3.fill_between(sV, BIVmm-BIVms, BIVmm+BIVms, facecolor=col2, alpha=0.3)
                self.ax3.fill_between(sV, BIVmm-2*BIVms, BIVmm+2*BIVms, facecolor=col2, alpha=0.2)
        for x in [self.ax1,self.ax1b,self.ax2,self.ax3,self.ax3b]:
            x.tick_params(axis='both', labelsize=FontSize)
        self.canvas.draw()