Ejemplo n.º 1
0
class Data_Reducer(QWidget):
    """
    This widget is developed to reduce on the fly 2D SAXS data to azimuthally averaged 1D SAXS data
    """
    def __init__(self,poniFile=None,dataFile=None, darkFile=None, maskFile=None,extractedFolder='/tmp', npt=1000, transmission_corr=True, azimuthRange=(-180.0,180.0), parent=None):
        """
        poniFile is the calibration file obtained after Q-calibration
        """
        QWidget.__init__(self,parent)
        self.layout=QGridLayout(self)
        self.setup_dict=json.load(open('./SetupData/reducer_setup.txt','r'))
        if poniFile is not None:
            self.poniFile=poniFile
        else:
            self.poniFile=self.setup_dict['poniFile']
        if maskFile is not None:
            self.maskFile=maskFile
        else:
            self.maskFile=self.setup_dict['maskFile']
        self.dataFile=dataFile
        if darkFile is None:
            self.dark_corrected=False
            self.darkFile=''
        else:
            self.darkFile=darkFile
            self.dark_corrected=True
       
        self.curDir=os.getcwd()
        
        self.extractedFolder=extractedFolder
        self.npt=npt
        self.set_externally=False
        self.transmission_corr=transmission_corr        
        #ai=AIWidget()
        #self.layout.addWidget(ai)
        self.azimuthRange=azimuthRange
        self.create_UI()
        if os.path.exists(self.poniFile):
            self.openPoniFile(file=self.poniFile)
        if os.path.exists(self.maskFile):
            self.openMaskFile(file=self.maskFile)
        
        
        
        
    def create_UI(self):
        """
        Creates the widget user interface
        """
        row=0
        col=0
        dataFileLabel=QLabel('Data file')
        self.layout.addWidget(dataFileLabel,row,col)
        col+=1
        self.dataFileLineEdit=QLineEdit(self.dataFile)
        self.layout.addWidget(self.dataFileLineEdit,row,col,1,2)
        col+=2
        self.openDataPushButton=QPushButton('Select')
        self.openDataPushButton.clicked.connect(self.openDataFiles)
        self.layout.addWidget(self.openDataPushButton,row,col)
        col+=1
        self.reducePushButton=QPushButton('Reduce data')
        self.reducePushButton.clicked.connect(self.reduce_multiple)
        self.layout.addWidget(self.reducePushButton,row,col,1,1)
        
        row+=1
        col=0
        darkFileLabel=QLabel('Dark file')
        self.layout.addWidget(darkFileLabel,row,col)
        col+=1
        self.darkFileLineEdit=QLineEdit(self.darkFile)
        self.layout.addWidget(self.darkFileLineEdit,row,col,1,2)
        col+=2
        self.openDarkPushButton=QPushButton('Select')
        self.openDarkPushButton.clicked.connect(self.openDarkFile)
        self.layout.addWidget(self.openDarkPushButton,row,col)
        col+=1
        self.darkCheckBox=QCheckBox('Dark Correction')
        self.layout.addWidget(self.darkCheckBox,row,col)
        
        row+=1
        col=0
        poniFileLabel=QLabel('Calibration file')
        self.layout.addWidget(poniFileLabel,row,col)
        col+=1
        self.poniFileLineEdit=QLineEdit(self.poniFile)
        self.layout.addWidget(self.poniFileLineEdit,row,col,1,2)
        col+=2
        self.openPoniPushButton=QPushButton('Select')
        self.openPoniPushButton.clicked.connect(lambda x: self.openPoniFile(file=None))
        self.layout.addWidget(self.openPoniPushButton,row,col)
        col+=1
        self.calibratePushButton=QPushButton('Calibrate')
        self.calibratePushButton.clicked.connect(self.calibrate)
        self.layout.addWidget(self.calibratePushButton,row,col)
        
        row+=1
        col=0
        maskFileLabel=QLabel('Mask file')
        self.layout.addWidget(maskFileLabel,row,col)
        col+=1
        self.maskFileLineEdit=QLineEdit(self.maskFile)
        self.maskFileLineEdit.returnPressed.connect(self.maskFileChanged)
        self.layout.addWidget(self.maskFileLineEdit,row,col,1,2)
        col+=2
        self.openMaskPushButton=QPushButton('Select')
        self.openMaskPushButton.clicked.connect(lambda x: self.openMaskFile(file=None))
        self.layout.addWidget(self.openMaskPushButton,row,col)
        col+=1
        self.createMaskPushButton=QPushButton('Create mask')
        self.createMaskPushButton.clicked.connect(self.createMask)
        self.layout.addWidget(self.createMaskPushButton,row,col)
        
        
        row+=1
        col=0
        extractedFolderLabel=QLabel('Extracted folder')
        self.layout.addWidget(extractedFolderLabel,row,col)
        col+=1
        self.extractedFolderLineEdit=QLineEdit()
        self.layout.addWidget(self.extractedFolderLineEdit,row,col,1,2)
        col+=2
        self.extractedFolderPushButton=QPushButton('Select')
        self.extractedFolderPushButton.clicked.connect(self.openFolder)
        self.layout.addWidget(self.extractedFolderPushButton,row,col)
        
        row+=1
        col=0
        radialPointsLabel=QLabel('Radial Points')
        self.layout.addWidget(radialPointsLabel,row,col)
        col+=1
        self.radialPointsLineEdit=QLineEdit(str(self.npt))
        self.radialPointsLineEdit.returnPressed.connect(self.nptChanged)
        self.layout.addWidget(self.radialPointsLineEdit,row,col)
        col+=1
        azimuthRangeLabel=QLabel('Azimuthal Range (min:max)')
        self.layout.addWidget(azimuthRangeLabel,row,col)
        col+=1
        self.azimuthRangeLineEdit=QLineEdit('%.2f:%.2f'%(self.azimuthRange[0],self.azimuthRange[1]))
        self.azimuthRangeLineEdit.returnPressed.connect(self.azimuthRangeChanged)
        self.layout.addWidget(self.azimuthRangeLineEdit,row,col)
        col+=1
        self.transCorrCheckBox=QCheckBox('Transmission Correction')
        self.transCorrCheckBox.setTristate(False)
        self.transCorrCheckBox.setChecked(self.transmission_corr)
        self.layout.addWidget(self.transCorrCheckBox)
        
        
        row+=1
        col=0
        progressLabel=QLabel('Status')
        self.layout.addWidget(progressLabel,row,col,1,1)
        col+=1
        self.progressBar=QProgressBar()
        self.layout.addWidget(self.progressBar,row,col,1,1)
        col+=1
        self.statusLabel=QLabel('Idle')
        self.layout.addWidget(self.statusLabel,row,col,1,1)
        col+=1
        normLabel=QLabel('Normalized by')
        self.normComboBox=QComboBox()
        self.normComboBox.addItems(['BSDiode','Image sum','Monitor'])
        self.layout.addWidget(normLabel,row,col,1,1)
        col+=1
        self.layout.addWidget(self.normComboBox,row,col,1,1)
        
        row+=1
        col=0
        self.tabWidget=QTabWidget(self)
        self.layout.addWidget(self.tabWidget,row,col,20,5)
        self.imageWidget=Image_Widget(zeros((100,100)))
        imgNumberLabel=QLabel('Image number')
        self.imgNumberSpinBox=QSpinBox()
        self.imgNumberSpinBox.setSingleStep(1)
        self.imageWidget.imageLayout.addWidget(imgNumberLabel,row=2,col=1)
        self.imageWidget.imageLayout.addWidget(self.imgNumberSpinBox,row=2,col=2)
        self.imageView=self.imageWidget.imageView.getView()
        self.plotWidget=PlotWidget()
        self.plotWidget.setXLabel('Q, &#8491;<sup>-1</sup>',fontsize=5)
        self.plotWidget.setYLabel('Intensity',fontsize=5)
        self.tabWidget.addTab(self.plotWidget,'Reduced 1D-data')
        self.tabWidget.addTab(self.imageWidget,'Masked 2D-data')
       
        
        
    def createMask(self):
        """
        Opens a mask-widget to create mask file
        """
        fname=str(QFileDialog.getOpenFileName(self,'Select an image file', directory=self.curDir,filter='Image file (*.edf *.tif)')[0])
        if fname is not None or fname!='':
            img=fb.open(fname).data
            self.maskWidget=MaskWidget(img)
            self.maskWidget.saveMaskPushButton.clicked.disconnect()
            self.maskWidget.saveMaskPushButton.clicked.connect(self.save_mask)
            self.maskWidget.show()
        else:
            QMessageBox.warning(self,'File error','Please import a data file first for creating the mask',QMessageBox.Ok)
            
    def maskFileChanged(self):
        """
        Changes the mask file
        """
        maskFile=str(self.maskFileLineEdit.text())
        if str(maskFile)=='':
            self.maskFile=None
        elif os.path.exists(maskFile):
            self.maskFile=maskFile
        else:
            self.maskFile=None
            
    def save_mask(self):
        """
        Saves the entire mask combining all the shape ROIs
        """
        fname=str(QFileDialog.getSaveFileName(filter='Mask Files (*.msk)')[0])
        name,extn=os.path.splitext(fname)
        if extn=='':
            fname=name+'.msk'
        elif extn!='.msk':
            QMessageBox.warning(self,'File extension error','Please donot provide file extension other than ".msk". Thank you!')
            return
        else:
            tmpfile=fb.edfimage.EdfImage(data=self.maskWidget.full_mask_data.T,header=None)
            tmpfile.save(fname)
            self.maskFile=fname
            self.maskFileLineEdit.setText(self.maskFile)
            
    def calibrate(self):
        """
        Opens a calibartion widget to create calibration file
        """
        fname=str(QFileDialog.getOpenFileName(self,'Select calibration image',directory=self.curDir, filter='Calibration image (*.edf *.tif)')[0])
        if fname is not None:
            img=fb.open(fname).data
            pixel1=79.0
            pixel2=79.0
            self.calWidget=CalibrationWidget(img,pixel1,pixel2)
            self.calWidget.saveCalibrationPushButton.clicked.disconnect()
            self.calWidget.saveCalibrationPushButton.clicked.connect(self.save_calibration)
            self.calWidget.show()
        else:
            QMessageBox.warning(self,'File error','Please import a data file first for creating the calibration file',QMessageBox.Ok)
            
    def save_calibration(self):
        fname=str(QFileDialog.getSaveFileName(self,'Calibration file',directory=self.curDir,filter='Clibration files (*.poni)')[0])
        tfname=os.path.splitext(fname)[0]+'.poni'
        self.calWidget.applyPyFAI()
        self.calWidget.geo.save(tfname)      
        self.poniFile=tfname
        self.poniFileLineEdit.setText(self.poniFile)
        
        
    def openPoniFile(self,file=None):
        """
        Select and imports the calibration file
        """
        if file is None:
            self.poniFile=QFileDialog.getOpenFileName(self,'Select calibration file',directory=self.curDir,filter='Calibration file (*.poni)')[0]
            self.poniFileLineEdit.setText(self.poniFile)
        else:
            self.poniFile=file
        if os.path.exists(self.poniFile):
            self.setup_dict['poniFile']=self.poniFile
            json.dump(self.setup_dict,open('./SetupData/reducer_setup.txt','w'))
            fh=open(self.poniFile,'r')
            lines=fh.readlines()
            self.calib_data={}
            for line in lines:
                if line[0]!='#':
                    key,val=line.split(': ')
                    self.calib_data[key]=float(val)
            self.dist=self.calib_data['Distance']
            self.pixel1=self.calib_data['PixelSize1']
            self.pixel2=self.calib_data['PixelSize2']
            self.poni1=self.calib_data['Poni1']
            self.poni2=self.calib_data['Poni2']
            self.rot1=self.calib_data['Rot1']
            self.rot2=self.calib_data['Rot2']
            self.rot3=self.calib_data['Rot3']
            self.wavelength=self.calib_data['Wavelength']
            self.ai=AzimuthalIntegrator(dist=self.dist,poni1=self.poni1,poni2=self.poni2,pixel1=self.pixel1,pixel2=self.pixel2,rot1=self.rot1,rot2=self.rot2,rot3=self.rot3,wavelength=self.wavelength)
            #pos=[self.poni2/self.pixel2,self.poni1/self.pixel1]
            #self.roi=cake(pos,movable=False)
            #self.roi.sigRegionChangeStarted.connect(self.endAngleChanged)
            
            #self.imageView.addItem(self.roi)
        else:
            QMessageBox.warning(self,'File error','The calibration file '+self.poniFile+' doesnot exists.',QMessageBox.Ok)                
        
    def endAngleChanged(self,evt):
        print(evt.pos())
        
        
    def nptChanged(self):
        """
        Changes the number of radial points
        """
        try:
            self.npt=int(self.radialPointsLineEdit.text())
        except:
            QMessageBox.warning(self,'Value error', 'Please input positive integers only.',QMessageBox.Ok)
            
    def azimuthRangeChanged(self):
        """
        Changes the azimuth angular range
        """
        try:
            self.azimuthRange=tuple(map(float, self.azimuthRangeLineEdit.text().split(':')))
        except:
            QMessageBox.warning(self,'Value error','Please input min:max angles in floating point numbers',QMessageBox.Ok)
        
    def openDataFile(self):
        """
        Select and imports one data file
        """
        dataFile=QFileDialog.getOpenFileName(self,'Select data file',directory=self.curDir,filter='Data file (*.edf *.tif)')[0]
        if dataFile!='':
            self.dataFile=dataFile
            self.curDir=os.path.dirname(self.dataFile)
            self.dataFileLineEdit.setText(self.dataFile)
            self.data2d=fb.open(self.dataFile).data
            if self.darkFile is not None:
                self.applyDark()
            if self.maskFile is not None:
                self.applyMask()    
            self.imageWidget.setImage(self.data2d,transpose=True)
            self.tabWidget.setCurrentWidget(self.imageWidget)
            if not self.set_externally:
                self.extractedFolder=os.path.join(self.curDir,'extracted_pyFAI')
                if not os.path.exists(self.extractedFolder):
                    os.makedirs(self.extractedFolder)
                    
    def openDataFiles(self):
        """
        Selects and imports multiple data files
        """
        self.dataFiles=QFileDialog.getOpenFileNames(self,'Select data files', directory=self.curDir,filter='Data files (*.edf *.tif)')[0]
        if len(self.dataFiles)!=0:
            self.imgNumberSpinBox.valueChanged.connect(self.imageChanged)
            self.imgNumberSpinBox.setMinimum(0)
            self.imgNumberSpinBox.setMaximum(len(self.dataFiles)-1)
            self.dataFileLineEdit.setText(str(self.dataFiles))
            self.curDir=os.path.dirname(self.dataFiles[0])
            self.extractedFolder=os.path.join(self.curDir,'extracted_pyFAI')
            if not os.path.exists(self.extractedFolder):
                os.makedirs(self.extractedFolder)
            self.extractedFolderLineEdit.setText(self.extractedFolder)
            self.imgNumberSpinBox.setValue(0)
            self.imageChanged()
            
    def imageChanged(self):
        self.data2d=fb.open(self.dataFiles[self.imgNumberSpinBox.value()]).data
        if self.darkFile is not None:
            self.applyDark()
        if self.maskFile is not None:
            self.applyMask()    
        self.imageWidget.setImage(self.data2d,transpose=True)
            

                  
            
                
    def applyDark(self):
        if not self.dark_corrected and self.darkFile!='':
            self.dark2d=fb.open(self.darkFile).data
            self.data2d=self.data2d-self.dark2d
            self.dark_corrected=True
                
    def applyMask(self):
        self.mask2d=fb.open(self.maskFile).data
        self.data2d=self.data2d*(1+self.mask2d)/2.0
        self.mask_applied=True

    def openDarkFile(self):
        """
        Select and imports the dark file
        """
        self.darkFile=QFileDialog.getOpenFileName(self,'Select dark file',directory=self.curDir,filter='Dark file (*.edf)')[0]
        if self.darkFile!='':
            self.dark_corrected=False
            self.darkFileLineEdit.setText(self.darkFile)
            if self.dataFile is not None:
                self.data2d=fb.open(self.dataFile).data
                self.applyDark()
        
    
    def openMaskFile(self,file=None):
        """
        Select and imports the Mask file
        """
        if file is None:
            self.maskFile=QFileDialog.getOpenFileName(self,'Select mask file',directory=self.curDir,filter='Mask file (*.msk)')[0]
        else:
            self.maskFile=file
        if self.maskFile!='':
            self.mask_applied=False
            if os.path.exists(self.maskFile):
                self.curDir=os.path.dirname(self.maskFile)
                self.maskFileLineEdit.setText(self.maskFile)
                self.setup_dict['maskFile']=self.maskFile
                self.setup_dict['poniFile']=self.poniFile
                json.dump(self.setup_dict,open('./SetupData/reducer_setup.txt','w'))
            else:
                self.openMaskFile(file=None)
            if self.dataFile is not None:
                self.applyMask()
        else:
            self.maskFile=None
            self.maskFileLineEdit.clear()
            
            
        
    def openFolder(self):
        """
        Select the folder to save the reduce data
        """
        self.extractedFolder=QFileDialog.getExistingDirectory(self,'Select extracted directory',directory=self.curDir)
        if self.extractedFolder!='':
            self.extractedFolderLineEdit.setText(self.extractedFolder)
            self.set_externally=True
        
        
    def reduceData(self):
        """
        Reduces the 2d data to 1d data
        """
        print('Iloveu', self.darkFile)
        if (self.dataFile is not None) and (os.path.exists(self.dataFile)):
            if (self.poniFile is not None) and (os.path.exists(self.poniFile)):
#                self.statusLabel.setText('Busy')
#                self.progressBar.setRange(0, 0)
                imageData=fb.open(self.dataFile)
                #self.data2d=imageData.data
                #if self.maskFile is not None:
                #    self.applyMask()    
                #self.imageWidget.setImage(self.data2d,transpose=True)
                #self.tabWidget.setCurrentWidget(self.imageWidget)
                
                self.header=imageData.header
                try:
                    self.ai.set_wavelength(float(self.header['Wavelength'])*1e-10)
                except:
                    self.ai.set_wavelength(self.wavelength)
                print('Iloveu',self.darkFile)
                if os.path.exists(self.dataFile.split('.')[0]+'_dark.edf') and self.darkCheckBox.isChecked():
                    self.darkFile=self.dataFile.split('.')[0]+'_dark.edf'
                    dark=fb.open(self.darkFile)
                    self.darkFileLineEdit.setText(self.darkFile)
                    imageDark=dark.data                                     
                    self.header['BSDiode_corr']=max([1.0,(float(imageData.header['BSDiode'])-float(dark.header['BSDiode']))])
                    self.header['Monitor_corr']=max([1.0,(float(imageData.header['Monitor'])-float(dark.header['Monitor']))])
                    print("Dark File read from existing dark files")                    
                elif self.darkFile is not None and self.darkFile!='' and self.darkCheckBox.isChecked():
                    dark=fb.open(self.darkFile)
                    imageDark=dark.data                                     
                    self.header['BSDiode_corr']=max([1.0,(float(imageData.header['BSDiode'])-float(dark.header['BSDiode']))])
                    self.header['Monitor_corr']=max([1.0,(float(imageData.header['Monitor'])-float(dark.header['Monitor']))])
                    print("Dark File from memory subtracted")                
                else:
                    imageDark=None
                    try:
                        self.header['BSDiode_corr']=float(imageData.header['BSDiode'])
                        self.header['Monitor_corr']=float(imageData.header['Monitor'])
                    except:
                        self.transCorrCheckBox.setCheckState(Qt.Unchecked)
                    print("No dark correction done")
                if self.transCorrCheckBox.isChecked():
                    if str(self.normComboBox.currentText())=='BSDiode':
                        norm_factor=self.header['BSDiode_corr']#/float(self.header['count_time'])
                    elif str(self.normComboBox.currentText())=='Monitor':
                        norm_factor=self.header['Monitor_corr']
                    else:
                        norm_factor=sum(imageData.data)
                else:
                    norm_factor=1.0
                    
                if self.maskFile is not None:
                    imageMask=fb.open(self.maskFile).data
                else:
                    imageMask=None
                print(self.maskFile)
#                QApplication.processEvents()
                #print(self.azimuthRange)
                self.q,self.I,self.Ierr=self.ai.integrate1d(imageData.data,self.npt,error_model='poisson',mask=imageMask,dark=imageDark,unit='q_A^-1',normalization_factor=norm_factor,azimuth_range=self.azimuthRange)
                self.plotWidget.add_data(self.q,self.I,yerr=self.Ierr,name='Reduced data')
                self.plotWidget.setTitle(self.dataFile,fontsize=2)
#                self.progressBar.setRange(0,100)
#                self.progressBar.setValue(100)
#                self.statusLabel.setText('Idle')
#                QApplication.processEvents()
                self.saveData()
                self.tabWidget.setCurrentWidget(self.plotWidget)
            else:
                QMessageBox.warning(self,'Calibration File Error','Data reduction failed because either no calibration file provided or the provided file or path do not exists',QMessageBox.Ok)
                
        else:
            QMessageBox.warning(self,'Data File Error','No data file provided', QMessageBox.Ok)
            
    def reduce_multiple(self):
        """
        Reduce multiple files
        """
        #try:
        i=0
        self.progressBar.setRange(0,len(self.dataFiles))
        self.progressBar.setValue(i)
        self.statusLabel.setText('Busy')
        for file in self.dataFiles:
            self.dataFile=file
            QApplication.processEvents()
            self.reduceData()
            i=i+1
            self.progressBar.setValue(i)
            QApplication.processEvents()
        self.statusLabel.setText('Idle')
        #except:
        #    QMessageBox.warning(self,'File error','No data files to reduce',QMessageBox.Ok)
        
    def saveData(self):
        """
        saves the extracted data into a file
        """
        if not os.path.exists(self.extractedFolder):
            os.makedirs(self.extractedFolder)
        filename=os.path.join(self.extractedFolder,os.path.splitext(os.path.basename(self.dataFile))[0]+'.txt')
        headers='File extracted on '+time.asctime()+'\n'
        headers='Files used for extraction are:\n'
        headers+='Data file: '+self.dataFile+'\n'
        if self.darkFile is not None:
            headers+='Dark file: '+self.darkFile+'\n'
        else:
            headers+='Dark file: None\n'
        headers+='Poni file: '+self.poniFile+'\n'
        if self.maskFile is not None:
            headers+='mask file: '+self.maskFile+'\n'
        else:
            headers+='mask file: None\n'
        for key in self.header.keys():
            headers+=key+'='+str(self.header[key])+'\n'
        headers+='Q (A^-1)\t\tIntensity\t\tIntensity_err'
        data=vstack((self.q,self.I,self.Ierr)).T
        savetxt(filename,data,header=headers,comments='#')
Ejemplo n.º 2
0
class Data_Dialog(QDialog):
    def __init__(self,
                 fname=None,
                 data=None,
                 comment='#',
                 skiprows=0,
                 delimiter=' ',
                 expressions={},
                 autoupdate=False,
                 parent=None,
                 matplotlib=False,
                 plotIndex=None,
                 colors=None):
        QDialog.__init__(self, parent=parent)
        loadUi('UI_Forms/Data_Dialog.ui', self)
        self.colcycler = cycle(['r', 'g', 'b', 'c', 'm', 'y', 'w'])
        self.plotWidget = PlotWidget(parent=self, matplotlib=matplotlib)
        self.plotTab = self.tabWidget.addTab(self.plotWidget, 'Plots')
        self.tabWidget.setCurrentIndex(0)
        self.show()
        self.fileWatcher = QFileSystemWatcher()
        self.fileWatcher.fileChanged.connect(self.fileUpdated)
        self.cwd = None
        self.plotNum = 0
        self.xlabel = []
        self.ylabel = []
        self.oldPlotIndex = {}
        self.oldColors = {}
        self.dataAltered = False
        self.expressions = expressions
        if data is not None:
            self.data = data
            self.autoUpdateCheckBox.setEnabled(False)
        elif fname is not None:
            self.data = self.readData(fname,
                                      comment=comment,
                                      skiprows=skiprows,
                                      delimiter=delimiter)
        else:
            self.data = None
            self.autoUpdateCheckBox.setEnabled(False)
            self.saveDataPushButton.setEnabled(False)
            self.addRowPushButton.setEnabled(False)
            self.removeRowsPushButton.setEnabled(False)
            self.removeColumnPushButton.setEnabled(False)
        if self.data is not None:
            self.setMeta2Table()
            self.setData2Table()
            if plotIndex is None:
                self.addPlots(color=None)
            else:
                self.addMultiPlots(plotIndex=plotIndex, colors=colors)
        self.init_signals()
        self.okPushButton.setAutoDefault(False)
        self.make_default()
        self.setWindowTitle('Data Dialog')
        self.acceptData = True

        #self.setWindowSize((600,400))
        # if self.parentWidget() is not None:
        #     self.addPlotPushButton.setEnabled(False)
        #     self.removePlotPushButton.setEnabled(False)

    def make_default(self):
        self.okPushButton.setAutoDefault(False)
        self.closePushButton.setAutoDefault(False)
        self.openDataFilePushButton.setAutoDefault(False)
        self.saveDataPushButton.setAutoDefault(False)
        self.okPushButton.setDefault(False)
        self.closePushButton.setDefault(False)
        self.openDataFilePushButton.setDefault(False)
        self.saveDataPushButton.setDefault(False)

    def init_signals(self):
        self.closePushButton.clicked.connect(self.closeWidget)
        self.okPushButton.clicked.connect(self.acceptWidget)
        self.openDataFilePushButton.clicked.connect(self.openFile)
        self.autoUpdateCheckBox.stateChanged.connect(self.autoUpdate_ON_OFF)
        self.saveDataPushButton.clicked.connect(self.saveData)
        self.addPlotPushButton.clicked.connect(
            lambda x: self.addPlots(plotIndex=None))
        self.plotSetupTableWidget.cellChanged.connect(self.updatePlotData)
        self.removePlotPushButton.clicked.connect(self.removePlots)

        self.addMetaDataPushButton.clicked.connect(self.addMetaData)
        self.metaDataTableWidget.itemChanged.connect(self.metaDataChanged)
        self.metaDataTableWidget.itemClicked.connect(self.metaDataClicked)
        self.metaDataTableWidget.itemSelectionChanged.connect(
            self.metaDataSelectionChanged)
        self.removeMetaDataPushButton.clicked.connect(self.removeMetaData)

        self.dataTableWidget.itemChanged.connect(self.dataChanged)
        self.editColumnPushButton.clicked.connect(self.editDataColumn)
        self.addColumnPushButton.clicked.connect(
            lambda x: self.addDataColumn(colName='Col_X'))
        self.removeColumnPushButton.clicked.connect(self.removeDataColumn)
        self.removeRowsPushButton.clicked.connect(self.removeDataRows)
        self.dataTableWidget.setSelection
        self.dataTableWidget.horizontalHeader().sortIndicatorChanged.connect(
            self.dataSorted)
        self.addRowPushButton.clicked.connect(self.addDataRow)

    def closeWidget(self):
        self.acceptData = False
        self.reject()

    def acceptWidget(self):
        self.acceptData = True
        self.accept()

    def addMetaData(self):
        """
        Opens a MetaData Dialog and by accepting the dialog inputs the data to the MetaDataTable
        """

        self.metaDialog = MetaData_Dialog()
        if self.metaDialog.exec_():
            name, value = self.metaDialog.parNameLineEdit.text(
            ), self.metaDialog.parValueLineEdit.text()
            if name not in self.data['meta'].keys():
                row = self.metaDataTableWidget.rowCount()
                self.metaDataTableWidget.insertRow(row)
                self.metaDataTableWidget.setItem(row, 0,
                                                 QTableWidgetItem(name))
                self.metaDataTableWidget.setItem(row, 1,
                                                 QTableWidgetItem(value))
                try:
                    self.data['meta'][name] = eval(value)
                except:
                    self.data['meta'][name] = value
            else:
                QMessageBox.warning(
                    self, "Parameter Exists",
                    "The parameter %s already exists in meta data. Please provide a different parameter name"
                    % name, QMessageBox.Ok)
                self.addMetaData()

    def removeMetaData(self):
        """
        Removes the selected Metadata from the table
        """
        self.metaDataTableWidget.itemSelectionChanged.disconnect()
        rows = list(
            set([
                item.row()
                for item in self.metaDataTableWidget.selectedItems()
            ]))
        for row in rows:
            key = self.metaDataTableWidget.item(row, 0).text()
            if key != 'col_names':
                del self.data['meta'][key]
                self.metaDataTableWidget.removeRow(row)
            else:
                QMessageBox.warning(self, 'Restricted Parameter',
                                    'You cannot delete the parameter %s' % key,
                                    QMessageBox.Ok)
        self.metaDataTableWidget.itemSelectionChanged.connect(
            self.metaDataSelectionChanged)

    def metaDataChanged(self, item):
        """
        Updates the value metadata as per the changes in the metaDataTableWidget
        """
        row = item.row()
        col = item.column()
        key = self.metaDataTableWidget.item(row, 0).text()
        if col != 0:
            try:
                self.data['meta'][key] = eval(item.text())
            except:
                self.data['meta'][key] = item.text()
            if self.metaDataTableWidget.item(
                    row, 0).text() == 'col_names' and len(
                        self.data['meta'][key]) != len(
                            self.data['data'].columns):
                QMessageBox.warning(
                    self, 'Restricted Parameter',
                    'Please provide same length of col_names as the number of the column of the data'
                )
                self.data['meta'][key] = eval(self.oldMetaText)
                item.setText(self.oldMetaText)
            elif self.metaDataTableWidget.item(
                    row, 0).text() == 'col_names' and len(
                        self.data['meta'][key]) == len(
                            self.data['data'].columns):
                self.data['data'].columns = self.data['meta'][key]
                self.dataTableWidget.setHorizontalHeaderLabels(
                    self.data['meta'][key])
                self.dataAltered = True
                self.resetPlotSetup()
                self.dataAltered = False
        else:
            if self.oldMetaText == 'col_names':
                QMessageBox.warning(
                    self, 'Restricted Parameter',
                    'col_names is a restricted parameter the name of which cannot be changed',
                    QMessageBox.Ok)
                item.setText(self.oldMetaText)
            elif item.text() not in self.data['meta'].keys():
                self.data['meta'][key] = self.data['meta'][self.oldMetaText]
                del self.data['meta'][self.oldMetaText]
            else:
                self.metaDataTableWidget.itemChanged.disconnect()
                QMessageBox.warning(
                    self, "Parameter Exists",
                    "The parameter %s already exists in meta data. Please provide a different parameter name"
                    % item.text(), QMessageBox.Ok)
                item.setText(self.oldMetaText)
                self.metaDataTableWidget.itemChanged.connect(
                    self.metaDataChanged)
        self.oldMetaText = item.text()

    def metaDataClicked(self, item):
        self.oldMetaText = item.text()

    def metaDataSelectionChanged(self):
        self.oldMetaText = self.metaDataTableWidget.selectedItems()[0].text()

    def dataChanged(self, item):
        row, col = item.row(), item.column()
        key = self.dataTableWidget.horizontalHeaderItem(col).text()
        self.data['data'][key][row] = eval(item.text())
        self.dataAltered = True
        self.resetPlotSetup()
        self.dataAltered = False

    def dataSorted(self):
        """
        Updates the data after sorting the DataTableWidget
        """
        self.getDataFromTable()
        self.dataAltered = True
        self.resetPlotSetup()
        self.dataAltered = False

    def addDataRow(self):
        try:
            self.dataTableWidget.itemChanged.disconnect()
        except:
            pass
        row = self.dataTableWidget.currentRow()
        self.dataTableWidget.insertRow(row + 1)
        for col in range(self.dataTableWidget.columnCount()):
            self.dataTableWidget.setItem(
                row + 1, col,
                QCustomTableWidgetItem(
                    float(self.dataTableWidget.item(row, col).text())))
        self.getDataFromTable()
        self.dataAltered = True
        self.resetPlotSetup()
        self.dataAltered = False
        self.dataTableWidget.itemChanged.connect(self.dataChanged)

    def editDataColumn(self):
        if self.data is not None:
            items = self.dataTableWidget.selectedItems()
            selCols = list([item.column() for item in items])
            if len(selCols) == 1:
                colName = self.dataTableWidget.horizontalHeaderItem(
                    selCols[0]).text()
                self.addDataColumn(colName=colName,
                                   expr=self.expressions[colName],
                                   new=False)
            else:
                QMessageBox.warning(
                    self, 'Column Selection Error',
                    'Please select only elements of a single column.',
                    QMessageBox.Ok)
        else:
            QMessageBox.warning(self, 'Data error', 'There is no data',
                                QMessageBox.Ok)

    def addDataColumn(self, colName='Col_X', expr=None, new=True):
        if self.data is not None:
            row, col = self.data['data'].shape
            self.insertColDialog = InsertCol_Dialog(colName=colName,
                                                    minCounter=1,
                                                    maxCounter=row,
                                                    expr=expr)
            if self.insertColDialog.exec_():
                imin = eval(self.insertColDialog.minCounterLineEdit.text())
                imax = eval(self.insertColDialog.maxCounterLineEdit.text())
                i = arange(imin, imax + 1)
                colname = self.insertColDialog.colNameLineEdit.text()
                data = copy.copy(self.data)
                if new:
                    if colname not in self.data['data'].columns:
                        try:
                            self.data['data'][colname] = eval(expr)
                        except:
                            try:
                                expr = self.insertColDialog.colExprTextEdit.toPlainText(
                                )
                                cexpr = expr.replace('col',
                                                     "self.data['data']")
                                self.data['data'][colname] = eval(cexpr)
                                self.data['meta']['col_names'].append(colname)
                            except:
                                QMessageBox.warning(
                                    self, 'Column Error',
                                    'Please check the expression.\n The expression should be in this format:\n col[column_name]*5',
                                    QMessageBox.Ok)
                                self.addDataColumn(colName='Col_X', expr=expr)
                        self.expressions[colname] = expr
                        self.setData2Table()
                        self.setMeta2Table()
                        self.dataAltered = True
                        self.resetPlotSetup()
                        self.dataAltered = False
                    else:
                        QMessageBox.warning(
                            self, 'Column Name Error',
                            'Please choose different column name than the exisiting ones',
                            QMessageBox.Ok)
                        self.addDataColumn(colName='Col_X', expr=expr)
                else:
                    try:
                        self.data['data'][colname] = eval(expr)
                    except:
                        try:
                            expr = self.insertColDialog.colExprTextEdit.toPlainText(
                            )
                            cexpr = expr.replace('col', "self.data['data\']")
                            self.data['data'][colname] = eval(cexpr)
                        except:
                            QMessageBox.warning(
                                self, 'Column Error',
                                'Please check the expression.\n The expression should be in this format:\n col[column_name]*5',
                                QMessageBox.Ok)
                            self.addDataColumn(colName='Col_X', expr=expr)
                        self.expressions[colname] = expr
                        self.setData2Table()
                        self.setMeta2Table()
                        self.dataAltered = True
                        self.resetPlotSetup()
                        self.dataAltered = False
        else:
            self.data = {}
            self.insertColDialog = InsertCol_Dialog(colName=colName,
                                                    minCounter=1,
                                                    maxCounter=100,
                                                    expr=expr)
            if self.insertColDialog.exec_():
                imin = eval(self.insertColDialog.minCounterLineEdit.text())
                imax = eval(self.insertColDialog.maxCounterLineEdit.text())
                i = arange(imin, imax + 1)
                colname = self.insertColDialog.colNameLineEdit.text()
                expr = self.insertColDialog.colExprTextEdit.toPlainText()
                expr = expr.replace('col.', "self.data['data']")
                try:
                    self.data['data'] = pd.DataFrame(eval(expr),
                                                     columns=[colname])
                    self.data['meta'] = {}
                    self.data['meta']['col_names'] = [colname]
                    self.setData2Table()
                    self.setMeta2Table()
                    self.dataAltered = True
                    self.resetPlotSetup()
                    self.dataAltered = False
                    self.saveDataPushButton.setEnabled(True)
                    self.addRowPushButton.setEnabled(True)
                    self.removeRowsPushButton.setEnabled(True)
                    self.removeColumnPushButton.setEnabled(True)
                    self.expressions[colname] = expr
                except:
                    QMessageBox.warning(
                        self, 'Column Error',
                        'Please check the expression.\n The expression should be in this format:\n col.column_name*5',
                        QMessageBox.Ok)
                    self.data = None
                    self.addDataColumn(colName='Col_X', expr=expr)

    def removeDataColumn(self):
        """
        Removes selected columns from dataTableWidget
        """
        colIndexes = [
            index.column() for index in
            self.dataTableWidget.selectionModel().selectedColumns()
        ]
        colIndexes.sort(reverse=True)
        if self.dataTableWidget.columnCount() - len(
                colIndexes) >= 2 or self.plotSetupTableWidget.rowCount() == 0:
            for index in colIndexes:
                colname = self.data['meta']['col_names'][index]
                self.data['meta']['col_names'].pop(index)
                del self.expressions[colname]
                self.dataTableWidget.removeColumn(index)
            if self.dataTableWidget.columnCount() != 0:
                self.getDataFromTable()
                self.setMeta2Table()
                self.dataAltered = True
                self.resetPlotSetup()
                self.dataAltered = False
            else:
                self.data['data'] = None
                self.dataTableWidget.clear()
                #self.metaDataTableWidget.clear()
                self.autoUpdateCheckBox.setEnabled(False)
                self.saveDataPushButton.setEnabled(False)
                self.addRowPushButton.setEnabled(False)
                self.removeRowsPushButton.setEnabled(False)
                self.removeColumnPushButton.setEnabled(False)
        else:
            QMessageBox.warning(
                self, 'Remove Error',
                'Cannot remove these many columns because Data Dialog needs to have atleast two columns',
                QMessageBox.Ok)

    def removeDataRows(self):
        rowIndexes = [
            index.row()
            for index in self.dataTableWidget.selectionModel().selectedRows()
        ]
        rowIndexes.sort(reverse=True)
        if len(rowIndexes) > 0:
            ans = QMessageBox.question(
                self, 'Confirmation',
                'Are you sure of removing the selected rows?', QMessageBox.Yes,
                QMessageBox.No)
            if ans == QMessageBox.Yes:
                for i in rowIndexes:
                    self.dataTableWidget.removeRow(i)
                self.getDataFromTable()
                self.dataAltered = True
                self.resetPlotSetup()
                self.dataAltered = False

    def setMeta2Table(self):
        """
        Populates the metaDataTable widget with metadata available from the data
        """
        try:
            self.metaDataTableWidget.itemChanged.disconnect()
            self.metaDataTableWidget.itemSelectionChanged.disconnect()
        except:
            pass
        self.metaDataTableWidget.clear()
        self.metaDataTableWidget.setColumnCount(2)
        self.metaDataTableWidget.setRowCount(len(self.data['meta'].keys()))
        for num, key in enumerate(self.data['meta'].keys()):
            self.metaDataTableWidget.setItem(num, 0, QTableWidgetItem(key))
            self.metaDataTableWidget.setItem(
                num, 1, QTableWidgetItem(str(self.data['meta'][key])))
        if 'col_names' not in self.data['meta'].keys():
            self.data['meta']['col_names'] = self.data['data'].columns.tolist()
            self.metaDataTableWidget.insertRow(
                self.metaDataTableWidget.rowCount())
            self.metaDataTableWidget.setItem(num + 1, 0,
                                             QTableWidgetItem('col_names'))
            self.metaDataTableWidget.setItem(
                num + 1, 1,
                QTableWidgetItem(str(self.data['meta']['col_names'])))
        self.metaDataTableWidget.setHorizontalHeaderLabels(
            ['Parameter', 'Value'])
        self.metaDataTableWidget.itemChanged.connect(self.metaDataChanged)
        self.metaDataTableWidget.itemSelectionChanged.connect(
            self.metaDataSelectionChanged)

    def getMetaFromTable(self):
        self.data['meta'] = {}
        for i in range(self.metaDataTableWidget.rowCount()):
            try:
                self.data['meta'][self.metaDataTableWidget.item(
                    i, 0).text()] = eval(
                        self.metaDataTableWidget.item(i, 1).text())
            except:
                self.data['meta'][self.metaDataTableWidget.item(
                    i, 0).text()] = self.metaDataTableWidget.item(i, 1).text()

    def setData2Table(self):
        """
        Populates the dataTableWidget with data available from data
        """
        try:
            self.dataTableWidget.itemChanged.disconnect()
        except:
            pass
        self.dataTableWidget.clear()
        self.dataTableWidget.setColumnCount(len(self.data['data'].columns))
        self.dataTableWidget.setRowCount(len(self.data['data'].index))
        for j, colname in enumerate(self.data['data'].columns):
            if colname not in self.expressions.keys():
                self.expressions[colname] = "col['%s']" % colname
            for i in range(len(self.data['data'].index)):
                #self.dataTableWidget.setItem(i,j,QTableWidgetItem(str(self.data['data'][colname][i])))
                self.dataTableWidget.setItem(
                    i, j,
                    QCustomTableWidgetItem(self.data['data'][colname][i]))
        self.dataTableWidget.setHorizontalHeaderLabels(
            self.data['data'].columns.values.tolist())
        self.dataTableWidget.itemChanged.connect(self.dataChanged)

    def getDataFromTable(self):
        self.data['data'] = pd.DataFrame()
        for col in range(self.dataTableWidget.columnCount()):
            label = self.dataTableWidget.horizontalHeaderItem(col).text()
            self.data['data'][label] = array([
                float(self.dataTableWidget.item(i, col).text())
                for i in range(self.dataTableWidget.rowCount())
            ])

    def readData(self, fname, skiprows=0, comment='#', delimiter=' '):
        """
        Read data from a file and put it in dictionary structure with keys 'meta' and 'data' and the data would look like the following
        data={'meta':meta_dictionary,'data'=pandas_dataframe}
        """
        if os.path.exists(os.path.abspath(fname)):
            self.data = {}
            self.fname = fname
            self.dataFileLineEdit.setText(self.fname)
            self.cwd = os.path.dirname(self.fname)
            fh = open(os.path.abspath(self.fname), 'r')
            lines = fh.readlines()
            fh.close()
            self.data['meta'] = {}
            for line in lines[skiprows:]:
                if line[0] == comment:
                    try:
                        key, value = line[1:].strip().split('=')
                        try:
                            self.data['meta'][key] = eval(
                                value
                            )  # When the value is either valid number, lists, arrays, dictionaries
                        except:
                            self.data['meta'][
                                key] = value  # When the value is just a string
                    except:
                        pass
                else:
                    if '\t' in line:
                        delimiter = '\t'
                    elif ',' in line:
                        delimiter = ','
                    elif ' ' in line:
                        delimiter = ' '
                    break
            if 'col_names' in self.data['meta'].keys():
                self.data['data'] = pd.read_csv(
                    self.fname,
                    comment=comment,
                    names=self.data['meta']['col_names'],
                    header=None,
                    sep=delimiter)
                if not all(self.data['data'].isnull().values):
                    self.data['data'] = pd.DataFrame(
                        loadtxt(self.fname, skiprows=skiprows),
                        columns=self.data['meta']['col_names'])
            else:
                self.data['data'] = pd.read_csv(self.fname,
                                                comment=comment,
                                                header=None,
                                                sep=delimiter)
                if not all(self.data['data'].isnull()):
                    self.data['data'] = pd.DataFrame(
                        loadtxt(self.fname, skiprows=skiprows))
                self.data['data'].columns = [
                    'Col_%d' % i
                    for i in self.data['data'].columns.values.tolist()
                ]
                self.data['meta']['col_names'] = self.data[
                    'data'].columns.values.tolist()
            self.autoUpdate_ON_OFF()
            self.autoUpdateCheckBox.setEnabled(True)
            self.saveDataPushButton.setEnabled(True)
            self.addRowPushButton.setEnabled(True)
            self.removeRowsPushButton.setEnabled(True)
            self.removeColumnPushButton.setEnabled(True)
            return self.data
        else:
            QMessageBox.warning(self, 'File Error', 'The file doesnot exists!')
            return None

    def fileUpdated(self, fname):
        QTest.qWait(1000)
        self.readData(fname=fname)
        if self.data is not None:
            self.setMeta2Table()
            self.setData2Table()
            self.dataAltered = True
            self.resetPlotSetup()
            self.dataAltered = False

    def autoUpdate_ON_OFF(self):
        files = self.fileWatcher.files()
        if len(files) != 0:
            self.fileWatcher.removePaths(files)
        if self.autoUpdateCheckBox.isChecked():
            self.fileWatcher.addPath(self.fname)

    def saveData(self):
        """
        Save data to a file
        """
        fname = QFileDialog.getSaveFileName(self,
                                            'Save file as',
                                            self.cwd,
                                            filter='*.*')[0]
        if fname != '':
            ext = os.path.splitext(fname)[1]
            if ext == '':
                ext = '.txt'
                fname = fname + ext
            header = 'File saved on %s\n' % time.asctime()
            for key in self.data['meta'].keys():
                header = header + '%s=%s\n' % (key, str(
                    self.data['meta'][key]))
            if 'col_names' not in self.data['meta'].keys():
                header = header + 'col_names=%s\n' % str(
                    self.data['data'].columns.tolist())
            savetxt(fname,
                    self.data['data'].values,
                    header=header,
                    comments='#')

    def openFile(self):
        """
        Opens a openFileDialog to open a data file
        """
        if self.cwd is not None:
            fname = QFileDialog.getOpenFileName(self,
                                                'Select a data file to open',
                                                directory=self.cwd,
                                                filter='*.*')[0]
        else:
            fname = QFileDialog.getOpenFileName(self,
                                                'Select a data file to open',
                                                directory='',
                                                filter='*.*')[0]
        if fname != '':
            self.data = self.readData(fname=fname)
            if self.data is not None:
                self.setMeta2Table()
                self.setData2Table()
                self.dataAltered = True
                self.resetPlotSetup()
                self.dataAltered = False

    def resetPlotSetup(self):
        try:
            self.plotSetupTableWidget.cellChanged.disconnect()
        except:
            pass
        columns = self.data['data'].columns.tolist()
        self.xlabel = []
        self.ylabel = []
        for row in range(self.plotSetupTableWidget.rowCount()):
            for i in range(1, 3):
                self.plotSetupTableWidget.cellWidget(
                    row, i).currentIndexChanged.disconnect()
                self.plotSetupTableWidget.cellWidget(row, i).clear()
                self.plotSetupTableWidget.cellWidget(row, i).addItems(columns)
                self.plotSetupTableWidget.cellWidget(row,
                                                     i).setCurrentIndex(i - 1)
                self.plotSetupTableWidget.cellWidget(
                    row, i).currentIndexChanged.connect(self.updateCellData)
            self.xlabel.append(
                '[%s]' %
                self.plotSetupTableWidget.cellWidget(row, 1).currentText())
            self.ylabel.append(
                '[%s]' %
                self.plotSetupTableWidget.cellWidget(row, 2).currentText())
            self.plotSetupTableWidget.cellWidget(
                row, 3).currentIndexChanged.disconnect()
            self.plotSetupTableWidget.cellWidget(row, 3).clear()
            self.plotSetupTableWidget.cellWidget(row, 3).addItems(['None'] +
                                                                  columns)
            self.plotSetupTableWidget.cellWidget(row, 3).setCurrentIndex(0)
            self.plotSetupTableWidget.cellWidget(
                row, 3).currentIndexChanged.connect(self.updateCellData)
            self.plotSetupTableWidget.setCurrentCell(row, 3)
            color = self.plotSetupTableWidget.cellWidget(row, 4).color()
            self.plotSetupTableWidget.setCellWidget(
                row, 4, pg.ColorButton(color=color))
            self.plotSetupTableWidget.cellWidget(
                row, 4).sigColorChanging.connect(self.updateCellData)
            self.plotSetupTableWidget.cellWidget(
                row, 4).sigColorChanged.connect(self.updateCellData)
            self.updatePlotData(row, i)
        self.plotSetupTableWidget.cellChanged.connect(self.updatePlotData)

    def addMultiPlots(self, plotIndex=None, colors=None):
        for key in plotIndex.keys():
            pi = plotIndex[key]
            if colors is None:
                color = next(self.colcycler
                             )  #array([random.randint(200, high=255),0,0])
                print(color)
            else:
                color = colors[key]
            self.addPlots(plotIndex=pi, color=color)

    def addPlots(self, plotIndex=None, color=None):
        #self.plotSetupTableWidget.clear()
        # if self.parentWidget() is None or self.plotSetupTableWidget.rowCount()==0:
        try:
            self.plotSetupTableWidget.cellChanged.disconnect()
        except:
            pass
        columns = self.data['data'].columns.tolist()
        if len(columns) >= 2:
            self.plotSetupTableWidget.insertRow(
                self.plotSetupTableWidget.rowCount())
            row = self.plotSetupTableWidget.rowCount() - 1
            self.plotSetupTableWidget.setItem(
                row, 0, QTableWidgetItem('Data_%d' % self.plotNum))
            for i in range(1, 3):
                self.plotSetupTableWidget.setCellWidget(row, i, QComboBox())
                self.plotSetupTableWidget.cellWidget(row, i).addItems(columns)
                if plotIndex is not None:
                    self.plotSetupTableWidget.cellWidget(
                        row, i).setCurrentIndex(plotIndex[i - 1])
                else:
                    self.plotSetupTableWidget.cellWidget(
                        row, i).setCurrentIndex(i - 1)
                self.plotSetupTableWidget.cellWidget(
                    row, i).currentIndexChanged.connect(self.updateCellData)
            self.xlabel.append(
                '[%s]' %
                self.plotSetupTableWidget.cellWidget(row, 1).currentText())
            self.ylabel.append(
                '[%s]' %
                self.plotSetupTableWidget.cellWidget(row, 2).currentText())
            self.plotSetupTableWidget.setCellWidget(row, 3, QComboBox())
            self.plotSetupTableWidget.cellWidget(row, 3).addItems(['None'] +
                                                                  columns)
            if color is None:
                color = next(self.colcycler
                             )  #array([random.randint(200, high=255),0,0])
            self.plotSetupTableWidget.setCellWidget(
                row, 4, pg.ColorButton(color=color))
            self.plotSetupTableWidget.cellWidget(
                row, 4).sigColorChanging.connect(self.updateCellData)
            self.plotSetupTableWidget.cellWidget(
                row, 4).sigColorChanged.connect(self.updateCellData)
            if plotIndex is not None:
                self.plotSetupTableWidget.cellWidget(row, 3).setCurrentIndex(
                    plotIndex[-1])
            else:
                # try:
                #     self.plotSetupTableWidget.cellWidget(row,3).setCurrentIndex(2)
                # except:
                #
                self.plotSetupTableWidget.cellWidget(row, 3).setCurrentIndex(0)
            self.plotSetupTableWidget.cellWidget(
                row, 3).currentIndexChanged.connect(self.updateCellData)
            self.plotSetupTableWidget.setCurrentCell(row, 3)
            self.updatePlotData(row, 3)
            self.plotNum += 1
        else:
            QMessageBox.warning(
                self, 'Data file error',
                'The data file do not have two or more columns to be plotted.',
                QMessageBox.Ok)
        self.plotSetupTableWidget.cellChanged.connect(self.updatePlotData)
        # else:
        #     QMessageBox.warning(self,'Warning','As the Data Dialog is used within another widget you cannot add more plots',QMessageBox.Ok)

    def removePlots(self):
        """
        Removes data for PlotSetup
        """
        try:
            self.plotSetupTableWidget.cellChanged.disconnect()
        except:
            pass
        rowIndexes = self.plotSetupTableWidget.selectionModel().selectedRows()
        selectedRows = [index.row() for index in rowIndexes]
        selectedRows.sort(reverse=True)
        if self.parentWidget() is None:
            for row in selectedRows:
                name = self.plotSetupTableWidget.item(row, 0).text()
                self.plotWidget.remove_data([name])
                self.plotSetupTableWidget.removeRow(row)
        else:
            if self.plotSetupTableWidget.rowCount() - len(rowIndexes) >= 1:
                for row in selectedRows:
                    name = self.plotSetupTableWidget.item(row, 0).text()
                    self.plotWidget.remove_data([name])
                    self.plotSetupTableWidget.removeRow(row)
            else:
                QMessageBox.warning(
                    self, 'Warning',
                    'Cannot remove single plots from Data Dialog because the Data Dialog is used within another widget',
                    QMessageBox.Ok)
        self.updatePlot()
        self.plotSetupTableWidget.cellChanged.connect(self.updatePlotData)

    def updatePlotData(self, row, col):
        #row=self.plotSetupTableWidget.currentRow()
        name = self.plotSetupTableWidget.item(row, 0).text()
        if self.dataAltered:
            for i in range(1, 4):
                try:
                    self.plotSetupTableWidget.cellWidget(
                        row, i).setCurrentIndex(self.oldPlotIndex[name][i - 1])
                except:
                    pass
        xcol, ycol, yerrcol = [
            self.plotSetupTableWidget.cellWidget(row, i).currentText()
            for i in range(1, 4)
        ]
        #ycol=self.plotSetupTableWidget.cellWidget(row,2).currentText()
        #yerrcol=self.plotSetupTableWidget.cellWidget(row,3).currentText()
        if yerrcol != 'None':
            if ycol == 'fit':
                self.plotWidget.add_data(
                    self.data['data'][xcol].values,
                    self.data['data'][ycol].values,
                    yerr=self.data['data'][yerrcol].values,
                    name=name,
                    fit=True,
                    color=self.plotSetupTableWidget.cellWidget(row, 4).color())
            else:
                self.plotWidget.add_data(
                    self.data['data'][xcol].values,
                    self.data['data'][ycol].values,
                    yerr=self.data['data'][yerrcol].values,
                    name=name,
                    fit=False,
                    color=self.plotSetupTableWidget.cellWidget(row, 4).color())
        else:
            if ycol == 'fit':
                self.plotWidget.add_data(
                    self.data['data'][xcol].values,
                    self.data['data'][ycol].values,
                    name=name,
                    fit=True,
                    color=self.plotSetupTableWidget.cellWidget(row, 4).color())
            else:
                self.plotWidget.add_data(
                    self.data['data'][xcol].values,
                    self.data['data'][ycol].values,
                    name=name,
                    fit=False,
                    color=self.plotSetupTableWidget.cellWidget(row, 4).color())
        self.xlabel[row] = '[%s]' % self.plotSetupTableWidget.cellWidget(
            row, 1).currentText()
        self.ylabel[row] = '[%s]' % self.plotSetupTableWidget.cellWidget(
            row, 2).currentText()
        self.updatePlot()
        self.oldPlotIndex[name] = [
            self.plotSetupTableWidget.cellWidget(row, i).currentIndex()
            for i in range(1, 4)
        ]

    def updateCellData(self, index):
        row = self.plotSetupTableWidget.indexAt(self.sender().pos()).row()
        self.updatePlotData(row, index)

    def updatePlot(self):
        self.make_default()
        names = [
            self.plotSetupTableWidget.item(i, 0).text()
            for i in range(self.plotSetupTableWidget.rowCount())
        ]
        #self.plotColIndex=[self.plotSetupTableWidget.cellWidget(0,i).currentIndex() for i in range(1,4)]
        self.plotColIndex = {}
        self.externalData = {}
        self.plotColors = {}
        for i in range(self.plotSetupTableWidget.rowCount()):
            key = self.plotSetupTableWidget.cellWidget(i, 2).currentText()
            self.plotColIndex[key] = [
                self.plotSetupTableWidget.cellWidget(i, j).currentIndex()
                for j in range(1, 4)
            ]
            self.plotColors[key] = self.plotSetupTableWidget.cellWidget(
                i, 4).color()
            self.externalData[key] = copy.copy(self.data['meta'])
            self.externalData[key]['x'] = copy.copy(
                self.data['data'][self.plotSetupTableWidget.cellWidget(
                    i, 1).currentText()].values)
            self.externalData[key]['y'] = copy.copy(
                self.data['data'][self.plotSetupTableWidget.cellWidget(
                    i, 2).currentText()].values)
            if self.plotSetupTableWidget.cellWidget(i,
                                                    3).currentText() == 'None':
                self.externalData[key]['yerr'] = ones_like(
                    self.externalData[key]['x'])
            else:
                self.externalData[key]['yerr'] = copy.copy(
                    self.data['data'][self.plotSetupTableWidget.cellWidget(
                        i, 3).currentText()].values)
            self.externalData[key][
                'color'] = self.plotSetupTableWidget.cellWidget(i, 4).color()
        self.plotWidget.Plot(names)
        self.plotWidget.setXLabel(' '.join(self.xlabel))
        self.plotWidget.setYLabel(' '.join(self.ylabel))
Ejemplo n.º 3
0
class XAnoS_Reducer(QWidget):
    """
    This widget is developed to reduce on the fly 2D SAXS data to azimuthally averaged 1D SAXS data
    """
    def __init__(self,poniFile=None,dataFile=None, darkFile=None, maskFile=None,extractedFolder='/tmp', npt=1000, azimuthalRange=(-180.0,180.0), parent=None):
        """
        poniFile is the calibration file obtained after Q-calibration
        """
        QWidget.__init__(self,parent)
        self.setup_dict=json.load(open('./SetupData/reducer_setup.txt','r'))
        if poniFile is not None:
            self.poniFile=poniFile
        else:
            self.poniFile=self.setup_dict['poniFile']
        if maskFile is not None:
            self.maskFile=maskFile
        else:
            self.maskFile=self.setup_dict['maskFile']
        self.dataFile=dataFile
        if darkFile is None:
            self.dark_corrected=False
            self.darkFile=''
        else:
            self.darkFile=darkFile
            self.dark_corrected=True
       
        self.curDir=os.getcwd()
        
        self.extractedBaseFolder=extractedFolder
        self.npt=npt
        self.set_externally=False
        #ai=AIWidget()
        #self.layout.addWidget(ai)
        self.azimuthalRange=azimuthalRange
        self.create_UI()
        if os.path.exists(self.poniFile):
            self.openPoniFile(file=self.poniFile)
        if os.path.exists(self.maskFile):
            self.openMaskFile(file=self.maskFile)   
        self.clientRunning=False     
        
        
    def create_UI(self):
        """
        Creates the widget user interface
        """
        loadUi('UI_Forms/Data_Reduction_Client.ui',self)
        self.poniFileLineEdit.setText(str(self.poniFile))
        self.maskFileLineEdit.setText(str(self.maskFile))
        self.darkFileLineEdit.setText(str(self.darkFile))
        self.extractedBaseFolderLineEdit.setText(self.extractedBaseFolder)
        self.radialPointsLineEdit.setText(str(self.npt))
        self.openDataPushButton.clicked.connect(self.openDataFiles)
        self.reducePushButton.clicked.connect(self.reduce_multiple)
        self.openDarkPushButton.clicked.connect(self.openDarkFile)
        self.openPoniPushButton.clicked.connect(lambda x: self.openPoniFile(file=None))
        self.calibratePushButton.clicked.connect(self.calibrate)
        self.maskFileLineEdit.returnPressed.connect(self.maskFileChanged)
        self.openMaskPushButton.clicked.connect(lambda x: self.openMaskFile(file=None))
        self.createMaskPushButton.clicked.connect(self.createMask)
        self.extractedFolderPushButton.clicked.connect(self.openFolder)
        self.extractedFolderLineEdit.textChanged.connect(self.extractedFolderChanged)
        self.polCorrComboBox.currentIndexChanged.connect(self.polarizationChanged)
        self.polarizationChanged()
        self.radialPointsLineEdit.returnPressed.connect(self.nptChanged)
        self.azimuthalRangeLineEdit.returnPressed.connect(self.azimuthalRangeChanged)
        self.azimuthalRangeChanged()
        #self.statusLabel.setStyleSheet("color:rgba(0,1,0,0)")
        self.imageWidget=Image_Widget(zeros((100,100)))
        self.cakedImageWidget=Image_Widget(zeros((100,100)))
        imgNumberLabel=QLabel('Image number')
        self.imgNumberSpinBox=QSpinBox()
        self.imgNumberSpinBox.setSingleStep(1)
        self.imageWidget.imageLayout.addWidget(imgNumberLabel,row=2,col=1)
        self.imageWidget.imageLayout.addWidget(self.imgNumberSpinBox,row=2,col=2)
        self.imageView=self.imageWidget.imageView.getView()
        self.plotWidget=PlotWidget()
        self.plotWidget.setXLabel('Q, &#8491;<sup>-1</sup>',fontsize=5)
        self.plotWidget.setYLabel('Intensity',fontsize=5)
        self.tabWidget.addTab(self.plotWidget,'Reduced 1D-data')
        self.tabWidget.addTab(self.imageWidget,'Masked 2D-data')
        self.tabWidget.addTab(self.cakedImageWidget,'Reduced Caked Data')
        
        self.serverAddress=self.serverAddressLineEdit.text()
        self.startClientPushButton.clicked.connect(self.startClient)
        self.stopClientPushButton.clicked.connect(self.stopClient)
        self.serverAddressLineEdit.returnPressed.connect(self.serverAddressChanged)
        
        self.startServerPushButton.clicked.connect(self.startServer)
        self.stopServerPushButton.clicked.connect(self.stopServer)
        
    def startServer(self):
        serverAddr=self.serverAddressLineEdit.text()
        dataDir=QFileDialog.getExistingDirectory(self,'Select data folder',options=QFileDialog.ShowDirsOnly)
        self.serverStatusLabel.setText('<font color="Red">Transmitting</font>')
        QApplication.processEvents()
        self.serverThread=QThread()
        self.zeromq_server=ZeroMQ_Server(serverAddr,dataDir)
        self.zeromq_server.moveToThread(self.serverThread)
        self.serverThread.started.connect(self.zeromq_server.loop)
        self.zeromq_server.messageEmitted.connect(self.updateServerMessage)
        self.zeromq_server.folderFinished.connect(self.serverDone)
        QTimer.singleShot(0,self.serverThread.start)

    
    def updateServerMessage(self,mesg):
        #self.serverStatusLabel.setText('<font color="Red">Transmitting</font>')
        self.serverMessageLabel.setText('Server sends: %s'%mesg)
        QApplication.processEvents()
        
    def serverDone(self):
        self.serverStatusLabel.setText('<font color="Green">Idle</font>')
        self.zeromq_server.socket.unbind(self.zeromq_server.socket.last_endpoint)
        self.serverThread.quit()
        self.serverThread.wait()
        self.serverThread.deleteLater()
        self.zeromq_server.deleteLater()
        
    def stopServer(self):
        try:
            self.zeromq_server.running=False
            self.serverStatusLabel.setText('<font color="Green">Idle</font>')
            self.zeromq_server.socket.unbind(self.zeromq_server.socket.last_endpoint)
            self.serverThread.quit()
            self.serverThread.wait()
            self.serverThread.deleteLater()
            self.zeromq_server.deleteLater()
        except:
            QMessageBox.warning(self,'Server Error','Start the server before stopping it')
        
    def enableClient(self,enable=True):
        self.startClientPushButton.setEnabled(enable)
        self.stopClientPushButton.setEnabled(enable)
        
    def enableServer(self,enable=True):
        self.startServerPushButton.setEnabled(enable)
        self.stopServerPushButton.setEnabled(enable)
        
        
    def startClient(self):
        if self.clientRunning:
            self.stopClient()
        else:
            self.clientFree=True
            self.clientRunning=True
            self.files=[]
            self.listenerThread = QThread()
            addr=self.clientAddressLineEdit.text()
            self.zeromq_listener = ZeroMQ_Listener(addr)
            self.zeromq_listener.moveToThread(self.listenerThread)
            self.listenerThread.started.connect(self.zeromq_listener.loop)
            self.zeromq_listener.messageReceived.connect(self.signal_received)
            QTimer.singleShot(0, self.listenerThread.start)
            QTimer.singleShot(0,self.clientReduce)
            self.clientStatusLabel.setText('<font color="red">Connected</font>')
            
    def stopClient(self):
        try:
            self.clientRunning=False
            self.clientFree=False
            self.zeromq_listener.messageReceived.disconnect()
            self.zeromq_listener.running=False
            self.listenerThread.quit()
            self.listenerThread.wait()
            self.listenerThread.deleteLater()
            self.zeromq_listener.deleteLater()
            self.clientStatusLabel.setText('<font color="green">Idle</font>')
        except:
            QMessageBox.warning(self,'Client Error', 'Please start the client first before closing.',QMessageBox.Ok)
        
        
    def serverAddressChanged(self):
        if self.clientRunning:
            self.startClient()
        
        
    def signal_received(self, message):
        self.clientMessageLabel.setText('Client receives: %s'%message)
        if 'dark.edf' not in message:
            self.files.append(message)
            
            
    def clientReduce(self):
        while self.clientFree:
            QApplication.processEvents()
            if len(self.files)>0:
                message=self.files[0]
                self.dataFiles=[message]
                self.dataFileLineEdit.setText(str(self.dataFiles))
                self.extractedBaseFolder=os.path.dirname(message)
                self.extractedFolder=os.path.join(self.extractedBaseFolder,self.extractedFolderLineEdit.text())
                if not os.path.exists(self.extractedFolder):
                    os.makedirs(self.extractedFolder)
                self.extractedBaseFolderLineEdit.setText(self.extractedBaseFolder)
                self.set_externally=True
                self.reduce_multiple()
                self.set_externally=False
                self.files.pop(0)
        
            
    def closeEvent(self, event):
        if self.clientRunning:
            self.stopClient()
        event.accept()
       
    def polarizationChanged(self):
        if self.polCorrComboBox.currentText()=='Horizontal':
            self.polarization_factor=1
        elif self.polCorrComboBox.currentText()=='Vertical':
            self.polarization_factor=-1
        elif self.polCorrComboBox.currentText()=='Circular':
            self.polarization_factor=0
        else:
            self.polarization_factor=None
            
    def createMask(self):
        """
        Opens a mask-widget to create mask file
        """
        fname=str(QFileDialog.getOpenFileName(self,'Select an image file', directory=self.curDir,filter='Image file (*.edf *.tif)')[0])
        if fname is not None or fname!='':
            img=fb.open(fname).data
            self.maskWidget=MaskWidget(img)
            self.maskWidget.saveMaskPushButton.clicked.disconnect()
            self.maskWidget.saveMaskPushButton.clicked.connect(self.save_mask)
            self.maskWidget.show()
        else:
            QMessageBox.warning(self,'File error','Please import a data file first for creating the mask',QMessageBox.Ok)
            
    def maskFileChanged(self):
        """
        Changes the mask file
        """
        maskFile=str(self.maskFileLineEdit.text())
        if str(maskFile)=='':
            self.maskFile=None
        elif os.path.exists(maskFile):
            self.maskFile=maskFile
        else:
            self.maskFile=None
            
    def save_mask(self):
        """
        Saves the entire mask combining all the shape ROIs
        """
        fname=str(QFileDialog.getSaveFileName(filter='Mask Files (*.msk)')[0])
        name,extn=os.path.splitext(fname)
        if extn=='':
            fname=name+'.msk'
        elif extn!='.msk':
            QMessageBox.warning(self,'File extension error','Please donot provide file extension other than ".msk". Thank you!')
            return
        else:
            tmpfile=fb.edfimage.EdfImage(data=self.maskWidget.full_mask_data.T,header=None)
            tmpfile.save(fname)
            self.maskFile=fname
            self.maskFileLineEdit.setText(self.maskFile)
            
    def calibrate(self):
        """
        Opens a calibartion widget to create calibration file
        """
        fname=str(QFileDialog.getOpenFileName(self,'Select calibration image',directory=self.curDir, filter='Calibration image (*.edf *.tif)')[0])
        if fname is not None:
            img=fb.open(fname).data
            if self.maskFile is not None:
                try:
                    mask=fb.open(self.maskFile).data
                except:
                    QMessageBox.warning(self,'Mask File Error','Cannot open %s.\n No masking will be done.'%self.maskFile)
                    mask=None
            else:
                mask=None
            pixel1=79.0
            pixel2=79.0
            self.calWidget=CalibrationWidget(img,pixel1,pixel2,mask=mask)
            self.calWidget.saveCalibrationPushButton.clicked.disconnect()
            self.calWidget.saveCalibrationPushButton.clicked.connect(self.save_calibration)
            self.calWidget.show()
        else:
            QMessageBox.warning(self,'File error','Please import a data file first for creating the calibration file',QMessageBox.Ok)
            
    def save_calibration(self):
        fname=str(QFileDialog.getSaveFileName(self,'Calibration file',directory=self.curDir,filter='Clibration files (*.poni)')[0])
        tfname=os.path.splitext(fname)[0]+'.poni'
        self.calWidget.applyPyFAI()
        self.calWidget.geo.save(tfname)      
        self.poniFile=tfname
        self.poniFileLineEdit.setText(self.poniFile)
        self.openPoniFile(file=self.poniFile)
        
    def openPoniFile(self,file=None):
        """
        Select and imports the calibration file
        """
        if file is None:
            self.poniFile=QFileDialog.getOpenFileName(self,'Select calibration file',directory=self.curDir,filter='Calibration file (*.poni)')[0]
            self.poniFileLineEdit.setText(self.poniFile)
        else:
            self.poniFile=file
        if os.path.exists(self.poniFile):
            self.setup_dict['poniFile']=self.poniFile
            json.dump(self.setup_dict,open('./SetupData/reducer_setup.txt','w'))
            fh=open(self.poniFile,'r')
            lines=fh.readlines()
            self.calib_data={}
            for line in lines:
                if line[0]!='#':
                    key,val=line.split(': ')
                    self.calib_data[key]=float(val)
            self.dist=self.calib_data['Distance']
            self.pixel1=self.calib_data['PixelSize1']
            self.pixel2=self.calib_data['PixelSize2']
            self.poni1=self.calib_data['Poni1']
            self.poni2=self.calib_data['Poni2']
            self.rot1=self.calib_data['Rot1']
            self.rot2=self.calib_data['Rot2']
            self.rot3=self.calib_data['Rot3']
            self.wavelength=self.calib_data['Wavelength']
            self.ai=AzimuthalIntegrator(dist=self.dist,poni1=self.poni1,poni2=self.poni2,pixel1=self.pixel1,pixel2=self.pixel2,rot1=self.rot1,rot2=self.rot2,rot3=self.rot3,wavelength=self.wavelength)
            #pos=[self.poni2/self.pixel2,self.poni1/self.pixel1]
            #self.roi=cake(pos,movable=False)
            #self.roi.sigRegionChangeStarted.connect(self.endAngleChanged)
            
            #self.imageView.addItem(self.roi)
        else:
            QMessageBox.warning(self,'File error','The calibration file '+self.poniFile+' doesnot exists.',QMessageBox.Ok)                
        
    def endAngleChanged(self,evt):
        print(evt.pos())
        
        
    def nptChanged(self):
        """
        Changes the number of radial points
        """
        try:
            self.npt=int(self.radialPointsLineEdit.text())
        except:
            QMessageBox.warning(self,'Value error', 'Please input positive integers only.',QMessageBox.Ok)
            
    def azimuthalRangeChanged(self):
        """
        Changes the azimuth angular range
        """
        try:
            self.azimuthalRange=tuple(map(float, self.azimuthalRangeLineEdit.text().split(':')))
        except:
            QMessageBox.warning(self,'Value error','Please input min:max angles in floating point numbers',QMessageBox.Ok)
        
    def openDataFile(self):
        """
        Select and imports one data file
        """
        dataFile=QFileDialog.getOpenFileName(self,'Select data file',directory=self.curDir,filter='Data file (*.edf *.tif)')[0]
        if dataFile!='':
            self.dataFile=dataFile
            self.curDir=os.path.dirname(self.dataFile)
            self.dataFileLineEdit.setText(self.dataFile)
            self.data2d=fb.open(self.dataFile).data
            if self.darkFile is not None:
                self.applyDark()
            if self.maskFile is not None:
                self.applyMask()    
            self.imageWidget.setImage(self.data2d,transpose=True)
            self.tabWidget.setCurrentWidget(self.imageWidget)
            if not self.set_externally:
                self.extractedFolder=os.path.join(self.curDir,self.extractedFolderLineEdit.text())
                if not os.path.exists(self.extractedFolder):
                    os.makedirs(self.extractedFolder)
                    
    def openDataFiles(self):
        """
        Selects and imports multiple data files
        """
        self.dataFiles=QFileDialog.getOpenFileNames(self,'Select data files', directory=self.curDir,filter='Data files (*.edf *.tif)')[0]
        if len(self.dataFiles)!=0:
            self.imgNumberSpinBox.valueChanged.connect(self.imageChanged)
            self.imgNumberSpinBox.setMinimum(0)
            self.imgNumberSpinBox.setMaximum(len(self.dataFiles)-1)
            self.dataFileLineEdit.setText(str(self.dataFiles))
            self.curDir=os.path.dirname(self.dataFiles[0])
            self.extractedBaseFolder=self.curDir
            self.extractedFolder=os.path.abspath(os.path.join(self.extractedBaseFolder,self.extractedFolderLineEdit.text()))
            if not os.path.exists(self.extractedFolder):
                os.makedirs(self.extractedFolder)
            self.extractedBaseFolderLineEdit.setText(self.extractedBaseFolder)
            self.imgNumberSpinBox.setValue(0)
            self.imageChanged()
            
    def imageChanged(self):
        self.data2d=fb.open(self.dataFiles[self.imgNumberSpinBox.value()]).data
        if self.darkFile is not None:
            self.applyDark()
        if self.maskFile is not None:
            self.applyMask()    
        self.imageWidget.setImage(self.data2d,transpose=True)
            

                  
            
                
    def applyDark(self):
        if not self.dark_corrected and self.darkFile!='':
            self.dark2d=fb.open(self.darkFile).data
            self.data2d=self.data2d-self.dark2d
            self.dark_corrected=True
                
    def applyMask(self):
        self.mask2d=fb.open(self.maskFile).data
        self.data2d=self.data2d*(1+self.mask2d)/2.0
        self.mask_applied=True

    def openDarkFile(self):
        """
        Select and imports the dark file
        """
        self.darkFile=QFileDialog.getOpenFileName(self,'Select dark file',directory=self.curDir,filter='Dark file (*.edf)')[0]
        if self.darkFile!='':
            self.dark_corrected=False
            self.darkFileLineEdit.setText(self.darkFile)
            if self.dataFile is not None:
                self.data2d=fb.open(self.dataFile).data
                self.applyDark()
        
    
    def openMaskFile(self,file=None):
        """
        Select and imports the Mask file
        """
        if file is None:
            self.maskFile=QFileDialog.getOpenFileName(self,'Select mask file',directory=self.curDir,filter='Mask file (*.msk)')[0]
        else:
            self.maskFile=file
        if self.maskFile!='':
            self.mask_applied=False
            if os.path.exists(self.maskFile):
                self.curDir=os.path.dirname(self.maskFile)
                self.maskFileLineEdit.setText(self.maskFile)
                self.setup_dict['maskFile']=self.maskFile
                self.setup_dict['poniFile']=self.poniFile
                json.dump(self.setup_dict,open('./SetupData/reducer_setup.txt','w'))
            else:
                self.openMaskFile(file=None)
            if self.dataFile is not None:
                self.applyMask()
        else:
            self.maskFile=None
            self.maskFileLineEdit.clear()
            
            
        
    def openFolder(self):
        """
        Select the folder to save the reduce data
        """
        oldfolder=self.extractedBaseFolder.text()
        folder=QFileDialog.getExistingDirectory(self,'Select extracted directory',directory=self.curDir)
        if folder!='':
            self.extractedBaseFolder=folder
            self.extractedBaseFolderLineEdit.setText(folder)
            self.extractedFolder=os.path.join(folder,self.extractedFolderLineEdit.text())
            self.set_externally=True
        else:
            self.extractedBaseFolder=oldfolder
            self.extractedBaseFolderLineEdit.setText(oldfolder)
            self.extractedFolder = os.path.join(oldfolder, self.extractedFolderLineEdit.text())
            self.set_externally = True


    def extractedFolderChanged(self,txt):
        self.extractedFolder=os.path.join(self.extractedBaseFolder,txt)
        self.set_externally=True

        
        
    def reduceData(self):
        """
        Reduces the 2d data to 1d data
        """
        if (self.dataFile is not None) and (os.path.exists(self.dataFile)):
            if (self.poniFile is not None) and (os.path.exists(self.poniFile)):
#                self.statusLabel.setText('Busy')
#                self.progressBar.setRange(0, 0)
                imageData=fb.open(self.dataFile)
                #self.data2d=imageData.data
                #if self.maskFile is not None:
                #    self.applyMask()    
                #self.imageWidget.setImage(self.data2d,transpose=True)
                #self.tabWidget.setCurrentWidget(self.imageWidget)
                
                self.header=imageData.header
                try:
                    self.ai.set_wavelength(float(self.header['Wavelength'])*1e-10)
                except:
                    self.ai.set_wavelength(self.wavelength)
                #print(self.darkFile)
                if os.path.exists(self.dataFile.split('.')[0]+'_dark.edf') and self.darkCheckBox.isChecked():
                    self.darkFile=self.dataFile.split('.')[0]+'_dark.edf'
                    dark=fb.open(self.darkFile)
                    self.darkFileLineEdit.setText(self.darkFile)
                    imageDark=dark.data                                     
                    self.header['BSDiode_corr']=max([1.0,(float(imageData.header['BSDiode'])-float(dark.header['BSDiode']))])
                    self.header['Monitor_corr']=max([1.0,(float(imageData.header['Monitor'])-float(dark.header['Monitor']))])
                    print("Dark File read from existing dark files")                    
                elif self.darkFile is not None and self.darkFile!='' and self.darkCheckBox.isChecked():
                    dark=fb.open(self.darkFile)
                    imageDark=dark.data                                     
                    self.header['BSDiode_corr']=max([1.0,(float(imageData.header['BSDiode'])-float(dark.header['BSDiode']))])
                    self.header['Monitor_corr']=max([1.0,(float(imageData.header['Monitor'])-float(dark.header['Monitor']))])
                    print("Dark File from memory subtracted")                
                else:
                    imageDark=None
                    try:
                        self.header['BSDiode_corr']=float(imageData.header['BSDiode'])
                        self.header['Monitor_corr']=float(imageData.header['Monitor'])
                        self.header['Transmission'] = float(imageData.header['Transmission'])
                    except:
                        self.normComboBox.setCurrentText('None')
                    print("No dark correction done")
                if str(self.normComboBox.currentText())=='BSDiode':
                    norm_factor=self.header['BSDiode_corr']#/self.header['Monitor_corr']#float(self.header[
                    # 'count_time'])
                elif str(self.normComboBox.currentText())=='TransDiode':
                    norm_factor=self.header['Transmission']*self.header['Monitor_corr']
                elif str(self.normComboBox.currentText())=='Monitor':
                    norm_factor=self.header['Monitor_corr']
                elif str(self.normComboBox.currentText())=='Image Sum':
                    norm_factor=sum(imageData.data)
                else:
                    norm_factor=1.0
                    
                if self.maskFile is not None:
                    imageMask=fb.open(self.maskFile).data
                else:
                    imageMask=None
#                QApplication.processEvents()
                #print(self.azimuthalRange)
                self.q,self.I,self.Ierr=self.ai.integrate1d(imageData.data,self.npt,error_model='poisson',mask=imageMask,dark=imageDark,unit='q_A^-1',normalization_factor=norm_factor,azimuth_range=self.azimuthalRange,polarization_factor=self.polarization_factor)
                self.plotWidget.add_data(self.q,self.I,yerr=self.Ierr,name='Reduced data')
                if not self.set_externally:
                    cakedI,qr,phir=self.ai.integrate2d(imageData.data,self.npt,mask=imageMask,dark=imageDark,unit='q_A^-1',normalization_factor=norm_factor,polarization_factor=self.polarization_factor)
                    self.cakedImageWidget.setImage(cakedI,xmin=qr[0],xmax=qr[-1],ymin=phir[0],ymax=phir[-1],transpose=True,xlabel='Q ', ylabel='phi ',unit=['&#8491;<sup>-1</sup>','degree'])
                    self.cakedImageWidget.imageView.view.setAspectLocked(False)
                    try:
                        self.azimuthalRegion.setRegion(self.azimuthalRange)
                    except:
                        self.azimuthalRegion=pg.LinearRegionItem(values=self.azimuthalRange,orientation=pg.LinearRegionItem.Horizontal,movable=True,bounds=[-180,180])
                        self.cakedImageWidget.imageView.getView().addItem(self.azimuthalRegion)
                        self.azimuthalRegion.sigRegionChanged.connect(self.azimuthalRegionChanged)
                self.plotWidget.setTitle(self.dataFile,fontsize=3)
#                self.progressBar.setRange(0,100)
#                self.progressBar.setValue(100)
#                self.statusLabel.setText('Idle')
#                QApplication.processEvents()
                self.saveData()
                #self.tabWidget.setCurrentWidget(self.plotWidget)
            else:
                QMessageBox.warning(self,'Calibration File Error','Data reduction failed because either no calibration file provided or the provided file or path do not exists',QMessageBox.Ok)
                
        else:
            QMessageBox.warning(self,'Data File Error','No data file provided', QMessageBox.Ok)
            
    def azimuthalRegionChanged(self):
        minp,maxp=self.azimuthalRegion.getRegion()
        self.azimuthalRangeLineEdit.setText('%.1f:%.1f'%(minp,maxp))
        self.azimuthalRange=[minp,maxp]
        self.set_externally=True
        
        
            
    def reduce_multiple(self):
        """
        Reduce multiple files
        """
        try:
            i=0
            self.progressBar.setRange(0,len(self.dataFiles))
            self.progressBar.setValue(i)
            self.statusLabel.setText('<font color="red">Busy</font>')
            for file in self.dataFiles:
                self.dataFile=file
                QApplication.processEvents()
                self.reduceData()
                i=i+1
                self.progressBar.setValue(i)
                QApplication.processEvents()
            self.statusLabel.setText('<font color="green">Idle</font>')
            self.progressBar.setValue(0)
        except:
            QMessageBox.warning(self,'File error','No data files to reduce',QMessageBox.Ok)
        
    def saveData(self):
        """
        saves the extracted data into a file
        """
        if not os.path.exists(self.extractedFolder):
            os.makedirs(self.extractedFolder)
        filename=os.path.join(self.extractedFolder,os.path.splitext(os.path.basename(self.dataFile))[0]+'.txt')
        headers='File extracted on '+time.asctime()+'\n'
        headers='Files used for extraction are:\n'
        headers+='Data file: '+self.dataFile+'\n'
        if self.darkFile is not None:
            headers+='Dark file: '+self.darkFile+'\n'
        else:
            headers+='Dark file: None\n'
        headers+='Poni file: '+self.poniFile+'\n'
        if self.maskFile is not None:
            headers+='mask file: '+self.maskFile+'\n'
        else:
            headers+='mask file: None\n'
        for key in self.header.keys():
            headers+=key+'='+str(self.header[key])+'\n'
        headers+="col_names=['Q (inv Angs)','Int','Int_err']\n"
        headers+='Q (inv Angs)\tInt\tInt_err'
        data=vstack((self.q,self.I,self.Ierr)).T
        savetxt(filename,data,header=headers,comments='#')