Esempio n. 1
0
    def show_overshoot(self):
        """

        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        tree.setParameters(self.overshoot_params, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)

        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this managers')
        res = dialog.exec()

        if res == dialog.Accepted:
            # save managers parameters in a xml file
            # start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            # start = os.path.join("..",'daq_scan')
            ioxml.parameter_to_xml_file(
                self.overshoot_params,
                os.path.join(overshoot_path,
                             self.overshoot_params.child('filename').value()))
Esempio n. 2
0
    def show_file_attributes(self, type_info='dataset'):
        """
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res
Esempio n. 3
0
    def show_preset(self):
        """

        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        tree.setParameters(self.preset_params, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)

        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this preset')
        res = dialog.exec()

        if self.pid_type:
            path = pid_path
        else:
            path = preset_path

        if res == dialog.Accepted:
            # save preset parameters in a xml file
            #start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            #start = os.path.join("..",'daq_scan')
            custom_tree.parameter_to_xml_file(
                self.preset_params,
                os.path.join(path,
                             self.preset_params.child(('filename')).value()))

            if not self.pid_type:
                #check if overshoot configuration and layout configuration with same name exists => delete them if yes
                overshoot_path = os.path.join(local_path,
                                              'overshoot_configurations')
                file = os.path.splitext(
                    self.preset_params.child(('filename')).value())[0]
                file = os.path.join(overshoot_path, file + '.xml')
                if os.path.isfile(file):
                    os.remove(file)

                layout_path = os.path.join(local_path, 'layout')
                file = os.path.splitext(
                    self.preset_params.child(('filename')).value())[0]
                file = os.path.join(layout_path, file + '.dock')
                if os.path.isfile(file):
                    os.remove(file)
Esempio n. 4
0
    def show_file_attributes(self, type_info='dataset'):
        """
            Switch the type_info value.

            In case of :
                * *scan* : Set parameters showing top false
                * *dataset* : Set parameters showing top false
                * *managers* : Set parameters showing top false. Add the save/cancel buttons to the accept/reject dialog (to save managers parameters in a xml file).

            Finally, in case of accepted managers type info, save the managers parameters in a xml file.

            =============== =========== ====================================
            **Parameters**    **Type**    **Description**
            *type_info*       string      The file type information between
                                            * scan
                                            * dataset
                                            * managers
            =============== =========== ====================================

            See Also
            --------
            custom_tree.parameter_to_xml_file, create_menu
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res
Esempio n. 5
0
class ScanSelector(QObject):

    scan_select_signal = pyqtSignal(ROI)

    params = [
        {
            'title':
            'Scan options',
            'name':
            'scan_options',
            'type':
            'group',
            'children': [
                {
                    'title': 'Sources:',
                    'name': 'sources',
                    'type': 'list',
                },
                {
                    'title': 'Viewers:',
                    'name': 'viewers',
                    'type': 'list',
                },
                {
                    'title': 'Scan type:',
                    'name': 'scan_type',
                    'type': 'list',
                    'values': ['Scan1D', 'Scan2D'],
                    'value': 'Scan2D'
                },
            ]
        },
        {
            'title':
            'Scan Area',
            'name':
            'scan_area',
            'type':
            'group',
            'children': [
                {
                    'title':
                    'ROI select:',
                    'name':
                    'ROIselect',
                    'type':
                    'group',
                    'visible':
                    True,
                    'children': [
                        {
                            'title': 'x0:',
                            'name': 'x0',
                            'type': 'int',
                            'value': 0,
                            'min': 0
                        },
                        {
                            'title': 'y0:',
                            'name': 'y0',
                            'type': 'int',
                            'value': 0,
                            'min': 0
                        },
                        {
                            'title': 'width:',
                            'name': 'width',
                            'type': 'int',
                            'value': 10,
                            'min': 1
                        },
                        {
                            'title': 'height:',
                            'name': 'height',
                            'type': 'int',
                            'value': 10,
                            'min': 1
                        },
                    ]
                },
                {
                    'title': 'Coordinates:',
                    'name': 'coordinates',
                    'type': 'itemselect',
                    'visible': True
                },
            ]
        },
    ]

    def __init__(self, viewer_items=[], scan_type='Scan2D', positions=[]):
        """

        Parameters
        ----------
        viewer_items: dict where the keys are the titles of the sources while the values are dict with keys
                        viewers: list of plotitems
                        names: list of viewer titles
        scan_type: (str) either 'Scan1D' correspondign to a polyline ROI or 'Scan2D' for a rect Roi
        positions: list
                        in case of 'Scan1D', should be a sequence of 2 floats sequence [(x1,y1),(x2,y2),(x3,y3),...]
                        in case of 'Scan2D', should be a sequence of 4 floats (x, y , w, h)
        """
        super(ScanSelector, self).__init__()
        self._viewers_items = viewer_items
        self.sources_names = list(viewer_items.keys())
        if len(viewer_items) != 0:
            self.scan_selector_source = viewer_items[
                self.sources_names[0]]['viewers'][0]
        else:
            self.scan_selector_source = None
        self.scan_selector = None
        self.setupUI()
        self.settings.child('scan_options', 'scan_type').setValue(scan_type)

        self.remove_scan_selector()
        if self.scan_selector_source is not None:
            if len(viewer_items[self.sources_names[0]]['viewers']) == 1:
                self.settings.child('scan_options', 'viewers').hide()
        else:
            self.settings.child('scan_options', 'viewers').hide()
        self.update_scan_area_type()

        if scan_type == "Scan1D" and positions != []:
            self.scan_selector.setPoints(positions)
        elif scan_type == 'Scan2D' and positions != []:
            self.scan_selector.setPos(positions[:2])
            self.scan_selector.setSize(positions[3:])

    @property
    def viewers_items(self):
        return self._viewers_items

    @viewers_items.setter
    def viewers_items(self, items):
        self._viewers_items = items
        self.sources_names = list(items.keys())
        self.scan_selector_source = items[self.sources_names[0]]['viewers'][0]
        self.settings.child('scan_options',
                            'sources').setOpts(limits=self.sources_names)
        viewer_names = self._viewers_items[self.sources_names[0]]['names']
        self.settings.child('scan_options',
                            'viewers').setOpts(limits=viewer_names)

    def show(self, visible=True):
        self.show_scan_selector(visible)
        if visible:
            self.widget.show()
        else:
            self.widget.hide()

    def hide(self):
        self.show(False)

    def setupUI(self):
        self.widget = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout()

        self.settings_tree = ParameterTree()
        layout.addWidget(self.settings_tree, 10)
        self.settings_tree.setMinimumWidth(300)
        self.settings = Parameter.create(name='Settings',
                                         type='group',
                                         children=self.params)
        self.settings_tree.setParameters(self.settings, showTop=False)

        self.settings.child('scan_options',
                            'sources').setOpts(limits=self.sources_names)
        if len(self.viewers_items):
            viewer_names = self._viewers_items[self.sources_names[0]]['names']
        else:
            viewer_names = []
        self.settings.child('scan_options',
                            'viewers').setOpts(limits=viewer_names)

        self.settings.sigTreeStateChanged.connect(self.source_changed)
        self.widget.setLayout(layout)

        #self.widget.show()
        self.widget.setWindowTitle('Scan Selector')

    def source_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'sources' and param.value() is not None:
                    viewer_names = self._viewers_items[param.value()]['names']
                    self.settings.child('scan_options',
                                        'viewers').setOpts(limits=viewer_names)
                    if len(viewer_names) == 1:
                        self.settings.child('scan_options', 'viewers').hide()

                    self.remove_scan_selector()
                    self.scan_selector_source = self._viewers_items[
                        param.value()]['viewers'][0]
                    self.update_scan_area_type()

                if param.name() == 'scan_type':

                    if param.value() == 'Scan1D':
                        self.settings.child('scan_area', 'ROIselect').hide()
                        self.settings.child('scan_area', 'coordinates').show()
                        self.remove_scan_selector()
                        self.update_scan_area_type()
                    else:
                        self.settings.child('scan_area', 'ROIselect').show()
                        self.settings.child('scan_area', 'coordinates').hide()
                        self.remove_scan_selector()
                        self.update_scan_area_type()
                    self.scan_selector.sigRegionChangeFinished.emit(
                        self.scan_selector)

            elif change == 'parent':
                pass

    def remove_scan_selector(self):
        if self.scan_selector_source is not None:
            try:
                self.scan_selector_source.image_widget.plotitem.removeItem(
                    self.scan_selector)
            except:
                pass

    pyqtSlot(str)

    def update_scan_area_type(self):

        if self.settings.child('scan_options',
                               'scan_type').value() == 'Scan1D':
            scan_area_type = 'PolyLines'
        else:
            scan_area_type = 'Rect'

        self.remove_scan_selector()
        if scan_area_type == 'Rect':
            self.scan_selector = RectROI([0, 0], [10, 10])

        elif scan_area_type == 'PolyLines':
            self.scan_selector = PolyLineROI_custom([(0, 0), [10, 10]])
        if self.scan_selector_source is not None:
            self.scan_selector.sigRegionChangeFinished.connect(
                self.update_scan)
            self.scan_selector_source.image_widget.plotitem.addItem(
                self.scan_selector)
            self.show_scan_selector()

            self.scan_selector.sigRegionChangeFinished.emit(self.scan_selector)

    def show_scan_selector(self, visible=True):
        self.scan_selector.setVisible(visible)

    def update_scan(self, roi):
        if self.scan_selector_source is not None:
            if isinstance(roi, RectROI):
                self.settings.child('scan_area', 'ROIselect',
                                    'x0').setValue(roi.pos().x())
                self.settings.child('scan_area', 'ROIselect',
                                    'y0').setValue(roi.pos().y())
                self.settings.child('scan_area', 'ROIselect',
                                    'width').setValue(roi.size().x())
                self.settings.child('scan_area', 'ROIselect',
                                    'height').setValue(roi.size().y())
            elif isinstance(roi, PolyLineROI_custom):
                self.settings.child('scan_area', 'coordinates').setValue(
                    dict(all_items=[
                        '({:.03f} , {:.03f})'.format(pt.x(), pt.y())
                        for pt in roi.get_vertex()
                    ],
                         selected=[]))

            self.scan_select_signal.emit(roi)
Esempio n. 6
0
class GuiManager(QtGui.QMainWindow):
    
    def __init__(self):
        super(GuiManager, self).__init__()
        self.createLayout()
        
    def closeEvent(self, event):
        print 'User asked to close the app'
        self.stopAcquisition()
        Parameters.isAppKilled = True
        #time.sleep(0.1) #Wait for the worker death
        event.accept() # let the window close         
    
    def startAcquisition(self):
        if Parameters.isConnected == False:
            return
        Parameters.isSaving = Parameters.paramObject.child("Saving parameters", "saveResults").value()
        if Parameters.isSaving == True:
            theDate = datetime.datetime.today() .strftime('%Y%m%d')   
            theTime = datetime.datetime.today() .strftime('%H%M%S')   
            theName=Parameters.paramObject.child("Saving parameters", "Experiment name").value()
            #Check counter increment
            folderParent = 'C:/InterferometryResults/' + theDate
            counter = 1
            folderFound = False
            theFolder = folderParent + '/' + theName + '_' + str(counter).zfill(3)
            if not os.path.exists(folderParent): #Make sure parent exist
                os.makedirs(folderParent)                
            while folderFound == False and counter < 1000: #Loop until folder is found
                if not os.path.exists(theFolder): #Make sure parent exist
                    os.makedirs(theFolder)        
                    folderFound = True
                else:
                    counter = counter + 1
                    theFolder = folderParent + '/' + theName + '_' + str(counter).zfill(3)
            if counter < 1000:
                Parameters.savingFolder = theFolder
                if not os.path.exists(theFolder):
                    os.makedirs(theFolder)               
            else:
                Parameters.isSaving = False; #Should not happen.
        self.btStart.setEnabled(False)
        self.btStop.setEnabled(True)
        self.btOpen.setEnabled(False)
        #Get the parameter values
        Parameters.nSamples=Parameters.paramObject.child("Acquisition Parameters", "Number of samples to acquire").value()
        acqMode=Parameters.paramObject.child("Trigger Options", "Acquisition mode").value()
        triggerAmplitude=Parameters.paramObject.child("Trigger Options", "Trigger amplitude").value()
        motorSpeed=Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").value()+28 #28 is calibration
        nBlocks=int(math.ceil(float(Parameters.nSamples)/512)) #Must be a multiple of 512
        Parameters.nSamples = nBlocks*512
        Parameters.paramObject.child("Acquisition Parameters", "Number of samples to acquire").setValue(Parameters.nSamples)

        #Set frequency in free mode. These settings could be optimized depending on the computer.
        freq=2500000 #10im/s
        if Parameters.nSamples > 100352:
            freq=5000000 #5im/s
        if Parameters.nSamples > 300032:
            freq=12500000 #2im/s               
        if Parameters.nSamples > 1000000:
            freq=25000000 #1im/s     
        if Parameters.nSamples > 2000000:
            freq=50000000 #0.5im/s               
        
        #Start the acquisition on the FPGA
        data = []
        data = array('i')
        data.append(1)
        data.append(freq)
        data.append(2)
        data.append(acqMode)
        data.append(3)
        data.append(nBlocks)
        data.append(4)
        data.append(motorSpeed)
        data.append(5)
        data.append(triggerAmplitude)
        data.append(6)
        data.append(0)
        
        theBytes = struct.pack('i' * len(data), *data)
        buf = bytearray(theBytes)
        Parameters.dev.WriteToPipeIn(128, buf)
    
        Parameters.dev.SetWireInValue(0, 1+2+8, 1+2+8);Parameters.dev.UpdateWireIns() #Enable DDR2 reading and writing and activate memory.
        time.sleep(0.1); #Wait to make sure everything is ready. TODO: Reduce this.
        Parameters.dev.SetWireInValue(0, 4, 4);Parameters.dev.UpdateWireIns() #Start acquisition clock.
        
        #self.plotTr.enableAutoRange('xy', True)  ## stop auto-scaling after the first data set is plotted
        Parameters.theQueue = Queue.Queue() #Create the queue
        #self.DisplayUpdater(0)
        self.workThread.start(); #Start the display worker

    
    def stopAcquisition(self):
        print 'Stopping...'
        if hasattr(self,'tDisplay'):
            self.tDisplay.cancel()        
        self.workThread.exitWorker();
        while self.workThread.isRunning == True:
            time.sleep(0.01) #Wait for the worker death, before resetting the board
        Parameters.dev.SetWireInValue(0, 0, 1+2+4+8);Parameters.dev.UpdateWireIns() #Reset board.

        #Save format: Results / YYMMDD / ExperimentName_Counter. Could also use the time.
        if Parameters.isSaving == True:  
            #global state
            state = Parameters.paramObject.saveState()
            file = open(Parameters.savingFolder + '\Parameters.txt', 'w')
            pickle.dump(state, file)
            file.close()            
        print 'Stopped.'
        self.btStart.setEnabled(True)
        self.btStop.setEnabled(False)
        self.btOpen.setEnabled(True)
    '''
    def DisplayUpdater(self,dummy):
        if Parameters.isAppKilled == True:
            return;   
        if Parameters.theQueue.empty():
            print 'no data...'
        while not Parameters.theQueue.empty(): #Empty the display queue
            data = Parameters.theQueue.get()
            #print 'data available!' 
        if 'data' in locals():
            #print 'display data' + str(data[2])
            self.setDataCurveTr(data)
        tDisplay = Timer(2, self.DisplayUpdater, [0],{})
        tDisplay.start()          
    '''   
    def motorSpeedChanged(self,value):
        newSpeed=Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").value()
        newSpeed=newSpeed+28 #Calibration
        
        #Debug
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(enabled=False)
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(visible=False)
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(value=200)

        data = []
        data = array('i')
        data.append(4)
        data.append(newSpeed)
        data.append(0) #Minimum size is 8 'int'
        data.append(0)        
        data.append(0)
        data.append(0)        
        data.append(0)
        data.append(0)                    
        
        theBytes = struct.pack('i' * len(data), *data)
        Parameters.bufferToDev = bytearray(theBytes)
        Parameters.bufferToDevReady = True
        
        
    def triggerChanged(self,value):
        acqMode=Parameters.paramObject.child("Trigger Options", "Acquisition mode").value()
        triggerAmplitude=Parameters.paramObject.child("Trigger Options", "Trigger amplitude").value()

        data = []
        data = array('i')
        data.append(2)
        data.append(acqMode)
        data.append(5)
        data.append(triggerAmplitude)
        data.append(0)
        data.append(0)
        data.append(0)
        data.append(0)        
        
        theBytes = struct.pack('i' * len(data), *data)
        print str(theBytes)
        
        Parameters.bufferToDev = bytearray(theBytes)
        Parameters.bufferToDevReady = True     
        
    def triggerHalfSwitch(self):
        Parameters.triggerToDev = True
        
    def saveParam(self):
        #global state
        state = Parameters.paramObject.saveState()
        file = open('dump.txt', 'w')
        pickle.dump(state, file)
        file.close()
        
    def restoreParam(self):
        #lobal state
        file = open('dump.txt', 'r')
        state = pickle.load(file)
        #add = Parameters.paramObject['Save/Restore functionality', 'Restore State', 'Add missing items']
        #rem = Parameters.paramObject['Save/Restore functionality', 'Restore State', 'Remove extra items']
        Parameters.paramObject.restoreState(state, addChildren=False, removeChildren=False)           
    
    #Set the status text (system connected or not)
    def setStatus(self, isConnected, isError = False):
        def dotChange(item, nDots): #Timer function to display a varying number of dots after "retrying"
            if Parameters.isConnected == True:
                return;
            if Parameters.isAppKilled == True:
                return;                   
            textNotConnected = "System not connected, retrying"
            item.setText(textNotConnected+".")
            #Number of dots varies from 1 to 5
            if nDots == 1:
                textDots = "."
                nDots = 2
            elif nDots == 2:
                textDots = ".."
                nDots = 3
            elif nDots == 3:
                textDots = "..."
                nDots = 4
            elif nDots == 4:
                textDots = "...."
                nDots = 5        
            else:
                textDots = "....."
                nDots = 1    
            item.setForeground(QtGui.QColor("red"))
            item.setText(textNotConnected+textDots)
            self.timerDotChange = Timer(0.25, dotChange, [self.itemStatus, nDots])
            self.timerDotChange.start()          
        if (isError == True): #System not connected    
            print "Error"
            if hasattr(self,'timerDotChange'):
                self.timerDotChange.cancel()
                time.sleep(0.5)
            self.itemStatus.setForeground(QtGui.QColor("red"))                
            self.itemStatus.setText("Error with system. Please restart the application and the system.")              
        elif (isConnected == False): #System not connected      
            nDots = 1
            if hasattr(self,'timerDotChange'):
                self.timerDotChange.cancel()            
            self.timerDotChange = Timer(0.25, dotChange, [self.itemStatus, nDots])
            self.timerDotChange.start()              
        else:    
            print "Connected"
            if hasattr(self,'timerDotChange'):
                self.timerDotChange.cancel()
                time.sleep(0.1)
            self.itemStatus.setForeground(QtGui.QColor("green"))                
            self.itemStatus.setText("System connected.")
            print "Connected2"

    #Set the status text (system connected or not)
    def setCameraStatus(self, isConnected):
        def dotChange(item, nDots): #Timer function to display a varying number of dots after "retrying"
            if Parameters.isCameraConnected == True:
                return;
            if Parameters.isAppKilled == True:
                return;                
            textNotConnected = "Camera not connected, retrying"
            item.setText(textNotConnected+".")
            #Number of dots varies from 1 to 5
            if nDots == 1:
                textDots = "."
                nDots = 2
            elif nDots == 2:
                textDots = ".."
                nDots = 3
            elif nDots == 3:
                textDots = "..."
                nDots = 4
            elif nDots == 4:
                textDots = "...."
                nDots = 5        
            else:
                textDots = "....."
                nDots = 1    
            item.setForeground(QtGui.QColor("red"))
            item.setText(textNotConnected+textDots)
            self.timerDotChangeCamera = Timer(0.25, dotChange, [self.itemCameraStatus, nDots])
            self.timerDotChangeCamera.start()                      
        if (isConnected == False): #System not connected     
            print 'cam oups'
            nDots = 1
            if hasattr(self,'timerDotChangeCamera'):
                self.timerDotChangeCamera.cancel()            
            self.timerDotChangeCamera = Timer(0.25, dotChange, [self.itemCameraStatus, nDots])
            self.timerDotChangeCamera.start()              
        else:    
            print "Camera connected"
            if hasattr(self,'timerDotChangeCamera'):
                self.timerDotChangeCamera.cancel()
                time.sleep(0.1)
            self.itemCameraStatus.setForeground(QtGui.QColor("green"))                
            self.itemCameraStatus.setText("Camera connected.")
            print "Camera connected2"
            
    #Set the status text (system connected or not)
    def setInfo(self, text):
        self.tbInfo.append(text)
            
    #Set the status text (system connected or not)
    def setWire(self, mem1, mem2, mem3, mem4, maxValPos):
        self.itemMemory.setText("Acquisition board memory usage:\nDDR2: " + str(mem1) + " bytes.\nFIFO in: " + str(mem2) + " bytes.\nFIFO out: " + str(mem3) + " bytes.\nFIFO out (minimum): " + str(mem4) + " bytes.")
        self.itemMaxValPos.setText("Maximum RF value position: " + str(maxValPos))
                
    def createLayout(self):
        print 'Creating layout...'
        self.setWindowTitle('Interferometry Acquisition GUI')  
        #self.widget = QtGui.QWidget()
        #self.setCentralWidget(self.widget)
        self.layout = pg.LayoutWidget()
        #self.widget.setLayout(self.layout)
        self.setCentralWidget(self.layout)
        
        #Create GUI
        sizePolicyBt = QtGui.QSizePolicy(1, 1)
        sizePolicyBt.setHorizontalStretch(0)
        sizePolicyBt.setVerticalStretch(0)
        
        self.btOpen = QtGui.QPushButton("Open\nprevious results")
        sizePolicyBt.setHeightForWidth(self.btOpen.sizePolicy().hasHeightForWidth())
        self.btOpen.setSizePolicy(sizePolicyBt);
        self.btOpen.setStyleSheet("background-color: yellow; font-size: 16px; font: bold")
        
        self.btStart = QtGui.QPushButton("Start\nacquisition")
        sizePolicyBt.setHeightForWidth(self.btStart.sizePolicy().hasHeightForWidth())
        self.btStart.setSizePolicy(sizePolicyBt);
        self.btStart.setStyleSheet("background-color: green; font-size: 16px; font: bold")
        self.btStart.clicked.connect(self.startAcquisition)
        
        self.btStop = QtGui.QPushButton("Stop\nacquisition")
        sizePolicyBt.setHeightForWidth(self.btStop.sizePolicy().hasHeightForWidth())
        self.btStop.setSizePolicy(sizePolicyBt);
        self.btStop.setStyleSheet("background-color: red; font-size: 16px; font: bold")
        self.btStop.clicked.connect(self.stopAcquisition)
        self.btStop.setEnabled(False)
        
        self.paramTree = ParameterTree()
        self.paramTree.setParameters(Parameters.paramObject, showTop=False)
        self.paramTree.setWindowTitle('pyqtgraph example: Parameter Tree')
        self.paramTree.setMinimumWidth(350)
        self.paramTree.setMaximumWidth(350)
        sizePolicyPt = QtGui.QSizePolicy(1,1)
        sizePolicyPt.setHorizontalStretch(QtGui.QSizePolicy.Fixed)
        sizePolicyPt.setVerticalStretch(1)
        self.paramTree.setSizePolicy(sizePolicyPt);


        ## Create random 2D data
        data = np.random.normal(size=(512, 512)) + pg.gaussianFilter(np.random.normal(size=(512, 512)), (5, 5)) * 20 + 100
        data = data[:,:,np.newaxis]
        data = data.repeat(3,2)

        self.plotTl = pg.GraphicsView()
        self.plotTlImage = pg.ImageItem(data[:,:,:]) #parent=self.plotTl
        self.plotTlViewBox = pg.ViewBox()         
        self.plotTl.setCentralWidget(self.plotTlViewBox)
        self.plotTlViewBox.addItem(self.plotTlImage)

    
        self.plotTr = pg.PlotWidget(title="Interferometry", labels={'left': 'Signal amplitude (A.U.)', 'bottom': 'Distance (mm)'})
        #self.plotTlViewBox2.addItem(self.plotTr)
        self.plotTrCurve = self.plotTr.plot(pen=(255,0,0),name='C1') #Red
        self.plotTrCurve2 = self.plotTr.plot(pen=(0,255,0),name='C2') #Green
        #self.plotTlViewBox2.enableAutoRange('xy', True)  ## stop auto-scaling after the first data set is plotted
        #self.plotTr.addLegend('Test')
        self.plotTr.setYRange(-1000, 1000)
 
        self.plotBl = pg.PlotWidget(title="Distance", labels={'left': 'Distance (mm)', 'bottom': 'Number of acquisitions'})
        
        self.plotBlCurve = self.plotBl.plot(pen=(255,0,0),name='C1')
        self.plotBl.enableAutoRange('xy', True)  ## stop auto-scaling after the first data set is plotted       
        self.plotBl.setMaximumWidth(3500)
        
        self.tbInfo = QtGui.QTextEdit()
        self.tbInfo.setEnabled(False)
        palette = self.tbInfo.palette()
        palette.setColor(QtGui.QPalette.Base, QtGui.QColor("white")) #White background
        self.tbInfo.setPalette(palette)
        self.tbInfo.setTextColor(QtGui.QColor("black"))
        self.tbInfo.insertPlainText("Useful information will appear here.")
        
        #Create list view of multiple items
        self.tbStatus = QtGui.QListView()
        self.tbStatus.setEnabled(False)
        palette = self.tbStatus.palette()
        palette.setColor(QtGui.QPalette.Base, QtGui.QColor("white")) #White background
        self.tbStatus.setPalette(palette)
        itemModelStatus = QtGui.QStandardItemModel(self.tbStatus)
        self.tbStatus.setModel(itemModelStatus)
        #Add system status
        self.itemStatus = QtGui.QStandardItem()
        self.setStatus(False)      
        itemModelStatus.appendRow(self.itemStatus)    
        #Add camera status
        self.itemCameraStatus = QtGui.QStandardItem()
        self.setCameraStatus(False)      
        itemModelStatus.appendRow(self.itemCameraStatus)           
        #Add memory usage
        self.itemMemory = QtGui.QStandardItem("Acquisition board memory usage: N/A")
        self.itemMemory.setForeground(QtGui.QColor("black"))  
        itemModelStatus.appendRow(self.itemMemory)
        #Add max value position
        self.itemMaxValPos = QtGui.QStandardItem("Maximum RF value position: N/A")
        self.itemMaxValPos.setForeground(QtGui.QColor("black"))  
        itemModelStatus.appendRow(self.itemMaxValPos)        
        
        
        #layout.addWidget(QtGui.QLabel("These are two views of the same data. They should always display the same values."), 0, 0, 1, 2)
        self.layout.addWidget(self.btOpen, 9, 6, 1, 1)
        self.layout.addWidget(self.btStart, 9, 7, 1, 1)
        self.layout.addWidget(self.btStop, 9, 8, 1, 1)
        self.layout.addWidget(self.paramTree, 0, 0, 10, 3)
        self.layout.addWidget(self.plotTl, 0, 3, 5, 3) 
        self.layout.addWidget(self.plotTr, 0, 6, 5, 3)
        self.layout.addWidget(self.plotBl, 5, 3, 5, 3)
        self.layout.addWidget(self.tbInfo, 5, 6, 2, 3)
        self.layout.addWidget(self.tbStatus, 7, 6, 2, 3)

        self.layout.layout.setColumnStretch(3,1)
        self.layout.layout.setColumnStretch(4,1)
        self.layout.layout.setColumnStretch(5,1)
        self.layout.layout.setColumnStretch(6,1)
        self.layout.layout.setColumnStretch(7,1)
        self.layout.layout.setColumnStretch(8,1)

        self.show()
        self.resize(1500,800)
        self.move(100,100)    
        
        Parameters.paramObject.param('Save/Restore functionality', 'Save State').sigActivated.connect(self.saveParam)
        Parameters.paramObject.param('Save/Restore functionality', 'Restore State').sigActivated.connect(self.restoreParam)
        
        Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").sigValueChanged.connect(self.motorSpeedChanged)
        Parameters.paramObject.child("Trigger Options", "Acquisition mode").sigValueChanged.connect(self.triggerChanged)
        Parameters.paramObject.child("Trigger Options", "Trigger amplitude").sigValueChanged.connect(self.triggerChanged)
        Parameters.paramObject.child("Trigger Options", "Trigger switch 1/2").sigActivated.connect(self.triggerHalfSwitch)
        
        # adding by emitting signal in different thread
        self.workThread = AcquisitionWorker()
        self.workThread.updateDataCamera.connect(self.setDataCurveTl)
        self.workThread.updateDataInterf.connect(self.setDataCurveTr)
        self.workThread.updateDataDistance.connect(self.setDataCurveBl)
        self.workThread.updateDataDistance2.connect(self.setDataCurveBl2)
        self.workThread.updateWire.connect(self.setWire)
        self.workThread.setStatus.connect(self.setStatus)
        self.workThread.setInfo.connect(self.setInfo)
        self.testCount = 0;
        
        #Fill the plots with dummy data
        self.data = np.random.normal(size=(10,1000))    
        self.plotTrXAxis = np.arange(1000) * (0.01)
        self.plotBlXAxis = np.arange(1000) * (1)
        self.plotTrCurve.setData(x=self.plotTrXAxis,y=self.data[2%10],name='C1')
        self.plotTrCurve2.setData(x=self.plotTrXAxis,y=self.data[3%10],name='C2')    
        self.plotBlCurve.setData(x=self.plotBlXAxis,y=self.data[4%10],name='C1')            
        
        self.valueTest = 1
        
    def setDataCurveTl(self, data):
        self.dataImage1 = data
        self.plotTlImage.setImage(data)
        self.testCount = self.testCount + 1;
        
    def setDataCurveTr(self, dataIn):   
        self.plotTrCurve.setData(dataIn[0:len(dataIn):2],name='C1')        
        self.plotTrCurve2.setData(dataIn[1:len(dataIn):2],name='C2')    

    def setDataCurveBl(self, dataIn):
        self.plotBlCurve.setData(dataIn,name='C1')       
        
    def setDataCurveBl2(self, xIn, dataIn):
        self.plotBlCurve.setData(x=xIn,y=dataIn,name='C1')          
Esempio n. 7
0
class BeeActions(QObject):
    log_signal = pyqtSignal(str)

    def __init__(self, dockarea):
        super().__init__()
        self.dockarea = dockarea
        self.dockarea.dock_signal.connect(self.save_layout_state_auto)
        self.mainwindow = dockarea.parent()
        self.chrono = ChronoTimer(dockarea)
        self.author = 'Aurore Avargues'
        self.h5saver = H5Saver()
        self.h5saver.new_file_sig.connect(self.create_new_file)
        self.settings = None
        self.shortcut_file = None
        self.shortcuts = []
        self.shortcut_manager = ShortCutManager(list_actions)
        self.timestamp_array = None
        self.action_array = None
        self.bee_array = None
        self.setup_ui()

    def setup_ui(self):
        #creating the menubar
        self.menubar = self.mainwindow.menuBar()
        self.create_menu(self.menubar)

        #disconnect normal chrono/timer behaviour with the start button
        self.chrono.start_pb.disconnect()
        self.chrono.start_pb.clicked.connect(self.set_scan)
        self.chrono.reset_pb.clicked.connect(self.stop_daq)

        self.settings_dock = Dock('Settings')
        self.dockarea.addDock(self.settings_dock, 'bottom',
                              self.chrono.dock_controls)

        self.dock_daq = Dock('Data Acquisition')
        self.dockarea.addDock(self.dock_daq, 'right')
        self.logger_list = QtWidgets.QListWidget()
        self.logger_list.setMinimumWidth(300)
        self.dock_daq.addWidget(self.logger_list)

        self.init_tree = ParameterTree()
        self.init_tree.setMinimumWidth(300)
        self.init_tree.setMinimumHeight(150)
        self.settings_dock.addWidget(self.init_tree)
        self.settings_dock.addWidget(self.h5saver.settings_tree)
        self.h5saver.settings.child(('save_type')).hide()
        self.h5saver.settings.child(('save_2D')).hide()
        self.h5saver.settings.child(('save_raw_only')).hide()
        self.h5saver.settings.child(('do_save')).hide()
        self.h5saver.settings.child(('custom_name')).hide()

        self.settings = Parameter.create(name='init_settings',
                                         type='group',
                                         children=[
                                             {
                                                 'title':
                                                 'Loaded presets',
                                                 'name':
                                                 'loaded_files',
                                                 'type':
                                                 'group',
                                                 'children': [
                                                     {
                                                         'title':
                                                         'Shortcut file',
                                                         'name':
                                                         'shortcut_file',
                                                         'type': 'str',
                                                         'value': '',
                                                         'readonly': True
                                                     },
                                                     {
                                                         'title':
                                                         'Layout file',
                                                         'name': 'layout_file',
                                                         'type': 'str',
                                                         'value': '',
                                                         'readonly': True
                                                     },
                                                 ]
                                             },
                                             {
                                                 'title':
                                                 'Settings',
                                                 'name':
                                                 'settings',
                                                 'type':
                                                 'group',
                                                 'children': [
                                                     {
                                                         'title':
                                                         'Save Bee number',
                                                         'name':
                                                         'save_bee_number',
                                                         'type': 'bool',
                                                         'value': True
                                                     },
                                                 ]
                                             },
                                             {
                                                 'title': 'Shortcuts',
                                                 'name': 'shortcuts',
                                                 'type': 'group',
                                                 'children': []
                                             },
                                         ])
        self.init_tree.setParameters(self.settings, showTop=False)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        #params about dataset attributes and scan attibutes
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        params_dataset = [{
            'title':
            'Dataset information',
            'name':
            'dataset_info',
            'type':
            'group',
            'children': [{
                'title': 'Author:',
                'name': 'author',
                'type': 'str',
                'value': self.author
            }, {
                'title': 'Date/time:',
                'name': 'date_time',
                'type': 'date_time',
                'value': date
            }, {
                'title': 'Sample:',
                'name': 'sample',
                'type': 'str',
                'value': ''
            }, {
                'title': 'Experiment type:',
                'name': 'experiment_type',
                'type': 'str',
                'value': ''
            }, {
                'title': 'Description:',
                'name': 'description',
                'type': 'text',
                'value': ''
            }]
        }]

        params_scan = [{
            'title':
            'Scan information',
            'name':
            'scan_info',
            'type':
            'group',
            'children': [
                {
                    'title': 'Author:',
                    'name': 'author',
                    'type': 'str',
                    'value': self.author
                },
                {
                    'title': 'Date/time:',
                    'name': 'date_time',
                    'type': 'date_time',
                    'value': date
                },
                {
                    'title': 'Scan type:',
                    'name': 'scan_type',
                    'type': 'list',
                    'value': 'Scan1D',
                    'values': ['Scan1D', 'Scan2D']
                },
                {
                    'title': 'Scan name:',
                    'name': 'scan_name',
                    'type': 'str',
                    'value': '',
                    'readonly': True
                },
                {
                    'title': 'Description:',
                    'name': 'description',
                    'type': 'text',
                    'value': ''
                },
            ]
        }]

        self.dataset_attributes = Parameter.create(name='Attributes',
                                                   type='group',
                                                   children=params_dataset)
        self.scan_attributes = Parameter.create(name='Attributes',
                                                type='group',
                                                children=params_scan)

    def parameter_tree_changed(self, param, changes):
        """
            | Check eventual changes in the changes list parameter.
            |
            | In case of changed values, emit the signal containing the current path and parameter via update_settings_signal to the connected hardware.

            =============== ====================================    ==================================================
            **Parameters**   **Type**                                **Description**

             *param*         instance of pyqtgraph parameter         The parameter to be checked

             *changes*       (parameter,change,infos) tuple list     The (parameter,change,infos) list to be treated
            =============== ====================================    ==================================================
        """

        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass
            elif change == 'value':
                if param.name() in custom_tree.iter_children(
                        self.settings.child(('shortcuts')), []):
                    if param.parent().name() == 'shortcuts':
                        param_index = custom_tree.iter_children(
                            self.settings.child(('shortcuts')),
                            []).index(param.name())
                        action = self.shortcut_manager.shortcut_params.child(
                            ('actions')).children()[param_index].child(
                                ('action')).value()
                        self.activate_shortcut(self.shortcuts[param_index],
                                               action,
                                               activate=param.value())

            elif change == 'parent':
                pass

    def activate_shortcut(self, shortcut, action='', activate=True):
        if activate:
            shortcut.activated.connect(self.create_activated_slot(action))
        else:
            try:
                shortcut.activated.disconnect()
            except:
                pass

    def create_activated_slot(self, action):
        return lambda: self.log_data(action)

    def log_data(self, action=''):
        now = self.chrono.get_elapsed_time()
        if self.settings.child('settings', 'save_bee_number').value():
            widget = QtWidgets.QWidget()
            index, res = QtWidgets.QInputDialog.getInt(
                widget, 'Bee number', 'Pick a number for this bee!')
            if res:
                new_item = QtWidgets.QListWidgetItem(
                    f'Elapsed time: {int(now)} s, Bee {index} did :{action}')
                self.logger_list.insertItem(0, new_item)

                self.h5saver.append(self.action_array, action)
                self.h5saver.append(self.timestamp_array, np.array([now]))
                self.h5saver.append(self.bee_array, np.array([index]))
        else:
            new_item = QtWidgets.QListWidgetItem(
                f'Elapsed time: {int(now)} s:{action}')
            self.logger_list.insertItem(0, new_item)
            self.h5saver.append(self.action_array, action)
            self.h5saver.append(self.timestamp_array, np.array([now]))
        self.h5saver.flush()

    def create_shortcuts(self):
        pass

    def create_new_file(self, new_file):
        self.h5saver.init_file(update_h5=new_file)
        res = self.update_file_settings(new_file)
        return res

    def set_scan(self):
        """
        Sets the current scan given the selected settings. Makes some checks, increments the h5 file scans.
        In case the dialog is cancelled, return False and aborts the scan
        """
        try:
            if self.shortcut_file is not None:

                # set the filename and path
                res = self.create_new_file(False)
                if not res:
                    return

                #create the arrays within the current scan group
                self.timestamp_array = self.h5saver.add_array(
                    self.h5saver.current_scan_group,
                    'time_axis',
                    'data',
                    scan_type='scan1D',
                    enlargeable=True,
                    array_to_save=np.array([
                        0.,
                    ]),
                    data_shape=(1, ),
                    title='Timestamps',
                    metadata=dict(units='seconds'))

                self.action_array = self.h5saver.add_string_array(
                    self.h5saver.current_scan_group,
                    'actions',
                    title='Actions',
                    metadata=dict([]))
                if self.settings.child('settings', 'save_bee_number').value():
                    self.bee_array = self.h5saver.add_array(
                        self.h5saver.current_scan_group,
                        'bees',
                        'data',
                        scan_type='scan1D',
                        enlargeable=True,
                        array_to_save=np.array([
                            0,
                        ]),
                        title='Bees',
                        data_shape=(1, ))

                current_filename = self.h5saver.settings.child(
                    ('current_scan_name')).value()
                self.init_tree.setEnabled(False)
                self.h5saver.settings_tree.setEnabled(False)
                self.logger_list.clear()

                self.h5saver.current_scan_group._v_attrs['scan_done'] = False
                # if all metadat steps have been validated, start the chrono
                self.chrono.start()

                return True
            else:
                mssg = QtWidgets.QMessageBox()
                mssg.setText(
                    'You have to load a shortcut file configuration before starting'
                )
                mssg.exec()
                return False

        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def stop_daq(self):
        self.h5saver.current_scan_group._v_attrs['scan_done'] = True
        self.init_tree.setEnabled(True)
        self.h5saver.settings_tree.setEnabled(True)
        self.h5saver.flush()

    def update_file_settings(self, new_file=False):
        try:
            if self.h5saver.current_scan_group is None:
                new_file = True

            if new_file:
                self.set_metadata_about_dataset()
                self.save_metadata(self.h5saver.raw_group, 'dataset_info')

            if self.h5saver.current_scan_name is None:
                self.h5saver.add_scan_group()
            elif not self.h5saver.is_node_in_group(
                    self.h5saver.raw_group, self.h5saver.current_scan_name):
                self.h5saver.add_scan_group()

            #set attributes to the current group, such as scan_type....
            self.scan_attributes.child('scan_info',
                                       'scan_type').setValue('Scan1D')
            self.scan_attributes.child('scan_info', 'scan_name').setValue(
                self.h5saver.current_scan_group._v_name)
            self.scan_attributes.child('scan_info', 'description').setValue(
                self.h5saver.current_scan_group._v_attrs['description'])
            res = self.set_metadata_about_current_scan()
            self.save_metadata(self.h5saver.current_scan_group, 'scan_info')
            return res

        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def set_metadata_about_current_scan(self):
        """
            Set the date/time and author values of the scan_info child of the scan_attributes tree.
            Show the 'scan' file attributes.

            See Also
            --------
            show_file_attributes
        """
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        self.scan_attributes.child('scan_info', 'date_time').setValue(date)
        self.scan_attributes.child('scan_info', 'author').setValue(
            self.dataset_attributes.child('dataset_info', 'author').value())
        res = self.show_file_attributes('scan')
        return res

    def set_metadata_about_dataset(self):
        """
            Set the date value of the data_set_info-date_time child of the data_set_attributes tree.
            Show the 'dataset' file attributes.

            See Also
            --------
            show_file_attributes
        """
        date = QDateTime(QDate.currentDate(), QTime.currentTime())
        self.dataset_attributes.child('dataset_info',
                                      'date_time').setValue(date)
        res = self.show_file_attributes('dataset')
        return res

    def show_file_attributes(self, type_info='dataset'):
        """
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle(
            'Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res

    def save_metadata(self, node, type_info='dataset_info'):
        """
        """

        attr = node._v_attrs
        if type_info == 'dataset_info':
            attr['type'] = 'dataset'
            params = self.dataset_attributes
        else:
            attr['type'] = 'scan'
            params = self.scan_attributes
        for child in params.child((type_info)).children():
            if isinstance(child.value(), QDateTime):
                attr[child.name()] = child.value().toString(
                    'dd/mm/yyyy HH:MM:ss')
            else:
                attr[child.name()] = child.value()
        if type_info == 'dataset_info':
            #save contents of given parameter object into an xml string under the attribute settings
            settings_str = b'<All_settings title="All Settings" type="group">'
            settings_str += custom_tree.parameter_to_xml_string(params)
            settings_str += custom_tree.parameter_to_xml_string(self.settings)
            if hasattr(self.shortcut_manager, 'shortcut_params'):
                settings_str += custom_tree.parameter_to_xml_string(
                    self.shortcut_manager.shortcut_params)
            settings_str += b'</All_settings>'

            attr.settings = settings_str

        elif type_info == 'scan_info':
            settings_str = b'<All_settings title="All Settings" type="group">' + \
                           custom_tree.parameter_to_xml_string(params) + \
                           custom_tree.parameter_to_xml_string(self.settings) + \
                           custom_tree.parameter_to_xml_string(self.h5saver.settings) + b'</All_settings>'

            attr.settings = settings_str

    def show_log(self):
        import webbrowser
        webbrowser.open(logging.getLoggerClass().root.handlers[0].baseFilename)

    def show_file(self):
        self.h5saver.flush()
        self.h5saver.show_file_content()

    def create_menu(self, menubar):
        menubar.clear()

        # %% create Settings menu
        self.file_menu = menubar.addMenu('File')
        self.file_menu.addAction('Show log file', self.show_log)
        self.file_menu.addAction('Show data file', self.show_file)

        self.file_menu.addSeparator()
        quit_action = self.file_menu.addAction('Quit')
        quit_action.triggered.connect(self.quit_fun)

        self.settings_menu = menubar.addMenu('Settings')
        docked_menu = self.settings_menu.addMenu('Docked windows')
        action_load = docked_menu.addAction('Load Layout')
        action_save = docked_menu.addAction('Save Layout')

        action_load.triggered.connect(self.load_layout_state)
        action_save.triggered.connect(self.save_layout_state)
        docked_menu.addSeparator()

        self.preset_menu = menubar.addMenu('Preset Shortcuts')
        action_new_preset = self.preset_menu.addAction('New preset')
        # action.triggered.connect(lambda: self.show_file_attributes(type_info='preset'))
        action_new_preset.triggered.connect(self.create_preset)
        action_modify_preset = self.preset_menu.addAction('Modify preset')
        action_modify_preset.triggered.connect(self.modify_shortcuts)
        self.preset_menu.addSeparator()
        load_preset = self.preset_menu.addMenu('Load presets')

        slots = dict([])
        for ind_file, file in enumerate(os.listdir(shortcut_path)):
            if file.endswith(".xml"):
                (filesplited, ext) = os.path.splitext(file)
                slots[filesplited] = load_preset.addAction(filesplited)
                slots[filesplited].triggered.connect(
                    self.create_menu_slot(os.path.join(shortcut_path, file)))

    def modify_shortcuts(self):
        try:
            path = select_file(start_path=shortcut_path, save=False, ext='xml')
            if path != '':
                self.shortcut_manager.set_file_preset(str(path))

                mssg = QtWidgets.QMessageBox()
                mssg.setText(
                    f'You have to restart the application to take the modifications into account! '
                    f'Quitting the application...')
                mssg.exec()
                self.quit_fun()
            else:  # cancel
                pass
        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def create_menu_slot(self, filename):
        return lambda: self.set_shortcut_mode(filename)

    def set_shortcut_mode(self, filename):
        #TODO: apply shortcuts to this widget
        tail, fileext = os.path.split(filename)
        file, ext = os.path.splitext(fileext)
        if ext == '.xml':
            self.shortcut_file = filename
            self.shortcut_manager.set_file_preset(filename, show=False)
            self.settings.child('loaded_files',
                                'shortcut_file').setValue(filename)
            self.author = self.shortcut_manager.shortcut_params.child(
                ('author')).value()
            self.dataset_attributes.child('dataset_info',
                                          'author').setValue(self.author)
            self.scan_attributes.child('scan_info',
                                       'author').setValue(self.author)

            path = os.path.join(layout_path, file + '.dock')
            if os.path.isfile(path):
                self.load_layout_state(path)

            #remove existing shorcuts
            while len(self.shortcuts):
                self.shortcuts.pop(0)

            for ind, shortcut in enumerate(
                    self.shortcut_manager.shortcut_params.child(
                        ('actions')).children()):
                stc = QtWidgets.QShortcut(
                    QtGui.QKeySequence(shortcut.child(('shortcut')).value()),
                    self.dockarea)
                self.settings.child(('shortcuts')).addChild({
                    'title':
                    f"Shortcut{ind:02d}: {shortcut.child(('action')).value()} {shortcut.child(('shortcut')).value()}:",
                    'name': f'shortcut{ind:02d}',
                    'type': 'led_push',
                    'value': True
                })

                self.shortcuts.append(stc)
                self.activate_shortcut(stc,
                                       shortcut.child(('action')).value(),
                                       activate=True)

    def create_preset(self):
        try:
            self.shortcut_manager.set_new_preset()
            self.create_menu(self.menubar)
        except Exception as e:
            self.update_status(getLineInfo() + str(e))

    def save_layout_state(self, file=None):
        """
            Save the current layout state in the select_file obtained pathname file.
            Once done dump the pickle.

            See Also
            --------
            utils.select_file
        """
        try:
            dockstate = self.dockarea.saveState()
            if file is None:
                file = select_file(start_path=None, save=True, ext='dock')
            if file is not None:
                with open(str(file), 'wb') as f:
                    pickle.dump(dockstate, f, pickle.HIGHEST_PROTOCOL)
        except:
            pass

    def save_layout_state_auto(self):
        if self.shortcut_file is not None:
            file = os.path.split(self.shortcut_file)[1]
            file = os.path.splitext(file)[0]
            path = os.path.join(layout_path, file + '.dock')
            self.save_layout_state(path)

    def load_layout_state(self, file=None):
        """
            Load and restore a layout state from the select_file obtained pathname file.

            See Also
            --------
            utils.select_file
        """
        try:
            if file is None:
                file = select_file(save=False, ext='dock')
            if file is not None:
                with open(str(file), 'rb') as f:
                    dockstate = pickle.load(f)
                    self.dockarea.restoreState(dockstate)
            file = os.path.split(file)[1]
            self.settings.child('loaded_files', 'layout_file').setValue(file)
        except:
            pass

    def quit_fun(self):
        """
            Quit the current instance of DAQ_scan and close on cascade move and detector modules.

            See Also
            --------
            quit_fun
        """
        try:
            areas = self.dockarea.tempAreas[:]
            for area in areas:
                area.win.close()
                QtWidgets.QApplication.processEvents()
                QThread.msleep(1000)
                QtWidgets.QApplication.processEvents()

            if hasattr(self, 'mainwindow'):
                self.mainwindow.close()

        except Exception as e:
            pass

    def update_status(self, txt):
        """
            Show the txt message in the status bar with a delay of wait_time ms.

            =============== =========== =======================
            **Parameters**    **Type**    **Description**
            *txt*             string      The message to show
            *wait_time*       int         the delay of showing
            *log_type*        string      the type of the log
            =============== =========== =======================
        """
        try:
            self.log_signal.emit(txt)
            logging.info(txt)

        except Exception as e:
            pass
Esempio n. 8
0
class BatchManager:

    params = [{'title': 'Filename:', 'name': 'filename', 'type': 'str', 'value': 'batch_default'},
              {'title': 'Scans', 'name': 'scans', 'type': 'group', 'children': []}]

    def __init__(self, msgbox=False, actuators=[], detectors=[], path=None):
        self.actuators = actuators
        self.detectors = detectors

        self.scans = OrderedDict([])

        self.tree = ParameterTree()
        self.tree.setMinimumWidth(400)
        self.tree.setMaximumWidth(500)
        self.tree.setMinimumHeight(500)

        if path is None:
            path = batch_path
        else:
            assert isinstance(path, Path)
        self.batch_path = path

        self.settings = None


        if msgbox:
            msgBox = QtWidgets.QMessageBox()
            msgBox.setText("Scan Batch Manager?")
            msgBox.setInformativeText("What do you want to do?")
            cancel_button = msgBox.addButton(QtWidgets.QMessageBox.Cancel)
            new_button = msgBox.addButton("New", QtWidgets.QMessageBox.ActionRole)
            modify_button = msgBox.addButton('Modify', QtWidgets.QMessageBox.AcceptRole)
            msgBox.setDefaultButton(QtWidgets.QMessageBox.Cancel)
            ret = msgBox.exec()

            if msgBox.clickedButton() == new_button:
                self.set_new_batch()

            elif msgBox.clickedButton() == modify_button:
                self.set_file_batch()
            else:  # cancel
                pass


    def get_act_dets(self):
        acts = dict([])
        dets = dict([])
        for name in self.scans:
            acts[name] = self.settings.child('scans', name, 'modules',
                            'actuators').value()['selected']
            dets[name] = self.settings.child('scans', name, 'modules',
                                             'detectors').value()['selected']
        return acts, dets

    def set_file_batch(self, filename=None, show=True):
        """

        """

        if filename is None or filename == False:
            filename = pymodaq.daq_utils.gui_utils.file_io.select_file(start_path=self.batch_path, save=False, ext='xml')
            if filename == '':
                return

        status = False
        settings_tmp = Parameter.create(title='Batch', name='settings_tmp',
                                        type='group', children=ioxml.XML_file_to_parameter(str(filename)))

        children = settings_tmp.child('scans').children()
        self.settings = Parameter.create(title='Batch', name='settings', type='group', children=self.params)
        actuators = children[0].child('modules', 'actuators').value()['all_items']
        if actuators != self.actuators:
            pymodaq.daq_utils.messenger.show_message('The loaded actuators from the batch file do not corresponds to the'
                                ' dashboard actuators')
            return
        else:
            self.actuators = actuators

        detectors = children[0].child('modules', 'detectors').value()['all_items']
        if detectors != self.detectors:
            pymodaq.daq_utils.messenger.show_message('The loaded detectors from the batch file do not corresponds to the'
                                ' dashboard detectors')
            return
        else:
            self.detectors = detectors

        for child in children:
            self.add_scan(name=child.name(), title=child.opts['title'])
            self.settings.child('scans', child.name()).restoreState(child.saveState())

        if show:
            status = self.show_tree()
        else:
            self.tree.setParameters(self.settings, showTop=False)
        return status

    def set_scans(self):
        infos = []
        acts, dets = self.get_act_dets()
        for scan in self.scans:
            infos.append(f'{scan}: {acts[scan]} / {dets[scan]}')
            infos.append(f'{scan}: {self.scans[scan].set_scan()}')
        return infos

    def set_new_batch(self):
        self.settings = Parameter.create(title='Batch', name='settings', type='group', children=self.params)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        status = self.show_tree()
        return status

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if change == 'childAdded':
                pass

            elif change == 'value':

                pass

            elif change == 'parent':
                pass

    def show_tree(self):
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        add_scan = QtWidgets.QPushButton('Add Scan')
        add_scan.clicked.connect(self.add_scan)
        self.tree.setParameters(self.settings, showTop=False)
        vlayout.addWidget(add_scan)
        vlayout.addWidget(self.tree)
        dialog.setLayout(vlayout)

        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Save', buttonBox.AcceptRole)
        buttonBox.accepted.connect(dialog.accept)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.rejected.connect(dialog.reject)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this Scan batch')
        res = dialog.exec()

        if res == dialog.Accepted:
            # save managers parameters in a xml file
            # start = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0]
            # start = os.path.join("..",'daq_scan')
            ioxml.parameter_to_xml_file(
                self.settings, os.path.join(self.batch_path, self.settings.child('filename').value()))

        return res == dialog.Accepted

    def add_scan(self, name=None, title=None):
        if name is None or name is False:
            name_prefix = 'scan'
            child_indexes = [int(par.name()[len(name_prefix) + 1:]) for par in self.settings.child('scans').children()]
            if child_indexes == []:
                newindex = 0
            else:
                newindex = max(child_indexes) + 1
            name = f'{name_prefix}{newindex:02.0f}'
            title = f'Scan {newindex:02.0f}'

        child = {'title': title, 'name': name, 'type': 'group', 'removable': True, 'children': params}

        self.scans[name] = Scanner(actuators=[self.actuators[0]], adaptive_losses=adaptive_losses)
        self.settings.child('scans').addChild(child)
        self.settings.child('scans', name, 'modules',
                            'actuators').setValue(dict(all_items=self.actuators,
                                                       selected=[self.actuators[0]]))
        self.settings.child('scans', name, 'modules',
                            'detectors').setValue(dict(all_items=self.detectors,
                                                       selected=[self.detectors[0]]))

        self.settings.child('scans', name).addChild(
            self.scans[name].settings)
Esempio n. 9
0
class ModulesManager(QObject):
    detectors_changed = Signal(list)
    actuators_changed = Signal(list)
    det_done_signal = Signal(OrderedDict)
    move_done_signal = Signal(OrderedDict)
    timeout_signal = Signal(bool)

    params = [
        {
            'title':
            'Actuators/Detectors Selection',
            'name':
            'modules',
            'type':
            'group',
            'children': [
                {
                    'title': 'detectors',
                    'name': 'detectors',
                    'type': 'itemselect'
                },
                {
                    'title': 'Actuators',
                    'name': 'actuators',
                    'type': 'itemselect'
                },
            ]
        },
        {
            'title': "Moves done?",
            'name': 'move_done',
            'type': 'led',
            'value': False
        },
        {
            'title': "Detections done?",
            'name': 'det_done',
            'type': 'led',
            'value': False
        },
        {
            'title':
            'Data dimensions',
            'name':
            'data_dimensions',
            'type':
            'group',
            'children': [
                {
                    'title': "Probe detector's data",
                    'name': 'probe_data',
                    'type': 'action'
                },
                {
                    'title': 'Data0D list:',
                    'name': 'det_data_list0D',
                    'type': 'itemselect'
                },
                {
                    'title': 'Data1D list:',
                    'name': 'det_data_list1D',
                    'type': 'itemselect'
                },
                {
                    'title': 'Data2D list:',
                    'name': 'det_data_list2D',
                    'type': 'itemselect'
                },
                {
                    'title': 'DataND list:',
                    'name': 'det_data_listND',
                    'type': 'itemselect'
                },
            ]
        },
        {
            'title':
            'Actuators positions',
            'name':
            'actuators_positions',
            'type':
            'group',
            'children': [
                {
                    'title': "Test actuators",
                    'name': 'test_actuator',
                    'type': 'action'
                },
                {
                    'title': 'Positions:',
                    'name': 'positions_list',
                    'type': 'itemselect'
                },
            ]
        },
    ]

    def __init__(self,
                 detectors=[],
                 actuators=[],
                 selected_detectors=[],
                 selected_actuators=[],
                 timeout=10000):
        super().__init__()

        for mod in selected_actuators:
            assert mod in actuators
        for mod in selected_detectors:
            assert mod in detectors

        self.timeout = timeout  # in ms

        self.det_done_datas = OrderedDict()
        self.det_done_flag = False
        self.move_done_positions = OrderedDict()
        self.move_done_flag = False

        self.settings = Parameter.create(name='Settings',
                                         type='group',
                                         children=self.params)
        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumWidth(300)
        self.settings_tree.setParameters(self.settings, showTop=False)

        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        self.settings.child('data_dimensions',
                            'probe_data').sigActivated.connect(
                                self.get_det_data_list)
        self.settings.child('actuators_positions',
                            'test_actuator').sigActivated.connect(
                                self.test_move_actuators)

        self._detectors = []
        self._actuators = []

        self.grab_done_signals = []
        self.det_commands_signal = []

        self.actuators_connected = False
        self.detectors_connected = False

        self.set_actuators(actuators, selected_actuators)
        self.set_detectors(detectors, selected_detectors)

    @classmethod
    def get_names(cls, modules):
        if not hasattr(modules, '__iter__'):
            modules = [modules]
        return [mod.title for mod in modules]

    def get_mods_from_names(self, names, mod='det'):
        mods = []
        for name in names:
            d = self.get_mod_from_name(name, mod)
            if d is not None:
                mods.append(d)
        return mods

    def get_mod_from_name(self, name, mod='det'):
        if mod == 'det':
            modules = self._detectors
        else:
            modules = self._actuators

        if name in self.get_names(modules):
            return modules[self.get_names(modules).index(name)]
        else:
            logger.warning(f'No detector with this name: {name}')
            return None

    def set_actuators(self, actuators, selected_actuators):
        self._actuators = actuators
        self.settings.child('modules', 'actuators').setValue(
            dict(all_items=self.get_names(actuators),
                 selected=self.get_names(selected_actuators)))

    def set_detectors(self, detectors, selected_detectors):
        self._detectors = detectors
        self.settings.child('modules', 'detectors').setValue(
            dict(all_items=self.get_names(detectors),
                 selected=self.get_names(selected_detectors)))

    @property
    def detectors(self):
        return self.get_mods_from_names(self.selected_detectors_name)

    @property
    def detectors_all(self):
        return self._detectors

    @property
    def actuators(self):
        return self.get_mods_from_names(self.selected_actuators_name,
                                        mod='act')

    @property
    def actuators_all(self):
        return self._actuators

    @property
    def Ndetectors(self):
        return len(self.detectors)

    @property
    def Nactuators(self):
        return len(self.actuators)

    @property
    def detectors_name(self):
        return self.settings.child('modules', 'detectors').value()['all_items']

    @property
    def selected_detectors_name(self):
        return self.settings.child('modules', 'detectors').value()['selected']

    @selected_detectors_name.setter
    def selected_detectors_name(self, detectors):
        if set(detectors).issubset(self.detectors_name):
            self.settings.child('modules', 'detectors').setValue(
                dict(all_items=self.detectors_name, selected=detectors))

    @property
    def actuators_name(self):
        return self.settings.child('modules', 'actuators').value()['all_items']

    @property
    def selected_actuators_name(self):
        return self.settings.child('modules', 'actuators').value()['selected']

    @selected_actuators_name.setter
    def selected_actuators_name(self, actuators):
        if set(actuators).issubset(self.actuators_name):
            self.settings.child('modules', 'actuators').setValue(
                dict(all_items=self.actuators_name, selected=actuators))

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if change == 'childAdded':
                pass

            elif change == 'value':

                if param.name() == 'detectors':
                    self.detectors_changed.emit(data['selected'])

                elif param.name() == 'actuators':
                    self.actuators_changed.emit(data['selected'])

            elif change == 'parent':
                pass

    def get_det_data_list(self):
        self.connect_detectors()

        datas = self.grab_datas()

        data_list0D = []
        data_list1D = []
        data_list2D = []
        data_listND = []

        for k in datas.keys():
            if 'data0D' in datas[k].keys():
                data_list0D.extend(
                    [f'{k}/{name}' for name in datas[k]['data0D'].keys()])
            if 'data1D' in datas[k].keys():
                data_list1D.extend(
                    [f'{k}/{name}' for name in datas[k]['data1D'].keys()])
            if 'data2D' in datas[k].keys():
                data_list2D.extend(
                    [f'{k}/{name}' for name in datas[k]['data2D'].keys()])
            if 'dataND' in datas[k].keys():
                data_listND.extend(
                    [f'{k}/{name}' for name in datas[k]['dataND'].keys()])

        self.settings.child('data_dimensions', 'det_data_list0D').setValue(
            dict(all_items=data_list0D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_list1D').setValue(
            dict(all_items=data_list1D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_list2D').setValue(
            dict(all_items=data_list2D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_listND').setValue(
            dict(all_items=data_listND, selected=[]))

        self.connect_detectors(False)

    def get_selected_probed_data(self, dim='0D'):
        return self.settings.child(
            'data_dimensions',
            f'det_data_list{dim.upper()}').value()['selected']

    def grab_datas(self, **kwargs):
        self.det_done_datas = OrderedDict()
        self.det_done_flag = False
        self.settings.child(('det_done')).setValue(self.det_done_flag)
        tzero = time.perf_counter()

        for sig in [mod.command_detector for mod in self.detectors]:
            sig.emit(utils.ThreadCommand("single", [1, kwargs]))

        while not self.det_done_flag:
            # wait for grab done signals to end

            QtWidgets.QApplication.processEvents()
            if time.perf_counter() - tzero > self.timeout:
                self.timeout_signal.emit(True)
                logger.error(
                    'Timeout Fired during waiting for data to be acquired')
                break

        self.det_done_signal.emit(self.det_done_datas)
        return self.det_done_datas

    def connect_actuators(self, connect=True, slot=None):
        if slot is None:
            slot = self.move_done
        if connect:
            for sig in [mod.move_done_signal for mod in self.actuators]:
                sig.connect(slot)

        else:
            try:
                for sig in [mod.move_done_signal for mod in self.actuators]:
                    sig.disconnect(slot)
            except Exception as e:
                logger.error(str(e))

        self.actuators_connected = connect

    def connect_detectors(self, connect=True, slot=None):
        """
        Connect selected DAQ_Viewers's grab_done_signal to the given slot
        Parameters
        ----------
        connect: (bool) if True, connect to the given slot (or default slot)
                        if False, disconnect all detectors (not only the currently selected ones.
                        This is made because when selected detectors changed if you only disconnect those ones,
                        the previously connected ones will stay connected)

        slot: (method) A method that should be connected
        """
        if slot is None:
            slot = self.det_done

        if connect:
            for sig in [mod.grab_done_signal for mod in self.detectors]:
                sig.connect(slot)
        else:

            for sig in [mod.grab_done_signal for mod in self.detectors_all]:
                try:
                    sig.disconnect(slot)
                except TypeError as e:
                    # means the slot was not previously connected
                    logger.info(str(e))

        self.detectors_connected = connect

    def test_move_actuators(self):
        positions = dict()
        for act in self.get_names(self.actuators):
            pos, done = QtWidgets.QInputDialog.getDouble(
                None, f'Enter a target position for actuator {act}',
                'Position:')
            if not done:
                pos = 0.
            positions[act] = pos

        self.connect_actuators()

        positions = self.move_actuators(positions)

        self.settings.child('actuators_positions', 'positions_list').setValue(
            dict(all_items=[f'{k}: {positions[k]}' for k in positions],
                 selected=[]))

        self.connect_actuators(False)

    def move_actuators(self, positions, mode='abs', polling=True):
        """will apply positions to each currently selected actuators. By Default the mode is absolute but can be

        Parameters
        ----------
        positions: (list) the list of position to apply. Its length must be equal to the number of selected actutors
        mode: (str) either 'abs' for absolute positionning or 'rel' for relative
        poll: (bool) if True will wait for the selected actuators to reach their target positions (they have to be
        connected to a method checking for the position and letting the programm know the move is done (default
        connection is this object `move_done` method)

        Returns
        -------
        (OrderedDict) with the selected actuators's name as key and current actuators's value as value

        See Also
        --------
        move_done
        """
        self.move_done_positions = OrderedDict()
        self.move_done_flag = False
        self.settings.child(('move_done')).setValue(self.move_done_flag)

        if mode == 'abs':
            command = 'move_Abs'
        elif mode == 'rel':
            command = 'move_Rel'
        else:
            logger.error(f'Invalid positioning mode: {mode}')
            return self.move_done_positions

        if not hasattr(positions, '__iter__'):
            positions = [positions]

        if len(positions) == self.Nactuators:
            if isinstance(positions, dict):
                for k in positions:
                    act = self.get_mod_from_name(k, 'act')
                    if act is not None:
                        act.command_stage.emit(
                            utils.ThreadCommand(
                                command=command,
                                attributes=[positions[k], polling]))
            else:
                for ind, act in enumerate(self.actuators):
                    act.command_stage.emit(
                        utils.ThreadCommand(
                            command=command,
                            attributes=[positions[ind], polling]))

        else:
            logger.error(
                'Invalid number of positions compared to selected actuators')
            return self.move_done_positions

        tzero = time.perf_counter()
        if polling:
            while not self.move_done_flag:  # polling move done

                QtWidgets.QApplication.processEvents()
                if time.perf_counter() - tzero > self.timeout:
                    self.timeout_signal.emit(True)
                    logger.error(
                        'Timeout Fired during waiting for data to be acquired')
                    break
                QThread.msleep(20)

        self.move_done_signal.emit(self.move_done_positions)
        return self.move_done_positions

    def order_positions(self, positions_as_dict):
        actuators = self.selected_actuators_name
        pos = []
        for act in actuators:
            pos.append(positions_as_dict[act])
        return pos

    Slot(str, float)

    def move_done(self, name, position):
        """
        """
        try:
            if name not in list(self.move_done_positions.keys()):
                self.move_done_positions[name] = position

            if len(self.move_done_positions.items()) == len(self.actuators):
                self.move_done_flag = True
                self.settings.child('move_done').setValue(self.move_done_flag)
        except Exception as e:
            logger.exception(str(e))

    @Slot(OrderedDict)
    def det_done(self, data):
        try:
            if data['name'] not in list(self.det_done_datas.keys()):
                self.det_done_datas[data['name']] = data
            if len(self.det_done_datas.items()) == len(self.detectors):
                self.det_done_flag = True
                self.settings.child(('det_done')).setValue(self.det_done_flag)
        except Exception as e:
            logger.exception(str(e))
Esempio n. 10
0
class Spectrometer(QObject):
    """
    Defines a Spectrometer object, unified interface for many spectrometers

    Parameters that could be set in the selected detector plugin (should be defined there):
    'laser_wl' : value of the configured laser (could eventually be changed, case of Xplora, Labram...)
    'spectro_center_freq': value of the configured grating center wavelength (could eventually be changed, case of Shamrock, Xplora...)


    """
    #custom signal that will be fired sometimes. Could be connected to an external object method or an internal method
    log_signal = Signal(str)

    #list of dicts enabling the settings tree on the user interface
    params = [
        {
            'title':
            'Configuration settings:',
            'name':
            'config_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Laser wavelength (nm):',
                    'name': 'laser_wl',
                    'type': 'float',
                    'value': 515.
                },
                {
                    'title': 'Laser wavelength (nm):',
                    'name': 'laser_wl_list',
                    'type': 'list',
                    'limits': ['']
                },
                {
                    'title': 'Current Detector:',
                    'name': 'curr_det',
                    'type': 'str',
                    'value': ''
                },
                {
                    'title': 'Show detector:',
                    'name': 'show_det',
                    'type': 'bool',
                    'value': False
                },
            ],
        },
        {
            'title':
            'Calibration settings:',
            'name':
            'calib_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Use calibration:',
                    'name': 'use_calib',
                    'type': 'bool',
                    'value': False
                },
                {
                    'title': 'Save calibration',
                    'name': 'save_calib',
                    'type': 'bool_push',
                    'value': False
                },
                {
                    'title': 'Load calibration',
                    'name': 'load_calib',
                    'type': 'bool_push',
                    'value': False
                },
                {
                    'title':
                    'Calibration coeffs:',
                    'name':
                    'calib_coeffs',
                    'type':
                    'group',
                    'children': [
                        {
                            'title': 'Center wavelength (nm):',
                            'name': 'center_calib',
                            'type': 'float',
                            'value': 515.
                        },
                        {
                            'title': 'Slope (nm/pxl):',
                            'name': 'slope_calib',
                            'type': 'float',
                            'value': 1.
                        },
                        {
                            'title': 'Second order :',
                            'name': 'second_calib',
                            'type': 'float',
                            'value': 0
                        },
                        {
                            'title': 'third:',
                            'name': 'third_calib',
                            'type': 'float',
                            'value': 0
                        },
                    ]
                },
                {
                    'title': 'Perform calibration:',
                    'name': 'do_calib',
                    'type': 'bool',
                    'value': False
                },
            ]
        },
        {
            'title':
            'Acquisition settings:',
            'name':
            'acq_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'Spectro. Center:',
                    'name': 'spectro_center_freq',
                    'type': 'float',
                    'value': 800,
                },
                {
                    'title': 'Spectro. Center:',
                    'name': 'spectro_center_freq_txt',
                    'type': 'str',
                    'value': '????',
                    'readonly': True
                },
                {
                    'title': 'Units:',
                    'name': 'units',
                    'type': 'list',
                    'value': 'nm',
                    'limits': ['nm', 'cm-1', 'eV']
                },
                {
                    'title': 'Exposure (ms):',
                    'name': 'exposure_ms',
                    'type': 'float',
                    'value': 100,
                },
            ]
        },
    ]

    def __init__(self, parent):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super().__init__()
        if not isinstance(parent, DockArea):
            raise Exception('no valid parent container, expected a DockArea')

        self.wait_time = 2000  #ms
        self.offline = True
        self.dockarea = parent
        self.mainwindow = parent.parent()
        self.spectro_widget = QtWidgets.QWidget()
        self.data_dict = None
        """
        List of the possible plugins that could be used with Spectrometer module
        type : dimensionality of the detector
        name: name of the plugin
        calib = True means there is a builtin calibration of the frequency axis
        movable : tells if the dispersion can be set (for instance by moving a grating)
        unit: valid only if calib is True. Unit of the calibration axis (x_axis of the detector), most often in
              nanometers. Possible values are 'nm', 'radfs' (rad/femtosecond), 'eV'
        laser: if False,  laser cannot be changed by the program, do it manually
        laser_list: if laser is True, laser_list gives a list of selectable lasers
        
        """

        self.current_det = None  # will be after initialization

        self.laser_set_manual = True

        #init the object parameters
        self.detector = None
        self.save_file_pathname = None
        self._spectro_wl = 550  # center wavelngth of the spectrum
        self.viewer_freq_axis = utils.Axis(data=None,
                                           label='Photon energy',
                                           units='')
        self.raw_data = []

        #init the user interface
        self.dashboard = self.set_dashboard()
        self.dashboard.preset_loaded_signal.connect(
            lambda: self.show_detector(False))
        self.dashboard.preset_loaded_signal.connect(self.set_detector)
        self.dashboard.preset_loaded_signal.connect(self.initialized)
        self.set_GUI()
        self.dashboard.new_preset_created.connect(
            lambda: self.create_menu(self.menubar))

        self.show_detector(False)
        self.dockarea.setEnabled(False)

    def set_dashboard(self):
        params = [
            {
                'title':
                'Spectro Settings:',
                'name':
                'spectro_settings',
                'type':
                'group',
                'children': [
                    {
                        'title':
                        'Is calibrated?',
                        'name':
                        'iscalibrated',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has internal frequency calibration or not.'
                    },
                    {
                        'title':
                        'Movable?',
                        'name':
                        'ismovable',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has a functionality to change its central frequency: as a movable grating'
                        ' for instance.'
                    },
                    {
                        'title':
                        'Laser selectable?',
                        'name':
                        'laser_selectable',
                        'type':
                        'bool',
                        'value':
                        False,
                        'tooltip':
                        'Whether the selected plugin has a functionality to change its excitation ray'
                    },
                    {
                        'title': 'Laser ray:',
                        'name': 'laser_ray',
                        'type': 'list',
                        'value': '',
                        'show_pb': True,
                        'tooltip':
                        'List of settable laser rays (not manual ones)'
                    },
                ]
            },
        ]
        dashboard = DashBoard(self.dockarea.addTempArea())
        dashboard.set_preset_path(spectro_path)
        options = [
            dict(path='saving_options', options_dict=dict(visible=False)),
            dict(path='use_pid', options_dict=dict(visible=False)),
            dict(path='Moves', options_dict=dict(visible=False))
        ]
        dashboard.set_extra_preset_params(params, options)

        dashboard.dockarea.window().setVisible(False)
        return dashboard

    def set_GUI(self):
        ###########################################
        ###########################################
        #init the docks containing the main widgets

        #######################################################################################################################
        #create a dock containing a viewer object, displaying the data for the spectrometer
        self.dock_viewer = Dock('Viewer dock', size=(350, 350))
        self.dockarea.addDock(self.dock_viewer, 'left')
        target_widget = QtWidgets.QWidget()
        self.viewer = Viewer1D(target_widget)
        self.dock_viewer.addWidget(target_widget)

        ################################################################
        #create a logger dock where to store info senf from the programm
        self.dock_logger = Dock("Logger")
        self.logger_list = QtWidgets.QListWidget()
        self.logger_list.setMinimumWidth(300)
        self.dock_logger.addWidget(self.logger_list)
        self.dockarea.addDock(self.dock_logger, 'right')
        self.log_signal[str].connect(self.add_log)

        ############################################
        # creating a menubar
        self.menubar = self.mainwindow.menuBar()
        self.create_menu(self.menubar)

        #creating a toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.create_toolbar()
        self.mainwindow.addToolBar(self.toolbar)

        #creating a status bar
        self.statusbar = QtWidgets.QStatusBar()
        self.statusbar.setMaximumHeight(25)

        self.status_laser = QtWidgets.QLabel('????')
        self.status_laser.setAlignment(Qt.AlignCenter)
        #self.status_laser.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        #self.status_laser.setReadOnly(True)
        self.status_laser.setMaximumWidth(80)
        self.status_laser.setMinimumWidth(80)
        self.status_laser.setToolTip('Current laser wavelength')
        self.status_laser.setStyleSheet("background-color: red")

        self.status_center = QtWidgets.QLabel('????')
        self.status_center.setAlignment(Qt.AlignCenter)
        #self.status_center.setReadOnly(True)
        #self.status_center.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.status_center.setMaximumWidth(80)
        self.status_center.setMinimumWidth(80)
        self.status_center.setToolTip(
            'center frequency of the spectrum, either in nm or cm-1')
        self.status_center.setStyleSheet("background-color: red")

        self.status_init = QLED()
        self.status_init.setToolTip('Initialization state of the detector')
        self.status_init.set_as_false()
        self.status_init.clickable = False

        self.statusbar.addPermanentWidget(self.status_laser)
        self.statusbar.addPermanentWidget(self.status_center)
        self.statusbar.addPermanentWidget(self.status_init)
        self.dockarea.window().setStatusBar(self.statusbar)

        #############################################
        self.settings = Parameter.create(name='settings',
                                         type='group',
                                         children=self.params)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        dock_config_settings = Dock('Configuration', size=(300, 350))
        self.dockarea.addDock(dock_config_settings, 'above', self.dock_logger)
        # create main parameter tree
        self.config_settings_tree = ParameterTree()
        dock_config_settings.addWidget(self.config_settings_tree, 10)
        self.config_settings_tree.setMinimumWidth(300)
        self.config_settings_tree.setParameters(self.settings.child(
            ('config_settings')),
                                                showTop=False)
        #any change to the tree on the user interface will call the parameter_tree_changed method where all actions will be applied

        dock_calib_settings = Dock('Calibration', size=(300, 350))
        self.dockarea.addDock(dock_calib_settings, 'above', self.dock_logger)
        # create main parameter tree
        self.calib_settings_tree = ParameterTree()
        dock_calib_settings.addWidget(self.calib_settings_tree, 10)
        self.calib_settings_tree.setMinimumWidth(300)
        self.calib_settings_tree.setParameters(self.settings.child(
            ('calib_settings')),
                                               showTop=False)
        #any change to the tree on the user interface will call the parameter_tree_changed method where all actions will be applied

        #this one for the custom application settings
        dock_acq_settings = Dock('Acquisition', size=(300, 350))
        self.dockarea.addDock(dock_acq_settings, 'above', dock_config_settings)
        # create main parameter tree
        self.acq_settings_tree = ParameterTree()
        dock_acq_settings.addWidget(self.acq_settings_tree, 10)
        self.acq_settings_tree.setMinimumWidth(300)
        self.acq_settings_tree.setParameters(self.settings.child(
            ('acq_settings')),
                                             showTop=False)

    @Slot(ThreadCommand)
    def cmd_from_det(self, status):
        try:
            if status.command == 'spectro_wl':
                self.status_center.setStyleSheet("background-color: green")
                self.spectro_wl_is(status.attributes[0])

            elif status.command == 'laser_wl':
                #self.laser_set_manual = False
                self.settings.child('config_settings',
                                    'laser_wl_list').setValue(
                                        status.attributes[0])
                self.status_laser.setText('{:}nm'.format(status.attributes[0]))
                self.status_laser.setStyleSheet("background-color: green")
                self.update_center_frequency(self.spectro_wl)

            elif status.command == 'exposure_ms':
                self.settings.child('acq_settings', 'exposure_ms').setValue(
                    status.attributes[0])

            elif status.command == "x_axis":
                x_axis = status.attributes[0]
                if np.any(x_axis['data'] != self.viewer_freq_axis['data']
                          ) and self.current_det['calib']:
                    self.viewer_freq_axis.update(x_axis)
                    self.update_axis()

        except Exception as e:
            logger.exception(str(e))

    def update_status(self, txt, wait_time=1000, log_type=None):
        """

        """
        self.statusbar.showMessage(txt, wait_time)
        if log_type is not None:
            self.log_signal.emit(txt)

    def set_detector(self):

        self.detector = self.dashboard.detector_modules[0]
        self.settings.child('config_settings', 'curr_det').setValue(
            f"{self.detector.settings.child('main_settings','DAQ_type').value()} / "
            f"{self.detector.settings.child('main_settings','detector_type').value()} / {self.detector.title}"
        )
        self.detector.custom_sig[ThreadCommand].connect(self.cmd_from_det)
        self.current_det = \
            dict(laser=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'laser_selectable').value(),
                 laser_list=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'laser_ray').opts['limits'],
                 movable=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'ismovable').value(),
                 calib=self.dashboard.preset_manager.preset_params.child('spectro_settings', 'iscalibrated').value(),
                 )

        self.detector.grab_done_signal.connect(self.show_data)

        self.settings.sigTreeStateChanged.disconnect(
            self.parameter_tree_changed)
        if self.current_det['laser']:
            self.settings.child('config_settings', 'laser_wl_list').show()
            self.settings.child('config_settings', 'laser_wl').hide()
            self.settings.child(
                'config_settings',
                'laser_wl_list').setOpts(limits=self.current_det['laser_list'])
        else:
            self.settings.child('config_settings', 'laser_wl').show()
            self.settings.child('config_settings', 'laser_wl_list').hide()
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        #apply current detector particularities
        #self.settings.child('acq_settings', 'spectro_center_freq').setOpts(readonly=not self.current_det['movable'])
        self.get_spectro_wl()
        QtWidgets.QApplication.processEvents()

        self.get_laser_wl()
        QtWidgets.QApplication.processEvents()

        self.get_exposure_ms()
        QtWidgets.QApplication.processEvents()

    def get_exposure_ms(self):
        self.detector.command_detector.emit(ThreadCommand('get_exposure_ms'))

    def set_exposure_ms(self, data):
        self.detector.command_detector.emit(
            ThreadCommand('set_exposure_ms', [data]))

    @Slot(bool)
    def initialized(self, state, offline=False):
        self.offline = offline
        self.grab_action.setEnabled(state)
        self.snap_action.setEnabled(state)
        if state or offline:
            self.status_init.set_as_true()
            self.dockarea.setEnabled(True)
        else:
            self.status_init.set_as_false()

    def update_center_frequency(self, spectro_wl):
        self._spectro_wl = spectro_wl
        if self.settings.child('acq_settings', 'units').value() == 'nm':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(spectro_wl)
        elif self.settings.child('acq_settings', 'units').value() == 'cm-1':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(
                                    Enm2cmrel(
                                        spectro_wl,
                                        self.settings.child(
                                            'config_settings',
                                            'laser_wl').value()))
        elif self.settings.child('acq_settings', 'units').value() == 'eV':
            self.settings.child('acq_settings',
                                'spectro_center_freq').setValue(
                                    nm2eV(spectro_wl))

        self.set_status_center(
            self.settings.child('acq_settings', 'spectro_center_freq').value(),
            self.settings.child('acq_settings', 'units').value())

    def set_status_center(self, val, unit, precision=3):
        self.status_center.setText(f'{val:.{precision}f} {unit}')

    def spectro_wl_is(self, spectro_wl):
        """
        this slot receives a signal from the detector telling it what's the current spectro_wl
        Parameters
        ----------
        spectro_wl
        """
        self._spectro_wl = spectro_wl
        self.update_center_frequency(spectro_wl)

    def set_spectro_wl(self, spectro_wl):
        try:
            if self.current_det['movable']:
                self.detector.command_detector.emit(
                    ThreadCommand('set_spectro_wl', [spectro_wl]))
        except Exception as e:
            logger.exception(str(e))

    def get_spectro_wl(self):
        if self.current_det['calib']:
            self.settings.child('acq_settings', 'spectro_center_freq').show()
            self.settings.child('acq_settings',
                                'spectro_center_freq_txt').hide()
            self.detector.command_detector.emit(
                ThreadCommand('get_spectro_wl'))
            self.detector.command_detector.emit(ThreadCommand('get_axis'))
        else:
            self.settings.child('acq_settings', 'spectro_center_freq').hide()
            self.settings.child('acq_settings',
                                'spectro_center_freq_txt').show()
            self.viewer_freq_axis['units'] = 'Pxls'

    def get_laser_wl(self):
        if self.current_det['laser']:
            self.detector.command_detector.emit(ThreadCommand('get_laser_wl'))
        else:
            self.settings.child('config_settings', 'laser_wl').setValue(0)

    @property
    def spectro_wl(self):
        # try to get the param value from detector (if it has been added in the plugin)
        return self._spectro_wl

    @spectro_wl.setter
    def spectro_wl(self, spec_wl):
        # try to get the param value from detector (if it has been added in the plugin)
        self.set_spectro_wl(spec_wl)

    def show_detector(self, show=True):
        self.dashboard.mainwindow.setVisible(show)
        for area in self.dashboard.dockarea.tempAreas:
            area.window().setVisible(show)

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'show_det':
                    self.show_detector(data)

                elif param.name() == 'spectro_center_freq':
                    unit = self.settings.child('acq_settings', 'units').value()
                    if unit == 'nm':
                        center_wavelength = data
                    elif unit == 'cm-1':
                        center_wavelength = Ecmrel2Enm(
                            data,
                            self.settings.child('config_settings',
                                                'laser_wl').value())
                    elif unit == 'eV':
                        center_wavelength = eV2nm(data)

                    if int(self.spectro_wl * 100) != int(
                            100 * center_wavelength):  #comprison at 1e-2
                        self.spectro_wl = center_wavelength

                    self.update_axis()

                elif param.name() == 'units':
                    if self.settings.child(
                            'acq_settings',
                            'spectro_center_freq').value() > 0.000000001:
                        if data == 'nm':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    self._spectro_wl)
                        elif data == 'cm-1':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    Enm2cmrel(
                                        self._spectro_wl,
                                        self.settings.child(
                                            'config_settings',
                                            'laser_wl').value()))
                        elif data == 'eV':
                            self.settings.child(
                                'acq_settings',
                                'spectro_center_freq').setValue(
                                    nm2eV(self._spectro_wl))

                        self.set_status_center(
                            self.settings.child('acq_settings',
                                                'spectro_center_freq').value(),
                            self.settings.child('acq_settings',
                                                'units').value())

                elif param.name() == 'laser_wl_list':
                    if data is not None:
                        self.move_laser_wavelength(data)

                elif param.name() == 'laser_wl':
                    if data is not None:
                        self.move_laser_wavelength(data)
                        if int(data) == 0:
                            self.settings.child('acq_settings',
                                                'units').setValue('nm')
                            self.settings.child('acq_settings',
                                                'units').setOpts(readonly=True)
                        else:
                            self.settings.child(
                                'acq_settings',
                                'units').setOpts(readonly=False)
                        if data != 0:
                            self.set_manual_laser_wl(data)

                elif param.name() == 'exposure_ms':
                    self.set_exposure_ms(data)

                elif param.name() == 'do_calib':
                    if len(self.raw_data) != 0:
                        if data:
                            self.calib_dock = Dock('Calibration module')
                            self.dockarea.addDock(self.calib_dock)
                            self.calibration = Calibration(self.dockarea)
                            self.calib_dock.addWidget(self.calibration)

                            self.calibration.coeffs_calib.connect(
                                self.update_calibration)
                        else:
                            self.calib_dock.close()

                elif param.name() == 'save_calib':
                    filename = select_file(start_path=self.save_file_pathname,
                                           save=True,
                                           ext='xml')
                    if filename != '':
                        custom_tree.parameter_to_xml_file(
                            self.settings.child('calib_settings',
                                                'calib_coeffs'), filename)

                elif param.name() == 'load_calib':
                    filename = select_file(start_path=self.save_file_pathname,
                                           save=False,
                                           ext='xml')
                    if filename != '':
                        children = custom_tree.XML_file_to_parameter(filename)
                        self.settings.child(
                            'calib_settings', 'calib_coeffs').restoreState(
                                Parameter.create(
                                    title='Calibration coeffs:',
                                    name='calib_coeffs',
                                    type='group',
                                    children=children).saveState())



                elif param.name() in custom_tree.iter_children(self.settings.child('calib_settings', 'calib_coeffs')) \
                        or param.name() == 'use_calib':
                    if self.settings.child('calib_settings',
                                           'use_calib').value():
                        calib_coeffs = [
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'third_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'second_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'slope_calib').value(),
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'center_calib').value()
                        ]

                        self.update_center_frequency(
                            self.settings.child('calib_settings',
                                                'calib_coeffs',
                                                'center_calib').value())
                        self.settings.child('acq_settings',
                                            'spectro_center_freq').show()
                        self.settings.child(
                            'acq_settings',
                            'spectro_center_freq').setOpts(readonly=True)
                        self.status_center.setStyleSheet(
                            "background-color: green")
                        self.settings.child('acq_settings',
                                            'spectro_center_freq_txt').hide()
                        x_axis_pxls = np.linspace(0, self.raw_data[0].size - 1,
                                                  self.raw_data[0].size)
                        self.viewer_freq_axis['data'] = np.polyval(
                            calib_coeffs,
                            x_axis_pxls - np.max(x_axis_pxls) / 2)
                        self.update_axis()
                    else:
                        self.settings.child('acq_settings',
                                            'spectro_center_freq').hide()
                        self.settings.child('acq_settings',
                                            'spectro_center_freq_txt').show()
                        self.status_center.setStyleSheet(
                            "background-color: red")

            elif change == 'parent':
                pass

    @Slot(list)
    def update_calibration(self, coeffs):
        self.settings.child('calib_settings', 'calib_coeffs',
                            'center_calib').setValue(coeffs[0])
        self.settings.child('calib_settings', 'calib_coeffs',
                            'slope_calib').setValue(coeffs[1])
        if len(coeffs) > 2:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'second_calib').setValue(coeffs[2])
        else:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'second_calib').setValue(0)
        if len(coeffs) > 3:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'third_calib').setValue(coeffs[3])
        else:
            self.settings.child('calib_settings', 'calib_coeffs',
                                'third_calib').setValue(0)

    def set_manual_laser_wl(self, laser_wl):
        messg = QtWidgets.QMessageBox()
        messg.setText(
            'You manually changed the laser wavelength to {:}nm!'.format(
                laser_wl))
        messg.setInformativeText("Is that correct?")
        messg.setStandardButtons(QtWidgets.QMessageBox.Yes
                                 | QtWidgets.QMessageBox.No)
        ret = messg.exec()
        if ret == QtWidgets.QMessageBox.Yes:
            self.status_laser.setText('{:}nm'.format(laser_wl))
            self.status_laser.setStyleSheet("background-color: green")
            self.settings.child('acq_settings',
                                'units').setOpts(readonly=False)

    def move_laser_wavelength(self, laser_wavelength):
        #do hardware stuff if possible (Mock, labspec...)
        try:
            if self.current_det['laser']:
                self.detector.command_detector.emit(
                    ThreadCommand('set_laser_wl', [laser_wavelength]))
        except Exception as e:
            logger.exception(str(e))

    @Slot(OrderedDict)
    def show_data(self, data):
        """
        do stuff with data from the detector if its grab_done_signal has been connected
        Parameters
        ----------
        data: (OrderedDict) #OrderedDict(name=self.title,x_axis=None,y_axis=None,z_axis=None,data0D=None,data1D=None,data2D=None)
        """
        self.data_dict = data
        if 'data1D' in data:
            self.raw_data = []
            for key in data['data1D']:
                self.raw_data.append(data['data1D'][key]['data'])
                if 'x_axis' in data['data1D'][key]:
                    x_axis = data['data1D'][key]['x_axis']
                else:
                    x_axis = utils.Axis(data=np.linspace(
                        0,
                        len(data['data1D'][key]['data']) - 1,
                        len(data['data1D'][key]['data'])),
                                        units='pxls',
                                        label='')
                if self.viewer_freq_axis['data'] is None:
                    self.viewer_freq_axis.update(x_axis)
                elif np.any(x_axis['data'] != self.viewer_freq_axis['data']
                            ) and self.current_det['calib']:
                    self.viewer_freq_axis.update(x_axis)

            self.viewer.show_data(self.raw_data)
            self.update_axis()

    def update_axis(self):
        axis = utils.Axis()
        unit = self.settings.child('acq_settings', 'units').value()
        if unit == 'nm':
            axis['data'] = self.viewer_freq_axis['data']
        elif unit == 'cm-1':
            axis['data'] = Enm2cmrel(
                self.viewer_freq_axis['data'],
                self.settings.child('config_settings', 'laser_wl').value())
        elif unit == 'eV':
            axis['data'] = nm2eV(self.viewer_freq_axis['data'])
        axis['units'] = unit
        axis['label'] = 'Photon energy'
        self.viewer.x_axis = axis

    def create_menu(self, menubar):
        """
        """
        menubar.clear()

        # %% create file menu
        file_menu = menubar.addMenu('File')
        load_action = file_menu.addAction('Load file')
        load_action.triggered.connect(self.load_file)
        save_action = file_menu.addAction('Save file')
        save_action.triggered.connect(self.save_data)
        export_action = file_menu.addAction('Export as ascii')
        export_action.triggered.connect(lambda: self.save_data(export=True))

        file_menu.addSeparator()
        file_menu.addAction('Show log file', self.show_log)
        file_menu.addSeparator()
        quit_action = file_menu.addAction('Quit')
        quit_action.triggered.connect(self.quit_function)

        settings_menu = menubar.addMenu('Settings')
        settings_menu.addAction('Show Units Converter',
                                self.show_units_converter)
        docked_menu = settings_menu.addMenu('Docked windows')
        docked_menu.addAction('Load Layout', self.load_layout_state)
        docked_menu.addAction('Save Layout', self.save_layout_state)

        self.preset_menu = menubar.addMenu(self.dashboard.preset_menu)
        self.preset_menu.menu().addSeparator()
        self.preset_menu.menu().addAction(
            'Offline Mode',
            lambda: self.initialized(state=False, offline=True))

    def load_layout_state(self, file=None):
        """
            Load and restore a layout state from the select_file obtained pathname file.

            See Also
            --------
            utils.select_file
        """
        try:
            if file is None:
                file = select_file(save=False, ext='dock')
            if file is not None:
                with open(str(file), 'rb') as f:
                    dockstate = pickle.load(f)
                    self.dockarea.restoreState(dockstate)
            file = file.name
            self.settings.child('loaded_files', 'layout_file').setValue(file)
        except Exception as e:
            logger.exception(str(e))

    def save_layout_state(self, file=None):
        """
            Save the current layout state in the select_file obtained pathname file.
            Once done dump the pickle.

            See Also
            --------
            utils.select_file
        """
        try:
            dockstate = self.dockarea.saveState()
            if 'float' in dockstate:
                dockstate['float'] = []
            if file is None:
                file = select_file(start_path=None, save=True, ext='dock')
            if file is not None:
                with open(str(file), 'wb') as f:
                    pickle.dump(dockstate, f, pickle.HIGHEST_PROTOCOL)
        except Exception as e:
            logger.exception(str(e))

    def show_log(self):
        import webbrowser
        webbrowser.open(logging.getLogger('pymodaq').handlers[0].baseFilename)

    def show_units_converter(self):
        self.units_converter = UnitsConverter()
        dock_converter = Dock('Units Converter', size=(300, 350))
        self.dockarea.addDock(dock_converter, 'bottom', self.dock_logger)
        dock_converter.addWidget(self.units_converter.parent)

    def load_file(self):
        data, fname, node_path = browse_data(ret_all=True)
        if data is not None:
            h5utils = H5BrowserUtil()
            h5utils.open_file(fname)
            data, axes, nav_axes, is_spread = h5utils.get_h5_data(node_path)
            data_node = h5utils.get_node(node_path)
            if data_node.attrs['type'] == 'data':
                if data_node.attrs['data_dimension'] == '1D':
                    data_dict = OrderedDict(data1D=dict(
                        raw=dict(data=data, x_axis=axes['x_axis'])))
                    self.show_data(data_dict)
            h5utils.close_file()

    def quit_function(self):
        #close all stuff that need to be
        if self.detector is not None:
            self.detector.quit_fun()
            QtWidgets.QApplication.processEvents()
            self.mainwindow.close()

    def create_toolbar(self):
        self.toolbar.addWidget(QtWidgets.QLabel('Acquisition:'))

        iconquit = QtGui.QIcon()
        iconquit.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/close2.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.quit_action = QtWidgets.QAction(iconquit, "Quit program", None)
        self.toolbar.addAction(self.quit_action)
        self.quit_action.triggered.connect(self.quit_function)

        iconload = QtGui.QIcon()
        iconload.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/Open.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.loadaction = QtWidgets.QAction(
            iconload, "Load target file (.h5, .png, .jpg) or data from camera",
            None)
        self.toolbar.addAction(self.loadaction)
        self.loadaction.triggered.connect(self.load_file)

        iconsave = QtGui.QIcon()
        iconsave.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/SaveAs.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.saveaction = QtWidgets.QAction(iconsave, "Save current data",
                                            None)
        self.toolbar.addAction(self.saveaction)
        self.saveaction.triggered.connect(self.save_data)

        iconrun = QtGui.QIcon()
        iconrun.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/run2.png"),
                          QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.grab_action = QtWidgets.QAction(iconrun, 'Grab', None)
        self.grab_action.setCheckable(True)
        self.toolbar.addAction(self.grab_action)
        self.grab_action.triggered.connect(self.grab_detector)

        iconsnap = QtGui.QIcon()
        iconsnap.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/snap.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.snap_action = QtWidgets.QAction(iconsnap, 'Snap', None)
        self.snap_action.triggered.connect(self.snap_detector)
        self.toolbar.addAction(self.snap_action)

        self.grab_action.setEnabled(False)
        self.snap_action.setEnabled(False)

    def grab_detector(self):
        self.detector.ui.grab_pb.click()

    def snap_detector(self):
        self.detector.ui.single_pb.click()

    def save_data(self, export=False):
        try:
            if export:
                ext = 'dat'
            else:
                ext = 'h5'
            path = select_file(start_path=self.save_file_pathname,
                               save=True,
                               ext=ext)
            if not (not (path)):
                if not export:
                    h5saver = H5Saver(save_type='detector')
                    h5saver.init_file(update_h5=True,
                                      custom_naming=False,
                                      addhoc_file_path=path)

                    settings_str = b'<All_settings>' + custom_tree.parameter_to_xml_string(
                        self.settings)
                    if self.detector is not None:
                        settings_str += custom_tree.parameter_to_xml_string(
                            self.detector.settings)
                        if hasattr(self.detector.ui.viewers[0], 'roi_manager'):
                            settings_str += custom_tree.parameter_to_xml_string(
                                self.detector.ui.viewers[0].roi_manager.
                                settings)
                    settings_str += custom_tree.parameter_to_xml_string(
                        h5saver.settings)
                    settings_str += b'</All_settings>'

                    det_group = h5saver.add_det_group(h5saver.raw_group,
                                                      "Data", settings_str)
                    try:
                        self.channel_arrays = OrderedDict([])
                        data_dim = 'data1D'
                        if not h5saver.is_node_in_group(det_group, data_dim):
                            self.channel_arrays['data1D'] = OrderedDict([])
                            data_group = h5saver.add_data_group(
                                det_group, data_dim)
                            for ind_channel, data in enumerate(
                                    self.raw_data):  # list of numpy arrays
                                channel = f'CH{ind_channel:03d}'
                                channel_group = h5saver.add_CH_group(
                                    data_group, title=channel)

                                self.channel_arrays[data_dim][
                                    'parent'] = channel_group
                                self.channel_arrays[data_dim][
                                    channel] = h5saver.add_data(
                                        channel_group,
                                        dict(data=data,
                                             x_axis=self.viewer_freq_axis),
                                        scan_type='',
                                        enlargeable=False)
                        h5saver.close_file()
                    except Exception as e:
                        logger.exception(str(e))
                else:
                    data_to_save = [self.viewer_freq_axis['data']]
                    data_to_save.extend([dat for dat in self.raw_data])
                    np.savetxt(path, data_to_save, delimiter='\t')

        except Exception as e:
            logger.exception(str(e))

    @Slot(str)
    def add_log(self, txt):
        """
            Add a log to the logger list from the given text log and the current time

            ================ ========= ======================
            **Parameters**   **Type**   **Description**

             *txt*             string    the log to be added
            ================ ========= ======================

        """
        now = datetime.datetime.now()
        new_item = QtWidgets.QListWidgetItem(str(now) + ": " + txt)
        self.logger_list.addItem(new_item)
        ##to do
        ##self.save_parameters.logger_array.append(str(now)+": "+txt)

    @Slot(str)
    def emit_log(self, txt):
        """
            Emit a log-signal from the given log index

            =============== ======== =======================
            **Parameters**  **Type** **Description**

             *txt*           string   the log to be emitted
            =============== ======== =======================

        """
        self.log_signal.emit(txt)
Esempio n. 11
0
class DAQ_Logger(QObject):
    """
    Main class initializing a DAQ_Scan module with its dashboard and scanning control panel
    """
    command_DAQ_signal = pyqtSignal(list)
    status_signal = pyqtSignal(str)

    params = [
        {'title': 'Log Type:', 'name': 'log_type', 'type': 'str', 'value': '', 'readonly': True},
    ]

    def __init__(self, dockarea=None, dashboard=None):
        """

        Parameters
        ----------
        dockarea: (dockarea) instance of the modified pyqtgraph Dockarea (see daq_utils)
        dashboard: (DashBoard) instance of the pymodaq dashboard
        """
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super().__init__()
        self.dockarea = dockarea
        self.dashboard = dashboard
        if dashboard is None:
            raise Exception('No valid dashboard initialized')
        self.mainwindow = self.dockarea.parent()
        self.wait_time = 1000

        self.logger_thread = None
        self.detector_modules = self.dashboard.detector_modules
        self.det_modules_log = []
        self.log_types = ['None', 'H5 File']
        if is_sql:
            self.log_types.append('SQL DataBase')

        self.logger = None  # should be a reference either to self.h5saver or self.dblogger depending the choice of the user
        self.h5saver = H5Saver(save_type='logger')
        if is_sql:
            self.dblogger = DbLoggerGUI(self.dashboard.preset_file.stem)
        else:
            self.dblogger = None
        self.modules_manager = ModulesManager()

        self.setupUI()
        self.setup_modules(self.dashboard.title)

        self.h5saver.settings_tree.setVisible(False)
        if is_sql:
            self.dblogger.settings_tree.setVisible(False)

    def create_menu(self):
        """
        """
        # %% create Settings menu
        menubar = QtWidgets.QMenuBar()
        menubar.setMaximumHeight(30)
        self.ui.layout.insertWidget(0, menubar)

        self.file_menu = menubar.addMenu('File')

    def quit_fun(self):
        """
            Quit the current instance of DAQ_scan and close on cascade move and detector modules.

            See Also
            --------
            quit_fun
        """
        try:
            self.h5saver.close_file()
        except Exception as e:
            logger.exception(str(e))
        try:
            self.dblogger.close()
        except Exception as e:
            logger.exception(str(e))
        self.ui.logger_dock.close()

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'log_type':
                    if param.value() == 'H5 File':
                        self.logger = self.h5saver
                    elif param.value() == 'SQL DataBase':
                        self.logger = self.dblogger
                self.h5saver.settings_tree.setVisible(param.value() == 'H5 File')
                if self.dblogger is not None:
                    self.dblogger.settings_tree.setVisible(param.value() == 'SQL DataBase')
            elif change == 'parent':
                pass

    def setup_modules(self, filename):
        """

        """
        try:
            ######################################################################
            # setting moves and det in tree
            preset_items_det = []
            items_det = [module.title for module in self.detector_modules]
            if items_det != []:
                preset_items_det = items_det

            self.modules_manager.set_detectors(self.detector_modules, preset_items_det)

        except Exception as e:
            logger.exception(str(e))

    def set_continuous_save(self):
        """
            Set a continous save file using the base path located file with
            a header-name containing date as a string.

            See Also
            --------
            daq_utils.set_current_scan_path
        """
        self.do_continuous_save = True
        self.logger.settings.child(('N_saved')).show()
        self.logger.settings.child(('N_saved')).setValue(0)

        settings_str = b'<All_settings>'
        settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(self.dashboard.settings)
        settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(
            self.dashboard.preset_manager.preset_params)
        if self.dashboard.settings.child('loaded_files', 'overshoot_file').value() != '':
            settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(
                self.dashboard.overshoot_manager.overshoot_params)
        if self.dashboard.settings.child('loaded_files', 'roi_file').value() != '':
            settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(
                self.dashboard.roi_saver.roi_presets)
        settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(self.settings)
        settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(self.logger.settings)
        settings_str += b'</All_settings>'

        if self.settings.child(('log_type')).value() == 'H5 File':
            self.logger.settings.child(('base_name')).setValue('DataLogging')
            self.h5saver.init_file(update_h5=True, metadata=dict(settings=settings_str))
            logger.addHandler(H5LogHandler(self.h5saver))
            self.h5saver.h5_file.flush()

        elif self.settings.child(('log_type')).value() == 'SQL DataBase':
            if not self.logger.settings.child('connected_db').value():
                status = self.logger.connect_db()
                if not status:
                    logger.critical('the Database is not and cannot be connnect')
                    self.update_status('the Database is not and cannot be connnect')
                    return False

            self.logger.add_config(settings_str)
            logger.addHandler(DBLogHandler(self.logger))

        return True

    def set_logging(self):
        """

        """
        status = self.set_continuous_save()
        if status:
            det_modules_log = self.modules_manager.detectors
            if det_modules_log != []:
                # check if the modules are initialized
                for module in det_modules_log:
                    if not module.initialized_state:
                        logger.error(f'module {module.title} is not initialized')
                        return False

                # create the detectors in the chosen logger
                for det in det_modules_log:
                    settings_str = b'<All_settings>'
                    settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(det.settings)
                    for viewer in det.ui.viewers:
                        if hasattr(viewer, 'roi_manager'):
                            settings_str += pymodaq.daq_utils.parameter.ioxml.parameter_to_xml_string(
                                viewer.roi_manager.settings)
                    settings_str += b'</All_settings>'

                    if self.settings.child(('log_type')).value() == 'H5 File':
                        if det.title not in self.h5saver.raw_group.children_name():
                            det_group = self.h5saver.add_det_group(self.h5saver.raw_group, det.title, settings_str)
                            self.h5saver.add_navigation_axis(np.array([0.0, ]),
                                                             det_group, 'time_axis', enlargeable=True,
                                                             title='Time axis',
                                                             metadata=dict(label='Time axis', units='timestamp',
                                                                           nav_index=0))

                    elif self.settings.child(('log_type')).value() == 'SQL DataBase':
                        self.logger.add_detectors([dict(name=det.title, xml_settings=settings_str)])

                self.ui.start_button.setEnabled(True)
                self.ui.stop_button.setEnabled(True)
                return True
            else:
                self.update_status('Cannot start logging... No detectors selected')
                self.ui.start_button.setEnabled(False)
                self.ui.stop_button.setEnabled(True)
                return False

        else:
            self.update_status('Cannot start logging... check connections')
            self.ui.start_button.setEnabled(False)
            self.ui.stop_button.setEnabled(True)
            return False

    def show_log(self):
        import webbrowser
        webbrowser.open(logger.handlers[0].baseFilename)

    def setupUI(self):

        self.ui = QObject()

        widget_settings = QtWidgets.QWidget()
        self.ui.layout = QtWidgets.QVBoxLayout()

        widget_settings.setLayout(self.ui.layout)

        widget_buttons = QtWidgets.QWidget()
        layout_buttons = QtWidgets.QHBoxLayout()
        widget_buttons.setLayout(layout_buttons)
        self.ui.layout.addWidget(widget_buttons)

        iconquit = QtGui.QIcon()
        iconquit.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/close2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.ui.quit_button = QtWidgets.QPushButton(iconquit, 'Quit')

        iconstart = QtGui.QIcon()
        iconstart.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/run2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.ui.start_button = QtWidgets.QPushButton(iconstart, '')
        self.ui.start_button.setToolTip('Start logging into h5file or database')

        iconstop = QtGui.QIcon()
        iconstop.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/stop.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.ui.stop_button = QtWidgets.QPushButton(iconstop, '')
        self.ui.stop_button.setToolTip('Stop/pause logging')

        log_type_combo = QtWidgets.QComboBox()
        log_type_combo.addItems(self.log_types)
        log_type_combo.currentTextChanged.connect(self.set_log_type)

        iconstartall = QtGui.QIcon()
        iconstartall.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/run_all.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.ui.startall_button = QtWidgets.QPushButton(iconstartall, '')
        self.ui.startall_button.setToolTip('Grab all selected detectors')

        layout_buttons.addWidget(self.ui.quit_button)
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.ui.startall_button)
        layout_buttons.addWidget(log_type_combo)
        layout_buttons.addWidget(self.ui.start_button)
        layout_buttons.addWidget(self.ui.stop_button)

        # %% create logger dock and make it a floating window
        self.ui.logger_dock = Dock("Logger", size=(1, 1), autoOrientation=False)
        # give this dock the minimum possible size
        self.ui.logger_dock.setOrientation('vertical')
        self.ui.logger_dock.addWidget(widget_settings)
        self.dockarea.addDock(self.ui.logger_dock, 'left')
        self.ui.logger_dock.float()

        widget_hor = QtWidgets.QWidget()
        layout_hor = QtWidgets.QHBoxLayout()

        main_sett_widget = QtWidgets.QWidget()
        main_sett_widget.setLayout(QtWidgets.QVBoxLayout())

        widget_hor.setLayout(layout_hor)
        self.ui.layout.addWidget(widget_hor)

        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumWidth(300)
        layout_hor.addWidget(main_sett_widget)
        main_sett_widget.layout().addWidget(self.settings_tree)
        main_sett_widget.layout().addWidget(self.modules_manager.settings_tree)

        self.modules_manager.settings.child('modules', 'actuators').hide()
        self.modules_manager.settings.child(('data_dimensions')).hide()
        self.modules_manager.settings.child(('actuators_positions')).hide()

        self.h5saver.settings_tree.setMinimumWidth(300)
        layout_hor.addWidget(self.h5saver.settings_tree)

        if is_sql:
            self.dblogger.settings_tree.setMinimumWidth(300)
            layout_hor.addWidget(self.dblogger.settings_tree)

        self.settings = Parameter.create(name='Settings', type='group', children=self.params)
        self.settings_tree.setParameters(self.settings, showTop=False)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        # %% init and set the status bar
        self.ui.statusbar = QtWidgets.QStatusBar(self.dockarea)
        self.ui.statusbar.setMaximumHeight(25)
        self.ui.layout.addWidget(self.ui.statusbar)
        self.ui.log_message = QtWidgets.QLabel('Initializing')
        self.ui.statusbar.addPermanentWidget(self.ui.log_message)

        self.ui.start_log_time = QtWidgets.QDateTimeEdit()
        self.ui.start_log_time.setReadOnly(True)
        self.ui.start_log_time.setToolTip('Logging started at:')

        self.ui.logging_state = QLED()
        self.ui.logging_state.setToolTip('logging status: green (running), red (idle)')
        self.ui.logging_state.clickable = False

        self.ui.statusbar.addPermanentWidget(self.ui.start_log_time)
        self.ui.statusbar.addPermanentWidget(self.ui.logging_state)
        self.ui.layout.addWidget(self.ui.statusbar)

        #       connecting
        self.status_signal[str].connect(self.dashboard.add_status)
        self.ui.quit_button.clicked.connect(self.quit_fun)

        self.ui.start_button.clicked.connect(self.start_logging)
        self.ui.stop_button.clicked.connect(self.stop_logging)
        self.ui.startall_button.clicked.connect(self.start_all)

        self.create_menu()

    def start_all(self):
        preset_items_det = self.modules_manager.detectors
        for det in preset_items_det:
            det.ui.grab_pb.click()

    def set_log_type(self, log_type):

        self.settings.child(('log_type')).setValue(log_type)

    def show_file_attributes(self, type_info='dataset'):
        """
            Switch the type_info value.

            In case of :
                * *scan* : Set parameters showing top false
                * *dataset* : Set parameters showing top false
                * *managers* : Set parameters showing top false. Add the save/cancel buttons to the accept/reject dialog (to save managers parameters in a xml file).

            Finally, in case of accepted managers type info, save the managers parameters in a xml file.

            =============== =========== ====================================
            **Parameters**    **Type**    **Description**
            *type_info*       string      The file type information between
                                            * scan
                                            * dataset
                                            * managers
            =============== =========== ====================================

            See Also
            --------
            custom_tree.parameter_to_xml_file, create_menu
        """
        dialog = QtWidgets.QDialog()
        vlayout = QtWidgets.QVBoxLayout()
        tree = ParameterTree()
        tree.setMinimumWidth(400)
        tree.setMinimumHeight(500)
        if type_info == 'scan':
            tree.setParameters(self.scan_attributes, showTop=False)
        elif type_info == 'dataset':
            tree.setParameters(self.dataset_attributes, showTop=False)

        vlayout.addWidget(tree)
        dialog.setLayout(vlayout)
        buttonBox = QtWidgets.QDialogButtonBox(parent=dialog)
        buttonBox.addButton('Cancel', buttonBox.RejectRole)
        buttonBox.addButton('Apply', buttonBox.AcceptRole)
        buttonBox.rejected.connect(dialog.reject)
        buttonBox.accepted.connect(dialog.accept)

        vlayout.addWidget(buttonBox)
        dialog.setWindowTitle('Fill in information about this {}'.format(type_info))
        res = dialog.exec()
        return res

    def show_file_content(self):
        try:
            self.h5saver.init_file(addhoc_file_path=self.h5saver.settings.child(('current_h5_file')).value())
            self.h5saver.show_file_content()
        except Exception as e:
            logger.exception(str(e))

    def start_logging(self):
        """
            Start a logging.
        """
        self.ui.log_message.setText('Starting logging')

        self.overshoot = False
        res = self.set_logging()

        # mandatory to deal with multithreads
        if self.logger_thread is not None:
            self.command_DAQ_signal.disconnect()
            if self.logger_thread.isRunning():
                self.logger_thread.exit()
                while not self.logger_thread.isFinished():
                    QThread.msleep(100)
                self.logger_thread = None

        self.logger_thread = QThread()

        log_acquisition = DAQ_Logging(self.settings, self.logger, self.modules_manager)

        log_acquisition.moveToThread(self.logger_thread)

        self.command_DAQ_signal[list].connect(log_acquisition.queue_command)
        log_acquisition.status_sig[list].connect(self.thread_status)

        self.logger_thread.log_acquisition = log_acquisition
        self.logger_thread.start()

        self.ui.start_button.setEnabled(False)
        QtWidgets.QApplication.processEvents()
        self.ui.logging_state.set_as_false()

        self.command_DAQ_signal.emit(["start_logging"])
        self.ui.log_message.setText('Running acquisition')

    def stop_logging(self):
        """
            Emit the command_DAQ signal "stop_acquisiion".

            See Also
            --------
            set_ini_positions
        """
        preset_items_det = self.modules_manager.detectors
        for det in preset_items_det:
            det.ui.stop_pb.click()
        self.command_DAQ_signal.emit(["stop_acquisition"])

        if not self.dashboard.overshoot:
            status = 'Data Logging has been stopped by user'
        else:
            status = 'Data Logging has been stopped due to overshoot'

        self.update_status(status)
        self.ui.start_button.setEnabled(True)

    @pyqtSlot(list)
    def thread_status(self, status):  # general function to get datas/infos from all threads back to the main
        """
            | General function to get datas/infos from all threads back to the main.
            |

            Switch the status with :
                * *"Update status"* : Update the status bar with the status attribute txt message
                * *"Update_scan_index"* : Set the value of the User Interface - indice_scan_sb attribute.
                * *"Scan_done"* : Save the scan and init the positions
                * *"Timeout"* : Set the "Timeout occured" in the User Interface-log message

            See Also
            --------
            update_status, save_scan, set_ini_positions
        """
        if status[0] == "Update_Status":
            self.update_status(status[1], wait_time=self.wait_time)

        elif status[0] == "Timeout":
            self.ui.log_message.setText('Timeout occurred')

    def update_status(self, txt, wait_time=0):
        """
            Show the txt message in the status bar with a delay of wait_time ms.

            =============== =========== =======================
            **Parameters**    **Type**    **Description**
            *txt*             string      The message to show
            *wait_time*       int         the delay of showing
            *log_type*        string      the type of the log
            =============== =========== =======================
        """
        try:
            self.ui.statusbar.showMessage(txt, wait_time)
            logging.info(txt)
        except Exception as e:
            logger.exception(str(e))
Esempio n. 12
0
class Calibration(QtWidgets.QWidget):
    log_signal = Signal(str)
    coeffs_calib = Signal(list)

    params = [
        {
            'title': 'Laser wavelength (nm):',
            'name': 'laser_wl',
            'type': 'float',
            'value': 515.
        },
        {
            'title':
            'Fit options:',
            'name':
            'fit_options',
            'type':
            'group',
            'children': [
                {
                    'title': 'Fit in?:',
                    'name': 'fit_units',
                    'type': 'list',
                    'value': 'nm',
                    'limits': ['nm', 'cm-1', 'eV']
                },
                {
                    'title': 'Polynomial Fit order:',
                    'name': 'fit_order',
                    'type': 'int',
                    'value': 1,
                    'min': 1,
                    'max': 3
                },
                {
                    'title': 'Do calib:',
                    'name': 'do_calib',
                    'type': 'bool',
                    'value': False
                },
            ]
        },
        {
            'title': 'Peaks',
            'name': 'peaks_table',
            'type': 'table_view'
        },
        PeakGroup(title='Peak options:', name="peak_options", channels=[]),
    ]

    def __init__(self, parent):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super().__init__()
        if not isinstance(parent, DockArea):
            raise Exception('no valid parent container, expected a DockArea')
        self.dockarea = parent
        self.window = self.dockarea.parent()

        self.setupUI()

        self.raw_datas = dict([])
        self.raw_axis = None
        self.text_peak_items = []
        self.arrow_peak_items = []
        self.table_model = None
        self.calib_plot = None
        self.filenames = []

    def create_toolbar(self):
        self.toolbar.addWidget(QtWidgets.QLabel('Calibration:'))

        iconadd = QtGui.QIcon()
        iconadd.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/Add2.png"),
                          QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.addh5_action = QtWidgets.QAction(iconadd, "Add spectrum", None)
        self.toolbar.addAction(self.addh5_action)
        self.addh5_action.triggered.connect(self.add_spectrum_h5)

        iconreset = QtGui.QIcon()
        iconreset.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/Refresh2.png"),
                            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.reset_action = QtWidgets.QAction(iconreset, "Remove plots", None)
        self.toolbar.addAction(self.reset_action)
        self.reset_action.triggered.connect(self.reset)

    def add_spectrum_h5(self):
        data, fname, node_path = browse_data(ret_all=True)
        if data is not None:
            file = Path(fname).parts[-1]
            self.filenames.append(file)
            self.raw_datas[file] = data
            self.raw_axis = np.linspace(0, len(data) - 1, len(data))

            # with tables.open_file(fname) as h5file:
            #     data_node = h5file.get_node(node_path)
            #
            #
            #     if 'X_axis' in list(data_node._v_parent._v_children):
            #         self.raw_axis = data_node._v_parent._f_get_child('X_axis').read()

            self.viewer_data.show_data(self.raw_datas.values(),
                                       x_axis=self.raw_axis,
                                       labels=self.filenames)

    def update_peak_source(self):
        for child in self.settings.child(('peak_options')).children():
            child.child(('channel')).setOpts(limits=self.filenames)

    def reset(self):
        self.raw_datas = dict([])
        self.raw_axis = None

        self.viewer_data.remove_plots()

    def setupUI(self):
        horlayout = QtWidgets.QHBoxLayout()
        splitter = QtWidgets.QSplitter(Qt.Horizontal)
        self.setLayout(horlayout)
        horlayout.addWidget(splitter)

        tab = QtWidgets.QTabWidget()

        form = QtWidgets.QWidget()
        self.viewer_data = Viewer1D(form)
        self.plot_peak_item = self.viewer_data.viewer.plotwidget.plot()

        form1 = QtWidgets.QWidget()
        self.viewer_calib = Viewer1D(form1)
        self.viewer_calib.set_axis_label(axis_settings=dict(
            orientation='left', label='Photon wavelength', units='nm'))

        tab.addTab(form, 'Data Viewer')
        tab.addTab(form1, 'Calibration')

        splitter.addWidget(tab)

        self.settings = Parameter.create(name='settings',
                                         type='group',
                                         children=self.params)
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumWidth(300)
        self.settings_tree.setParameters(self.settings, showTop=False)

        splitter.addWidget(self.settings_tree)

        # creating a toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.create_toolbar()
        self.window.addToolBar(self.toolbar)

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                self.update_peak_source()
                if param.name() == 'peak_options':
                    QtWidgets.QApplication.processEvents()
                    #self.update_peak_finding()

            elif change == 'value':
                if param.name() in custom_tree.iter_children(
                        self.settings.child(('peak_options')), []):
                    self.update_peak_finding()

                elif param.name() == 'fit_units':
                    if self.table_model is not None:
                        self.table_model.setHeaderData(2, Qt.Horizontal, data)

                if self.settings.child('fit_options', 'do_calib').value():
                    self.calculate_calibration(
                        self.settings.child(('peaks_table')).value()._data)

            elif change == 'parent':
                pass

    def update_peak_finding(self):
        try:
            if len(self.raw_datas) != 0:
                peak_options = []

                for channel in self.filenames:

                    opts = dict([])
                    for child in self.settings.child(('peak_options')):
                        if child.child(('channel')).value() == channel:
                            children = [
                                ch.name() for ch in child.children()
                                if not (ch.name() == 'use_opts'
                                        or ch.name() == 'channel')
                            ]
                            if child.child(('use_opts')).value():
                                param_opt = child.child((children[0]))
                                opts[param_opt.name()] = param_opt.value()
                    if len(opts) != 0:
                        peak_options.append(dict(channel=channel, opts=opts))

                self.peak_indexes = []
                self.peak_amplitudes = []
                if len(peak_options) != 0:
                    for option in peak_options:
                        peak_indexes, properties = find_peaks(
                            self.raw_datas[option['channel']],
                            **option['opts'])
                        self.peak_indexes.extend(list(peak_indexes))
                        self.peak_amplitudes.extend(
                            list(self.raw_datas[option['channel']]
                                 [peak_indexes]))

                    self.peak_indexes = np.array(self.peak_indexes)
                    self.peak_amplitudes = np.array(self.peak_amplitudes)

                    arg_sorted_indexes = np.argsort(self.peak_indexes)

                    self.peak_indexes = self.peak_indexes[arg_sorted_indexes]
                    self.peak_amplitudes = self.peak_amplitudes[
                        arg_sorted_indexes]

                    if len(self.peak_indexes) != 0:
                        self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                            self.plot_peak_item)
                        while len(self.text_peak_items) != 0:
                            self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                                self.text_peak_items.pop(0))
                            self.viewer_data.viewer.plotwidget.plotItem.removeItem(
                                self.arrow_peak_items.pop(0))

                        self.plot_peak_item = self.viewer_data.viewer.plotwidget.plot(
                            self.raw_axis[self.peak_indexes],
                            self.peak_amplitudes,
                            pen=None,
                            symbol='+')

                        for ind, peak_index in enumerate(self.peak_indexes):
                            item = TextItem('({:.00f},{:.02f})'.format(
                                self.raw_axis[peak_index],
                                self.peak_amplitudes[ind]),
                                            angle=45,
                                            color='w',
                                            anchor=(0, 1))
                            size = self.viewer_data.viewer.plotwidget.plotItem.vb.itemBoundingRect(
                                item)
                            item.setPos(
                                self.raw_axis[peak_index],
                                self.peak_amplitudes[ind] + size.height())
                            self.text_peak_items.append(item)

                            item_ar = ArrowItem(
                                pos=(self.raw_axis[peak_index],
                                     self.peak_amplitudes[ind] +
                                     size.height() / 5),
                                angle=-90,
                                tipAngle=30,
                                baseAngle=20,
                                headLen=10,
                                tailLen=20,
                                tailWidth=1,
                                pen=None,
                                brush='w')
                            self.arrow_peak_items.append(item_ar)
                            self.viewer_data.viewer.plotwidget.plotItem.addItem(
                                item)
                            self.viewer_data.viewer.plotwidget.plotItem.addItem(
                                item_ar)

                        self.table_model = PandasModel(
                            pd.DataFrame([[False, ind, 0]
                                          for ind in self.peak_indexes],
                                         columns=[
                                             'Use', 'Pxl',
                                             self.settings.child(
                                                 'fit_options',
                                                 'fit_units').value()
                                         ]))
                        self.settings.child(
                            ('peaks_table')).setValue(self.table_model)
        except Exception as e:
            logger.exception(str(e))

    def update_status(self, txt, log_type=None):
        """

        """
        print(txt)
        if log_type is not None:
            self.log_signal.emit(txt)

    def calculate_calibration(self, dataframe=pd.DataFrame()):
        try:
            data_to_use = dataframe.query('Use == True')
            data = data_to_use[dataframe.columns[2]].to_numpy()
            indexes = data_to_use['Pxl'].to_numpy()

            unit = self.settings.child('fit_options', 'fit_units').value()
            if unit == 'nm':
                pass
            elif unit == 'cm-1':
                data = Ecmrel2Enm(data,
                                  self.settings.child(('laser_wl')).value())
            elif unit == 'eV':
                data = eV2nm(data)

            if data.size != 0:
                if self.calib_plot is not None:
                    self.viewer_calib.viewer.plotwidget.plotItem.removeItem(
                        self.calib_plot)
                self.calib_plot = self.viewer_calib.viewer.plotwidget.plot(
                    indexes, data, pen=None, symbol='+')

                calib_coeffs = np.polyfit(
                    indexes - np.max(self.raw_axis) / 2, data,
                    self.settings.child('fit_options', 'fit_order').value())
                calib_data = np.polyval(
                    calib_coeffs, self.raw_axis - np.max(self.raw_axis) / 2)

                self.viewer_calib.show_data([calib_data],
                                            labels=[
                                                'Fit of order {:d}'.format(
                                                    self.settings.child(
                                                        'fit_options',
                                                        'fit_order').value())
                                            ])

                self.coeffs_calib.emit(list(calib_coeffs)[::-1])

        except Exception as e:
            self.update_status(e, 'log')
Esempio n. 13
0
class CustomApp(QtWidgets.QWidget, QObject):
    # custom signal that will be fired sometimes. Could be connected to an external object method or an internal method
    log_signal = pyqtSignal(str)

    # list of dicts enabling the settings tree on the user interface
    params = [
        {
            'title':
            'Main settings:',
            'name':
            'main_settings',
            'type':
            'group',
            'children': [{
                'title': 'Save base path:',
                'name': 'base_path',
                'type': 'browsepath',
                'value': config['data_saving']['h5file']['save_path']
            }, {
                'title': 'File name:',
                'name': 'target_filename',
                'type': 'str',
                'value': "",
                'readonly': True
            }, {
                'title': 'Date:',
                'name': 'date',
                'type': 'date',
                'value': QDate.currentDate()
            }, {
                'title': 'Do something, such as showing data:',
                'name': 'do_something',
                'type': 'bool',
                'value': False
            }, {
                'title': 'Something done:',
                'name': 'something_done',
                'type': 'led',
                'value': False,
                'readonly': True
            }, {
                'title': 'Infos:',
                'name': 'info',
                'type': 'text',
                'value': ""
            }, {
                'title': 'push:',
                'name': 'push',
                'type': 'bool_push',
                'value': False
            }]
        },
        {
            'title':
            'Other settings:',
            'name':
            'other_settings',
            'type':
            'group',
            'children': [
                {
                    'title': 'List of stuffs:',
                    'name': 'list_stuff',
                    'type': 'list',
                    'value': 'first',
                    'values': ['first', 'second', 'third'],
                    'tip': 'choose a stuff from the list'
                },
                {
                    'title': 'List of integers:',
                    'name': 'list_int',
                    'type': 'list',
                    'value': 0,
                    'values': [0, 256, 512],
                    'tip': 'choose a stuff from this int list'
                },
                {
                    'title': 'one integer:',
                    'name': 'an_integer',
                    'type': 'int',
                    'value': 500,
                },
                {
                    'title': 'one float:',
                    'name': 'a_float',
                    'type': 'float',
                    'value': 2.7,
                },
            ]
        },
    ]

    def __init__(self, dockarea):
        QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
        super(CustomApp, self).__init__()
        if not isinstance(dockarea, DockArea):
            raise Exception('no valid parent container, expected a DockArea')
        self.dockarea = dockarea
        self.mainwindow = dockarea.parent()

        # init the object parameters
        self.detector = None
        self.raw_data = []

        # init the user interface
        self.setup_UI()

    def setup_UI(self):
        ###########################################
        ###########################################
        # init the docks containing the main widgets

        #############################################
        # this one for the custom application settings
        dock_settings = Dock('Settings', size=(350, 350))
        self.dockarea.addDock(dock_settings, 'left')

        # create main parameter tree
        self.settings_tree = ParameterTree()
        dock_settings.addWidget(self.settings_tree, 10)
        self.settings_tree.setMinimumWidth(300)
        # create a Parameter object containing the settings
        self.settings = Parameter.create(name='Settings',
                                         type='group',
                                         children=self.params)
        # load the tree with this parameter object
        self.settings_tree.setParameters(self.settings, showTop=False)
        # any change to the tree on the user interface will call the parameter_tree_changed method where all actions will be applied
        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        ################################################################
        # create a logger dock where to store info senf from the programm
        self.dock_logger = Dock("Logger")
        self.logger_list = QtWidgets.QListWidget()
        self.logger_list.setMinimumWidth(300)
        self.dock_logger.addWidget(self.logger_list)
        self.dockarea.addDock(self.dock_logger, 'bottom', dock_settings)
        # dock_logger.setVisible(False)
        # connect together this custom signal with the add_log method
        self.log_signal[str].connect(self.add_log)

        #######################################################################################################################
        # create a dock containing a viewer object, could be 0D, 1D or 2D depending what kind of data one want to plot here a 0D
        dock_Viewer0D = Dock('Viewer dock', size=(350, 350))
        self.dockarea.addDock(dock_Viewer0D, 'right', self.dock_logger)
        target_widget = QtWidgets.QWidget()
        self.target_viewer = Viewer0D(target_widget)
        dock_Viewer0D.addWidget(target_widget)

        ###################################################################################
        # create 2 docks to display the DAQ_Viewer (one for its settings, one for its viewer)
        dock_detector_settings = Dock("Detector Settings", size=(350, 350))
        self.dockarea.addDock(dock_detector_settings, 'right', dock_settings)
        dock_detector = Dock("Detector Viewer", size=(350, 350))
        self.dockarea.addDock(dock_detector, 'right', dock_detector_settings)
        # init one daq_viewer object named detector
        self.detector = DAQ_Viewer(self.dockarea,
                                   dock_settings=dock_detector_settings,
                                   dock_viewer=dock_detector,
                                   title="A detector",
                                   DAQ_type='DAQ0D')
        # set its type to 'Mock'
        control_type = 'Mock'
        self.detector.ui.Detector_type_combo.setCurrentText(control_type)
        # init the detector and wait 1000ms for the completion
        self.detector.ui.IniDet_pb.click()
        self.detector.settings.child('main_settings',
                                     'wait_time').setValue(100)
        QtWidgets.QApplication.processEvents()
        QThread.msleep(1000)
        self.detector.grab_done_signal.connect(self.data_done)

        #############################
        # create a dock for a DAQ_Move
        dock_move = Dock("Move module", size=(350, 350))
        self.dockarea.addDock(dock_move, 'right', self.dock_logger)
        move_widget = QtWidgets.QWidget()
        self.move = DAQ_Move(move_widget)
        dock_move.addWidget(move_widget)
        self.move.ui.IniStage_pb.click()
        QtWidgets.QApplication.processEvents()
        QThread.msleep(1000)

        ############################################
        # creating a menubar
        self.menubar = self.mainwindow.menuBar()
        self.create_menu(self.menubar)

        # creating a toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.create_toolbar()
        self.mainwindow.addToolBar(self.toolbar)

    @pyqtSlot(OrderedDict)
    def data_done(self, data):
        # print(data)
        pass

    @pyqtSlot(QRectF)
    def update_weighted_settings(self, rect):
        self.settings.child('weighting_settings', 'x0').setValue(int(rect.x()))
        self.settings.child('weighting_settings', 'y0').setValue(int(rect.y()))
        self.settings.child('weighting_settings',
                            'width').setValue(max([1, int(rect.width())]))
        self.settings.child('weighting_settings',
                            'height').setValue(max([1, int(rect.height())]))

    def parameter_tree_changed(self, param, changes):
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.name() == 'do_something':
                    if param.value():
                        self.log_signal.emit('Do something')
                        self.detector.grab_done_signal.connect(self.show_data)
                        self.raw_data = []  # init the data to be finally saved
                        self.settings.child('main_settings',
                                            'something_done').setValue(True)
                    else:
                        self.log_signal.emit('Stop Doing something')
                        self.detector.grab_done_signal.disconnect()
                        self.settings.child('main_settings',
                                            'something_done').setValue(False)

            elif change == 'parent':
                pass

    @pyqtSlot(OrderedDict)
    def show_data(self, data):
        """
        do stuff with data from the detector if its grab_done_signal has been connected
        Parameters
        ----------
        data: (OrderedDict) #OrderedDict(name=self.title,x_axis=None,y_axis=None,z_axis=None,data0D=None,data1D=None,data2D=None)
        """
        data0D = [[data['data0D'][key]['data']] for key in data['data0D']]
        if self.raw_data == []:
            self.raw_data = data0D
        else:
            if len(self.raw_data) != len(data0D):
                self.raw_data = data0D
            else:
                for ind in range(len(data0D)):
                    self.raw_data[ind].append(data0D[ind][0])

        self.target_viewer.show_data(data0D)

    def create_menu(self, menubar):
        """
        """
        menubar.clear()

        # %% create file menu
        file_menu = menubar.addMenu('File')
        load_action = file_menu.addAction('Load file')
        load_action.triggered.connect(self.load_file)
        save_action = file_menu.addAction('Save file')
        save_action.triggered.connect(self.save_data)

        file_menu.addSeparator()
        quit_action = file_menu.addAction('Quit')
        quit_action.triggered.connect(self.quit_function)

        settings_menu = menubar.addMenu('Settings')
        docked_menu = settings_menu.addMenu('Docked windows')
        action_load = docked_menu.addAction('Load Layout')
        action_save = docked_menu.addAction('Save Layout')

    def load_file(self):
        # init the data browser module
        widg = QtWidgets.QWidget()
        self.data_browser = H5Browser(widg)
        widg.show()

    def quit_function(self):
        # close all stuff that need to be
        self.detector.quit_fun()
        QtWidgets.QApplication.processEvents()
        self.mainwindow.close()

    def create_toolbar(self):
        iconquit = QtGui.QIcon()
        iconquit.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/close2.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.quit_action = QtWidgets.QAction(iconquit, "Quit program", None)
        self.toolbar.addAction(self.quit_action)
        self.quit_action.triggered.connect(self.quit_function)

        icon_detector = QtGui.QIcon()
        icon_detector.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/camera.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.detector_action = QtWidgets.QAction(icon_detector,
                                                 "Grab from camera", None)
        self.detector_action.setCheckable(True)
        self.toolbar.addAction(self.detector_action)
        self.detector_action.triggered.connect(lambda: self.run_detector())

        iconload = QtGui.QIcon()
        iconload.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/Open.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.loadaction = QtWidgets.QAction(
            iconload, "Load target file (.h5, .png, .jpg) or data from camera",
            None)
        self.toolbar.addAction(self.loadaction)
        self.loadaction.triggered.connect(self.load_file)

        iconsave = QtGui.QIcon()
        iconsave.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/SaveAs.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.saveaction = QtWidgets.QAction(iconsave, "Save current data",
                                            None)
        self.toolbar.addAction(self.saveaction)
        self.saveaction.triggered.connect(self.save_data)

    def run_detector(self):
        self.detector.ui.grab_pb.click()

    def save_data(self):
        try:
            path = gutils.select_file(start_path=self.settings.child(
                'main_settings', 'base_path').value(),
                                      save=True,
                                      ext='h5')
            if path is not None:
                # init the file object with an addhoc name given by the user
                h5saver = H5Saver(save_type='custom')
                h5saver.init_file(update_h5=True, addhoc_file_path=path)

                # save all metadata
                settings_str = ioxml.parameter_to_xml_string(self.settings)
                settings_str = b'<All_settings>' + settings_str
                settings_str += ioxml.parameter_to_xml_string(
                    self.detector.settings) + ioxml.parameter_to_xml_string(
                        h5saver.settings) + b'</All_settings>'

                data_group = h5saver.add_data_group(
                    h5saver.raw_group,
                    group_data_type='data0D',
                    title='data from custom app',
                    settings_as_xml=settings_str)

                for dat in self.raw_data:
                    channel = h5saver.add_CH_group(data_group)
                    data_dict = dict(data=np.array(dat),
                                     x_axis=dict(data=np.linspace(
                                         0,
                                         len(dat) - 1, len(dat)),
                                                 units='pxl'))
                    h5saver.add_data(channel,
                                     data_dict=data_dict,
                                     scan_type='')

                st = 'file {:s} has been saved'.format(str(path))
                self.add_log(st)
                self.settings.child('main_settings', 'info').setValue(st)

                h5saver.close_file()

        except Exception as e:
            self.add_log(getLineInfo() + str(e))

    @pyqtSlot(str)
    def add_log(self, txt):
        """
            Add a log to the logger list from the given text log and the current time

            ================ ========= ======================
            **Parameters**   **Type**   **Description**

             *txt*             string    the log to be added
            ================ ========= ======================

        """
        now = datetime.datetime.now()
        new_item = QtWidgets.QListWidgetItem(str(now) + ": " + txt)
        self.logger_list.addItem(new_item)
        # #to do
        # #self.save_parameters.logger_array.append(str(now)+": "+txt)

    @pyqtSlot(str)
    def emit_log(self, txt):
        """
            Emit a log-signal from the given log index

            =============== ======== =======================
            **Parameters**  **Type** **Description**

             *txt*           string   the log to be emitted
            =============== ======== =======================

        """
        self.log_signal.emit(txt)
Esempio n. 14
0
    def _ui_config_init(self):

        self._ui_init_buttons()
        self.ui_output_dir_widget = iowidgetqt.SetDirWidget(
            self.teigen.config["filepattern"], "output directory")
        self.ui_output_dir_widget.setToolTip(
            "Data are stored in defined directory.\nOutput format is based on file extension.\n\
For saving into image stack use 'filename{:06d}.jpg'")
        self.mainLayout.addWidget(self.ui_output_dir_widget, 1, 1, 1,
                                  2)  # , (gd_max_i / 2), text_col)

        postprocessing_params = self.teigen.config["postprocessing"]

        hide_keys = [
            "build", "gtree", "voxelsize_mm", "areasize_px", "resolution",
            "n_slice", "dims", "tube_shape", "radius_distribution_normal",
            "radius_distribution_uniform", "radius_distribution_fixed",
            "allow_overlap"
        ]
        self._ui_generators_tab_wg = QTabWidget()
        self._ui_generators_tab_wg.setMinimumWidth(400)
        self.mainLayout.addWidget(self._ui_generators_tab_wg, 0, 1, 1, 2)
        # l = QVBoxLayout(self)

        rename_captions_dict = {
            "voxelsize_mm": "voxel size [mm]",
        }
        dropdownoboxes = {
            "radius_distribution": ["normal", "fixed", "uniform"]
        }

        # list is pointer. It causes problems with temporary reconstruction information
        # copy fix this issue
        teigen_config = copy.deepcopy(self.teigen.config)

        self._ui_generator_widgets = []
        for generator_name in teigen_config["generators"]:
            wg = dictwidgetqt.DictWidget(
                teigen_config["generators"][generator_name],
                hide_keys=hide_keys,
                captions=rename_captions_dict,
                ncols=1,
                dropdownboxes=dropdownoboxes,
            )
            self._ui_generator_widgets.append(wg)
            self._ui_generators_tab_wg.addTab(
                wg, generator_name.replace(" ", "\n"))
            # self._ui_generators_tab_wg.

        # l.addWidget(self._ui_generators_tab_wg)
        # wgn = QtGui.QWidget()
        # layout = QtGui.QFormLayout()
        # layout.addRow("Name", QtGui.QLineEdit())
        # layout.addRow("Address",QtGui.QLineEdit())
        # wgn.setLayout(layout)
        # self._ui_generators_tab_wg.addTab(wgn, "ahoj")
        id = self.teigen.get_generator_id_by_name_or_number(
            teigen_config["generator_id"])
        self._ui_generators_tab_wg.setCurrentIndex(id)
        # self.mainLayout.setColumnMinimumWidth(text_col, 500)

        # pyqtgraph experiments
        input_params = {
            "Area Sampling":
            dictwidgetpg.AreaSamplingParameter(
                name='Area Sampling', **self.teigen.config["areasampling"]),
            "Postprocessing":
            postprocessing_params,
            "Batch processing":
            dictwidgetpg.BatchFileProcessingParameter(name="Batch processing",
                                                      children=[
                                                          {
                                                              'name':
                                                              'Run batch',
                                                              'type': 'action'
                                                          },
                                                      ]),
            "Appearance":
            self.teigen.config["appearance"],
            "Output":
            self.teigen.config["output"],
            "Measurement":
            self.teigen.config["measurement"]
            # 'name': {'type': 'action'},
            # "dur": i5,
            # TODO add more lines here
            # "Intensity Profile": dictwidgetpyqtgraph.ScalableFloatGroup(
            #     name="Intensity Profile", children=[
            #         {'name': '0.2', 'type': 'float', 'value': "100"},
            #         {'name': '0.4', 'type': 'float', 'value': "115"},
            #     ])
        }
        gr_struct = dictwidgetpg.to_pyqtgraph_struct('params',
                                                     input_params,
                                                     opts={})
        dictwidgetpg.add_tip(gr_struct, "noise_preview", "this is noise")
        dictwidgetpg.add_tips(gr_struct, teigen_keysdoc)
        gr_struct["children"][1]['tip'] = "Apperance tip"
        gr_struct["children"][2]['tip'] = "output tip"
        gr_struct["children"][3]['tip'] = "post processing tip"
        gr_struct["children"][4]['tip'] = "measurement"
        p = Parameter.create(**gr_struct)

        t = ParameterTree()
        t.setParameters(p, showTop=False)
        t.setMinimumWidth(380)
        # t.setColumnCount(3)
        t.show()

        p.sigTreeStateChanged.connect(self._parameters_changed)
        p.param('Batch processing',
                'Run batch').sigActivated.connect(self.run_batch)

        # how to add button
        # i5  = pg.TreeWidgetItem(["Item 5"])
        # b5 = QtGui.QPushButton('Button')
        # i5.setWidget(1, b5)
        # t.addTopLevelItem(i5)

        self.mainLayout.addWidget(t, 0, 0, 6, 1)
        self.config_wg = t
        # self.config_wg.setToolTip(teigendoc)
        self.area_sampling_params = p
        self.teigen.progress_callback = self._progressbar_update
        self._ui_btn_step2.setEnabled(False)
Esempio n. 15
0
class ModulesManager(QObject):

    detectors_changed = pyqtSignal(list)
    actuators_changed = pyqtSignal(list)
    det_done_signal = pyqtSignal(OrderedDict)
    move_done_signal = pyqtSignal(OrderedDict)
    timeout_signal = pyqtSignal(bool)

    params = [
        {
            'title':
            'Actuators/Detectors Selection',
            'name':
            'modules',
            'type':
            'group',
            'children': [
                {
                    'title': 'detectors',
                    'name': 'detectors',
                    'type': 'itemselect'
                },
                {
                    'title': 'Actuators',
                    'name': 'actuators',
                    'type': 'itemselect'
                },
            ]
        },
        {
            'title': "Moves done?",
            'name': 'move_done',
            'type': 'led',
            'value': False
        },
        {
            'title': "Detections done?",
            'name': 'det_done',
            'type': 'led',
            'value': False
        },
        {
            'title':
            'Data dimensions',
            'name':
            'data_dimensions',
            'type':
            'group',
            'children': [
                {
                    'title': "Probe detector's data",
                    'name': 'probe_data',
                    'type': 'action'
                },
                {
                    'title': 'Data0D list:',
                    'name': 'det_data_list0D',
                    'type': 'itemselect'
                },
                {
                    'title': 'Data1D list:',
                    'name': 'det_data_list1D',
                    'type': 'itemselect'
                },
                {
                    'title': 'Data2D list:',
                    'name': 'det_data_list2D',
                    'type': 'itemselect'
                },
                {
                    'title': 'DataND list:',
                    'name': 'det_data_listND',
                    'type': 'itemselect'
                },
            ]
        },
        {
            'title':
            'Actuators positions',
            'name':
            'actuators_positions',
            'type':
            'group',
            'children': [
                {
                    'title': "Test actuators",
                    'name': 'test_actuator',
                    'type': 'action'
                },
                {
                    'title': 'Positions:',
                    'name': 'positions_list',
                    'type': 'itemselect'
                },
            ]
        },
    ]

    def __init__(self,
                 detectors=[],
                 actuators=[],
                 selected_detectors=[],
                 selected_actuators=[],
                 timeout=10000):
        super().__init__()

        for mod in selected_actuators:
            assert mod in actuators
        for mod in selected_detectors:
            assert mod in detectors

        self.timeout = timeout  #in ms

        self.det_done_datas = OrderedDict()
        self.det_done_flag = False
        self.move_done_positions = OrderedDict()
        self.move_done_flag = False

        self.settings = Parameter.create(name='Settings',
                                         type='group',
                                         children=self.params)
        self.settings_tree = ParameterTree()
        self.settings_tree.setMinimumWidth(300)
        self.settings_tree.setParameters(self.settings, showTop=False)

        self.settings.sigTreeStateChanged.connect(self.parameter_tree_changed)

        self.settings.child('data_dimensions',
                            'probe_data').sigActivated.connect(
                                self.get_det_data_list)
        self.settings.child('actuators_positions',
                            'test_actuator').sigActivated.connect(
                                self.test_move_actuators)

        self._detectors = []
        self._actuators = []

        self.grab_done_signals = []
        self.det_commands_signal = []

        self.set_actuators(actuators, selected_actuators)
        self.set_detectors(detectors, selected_detectors)

    @classmethod
    def get_names(cls, modules):
        if not hasattr(modules, '__iter__'):
            modules = [modules]
        return [mod.title for mod in modules]

    def get_mods_from_names(self, names, mod='det'):
        mods = []
        for name in names:
            d = self.get_mod_from_name(name, mod)
            if d is not None:
                mods.append(d)
        return mods

    def get_mod_from_name(self, name, mod='det'):
        if mod == 'det':
            modules = self._detectors
        else:
            modules = self._actuators

        if name in self.get_names(modules):
            return modules[self.get_names(modules).index(name)]
        else:
            logger.warning(f'No detector with this name: {name}')
            return None

    def set_actuators(self, actuators, selected_actuators):
        self._actuators = actuators
        self.settings.child('modules', 'actuators').setValue(
            dict(all_items=self.get_names(actuators),
                 selected=self.get_names(selected_actuators)))

    def set_detectors(self, detectors, selected_detectors):
        self._detectors = detectors
        self.settings.child('modules', 'detectors').setValue(
            dict(all_items=self.get_names(detectors),
                 selected=self.get_names(selected_detectors)))

    @property
    def detectors(self):
        return self.get_mods_from_names(self.selected_detectors_name)

    @property
    def actuators(self):
        return self.get_mods_from_names(self.selected_actuators_name,
                                        mod='act')

    @property
    def Ndetectors(self):
        return len(self.detectors)

    @property
    def Nactuators(self):
        return len(self.actuators)

    @property
    def detectors_name(self):
        return self.settings.child('modules', 'detectors').value()['all_items']

    @property
    def selected_detectors_name(self):
        return self.settings.child('modules', 'detectors').value()['selected']

    @property
    def actuators_name(self):
        return self.settings.child('modules', 'actuators').value()['all_items']

    @property
    def selected_actuators_name(self):
        return self.settings.child('modules', 'actuators').value()['selected']

    def parameter_tree_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if change == 'childAdded':
                pass

            elif change == 'value':

                if param.name() == 'detectors':
                    self.detectors_changed.emit(data['selected'])

                elif param.name() == 'actuators':
                    self.actuators_changed.emit(data['selected'])

            elif change == 'parent':
                pass

    def get_det_data_list(self):
        self.connect_detectors()

        datas = self.grab_datas()

        data_list0D = []
        data_list1D = []
        data_list2D = []
        data_listND = []

        for k in datas.keys():
            if 'data0D' in datas[k].keys():
                data_list0D.extend(
                    [f'{k}/{name}' for name in datas[k]['data0D'].keys()])
            if 'data1D' in datas[k].keys():
                data_list1D.extend(
                    [f'{k}/{name}' for name in datas[k]['data1D'].keys()])
            if 'data2D' in datas[k].keys():
                data_list2D.extend(
                    [f'{k}/{name}' for name in datas[k]['data2D'].keys()])
            if 'dataND' in datas[k].keys():
                data_listND.extend(
                    [f'{k}/{name}' for name in datas[k]['dataND'].keys()])

        self.settings.child('data_dimensions', 'det_data_list0D').setValue(
            dict(all_items=data_list0D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_list1D').setValue(
            dict(all_items=data_list1D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_list2D').setValue(
            dict(all_items=data_list2D, selected=[]))
        self.settings.child('data_dimensions', 'det_data_listND').setValue(
            dict(all_items=data_listND, selected=[]))

        self.connect_detectors(False)

    def get_selected_probed_data(self, dim='0D'):
        return self.settings.child(
            'data_dimensions',
            f'det_data_list{dim.upper()}').value()['selected']

    def grab_datas(self, **kwargs):
        self.det_done_datas = OrderedDict()
        self.det_done_flag = False
        self.settings.child(('det_done')).setValue(self.det_done_flag)
        tzero = time.perf_counter()

        for sig in [mod.command_detector for mod in self.detectors]:
            sig.emit(utils.ThreadCommand("single", [1, kwargs]))

        while not self.det_done_flag:
            #wait for grab done signals to end

            QtWidgets.QApplication.processEvents()
            if time.perf_counter() - tzero > self.timeout:
                self.timeout_signal.emit(True)
                logger.error(
                    'Timeout Fired during waiting for data to be acquired')
                break

        self.det_done_signal.emit(self.det_done_datas)
        return self.det_done_datas

    def connect_actuators(self, connect=True, slot=None):
        if slot is None:
            slot = self.move_done
        if connect:
            for sig in [mod.move_done_signal for mod in self.actuators]:
                sig.connect(slot)
        else:
            try:
                for sig in [mod.move_done_signal for mod in self.actuators]:
                    sig.disconnect(slot)
            except Exception as e:
                logger.error(str(e))

    def connect_detectors(self, connect=True, slot=None):
        if slot is None:
            slot = self.det_done

        if connect:
            for sig in [mod.grab_done_signal for mod in self.detectors]:
                sig.connect(slot)
        else:
            try:
                for sig in [mod.grab_done_signal for mod in self.detectors]:
                    sig.disconnect(slot)
            except Exception as e:
                logger.error(str(e))

    def test_move_actuators(self):
        positions = dict()
        for act in self.get_names(self.actuators):
            pos, done = QtWidgets.QInputDialog.getDouble(
                None, f'Enter a target position for actuator {act}',
                'Position:')
            if not done:
                pos = 0.
            positions[act] = pos

        self.connect_actuators()

        positions = self.move_actuators(positions)

        self.settings.child('actuators_positions', 'positions_list').setValue(
            dict(all_items=[f'{k}: {positions[k]}' for k in positions],
                 selected=[]))

        self.connect_actuators(False)

    def move_actuators(self, positions):
        self.move_done_positions = OrderedDict()
        self.move_done_flag = False
        self.settings.child(('move_done')).setValue(self.move_done_flag)

        if not hasattr(positions, '__iter__'):
            positions = [positions]

        if len(positions) == self.Nactuators:
            if isinstance(positions, dict):
                for k in positions:
                    act = self.get_mod_from_name(k, 'act')
                    if act is not None:
                        act.command_stage.emit(
                            utils.ThreadCommand(command="move_Abs",
                                                attributes=[positions[k]]))
            else:
                for ind, act in enumerate(self.actuators):
                    act.command_stage.emit(
                        utils.ThreadCommand(command="move_Abs",
                                            attributes=[positions[ind]]))

        else:
            logger.error(
                'Invalid number of positions compared to selected actuators')
            return self.move_done_positions

        tzero = time.perf_counter()

        while not self.move_done_flag:
            QtWidgets.QApplication.processEvents()
            if time.perf_counter() - tzero > self.timeout:
                self.timeout_signal.emit(True)
                logger.error(
                    'Timeout Fired during waiting for data to be acquired')
                break

        self.move_done_signal.emit(self.move_done_positions)
        return self.move_done_positions

    def order_positions(self, positions_as_dict):
        actuators = self.selected_actuators_name
        pos = []
        for act in actuators:
            pos.append(positions_as_dict[act])
        return pos

    pyqtSlot(str, float)

    def move_done(self, name, position):
        """
        """
        try:
            if name not in list(self.move_done_positions.keys()):
                self.move_done_positions[name] = position

            if len(self.move_done_positions.items()) == len(self.actuators):
                self.move_done_flag = True
                self.settings.child(
                    ('move_done')).setValue(self.move_done_flag)
        except Exception as e:
            logger.exception(str(e))

    @pyqtSlot(OrderedDict)
    def det_done(self, data):
        try:
            if data['name'] not in list(self.det_done_datas.keys()):
                self.det_done_datas[data['name']] = data
            if len(self.det_done_datas.items()) == len(self.detectors):
                self.det_done_flag = True
                self.settings.child(('det_done')).setValue(self.det_done_flag)
        except Exception as e:
            logger.exception(str(e))
Esempio n. 16
0
class Navigator(QObject):
    log_signal = pyqtSignal(str)
    sig_double_clicked = pyqtSignal(float, float)

    def __init__(self, parent=None, h5file_path=None):
        super(Navigator, self).__init__(parent)

        if parent is None:
            parent = QtWidgets.QWidget()
        self.parent = parent
        self.title = 'Navigator'
        self.status_time = 1000
        self.x_range = []
        self.y_range = []
        self.filters = tables.Filters(complevel=5)
        self.next_scan_index = 0
        self.viewer = None
        self.overlays = []  # %list of imageItem items displaying 2D scans info
        self.h5module_path = h5file_path
        self.h5module = H5BrowserUtil()

        if h5file_path is not None:
            self.h5module.open_file(h5file_path, 'a')
            self.settings.child('settings', 'filepath').setValue(h5file_path)
            self.settings.child('settings', 'Load h5').hide()
            self.show_overlay()

        self.setupUI()

    def create_toolbar(self):
        iconload = QtGui.QIcon()
        iconload.addPixmap(QtGui.QPixmap(":/icons/Icon_Library/NewLayer.png"),
                           QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.loadaction = QtWidgets.QAction(iconload, "Load scan file (.h5)",
                                            None)
        self.toolbar.addAction(self.loadaction)
        self.loadaction.triggered.connect(self.load_data)

        iconloadim = QtGui.QIcon()
        iconloadim.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/Open_File_32.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.loadactionim = QtWidgets.QAction(iconloadim,
                                              "Load image file (.h5)", None)
        self.toolbar.addAction(self.loadactionim)
        self.loadactionim.triggered.connect(self.load_image)

        icon_ratio = QtGui.QIcon()
        icon_ratio.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/Zoom_1_1.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.action_ratio = QtWidgets.QAction(icon_ratio,
                                              "Set viewbox aspect ratio to 1",
                                              None)
        self.action_ratio.setCheckable(True)
        self.toolbar.addAction(self.action_ratio)
        self.action_ratio.triggered.connect(self.set_aspect_ratio)

        icon_moveat = QtGui.QIcon()
        icon_moveat.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/move_contour.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.moveat_action = QtWidgets.QAction(
            icon_moveat,
            "When selected, double clicking on viewbox will move DAQ_Move modules",
            None)
        self.moveat_action.setCheckable(True)
        self.toolbar.addAction(self.moveat_action)

        icon_sel_all = QtGui.QIcon()
        icon_sel_all.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/select_all2.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.sel_all_action = QtWidgets.QAction(
            icon_sel_all, "Select (show) all 2D scans on the viewer", None)
        self.toolbar.addAction(self.sel_all_action)
        self.sel_all_action.triggered.connect(self.show_all)

        icon_sel_none = QtGui.QIcon()
        icon_sel_none.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/select_none.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.sel_none_action = QtWidgets.QAction(
            icon_sel_none, "Unselect (hide) all 2D scans on the viewer", None)
        self.toolbar.addAction(self.sel_none_action)
        self.sel_none_action.triggered.connect(self.show_none)

        icon_histo = QtGui.QIcon()
        icon_histo.addPixmap(
            QtGui.QPixmap(":/icons/Icon_Library/Histogram.png"),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.histo_action = QtWidgets.QAction(icon_histo,
                                              "Show (hide) histograms", None)
        self.toolbar.addAction(self.histo_action)
        self.histo_action.setCheckable(True)
        self.histo_action.triggered.connect(self.show_histo)

    @pyqtSlot(float, float)
    def move_at(self, posx, posy):
        if self.moveat_action.isChecked():
            self.sig_double_clicked.emit(posx, posy)

    def show_histo(self):
        show_state = self.histo_action.isChecked()
        self.viewer.histo_widget.setVisible(show_state)

    def show_all(self):
        self.show_scans()

    def show_none(self):
        self.show_scans(False)

    def show_scans(self, show=True):
        for child in self.settings.child('scans'):
            val = child.value()
            val['checked'] = show
            child.setValue(val)
            child.sigValueChanged.emit(child, val)

    def list_2Dscans(self):
        try:
            scans = self.h5module.get_h5file_scans()
            # settings=[dict(scan_name=node._v_name,path=node._v_pathname, pixmap=nparray2Qpixmap(node.read()))),...]
            params = []
            for child in self.settings.child(('scans')).children():
                if 'Scan' in child.name():
                    self.settings.child(('scans')).removeChild(child)
            for scan in scans:
                params.append({
                    'name':
                    scan['scan_name'],
                    'type':
                    'pixmap_check',
                    'value':
                    dict(data=scan['data'], checked=False, path=scan['path'])
                })
            self.settings.child(('scans')).addChildren(params)

            for child in self.settings.child(('scans')).children():
                val = child.value()
                val.update(dict(checked=True))
                child.setValue(val)
                child.sigValueChanged.emit(child, child.value())

        except Exception as e:
            logger.exception(str(e))

    def load_image(self):
        #image_filepath = str(utils.select_file(start_path=None, save=False, ext='h5'))
        data, fname, node_path = browse_data(ret_all=True)
        if data is not None and fname != '':
            self.h5module_image = H5BrowserUtil()
            self.h5module_image.open_file(fname, 'a')
            node = self.h5module_image.get_node(node_path)
            pixmaps = self.h5module_image.get_h5file_scans(node.parent_node)

            self.settings.child('settings', 'imagepath').setValue(fname)
            other_child = [
                child for child in self.settings.child(('scans')).children()
                if 'Scan' not in child.name()
            ]
            if len(other_child) >= 1:
                for child in other_child:
                    self.settings.child(('scans')).removeChild(child)
            params = []
            for pixmap in pixmaps:
                params.append({
                    'name':
                    pixmap['scan_name'],
                    'type':
                    'pixmap_check',
                    'value':
                    dict(data=pixmap['data'],
                         checked=False,
                         path=pixmap['path'])
                })
            self.settings.child(('scans')).addChildren(params)

            val = self.settings.child('scans', pixmaps[0]['scan_name']).value()
            val.update(dict(checked=True))
            self.settings.child('scans', pixmaps[0]['scan_name']).setValue(val)
            self.settings.child(
                'scans', pixmaps[0]['scan_name']).sigValueChanged.emit(
                    self.settings.child('scans', pixmaps[0]['scan_name']),
                    self.settings.child('scans',
                                        pixmaps[0]['scan_name']).value())

    def load_data(self):
        self.h5module_path = str(
            gutils.select_file(start_path=None, save=False, ext='h5'))
        if self.h5module_path != '':
            self.settings.child('settings',
                                'filepath').setValue(self.h5module_path)
            if self.h5module is not None:
                if self.h5module.isopen():
                    self.h5module.close_file()
            self.h5module.open_file(self.h5module_path, 'a')
            self.list_2Dscans()

    def set_aspect_ratio(self):
        if self.action_ratio.isChecked():
            self.viewer.image_widget.plotitem.vb.setAspectLocked(lock=True,
                                                                 ratio=1)
        else:
            self.viewer.image_widget.plotitem.vb.setAspectLocked(lock=False,
                                                                 ratio=1)

    def settings_changed(self, param, changes):
        """
            Check for changes in the given (parameter,change,information) tuple list.
            In case of value changed, update the DAQscan_settings tree consequently.

            =============== ============================================ ==============================
            **Parameters**    **Type**                                     **Description**
            *param*           instance of pyqtgraph parameter              the parameter to be checked
            *changes*         (parameter,change,information) tuple list    the current changes state
            =============== ============================================ ==============================
        """
        for param, change, data in changes:
            path = self.settings.childPath(param)
            if path is not None:
                childName = '.'.join(path)
            else:
                childName = param.name()
            if change == 'childAdded':
                pass

            elif change == 'value':
                if param.parent().name() == 'scans':
                    if data['checked']:
                        try:
                            if 'Scan' in param.name():
                                h5module = self.h5module
                                nodes = [
                                    node for node in h5module.walk_nodes(
                                        data['path'])
                                ]
                            else:
                                h5module = self.h5module_image
                                nodes = [h5module.get_node(data['path'])]
                            ind = 0
                            for node in nodes:
                                flag = False
                                if 'type' in node.attrs.attrs_name and 'data_dimension' in node.attrs.attrs_name:
                                    if 'scan_type' in node.attrs.attrs_name:
                                        if node.attrs[
                                                'scan_type'] == 'scan2D' and node.attrs[
                                                    'data_dimension'] == '0D':  #2d scan of 0D data
                                            flag = True
                                        elif node.attrs[
                                                'scan_type'] == '' and node.attrs[
                                                    'data_dimension'] == '2D':  #image data (2D) with no scan
                                            flag = True

                                if flag:
                                    isadaptive = 'adaptive' in node.attrs[
                                        'scan_subtype'].lower()
                                    if isadaptive:
                                        im = TriangulationItem()
                                    else:
                                        im = ImageItem()
                                    im.setOpacity(1)
                                    # im.setOpts(axisOrder='row-major')
                                    self.viewer.image_widget.plotitem.addItem(
                                        im)
                                    im.setCompositionMode(
                                        QtGui.QPainter.CompositionMode_Plus)

                                    if 'Scan' in param.name():
                                        if isadaptive:
                                            x_axis = h5module.get_node(
                                                h5module.get_node(
                                                    data['path']).parent_node,
                                                utils.capitalize(
                                                    'scan_x_axis')).read()
                                            y_axis = h5module.get_node(
                                                h5module.get_node(
                                                    data['path']).parent_node,
                                                utils.capitalize(
                                                    'scan_y_axis')).read()
                                        else:
                                            x_axis = np.unique(
                                                h5module.get_node(
                                                    h5module.get_node(
                                                        data['path']).
                                                    parent_node,
                                                    utils.capitalize(
                                                        'scan_x_axis')).read())
                                            y_axis = np.unique(
                                                h5module.get_node(
                                                    h5module.get_node(
                                                        data['path']).
                                                    parent_node,
                                                    utils.capitalize(
                                                        'scan_y_axis')).read())
                                    else:
                                        x_axis = np.unique(
                                            h5module.get_node(
                                                h5module.get_node(
                                                    data['path']).parent_node,
                                                utils.capitalize(
                                                    'x_axis')).read())
                                        y_axis = np.unique(
                                            h5module.get_node(
                                                h5module.get_node(
                                                    data['path']).parent_node,
                                                utils.capitalize(
                                                    'y_axis')).read())
                                    if not isadaptive:
                                        rect = QtCore.QRectF(
                                            np.min(x_axis), np.min(y_axis),
                                            (np.max(x_axis) - np.min(x_axis)),
                                            (np.max(y_axis) - np.min(y_axis)))
                                        im.setOpts(rescale=rect)
                                        im.setImage(node.read())
                                    else:
                                        im.setImage(
                                            np.vstack((x_axis, y_axis,
                                                       node.read())).T)

                                    if ind == 0:
                                        #im.setLookupTable(colors_red)
                                        self.viewer.histogram_red.setImageItem(
                                            im)
                                        if not self.viewer.histogram_red.isVisible(
                                        ):
                                            self.viewer.histogram_red.setVisible(
                                                True)
                                    elif ind == 1:
                                        #im.setLookupTable(colors_green)
                                        self.viewer.histogram_green.setImageItem(
                                            im)
                                        if not self.viewer.histogram_green.isVisible(
                                        ):
                                            self.viewer.histogram_green.setVisible(
                                                True)
                                    else:
                                        #im.setLookupTable(colors_blue)
                                        self.viewer.histogram_blue.setImageItem(
                                            im)
                                        if not self.viewer.histogram_blue.isVisible(
                                        ):
                                            self.viewer.histogram_blue.setVisible(
                                                True)

                                    self.overlays.append(
                                        dict(name='{:s}_{:03d}'.format(
                                            param.name(), ind),
                                             image=im))

                                    ind += 1
                            #self.viewer.image_widget.view.autoRange()
                        except Exception as e:
                            logger.exception(str(e))

                    else:
                        for overlay in self.overlays[:]:
                            if param.name() in overlay['name']:
                                ind = self.overlays.index(overlay)
                                self.viewer.image_widget.plotitem.removeItem(
                                    overlay['image'])
                                self.overlays.pop(ind)

            elif change == 'parent':
                for overlay in self.overlays[:]:
                    if param.name() in overlay['name']:
                        ind = self.overlays.index(overlay)
                        self.viewer.image_widget.plotitem.removeItem(
                            overlay['image'])
                        self.overlays.pop(ind)

    def setupUI(self):
        self.ui = QObject()
        layout = QtWidgets.QVBoxLayout()

        self.parent.setLayout(layout)
        sett_widget = QtWidgets.QWidget()
        self.sett_layout = QtWidgets.QHBoxLayout()
        sett_widget.setLayout(self.sett_layout)
        # creating a toolbar
        self.toolbar = QtWidgets.QToolBar()
        self.create_toolbar()
        layout.addWidget(self.toolbar)

        splitter = QtWidgets.QSplitter(Qt.Horizontal)
        layout.addWidget(splitter)

        #set viewer area
        widg = QtWidgets.QWidget()
        #self.viewer = Viewer2D(widg)
        self.viewer = Viewer2DBasic(widg)
        self.viewer.histogram_red.setVisible(False)
        self.viewer.histogram_green.setVisible(False)
        self.viewer.histogram_blue.setVisible(False)
        self.viewer.sig_double_clicked.connect(self.move_at)

        #displaying the scan list tree
        self.settings_tree = ParameterTree()
        #self.settings_tree.setMaximumWidth(300)
        self.settings_tree.setMinimumWidth(300)
        #self.settings_tree.setVisible(False)
        params_scan = [
            {
                'title':
                'Settings',
                'name':
                'settings',
                'type':
                'group',
                'children': [
                    {
                        'title': 'Load h5:',
                        'name': 'Load h5',
                        'type': 'action'
                    },
                    {
                        'title': 'h5 path:',
                        'name': 'filepath',
                        'type': 'str',
                        'value': '',
                        'readonly': True
                    },
                    {
                        'title': 'Load Image:',
                        'name': 'Load Image',
                        'type': 'action'
                    },
                    {
                        'title': 'Image path:',
                        'name': 'imagepath',
                        'type': 'str',
                        'value': '',
                        'readonly': True
                    },
                ]
            },
            {
                'title': 'Scans',
                'name': 'scans',
                'type': 'group',
                'children': []
            },
        ]
        self.settings = Parameter.create(name='settings',
                                         type='group',
                                         children=params_scan)
        self.settings_tree.setParameters(self.settings, showTop=False)
        self.settings.sigTreeStateChanged.connect(self.settings_changed)

        self.settings.child('settings',
                            'Load h5').sigActivated.connect(self.load_data)
        self.settings.child('settings',
                            'Load Image').sigActivated.connect(self.load_image)

        self.ui.statusbar = QtWidgets.QStatusBar()
        self.ui.statusbar.setMaximumHeight(25)
        layout.addWidget(self.ui.statusbar)
        self.ui.log_message = QtWidgets.QLabel('Initializing')
        self.ui.statusbar.addPermanentWidget(self.ui.log_message)

        self.sett_layout.addWidget(self.settings_tree)
        splitter.addWidget(sett_widget)
        splitter.addWidget(self.viewer.parent)

    def show_image(self, data):
        """

        Parameters
        ----------
        data: (dict) with keys 'names', 'data', 'x_axis', 'y_axis', 'pixmap2D'
        """

        if self.h5module is None:
            scan_path, current_filename, dataset_path = H5Saver.set_current_scan_path(
                navigator_path,
                base_name='Scan',
                update_h5=True,
                next_scan_index=self.next_scan_index,
                create_scan_folder=False)
            self.h5module = H5BrowserUtil()
            self.h5module.open_file(
                str(dataset_path.joinpath(dataset_path.name + ".h5")), 'w')

        else:
            scan_path, current_filename, dataset_path = H5Saver.set_current_scan_path(
                navigator_path,
                base_name='Scan',
                update_h5=False,
                next_scan_index=self.next_scan_index,
                create_scan_folder=False)
            if not self.h5module.isopen():
                self.h5module.open_file(
                    str(dataset_path.joinpath(dataset_path.name + ".h5")), 'a')

        h5group = self.h5module.root()
        data2D_group = self.h5module.get_set_group(h5group, 'Data2D')
        data2D_group.attrs.type = 'data2D'

        self.next_scan_index += 1
        curr_group = self.h5module.get_set_group('/Data2D', current_filename)
        live_group = self.h5module.get_set_group(curr_group, 'Live_scan_2D')
        live_group.attrs['pixmap2D'] = data['pixmap2D']

        xdata = data['x_axis']
        if isinstance(xdata, dict):
            xdata = xdata['data']
        xarray = self.h5module.create_carray(curr_group,
                                             "Scan_x_axis",
                                             obj=xdata,
                                             title=current_filename)
        xarray.attrs['type'] = 'navigation_axis'
        xarray.attrs['data_dimension'] = '1D'
        xarray.attrs['nav_index'] = 0

        ydata = data['y_axis']
        if isinstance(ydata, dict):
            ydata = ydata['data']
        yarray = self.h5module.create_carray(curr_group,
                                             "Scan_y_axis",
                                             obj=ydata,
                                             title=current_filename)
        yarray.attrs['type'] = 'navigation_axis'
        yarray.attrs['data_dimension'] = '1D'
        yarray.attrs['nav_index'] = 1

        for ind_channel, name in enumerate(data['names']):
            try:
                channel_group = self.h5module.get_set_group(live_group, name)
                channel_group.attrs.Channel_name = name
                array = self.h5module.create_carray(
                    channel_group,
                    current_filename + '_' + name,
                    obj=data['data'][ind_channel],
                    title='data',
                )
                array.attrs['type'] = 'data'
                array.attrs['data_dimension'] = '0D'
                array.attrs['data_name'] = name
                array.attrs['scan_type'] = 'scan2D'
                array.attrs['scan_subtype'] = ''
            except Exception as e:
                logger.exception(str(e))

        self.update_2Dscans()

    def update_2Dscans(self):
        try:
            if not self.h5module.isopen():
                self.h5module.open_file(self.h5module.filename, 'a')
            scans = self.h5module.get_h5file_scans(self.h5module.root())
            # settings=[dict(scan_name=node._v_name,path=node._v_pathname, pixmap=nparray2Qpixmap(node.read()))),...]
            params = []
            children = [
                child.name()
                for child in self.settings.child(('scans')).children()
            ]
            for scan in scans:
                if scan['scan_name'] not in children:
                    params.append({
                        'name':
                        scan['scan_name'],
                        'type':
                        'pixmap_check',
                        'value':
                        dict(data=scan['data'],
                             checked=False,
                             path=scan['path'])
                    })
            self.settings.child(('scans')).addChildren(params)

            for child in self.settings.child(('scans')).children():
                if child.name() not in children:
                    val = child.value()
                    val.update(dict(checked=True))
                    child.setValue(val)
                    child.sigValueChanged.emit(child, child.value())

        except Exception as e:
            logger.exception(str(e))

    def update_h5file(self, h5file):
        if self.h5module is not None:
            self.h5module.h5file = h5file
        self.update_2Dscans()

    def update_status(self, txt, status_time=0, log_type=None):
        """
            Show the txt message in the status bar with a delay of status_time ms.

            =============== =========== =======================
            **Parameters**    **Type**    **Description**
            *txt*             string      The message to show
            *status_time*       int         the delay of showing
            *log_type*        string      the type of the log
            =============== =========== =======================
        """
        try:
            self.ui.statusbar.showMessage(txt, status_time)
            logger.info(txt)
        except Exception as e:
            logger.exception(str(e))
Esempio n. 17
0
class GuiManager(QtGui.QMainWindow):
    def __init__(self):
        super(GuiManager, self).__init__()
        self.createLayout()

    def closeEvent(self, event):
        print 'User asked to close the app'
        self.stopAcquisition()
        Parameters.isAppKilled = True
        #time.sleep(0.1) #Wait for the worker death
        event.accept()  # let the window close

    def startAcquisition(self):
        if Parameters.isConnected == False:
            return
        Parameters.isSaving = Parameters.paramObject.child(
            "Saving parameters", "saveResults").value()
        if Parameters.isSaving == True:
            theDate = datetime.datetime.today().strftime('%Y%m%d')
            theTime = datetime.datetime.today().strftime('%H%M%S')
            theName = Parameters.paramObject.child("Saving parameters",
                                                   "Experiment name").value()
            #Check counter increment
            folderParent = 'C:/InterferometryResults/' + theDate
            counter = 1
            folderFound = False
            theFolder = folderParent + '/' + theName + '_' + str(
                counter).zfill(3)
            if not os.path.exists(folderParent):  #Make sure parent exist
                os.makedirs(folderParent)
            while folderFound == False and counter < 1000:  #Loop until folder is found
                if not os.path.exists(theFolder):  #Make sure parent exist
                    os.makedirs(theFolder)
                    folderFound = True
                else:
                    counter = counter + 1
                    theFolder = folderParent + '/' + theName + '_' + str(
                        counter).zfill(3)
            if counter < 1000:
                Parameters.savingFolder = theFolder
                if not os.path.exists(theFolder):
                    os.makedirs(theFolder)
            else:
                Parameters.isSaving = False
                #Should not happen.
        self.btStart.setEnabled(False)
        self.btStop.setEnabled(True)
        self.btOpen.setEnabled(False)
        #Get the parameter values
        Parameters.nSamples = Parameters.paramObject.child(
            "Acquisition Parameters", "Number of samples to acquire").value()
        acqMode = Parameters.paramObject.child("Trigger Options",
                                               "Acquisition mode").value()
        triggerAmplitude = Parameters.paramObject.child(
            "Trigger Options", "Trigger amplitude").value()
        motorSpeed = Parameters.paramObject.child(
            "Acquisition Parameters",
            "Rotation speed (%)").value() + 28  #28 is calibration
        nBlocks = int(math.ceil(float(Parameters.nSamples) /
                                512))  #Must be a multiple of 512
        Parameters.nSamples = nBlocks * 512
        Parameters.paramObject.child("Acquisition Parameters",
                                     "Number of samples to acquire").setValue(
                                         Parameters.nSamples)

        #Set frequency in free mode. These settings could be optimized depending on the computer.
        freq = 2500000  #10im/s
        if Parameters.nSamples > 100352:
            freq = 5000000  #5im/s
        if Parameters.nSamples > 300032:
            freq = 12500000  #2im/s
        if Parameters.nSamples > 1000000:
            freq = 25000000  #1im/s
        if Parameters.nSamples > 2000000:
            freq = 50000000  #0.5im/s

        #Start the acquisition on the FPGA
        data = []
        data = array('i')
        data.append(1)
        data.append(freq)
        data.append(2)
        data.append(acqMode)
        data.append(3)
        data.append(nBlocks)
        data.append(4)
        data.append(motorSpeed)
        data.append(5)
        data.append(triggerAmplitude)
        data.append(6)
        data.append(0)

        theBytes = struct.pack('i' * len(data), *data)
        buf = bytearray(theBytes)
        Parameters.dev.WriteToPipeIn(128, buf)

        Parameters.dev.SetWireInValue(0, 1 + 2 + 8, 1 + 2 + 8)
        Parameters.dev.UpdateWireIns(
        )  #Enable DDR2 reading and writing and activate memory.
        time.sleep(0.1)
        #Wait to make sure everything is ready. TODO: Reduce this.
        Parameters.dev.SetWireInValue(0, 4, 4)
        Parameters.dev.UpdateWireIns()  #Start acquisition clock.

        #self.plotTr.enableAutoRange('xy', True)  ## stop auto-scaling after the first data set is plotted
        Parameters.theQueue = Queue.Queue()  #Create the queue
        #self.DisplayUpdater(0)
        self.workThread.start()
        #Start the display worker

    def stopAcquisition(self):
        print 'Stopping...'
        if hasattr(self, 'tDisplay'):
            self.tDisplay.cancel()
        self.workThread.exitWorker()
        while self.workThread.isRunning == True:
            time.sleep(
                0.01)  #Wait for the worker death, before resetting the board
        Parameters.dev.SetWireInValue(0, 0, 1 + 2 + 4 + 8)
        Parameters.dev.UpdateWireIns()  #Reset board.

        #Save format: Results / YYMMDD / ExperimentName_Counter. Could also use the time.
        if Parameters.isSaving == True:
            #global state
            state = Parameters.paramObject.saveState()
            file = open(Parameters.savingFolder + '\Parameters.txt', 'w')
            pickle.dump(state, file)
            file.close()
        print 'Stopped.'
        self.btStart.setEnabled(True)
        self.btStop.setEnabled(False)
        self.btOpen.setEnabled(True)

    '''
    def DisplayUpdater(self,dummy):
        if Parameters.isAppKilled == True:
            return;   
        if Parameters.theQueue.empty():
            print 'no data...'
        while not Parameters.theQueue.empty(): #Empty the display queue
            data = Parameters.theQueue.get()
            #print 'data available!' 
        if 'data' in locals():
            #print 'display data' + str(data[2])
            self.setDataCurveTr(data)
        tDisplay = Timer(2, self.DisplayUpdater, [0],{})
        tDisplay.start()          
    '''

    def motorSpeedChanged(self, value):
        newSpeed = Parameters.paramObject.child("Acquisition Parameters",
                                                "Rotation speed (%)").value()
        newSpeed = newSpeed + 28  #Calibration

        #Debug
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(enabled=False)
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(visible=False)
        #Parameters.paramObject.child("Acquisition Parameters", "Rotation speed (%)").setOpts(value=200)

        data = []
        data = array('i')
        data.append(4)
        data.append(newSpeed)
        data.append(0)  #Minimum size is 8 'int'
        data.append(0)
        data.append(0)
        data.append(0)
        data.append(0)
        data.append(0)

        theBytes = struct.pack('i' * len(data), *data)
        Parameters.bufferToDev = bytearray(theBytes)
        Parameters.bufferToDevReady = True

    def triggerChanged(self, value):
        acqMode = Parameters.paramObject.child("Trigger Options",
                                               "Acquisition mode").value()
        triggerAmplitude = Parameters.paramObject.child(
            "Trigger Options", "Trigger amplitude").value()

        data = []
        data = array('i')
        data.append(2)
        data.append(acqMode)
        data.append(5)
        data.append(triggerAmplitude)
        data.append(0)
        data.append(0)
        data.append(0)
        data.append(0)

        theBytes = struct.pack('i' * len(data), *data)
        print str(theBytes)

        Parameters.bufferToDev = bytearray(theBytes)
        Parameters.bufferToDevReady = True

    def triggerHalfSwitch(self):
        Parameters.triggerToDev = True

    def saveParam(self):
        #global state
        state = Parameters.paramObject.saveState()
        file = open('dump.txt', 'w')
        pickle.dump(state, file)
        file.close()

    def restoreParam(self):
        #lobal state
        file = open('dump.txt', 'r')
        state = pickle.load(file)
        #add = Parameters.paramObject['Save/Restore functionality', 'Restore State', 'Add missing items']
        #rem = Parameters.paramObject['Save/Restore functionality', 'Restore State', 'Remove extra items']
        Parameters.paramObject.restoreState(state,
                                            addChildren=False,
                                            removeChildren=False)

    #Set the status text (system connected or not)
    def setStatus(self, isConnected, isError=False):
        def dotChange(
            item, nDots
        ):  #Timer function to display a varying number of dots after "retrying"
            if Parameters.isConnected == True:
                return
            if Parameters.isAppKilled == True:
                return
            textNotConnected = "System not connected, retrying"
            item.setText(textNotConnected + ".")
            #Number of dots varies from 1 to 5
            if nDots == 1:
                textDots = "."
                nDots = 2
            elif nDots == 2:
                textDots = ".."
                nDots = 3
            elif nDots == 3:
                textDots = "..."
                nDots = 4
            elif nDots == 4:
                textDots = "...."
                nDots = 5
            else:
                textDots = "....."
                nDots = 1
            item.setForeground(QtGui.QColor("red"))
            item.setText(textNotConnected + textDots)
            self.timerDotChange = Timer(0.25, dotChange,
                                        [self.itemStatus, nDots])
            self.timerDotChange.start()

        if (isError == True):  #System not connected
            print "Error"
            if hasattr(self, 'timerDotChange'):
                self.timerDotChange.cancel()
                time.sleep(0.5)
            self.itemStatus.setForeground(QtGui.QColor("red"))
            self.itemStatus.setText(
                "Error with system. Please restart the application and the system."
            )
        elif (isConnected == False):  #System not connected
            nDots = 1
            if hasattr(self, 'timerDotChange'):
                self.timerDotChange.cancel()
            self.timerDotChange = Timer(0.25, dotChange,
                                        [self.itemStatus, nDots])
            self.timerDotChange.start()
        else:
            print "Connected"
            if hasattr(self, 'timerDotChange'):
                self.timerDotChange.cancel()
                time.sleep(0.1)
            self.itemStatus.setForeground(QtGui.QColor("green"))
            self.itemStatus.setText("System connected.")
            print "Connected2"

    #Set the status text (system connected or not)
    def setCameraStatus(self, isConnected):
        def dotChange(
            item, nDots
        ):  #Timer function to display a varying number of dots after "retrying"
            if Parameters.isCameraConnected == True:
                return
            if Parameters.isAppKilled == True:
                return
            textNotConnected = "Camera not connected, retrying"
            item.setText(textNotConnected + ".")
            #Number of dots varies from 1 to 5
            if nDots == 1:
                textDots = "."
                nDots = 2
            elif nDots == 2:
                textDots = ".."
                nDots = 3
            elif nDots == 3:
                textDots = "..."
                nDots = 4
            elif nDots == 4:
                textDots = "...."
                nDots = 5
            else:
                textDots = "....."
                nDots = 1
            item.setForeground(QtGui.QColor("red"))
            item.setText(textNotConnected + textDots)
            self.timerDotChangeCamera = Timer(0.25, dotChange,
                                              [self.itemCameraStatus, nDots])
            self.timerDotChangeCamera.start()

        if (isConnected == False):  #System not connected
            print 'cam oups'
            nDots = 1
            if hasattr(self, 'timerDotChangeCamera'):
                self.timerDotChangeCamera.cancel()
            self.timerDotChangeCamera = Timer(0.25, dotChange,
                                              [self.itemCameraStatus, nDots])
            self.timerDotChangeCamera.start()
        else:
            print "Camera connected"
            if hasattr(self, 'timerDotChangeCamera'):
                self.timerDotChangeCamera.cancel()
                time.sleep(0.1)
            self.itemCameraStatus.setForeground(QtGui.QColor("green"))
            self.itemCameraStatus.setText("Camera connected.")
            print "Camera connected2"

    #Set the status text (system connected or not)
    def setInfo(self, text):
        self.tbInfo.append(text)

    #Set the status text (system connected or not)
    def setWire(self, mem1, mem2, mem3, mem4, maxValPos):
        self.itemMemory.setText("Acquisition board memory usage:\nDDR2: " +
                                str(mem1) + " bytes.\nFIFO in: " + str(mem2) +
                                " bytes.\nFIFO out: " + str(mem3) +
                                " bytes.\nFIFO out (minimum): " + str(mem4) +
                                " bytes.")
        self.itemMaxValPos.setText("Maximum RF value position: " +
                                   str(maxValPos))

    def createLayout(self):
        print 'Creating layout...'
        self.setWindowTitle('Interferometry Acquisition GUI')
        #self.widget = QtGui.QWidget()
        #self.setCentralWidget(self.widget)
        self.layout = pg.LayoutWidget()
        #self.widget.setLayout(self.layout)
        self.setCentralWidget(self.layout)

        #Create GUI
        sizePolicyBt = QtGui.QSizePolicy(1, 1)
        sizePolicyBt.setHorizontalStretch(0)
        sizePolicyBt.setVerticalStretch(0)

        self.btOpen = QtGui.QPushButton("Open\nprevious results")
        sizePolicyBt.setHeightForWidth(
            self.btOpen.sizePolicy().hasHeightForWidth())
        self.btOpen.setSizePolicy(sizePolicyBt)
        self.btOpen.setStyleSheet(
            "background-color: yellow; font-size: 16px; font: bold")

        self.btStart = QtGui.QPushButton("Start\nacquisition")
        sizePolicyBt.setHeightForWidth(
            self.btStart.sizePolicy().hasHeightForWidth())
        self.btStart.setSizePolicy(sizePolicyBt)
        self.btStart.setStyleSheet(
            "background-color: green; font-size: 16px; font: bold")
        self.btStart.clicked.connect(self.startAcquisition)

        self.btStop = QtGui.QPushButton("Stop\nacquisition")
        sizePolicyBt.setHeightForWidth(
            self.btStop.sizePolicy().hasHeightForWidth())
        self.btStop.setSizePolicy(sizePolicyBt)
        self.btStop.setStyleSheet(
            "background-color: red; font-size: 16px; font: bold")
        self.btStop.clicked.connect(self.stopAcquisition)
        self.btStop.setEnabled(False)

        self.paramTree = ParameterTree()
        self.paramTree.setParameters(Parameters.paramObject, showTop=False)
        self.paramTree.setWindowTitle('pyqtgraph example: Parameter Tree')
        self.paramTree.setMinimumWidth(350)
        self.paramTree.setMaximumWidth(350)
        sizePolicyPt = QtGui.QSizePolicy(1, 1)
        sizePolicyPt.setHorizontalStretch(QtGui.QSizePolicy.Fixed)
        sizePolicyPt.setVerticalStretch(1)
        self.paramTree.setSizePolicy(sizePolicyPt)

        ## Create random 2D data
        data = np.random.normal(size=(
            512, 512)) + pg.gaussianFilter(np.random.normal(size=(512, 512)),
                                           (5, 5)) * 20 + 100
        data = data[:, :, np.newaxis]
        data = data.repeat(3, 2)

        self.plotTl = pg.GraphicsView()
        self.plotTlImage = pg.ImageItem(data[:, :, :])  #parent=self.plotTl
        self.plotTlViewBox = pg.ViewBox()
        self.plotTl.setCentralWidget(self.plotTlViewBox)
        self.plotTlViewBox.addItem(self.plotTlImage)

        self.plotTr = pg.PlotWidget(title="Interferometry",
                                    labels={
                                        'left': 'Signal amplitude (A.U.)',
                                        'bottom': 'Distance (mm)'
                                    })
        #self.plotTlViewBox2.addItem(self.plotTr)
        self.plotTrCurve = self.plotTr.plot(pen=(255, 0, 0), name='C1')  #Red
        self.plotTrCurve2 = self.plotTr.plot(pen=(0, 255, 0),
                                             name='C2')  #Green
        #self.plotTlViewBox2.enableAutoRange('xy', True)  ## stop auto-scaling after the first data set is plotted
        #self.plotTr.addLegend('Test')
        self.plotTr.setYRange(-1000, 1000)

        self.plotBl = pg.PlotWidget(title="Distance",
                                    labels={
                                        'left': 'Distance (mm)',
                                        'bottom': 'Number of acquisitions'
                                    })

        self.plotBlCurve = self.plotBl.plot(pen=(255, 0, 0), name='C1')
        self.plotBl.enableAutoRange(
            'xy',
            True)  ## stop auto-scaling after the first data set is plotted
        self.plotBl.setMaximumWidth(3500)

        self.tbInfo = QtGui.QTextEdit()
        self.tbInfo.setEnabled(False)
        palette = self.tbInfo.palette()
        palette.setColor(QtGui.QPalette.Base,
                         QtGui.QColor("white"))  #White background
        self.tbInfo.setPalette(palette)
        self.tbInfo.setTextColor(QtGui.QColor("black"))
        self.tbInfo.insertPlainText("Useful information will appear here.")

        #Create list view of multiple items
        self.tbStatus = QtGui.QListView()
        self.tbStatus.setEnabled(False)
        palette = self.tbStatus.palette()
        palette.setColor(QtGui.QPalette.Base,
                         QtGui.QColor("white"))  #White background
        self.tbStatus.setPalette(palette)
        itemModelStatus = QtGui.QStandardItemModel(self.tbStatus)
        self.tbStatus.setModel(itemModelStatus)
        #Add system status
        self.itemStatus = QtGui.QStandardItem()
        self.setStatus(False)
        itemModelStatus.appendRow(self.itemStatus)
        #Add camera status
        self.itemCameraStatus = QtGui.QStandardItem()
        self.setCameraStatus(False)
        itemModelStatus.appendRow(self.itemCameraStatus)
        #Add memory usage
        self.itemMemory = QtGui.QStandardItem(
            "Acquisition board memory usage: N/A")
        self.itemMemory.setForeground(QtGui.QColor("black"))
        itemModelStatus.appendRow(self.itemMemory)
        #Add max value position
        self.itemMaxValPos = QtGui.QStandardItem(
            "Maximum RF value position: N/A")
        self.itemMaxValPos.setForeground(QtGui.QColor("black"))
        itemModelStatus.appendRow(self.itemMaxValPos)

        #layout.addWidget(QtGui.QLabel("These are two views of the same data. They should always display the same values."), 0, 0, 1, 2)
        self.layout.addWidget(self.btOpen, 9, 6, 1, 1)
        self.layout.addWidget(self.btStart, 9, 7, 1, 1)
        self.layout.addWidget(self.btStop, 9, 8, 1, 1)
        self.layout.addWidget(self.paramTree, 0, 0, 10, 3)
        self.layout.addWidget(self.plotTl, 0, 3, 5, 3)
        self.layout.addWidget(self.plotTr, 0, 6, 5, 3)
        self.layout.addWidget(self.plotBl, 5, 3, 5, 3)
        self.layout.addWidget(self.tbInfo, 5, 6, 2, 3)
        self.layout.addWidget(self.tbStatus, 7, 6, 2, 3)

        self.layout.layout.setColumnStretch(3, 1)
        self.layout.layout.setColumnStretch(4, 1)
        self.layout.layout.setColumnStretch(5, 1)
        self.layout.layout.setColumnStretch(6, 1)
        self.layout.layout.setColumnStretch(7, 1)
        self.layout.layout.setColumnStretch(8, 1)

        self.show()
        self.resize(1500, 800)
        self.move(100, 100)

        Parameters.paramObject.param('Save/Restore functionality',
                                     'Save State').sigActivated.connect(
                                         self.saveParam)
        Parameters.paramObject.param('Save/Restore functionality',
                                     'Restore State').sigActivated.connect(
                                         self.restoreParam)

        Parameters.paramObject.child(
            "Acquisition Parameters",
            "Rotation speed (%)").sigValueChanged.connect(
                self.motorSpeedChanged)
        Parameters.paramObject.child(
            "Trigger Options",
            "Acquisition mode").sigValueChanged.connect(self.triggerChanged)
        Parameters.paramObject.child(
            "Trigger Options",
            "Trigger amplitude").sigValueChanged.connect(self.triggerChanged)
        Parameters.paramObject.child(
            "Trigger Options",
            "Trigger switch 1/2").sigActivated.connect(self.triggerHalfSwitch)

        # adding by emitting signal in different thread
        self.workThread = AcquisitionWorker()
        self.workThread.updateDataCamera.connect(self.setDataCurveTl)
        self.workThread.updateDataInterf.connect(self.setDataCurveTr)
        self.workThread.updateDataDistance.connect(self.setDataCurveBl)
        self.workThread.updateDataDistance2.connect(self.setDataCurveBl2)
        self.workThread.updateWire.connect(self.setWire)
        self.workThread.setStatus.connect(self.setStatus)
        self.workThread.setInfo.connect(self.setInfo)
        self.testCount = 0

        #Fill the plots with dummy data
        self.data = np.random.normal(size=(10, 1000))
        self.plotTrXAxis = np.arange(1000) * (0.01)
        self.plotBlXAxis = np.arange(1000) * (1)
        self.plotTrCurve.setData(x=self.plotTrXAxis,
                                 y=self.data[2 % 10],
                                 name='C1')
        self.plotTrCurve2.setData(x=self.plotTrXAxis,
                                  y=self.data[3 % 10],
                                  name='C2')
        self.plotBlCurve.setData(x=self.plotBlXAxis,
                                 y=self.data[4 % 10],
                                 name='C1')

        self.valueTest = 1

    def setDataCurveTl(self, data):
        self.dataImage1 = data
        self.plotTlImage.setImage(data)
        self.testCount = self.testCount + 1

    def setDataCurveTr(self, dataIn):
        self.plotTrCurve.setData(dataIn[0:len(dataIn):2], name='C1')
        self.plotTrCurve2.setData(dataIn[1:len(dataIn):2], name='C2')

    def setDataCurveBl(self, dataIn):
        self.plotBlCurve.setData(dataIn, name='C1')

    def setDataCurveBl2(self, xIn, dataIn):
        self.plotBlCurve.setData(x=xIn, y=dataIn, name='C1')