class CONNECTIONS(QtGui.QGraphicsObject):
    '''
    The CONNECTIONS serves as a mediator between the Dataset class and the GrapherWindow
    class. 
    
    A grapher works by keeping track of datasets and determining which windows
    to plot them on. The main dictionary, dwDict, relates Dataset objects with GrapherWindow
    objects. Each time a new dataset is created, CONNECTIONS creates a unique 
    Dataset object. It then determines which GrapherWindow objects the dataset should
    be drawn on. i.e.:
    
        Without dataset overlaying (dwDict):
        
            [Dataset1] = [GrapherWindow1]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3]
                       .
                       .
                       .
    
        With dataset overlaying (dwDict):

            [Dataset1] = [GrapherWindow1, GrapherWindow3]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3, GrapherWindow2]
                       .
                       .
                       .
    
    GrapherWindow objects are added and removed from the dictionary depending on factors
    such as overlaying datasets or closing windows.
    
    Note: the grapher will only plot datasets that possess the 'plotLive' parameter. This 
    parameter is checked for in the Dataset class. This prevents unwanted new datasets from being plotted
    Old datasets that are manually loaded from graph are exempt from this requirement.
    
    There is a main timer event that retrieves data from the Dataset buffer, sends it to
    the GrapherWindow, and calls on GrapherWindow to draw the plot. This ensures that all datasets
    are plotted constantly in order to maintain a live update.     

    '''

    def __init__(self, reactor, parent=None):
        super(CONNECTIONS, self).__init__()
        self.reactor = reactor
        self.dwDict = {} # dictionary relating Dataset and ApplicationWindow
        self.datasetDict = {} # dictionary relating a Dataset object with the dataset and directory 
#        self.winList = []
        self.histList = []
        self.windowCounter = 0
        self.winDict = {}
        self.attemptLabRadConnect()               
        self.startTimer()
        self.communicate = COMMUNICATE()

    def attemptLabRadConnect(self):
        from labrad.errors import LoginFailedError
        deferred = self.connectLabRAD()
        def handleLabRadError(failure):
            if (failure.trap(ConnectionRefusedError)):
                self.retryLabradConnectDialog = RetryConnectingDialog(self, 'LabRAD')
                self.retryLabradConnectDialog.show()
        deferred.addErrback(handleLabRadError)

    def attemptDataVaultConnect(self):
        deferred = self.connectDataVault()
        def handleDataVaultError(failure):
            if (failure.trap(AttributeError)):
                self.retryLabradConnectDialog = RetryConnectingDialog(self, 'DataVault')
                self.retryLabradConnectDialog.show()
        deferred.addErrback(handleDataVaultError)

    # connect to the data vault    
    @inlineCallbacks    
    def connectLabRAD(self):
        from labrad.wrappers import connectAsync
        from labrad.types import Error
        try: # if the connection failed and was retried, close the dialog
            self.retryLabradConnectDialog.close()
        except AttributeError:
            pass
        self.cxn = yield connectAsync()
        self.attemptDataVaultConnect()

    @inlineCallbacks
    def connectDataVault(self):
        try: # if the connection failed and was retried, close the dialog
            self.retryLabradConnectDialog.close()
        except AttributeError:
            pass
        self.server = yield self.cxn.data_vault
        yield self.setupListeners()
        context = yield self.cxn.context() # create a new context
        self.introWindow = FirstWindow(self, context, self.reactor)
        self.introWindow.show()
        print 'Connection established: now listening dataset.'
        self.communicate.connectionReady.emit()
        
        
        
    # set up dataset listener    
    @inlineCallbacks
    def setupListeners(self):               
        yield self.server.signal__new_dataset_dir(88888)#, context = context)
        yield self.server.addListener(listener = self.updateDataset, source = None, ID = 88888)#, context = context)    
        yield self.server.signal__new_directory(77777)#, context = context)
        yield self.server.addListener(listener = self.addDirItem, source = None, ID = 77777)#, context = context)
        yield self.server.signal__new_parameter_dataset(99999)#, context = context)
        yield self.server.addListener(listener = self.updateParameter, source = None, ID = 99999)#, context = context)    

    def addDirItem(self,x,y):
        #directory = tuple(eval(str(y))) 
        self.introWindow.datavaultwidget.populateList()
#        for i in self.winDict.values():
#            i.datavaultwidget.populateList()
#        for i in self.winList:
#            i.datavaultwidget.populateList()
           
    # new dataset signal
    def updateParameter(self,x,y):
        dataset = y[0]
        datasetName = y[1]
#        print datasetName
        directory = y[2]
        itemLabel = (str(dataset) + ' - ' + str(datasetName))
        # process parameter 
        if (y[3] == 'plotLive'):
            manuallyLoaded = False # ensure that this dataset was not loaded manually
            self.newDataset(dataset, directory, manuallyLoaded, datasetName)
        elif (y[3] == 'Histogram'):
            self.createHistogram(dataset, directory, datasetName)
        elif (y[3] == 'Fit'):
            try:
                self.datasetDict[dataset, directory].fit()
            except:
                print 'Was plotLive set for this dataset?'

    def updateDataset(self, x, y):
#        dataset = int(y[0][0:5]) # retrieve dataset number
#        datasetName = str(y[0][8:len(y[0])])
#        print datasetName
        directory = y[1] # retrieve directory
        itemLabel = y[0] # 'dataset - datasetName' 
        self.addDatasetItem(itemLabel, directory)
#        print directory
#        print dataset
#        print x, y
 
    def addDatasetItem(self, itemLabel, directory):
        self.introWindow.datavaultwidget.addDatasetItem(itemLabel, directory)
#        for i in self.winDict.values():
#            i.datavaultwidget.addDatasetItem(itemLabel, directory)
#        for i in self.winList:
#            i.datavaultwidget.addDatasetItem(itemLabel, directory)
 
    @inlineCallbacks
    def createHistogram(self, dataset, directory, datasetName):
        
        context = yield self.cxn.context()
        yield self.server.cd(directory, context=context)
        yield self.server.open(dataset, context=context)
            
        threshold = yield self.server.get_parameter('Histogram', context=context)
        Data = yield self.server.get(context=context)
        data = Data.asarray
        
        histWindow = HistWindow(self, data, threshold, datasetName)
        self.histList.append(histWindow)
        histWindow.show()        
    
    # Creates a new Dataset object and checks if it has the 'plotLive' parameter
    @inlineCallbacks
    def newDataset(self, dataset, directory, manuallyLoaded, datasetName):
        context = yield self.cxn.context() # create a new context
        datasetObject = Dataset(self, self.cxn, context, dataset, directory, datasetName, self.reactor)
        self.datasetDict[dataset, directory] = datasetObject
        yield datasetObject.openDataset(context)
#        yield datasetObject.setupParameterListener(context)
#        yield datasetObject.checkForPlotParameter()
        datasetLabels = yield datasetObject.getYLabels()
        windowName = []
        if (len(self.winDict.values()) < MAXWINDOWS):
            # if the dataset was loaded manually, it does not require the 'Window' parameter 
            if (manuallyLoaded == True):
                try:
                    histValue = yield self.server.get_parameter('Histogram', context = context)
                    self.createHistogram(dataset, directory, datasetName)
                    datasetObject.endTimer()
                    del datasetObject
                except:
                    self.prepareDataset(datasetObject, dataset, directory, datasetLabels, windowName)#, context)
            else:        
#               hasPlotParameter = yield datasetObject.listenForPlotParameter()
#               if (hasPlotParameter == True):
                windowParameter = yield datasetObject.getWindowParameter()
                # if windows are specified (via parameter), send that instead
                if (windowParameter != None):
                    self.prepareDataset(datasetObject, dataset, directory, datasetLabels, windowParameter)#, context)
                else:
                    self.prepareDataset(datasetObject, dataset, directory, datasetLabels, windowName)#, context)
#            else:
#                    # This data is not for plotting. Remove it.
#                    # There should be a cleaner way of doing this
#                    datasetObject.endTimer()
#                    del datasetObject
        else:
            print 'Too many windows open!'
            datasetObject.endTimer()
            del datasetObject

    # Prepare the dataset for plotting
    @inlineCallbacks
    def prepareDataset(self, datasetObject, dataset, directory, datasetLabels, windowNames):#, context):      
        #if windows request overlay, update those. else, create a new window.
        overlayWindows = self.getOverlayingWindows()
        overlayWindowNames = []
        if overlayWindows:
            # if the dataset is already in the window
            overlayWindows = [x for x in overlayWindows if ((dataset, directory) not in x.qmc.dataDict.keys())]
            for overlayWindow in overlayWindows:
                overlayWindow.qmc.initializeDataset(dataset, directory, datasetLabels)
#                overlayWindow.createDatasetCheckbox(dataset, directory)
                overlayWindowNames.append(overlayWindow.windowName)
            if overlayWindows:
                self.dwDict[datasetObject] = overlayWindows
        elif (len(windowNames) == 0):
            windowName = 'Window ' + str(self.windowCounter)
            self.windowCounter = self.windowCounter + 1
            context = yield self.cxn.context() # create a new context
            win = self.newGraph(context, windowName)
            yield deferToThread(time.sleep, .01)
            self.dwDict[datasetObject] = [win]
            win.qmc.initializeDataset(dataset, directory, datasetLabels)
#            win.createDatasetCheckbox(dataset, directory)
                    
        # process windowNames that came from parameters (the following won't happen without window parameters specified)
        for windowName in windowNames:
            if windowName in overlayWindowNames:
                pass
            # if the window is open and it isn't asking for overlay    
            elif windowName in self.winDict.keys():
                try:
                    self.dwDict[datasetObject].append(self.winDict[windowName])
                except KeyError:
                    self.dwDict[datasetObject] = [self.winDict[windowName]]    
                self.winDict[windowName].qmc.initializeDataset(dataset, directory, datasetLabels)
#                self.winDict[windowName].createDatasetCheckbox(dataset, directory)
            else:
                context = yield self.cxn.context() # create a new context
                win = self.newGraph(context, windowName)
                yield deferToThread(time.sleep, .01)
                try:
                    self.dwDict[datasetObject].append(win)
                except KeyError:
                    self.dwDict[datasetObject] = [win]    
                win.qmc.initializeDataset(dataset, directory, datasetLabels)
#                win.createDatasetCheckbox(dataset, directory)

    # create a new graph window
#    def newGraph(self, context, windowName):
    def newGraph(self, context, windowName):
        win = GrapherWindow(self, context, windowName)
        self.winDict[windowName] = win
#        self.winList.append(win)
        win.show()
        return win
            
    def startTimer(self): 
        lc = LoopingCall(self.timerEvent)
        lc.start(GraphRefreshTime)
     
    # Main timer, cycles through dwDict. For each dataset, determines...
    # ... which windows to draw the dataset on. Then draws the plot.   
    @inlineCallbacks
    def timerEvent(self):
#        print 'in connections: {0}'.format( len(self.dwDict.keys()) )
        for datasetObject in self.dwDict.keys():
            windowsToDrawOn = self.dwDict[datasetObject]
            if (datasetObject.data != None):
                data = datasetObject.data
                yield datasetObject.emptyDataBuffer()
                for i in windowsToDrawOn:
#                    print 'still happening connections'
                    i.qmc.setPlotData(datasetObject.dataset, datasetObject.directory, data)
    # Cycles through the values in each key for checked Overlay boxes, returns the windows...
    # ...with the overlay button checked
    def getOverlayingWindows(self):
        self.overlaidWindows = []
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j.cb2.isChecked():
                    # skip duplicates
                    if j in self.overlaidWindows:
                        pass
                    else:
                        self.overlaidWindows.append(j)
        return self.overlaidWindows
    
    def getParameters(self, dataset, directory):
        parametersValues = []
        parameters = self.datasetDict[dataset, directory].parameters
        values = self.datasetDict[dataset, directory].parameterValues
        for parameter, value in zip(parameters, values):
            parametersValues.append((parameter, value))
        
        return parametersValues
    
    def changeWindowName(self, oldWindowName, newWindowName):
        self.winDict[newWindowName] = self.winDict[oldWindowName]
        del self.winDict[oldWindowName]
        
    
    # Datasets no longer need to be drawn on closed windows
    @inlineCallbacks
    def removeWindowFromDictionary(self, win):
        print sys.getrefcount(win)
        #objgraph.show_most_common_types(limit=20)
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j == win:
                    # if the last window is being removed, delete the dataset object
                    # from the dictionary
                    if (len(values) == 1):
                        #self.dwDict[i].remove(j)
                        i.endTimer()
                        print 'disconnecting data signal'
                        yield i.disconnectDataSignal()
                        del self.dwDict[i]
                    else:
                        self.dwDict[i].remove(j)

        
    # Datavault widgets no longer need to be updated
    def removeWindowFromWinList(self, win):
        for i in self.winList:
            if i == win:
                self.winList.remove(i)
                
    # Datavault widgets no longer need to be updated
    def removeWindowFromWinDict(self, windowName):
        del self.winDict[windowName]
    
    @inlineCallbacks
    def cleanUp(self):
        print 'clean!'
        yield deferToThread(time.sleep, 5)
        gc.collect()
Пример #2
0
class CONNECTIONS(QtGui.QGraphicsObject):
    '''
    The CONNECTIONS serves as a mediator between the Dataset class and the GrapherWindow
    class. 
    
    A grapher works by keeping track of datasets and determining which windows
    to plot them on. The main dictionary, dwDict, relates Dataset objects with GrapherWindow
    objects. Each time a new dataset is created, CONNECTIONS creates a unique 
    Dataset object. It then determines which GrapherWindow objects the dataset should
    be drawn on. i.e.:
    
        Without dataset overlaying (dwDict):
        
            [Dataset1] = [GrapherWindow1]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3]
                       .
                       .
                       .
    
        With dataset overlaying (dwDict):

            [Dataset1] = [GrapherWindow1, GrapherWindow3]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3, GrapherWindow2]
                       .
                       .
                       .
    
    GrapherWindow objects are added and removed from the dictionary depending on factors
    such as overlaying datasets or closing windows.
    
    Note: the grapher will only plot datasets that possess the 'plotLive' parameter. This 
    parameter is checked for in the Dataset class. This prevents unwanted new datasets from being plotted
    Old datasets that are manually loaded from graph are exempt from this requirement.
    
    There is a main timer event that retrieves data from the Dataset buffer, sends it to
    the GrapherWindow, and calls on GrapherWindow to draw the plot. This ensures that all datasets
    are plotted constantly in order to maintain a live update.     

    '''

    def __init__(self, reactor, parent=None):
        super(CONNECTIONS, self).__init__()
        self.reactor = reactor
        self.dwDict = {} # dictionary relating Dataset and ApplicationWindow
        self.datasetDict = {} # dictionary relating a Dataset object with the dataset and directory 
        self.winList = []
        self.connect()
        self.startTimer()

    # connect to the data vault    
    @inlineCallbacks    
    def connect(self):
        from labrad.wrappers import connectAsync
        from labrad.types import Error
        self.cxn = yield connectAsync()
        self.server = yield self.cxn.data_vault
        yield self.setupListeners()
        context = yield self.cxn.context() # create a new context
        self.introWindow = FirstWindow(self, context)
        self.introWindow.show()
        print 'Connection established: now listening dataset.'

    # set up dataset listener    
    @inlineCallbacks
    def setupListeners(self):               
        yield self.server.signal__new_dataset_dir(99999)#, context = context)
        yield self.server.addListener(listener = self.updateDataset, source = None, ID = 99999)#, context = context)    
        yield self.server.signal__new_directory(77777)#, context = context)
        yield self.server.addListener(listener = self.addDirItem, source = None, ID = 77777)#, context = context)

    def addDirItem(self,x,y):
        #directory = tuple(eval(str(y))) 
        self.introWindow.datavaultwidget.populateList()
        for i in self.winList:
            i.datavaultwidget.populateList()
           
    # new dataset signal
    def updateDataset(self,x,y):
        dataset = int(y[0][0:5]) # retrieve dataset number
        directory = y[1] # retrieve directory
        itemLabel = y[0]
        self.addDatasetItem(itemLabel, directory)
        print directory
        print dataset
        manuallyLoaded = False # ensure that this dataset was not loaded manually
        self.newDataset(dataset, directory, manuallyLoaded)
 
    def addDatasetItem(self, itemLabel, directory):
        self.introWindow.datavaultwidget.addDatasetItem(itemLabel, directory)
        for i in self.winList:
            i.datavaultwidget.addDatasetItem(itemLabel, directory)
 
    # Creates a new Dataset object and checks if it has the 'plotLive' parameter
    @inlineCallbacks
    def newDataset(self, dataset, directory, manuallyLoaded):
        context = yield self.cxn.context() # create a new context
        datasetObject = Dataset(self.cxn, context, dataset, directory)
        self.datasetDict[dataset, directory] = datasetObject
        yield datasetObject.openDataset(context)
        yield datasetObject.setupParameterListener(context)
        yield datasetObject.checkForPlotParameter()
        datasetLabels = yield datasetObject.getYLabels()
        # if the dataset was loaded manually, it does not require the 'plotLive' parameter 
        if (manuallyLoaded == True):
            self.prepareDataset(datasetObject, dataset, directory, datasetLabels, context)
        else:        
            hasPlotParameter = yield datasetObject.listenForPlotParameter()
            if (hasPlotParameter == True):
                self.prepareDataset(datasetObject, dataset, directory, datasetLabels, context)
            else:
                # This data is not for plotting. Remove it.
                # There should be a cleaner way of doing this
                del datasetObject

    # Prepare the dataset for plotting
    @inlineCallbacks
    def prepareDataset(self, datasetObject, dataset, directory, datasetLabels, context):
        #if windows request overlay, update those. else, create a new window.
        overlayWindows = self.getOverlayingWindows()
        if overlayWindows:
            self.dwDict[datasetObject] = overlayWindows
            for window in overlayWindows:
                window.qmc.initializeDataset(dataset, directory, datasetLabels)
                window.createDatasetCheckbox(dataset, directory) 
        else:
            win = self.newGraph(context)
            yield deferToThread(time.sleep, .01)
            self.dwDict[datasetObject] = [win]
            win.qmc.initializeDataset(dataset, directory, datasetLabels)
            win.createDatasetCheckbox(dataset, directory) 

    # create a new graph window
    def newGraph(self, context):
        win = GrapherWindow(self, context)
        self.winList.append(win)
        win.show()
        return win
            
    def startTimer(self): 
        lc = LoopingCall(self.timerEvent)
        lc.start(GraphRefreshTime)
     
    # Main timer, cycles through dwDict. For each dataset, determines...
    # ... which windows to draw the dataset on. Then draws the plot.   
    @inlineCallbacks
    def timerEvent(self):
        for datasetObject in self.dwDict.keys():
            windowsToDrawOn = self.dwDict[datasetObject]
            if (datasetObject.data != None):
                data = datasetObject.data
                yield datasetObject.emptyDataBuffer()
                for i in windowsToDrawOn:
                    i.qmc.setPlotData(datasetObject.dataset, datasetObject.directory, data)
            for i in windowsToDrawOn:
                # if dataset is intended to be drawn (a checkbox governs this)
                if i.datasetCheckboxes[datasetObject.dataset, datasetObject.directory].isChecked():
                    i.qmc.drawPlot(datasetObject.dataset, datasetObject.directory)
    
    # Cycles through the values in each key for checked Overlay boxes, returns the windows...
    # ...with the overlay button checked
    def getOverlayingWindows(self):
        self.overlaidWindows = []
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j.cb2.isChecked():
                    # skip duplicates
                    if j in self.overlaidWindows:
                        pass
                    else:
                        self.overlaidWindows.append(j)
        return self.overlaidWindows
    
    def getParameters(self, dataset, directory):
        parameters = self.datasetDict[dataset, directory].parameters
        return parameters
    
    # Datasets no longer need to be drawn on closed windows
    def removeWindowFromDictionary(self, win):
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j == win:
                    self.dwDict[i].remove(j)
                    
    # Datavault widgets no longer need to be updated
    def removeWindowFromWinList(self, win):
        for i in self.winList:
            if i == win:
                self.winList.remove(i)
Пример #3
0
class CONNECTIONS(QtGui.QGraphicsObject):
    '''
    The CONNECTIONS serves as a mediator between the Dataset class and the GrapherWindow  class. 
    
    A grapher works by keeping track of datasets and determining which windows
    to plot them on. The main dictionary, dwDict, relates Dataset objects with GrapherWindow
    objects. Each time a new dataset is created, CONNECTIONS creates a unique 
    Dataset object. It then determines which GrapherWindow objects the dataset should
    be drawn on. i.e.:
    
        Without dataset overlaying (dwDict):
        
            [Dataset1] = [GrapherWindow1]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3]
                       .
                       .
                       .
    
        With dataset overlaying (dwDict):

            [Dataset1] = [GrapherWindow1, GrapherWindow3]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3, GrapherWindow2]
                       .
                       .
                       .
    
    GrapherWindow objects are added and removed from the dictionary depending on factors
    such as overlaying datasets or closing windows.
    
    Note: the grapher will only plot datasets that possess the 'plotLive' parameter. This 
    parameter is checked for in the Dataset class. This prevents unwanted new datasets from being plotted
    Old datasets that are manually loaded from graph are exempt from this requirement.
    
    There is a main timer event that retrieves data from the Dataset buffer, sends it to
    the GrapherWindow, and calls on GrapherWindow to draw the plot. This ensures that all datasets
    are plotted constantly in order to maintain a live update.     

    '''
    def __init__(self, reactor, parent=None):
        super(CONNECTIONS, self).__init__()
        self.reactor = reactor
        self.dwDict = {}  # dictionary relating Dataset and ApplicationWindow
        self.datasetDict = {
        }  # dictionary relating a Dataset object with the dataset and directory
        #        self.winList = []
        self.histList = []
        self.windowCounter = 0
        self.winDict = {}
        self.attemptLabRadConnect()
        self.startTimer()
        self.communicate = COMMUNICATE()

    def attemptLabRadConnect(self):
        from labrad.errors import LoginFailedError
        deferred = self.connectLabRAD()

        def handleLabRadError(failure):
            if (failure.trap(ConnectionRefusedError)):
                self.retryLabradConnectDialog = RetryConnectingDialog(
                    self, 'LabRAD')
                self.retryLabradConnectDialog.show()

        deferred.addErrback(handleLabRadError)

    def attemptDataVaultConnect(self):
        deferred = self.connectDataVault()

        def handleDataVaultError(failure):
            if (failure.trap(AttributeError)):
                self.retryLabradConnectDialog = RetryConnectingDialog(
                    self, 'DataVault')
                self.retryLabradConnectDialog.show()

        deferred.addErrback(handleDataVaultError)

    # connect to the data vault
    @inlineCallbacks
    def connectLabRAD(self):
        from labrad.wrappers import connectAsync
        from labrad.types import Error
        try:  # if the connection failed and was retried, close the dialog
            self.retryLabradConnectDialog.close()
        except AttributeError:
            pass
        self.cxn = yield connectAsync(name='PyGrapherLive')
        self.attemptDataVaultConnect()

    @inlineCallbacks
    def connectDataVault(self):
        try:  # if the connection failed and was retried, close the dialog
            self.retryLabradConnectDialog.close()
        except AttributeError:
            pass
        self.server = yield self.cxn.data_vault
        yield self.setupListeners()
        context = yield self.cxn.context()  # create a new context
        self.introWindow = FirstWindow(self, context, self.reactor)
        self.introWindow.show()
        print 'Connection established: now listening dataset.'
        self.communicate.connectionReady.emit()

    # set up dataset listener
    @inlineCallbacks
    def setupListeners(self):
        yield self.server.signal__new_dataset_dir(88888)  #, context = context)
        yield self.server.addListener(listener=self.updateDataset,
                                      source=None,
                                      ID=88888)  #, context = context)
        yield self.server.signal__new_directory(77777)  #, context = context)
        yield self.server.addListener(listener=self.addDirItem,
                                      source=None,
                                      ID=77777)  #, context = context)
        yield self.server.signal__new_parameter_dataset(
            99999)  #, context = context)
        yield self.server.addListener(listener=self.updateParameter,
                                      source=None,
                                      ID=99999)  #, context = context)

    def addDirItem(self, x, y):
        #directory = tuple(eval(str(y)))
        self.introWindow.datavaultwidget.populateList()
#        for i in self.winDict.values():
#            i.datavaultwidget.populateList()
#        for i in self.winList:
#            i.datavaultwidget.populateList()

# new dataset signal

    def updateParameter(self, x, y):
        dataset = y[0]
        datasetName = y[1]
        #        print datasetName
        directory = y[2]
        itemLabel = (str(dataset) + ' - ' + str(datasetName))
        # process parameter
        if (y[3] == 'plotLive'):
            manuallyLoaded = False  # ensure that this dataset was not loaded manually
            self.newDataset(dataset, directory, manuallyLoaded, datasetName)
        elif (y[3] == 'Histogram'):
            self.createHistogram(dataset, directory, datasetName)
        elif (y[3] == 'Fit'):
            try:
                self.datasetDict[dataset, directory].fit()
            except:
                print 'Was plotLive set for this dataset?'

    def updateDataset(self, x, y):
        #        dataset = int(y[0][0:5]) # retrieve dataset number
        #        datasetName = str(y[0][8:len(y[0])])
        #        print datasetName
        directory = y[1]  # retrieve directory
        itemLabel = y[0]  # 'dataset - datasetName'
        self.addDatasetItem(itemLabel, directory)
#        print directory
#        print dataset
#        print x, y

    def addDatasetItem(self, itemLabel, directory):
        self.introWindow.datavaultwidget.addDatasetItem(itemLabel, directory)
#        for i in self.winDict.values():
#            i.datavaultwidget.addDatasetItem(itemLabel, directory)
#        for i in self.winList:
#            i.datavaultwidget.addDatasetItem(itemLabel, directory)

    @inlineCallbacks
    def createHistogram(self, dataset, directory, datasetName):

        context = yield self.cxn.context()
        yield self.server.cd(directory, context=context)
        yield self.server.open(dataset, context=context)

        threshold = yield self.server.get_parameter('Histogram',
                                                    context=context)
        Data = yield self.server.get(context=context)
        data = Data.asarray

        histWindow = HistWindow(self, data, threshold, datasetName)
        self.histList.append(histWindow)
        histWindow.show()

    # Creates a new Dataset object and checks if it has the 'plotLive' parameter
    @inlineCallbacks
    def newDataset(self, dataset, directory, manuallyLoaded, datasetName):
        context = yield self.cxn.context()  # create a new context
        datasetObject = Dataset(self, self.cxn, context, dataset, directory,
                                datasetName, self.reactor)
        self.datasetDict[dataset, directory] = datasetObject
        yield datasetObject.openDataset(context)
        #        yield datasetObject.setupParameterListener(context)
        #        yield datasetObject.checkForPlotParameter()
        datasetLabels = yield datasetObject.getYLabels()
        windowName = []
        if (len(self.winDict.values()) < MAXWINDOWS):
            # if the dataset was loaded manually, it does not require the 'Window' parameter
            if (manuallyLoaded == True):
                try:
                    histValue = yield self.server.get_parameter(
                        'Histogram', context=context)
                    self.createHistogram(dataset, directory, datasetName)
                    datasetObject.endTimer()
                    del datasetObject
                except:
                    self.prepareDataset(datasetObject, dataset, directory,
                                        datasetLabels, windowName)  #, context)
            else:
                #               hasPlotParameter = yield datasetObject.listenForPlotParameter()
                #               if (hasPlotParameter == True):
                windowParameter = yield datasetObject.getWindowParameter()
                # if windows are specified (via parameter), send that instead
                if (windowParameter != None):
                    self.prepareDataset(datasetObject, dataset, directory,
                                        datasetLabels,
                                        windowParameter)  #, context)
                else:
                    self.prepareDataset(datasetObject, dataset, directory,
                                        datasetLabels, windowName)  #, context)
#            else:
#                    # This data is not for plotting. Remove it.
#                    # There should be a cleaner way of doing this
#                    datasetObject.endTimer()
#                    del datasetObject
        else:
            print 'Too many windows open!'
            datasetObject.endTimer()
            del datasetObject

    # Prepare the dataset for plotting
    @inlineCallbacks
    def prepareDataset(self, datasetObject, dataset, directory, datasetLabels,
                       windowNames):  #, context):
        #if windows request overlay, update those. else, create a new window.
        overlayWindows = self.getOverlayingWindows()
        overlayWindowNames = []
        if overlayWindows:
            # if the dataset is already in the window
            overlayWindows = [
                x for x in overlayWindows
                if ((dataset, directory) not in x.qmc.dataDict.keys())
            ]
            for overlayWindow in overlayWindows:
                overlayWindow.qmc.initializeDataset(dataset, directory,
                                                    datasetLabels)
                #                overlayWindow.createDatasetCheckbox(dataset, directory)
                overlayWindowNames.append(overlayWindow.windowName)
            if overlayWindows:
                self.dwDict[datasetObject] = overlayWindows
        elif (len(windowNames) == 0):
            windowName = 'Window ' + str(self.windowCounter)
            self.windowCounter = self.windowCounter + 1
            context = yield self.cxn.context()  # create a new context
            win = self.newGraph(context, windowName)
            yield deferToThread(time.sleep, .01)
            self.dwDict[datasetObject] = [win]
            win.qmc.initializeDataset(dataset, directory, datasetLabels)
#            win.createDatasetCheckbox(dataset, directory)

# process windowNames that came from parameters (the following won't happen without window parameters specified)
        for windowName in windowNames:
            if windowName in overlayWindowNames:
                pass
            # if the window is open and it isn't asking for overlay
            elif windowName in self.winDict.keys():
                try:
                    self.dwDict[datasetObject].append(self.winDict[windowName])
                except KeyError:
                    self.dwDict[datasetObject] = [self.winDict[windowName]]
                self.winDict[windowName].qmc.initializeDataset(
                    dataset, directory, datasetLabels)
#                self.winDict[windowName].createDatasetCheckbox(dataset, directory)
            else:
                context = yield self.cxn.context()  # create a new context
                win = self.newGraph(context, windowName)
                yield deferToThread(time.sleep, .01)
                try:
                    self.dwDict[datasetObject].append(win)
                except KeyError:
                    self.dwDict[datasetObject] = [win]
                win.qmc.initializeDataset(dataset, directory, datasetLabels)


#                win.createDatasetCheckbox(dataset, directory)

# create a new graph window
#    def newGraph(self, context, windowName):

    def newGraph(self, context, windowName):
        win = GrapherWindow(self, context, windowName)
        self.winDict[windowName] = win
        #        self.winList.append(win)
        win.show()
        return win

    def startTimer(self):
        lc = LoopingCall(self.timerEvent)
        lc.start(GraphRefreshTime)

    # Main timer, cycles through dwDict. For each dataset, determines...
    # ... which windows to draw the dataset on. Then draws the plot.
    @inlineCallbacks
    def timerEvent(self):
        #        print 'in connections: {0}'.format( len(self.dwDict.keys()) )
        for datasetObject in self.dwDict.keys():
            windowsToDrawOn = self.dwDict[datasetObject]
            if (datasetObject.data != None):
                data = datasetObject.data
                yield datasetObject.emptyDataBuffer()
                for i in windowsToDrawOn:
                    #                    print 'still happening connections'
                    i.qmc.setPlotData(datasetObject.dataset,
                                      datasetObject.directory, data)

    # Cycles through the values in each key for checked Overlay boxes, returns the windows...
    # ...with the overlay button checked
    def getOverlayingWindows(self):
        self.overlaidWindows = []
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j.cb2.isChecked():
                    # skip duplicates
                    if j in self.overlaidWindows:
                        pass
                    else:
                        self.overlaidWindows.append(j)
        return self.overlaidWindows

    @inlineCallbacks
    def getParameters(self, dataset, directory):
        parametersValues = []
        parameters = yield self.cxn.data_vault.parameters(
            context=self.datasetDict[dataset, directory].context)
        values = []
        for parameter in parameters:
            parameterValue = yield self.cxn.data_vault.get_parameter(
                parameter,
                context=self.datasetDict[dataset, directory].context)
            values.append(parameterValue)
        for parameter, value in zip(parameters, values):
            parametersValues.append((parameter, value))

        returnValue(parametersValues)

    def changeWindowName(self, oldWindowName, newWindowName):
        self.winDict[newWindowName] = self.winDict[oldWindowName]
        del self.winDict[oldWindowName]

    # Datasets no longer need to be drawn on closed windows
    @inlineCallbacks
    def removeWindowFromDictionary(self, win):
        #        print sys.getrefcount(win)
        #objgraph.show_most_common_types(limit=20)
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j == win:
                    # if the last window is being removed, delete the dataset object
                    # from the dictionary
                    if (len(values) == 1):
                        #self.dwDict[i].remove(j)
                        i.endTimer()
                        print 'disconnecting data signal'
                        yield i.disconnectDataSignal()
                        del self.dwDict[i]
                    else:
                        self.dwDict[i].remove(j)

    # Datavault widgets no longer need to be updated
    def removeWindowFromWinList(self, win):
        for i in self.winList:
            if i == win:
                self.winList.remove(i)

    # Datavault widgets no longer need to be updated
    def removeWindowFromWinDict(self, windowName):
        del self.winDict[windowName]

    @inlineCallbacks
    def cleanUp(self):
        print 'clean!'
        yield deferToThread(time.sleep, 5)
        gc.collect()
Пример #4
0
class CONNECTIONS(QtGui.QGraphicsObject):
    '''
    The CONNECTIONS serves as a mediator between the Dataset class and the GrapherWindow
    class. 
    
    A grapher works by keeping track of datasets and determining which windows
    to plot them on. The main dictionary, dwDict, relates Dataset objects with GrapherWindow
    objects. Each time a new dataset is created, CONNECTIONS creates a unique 
    Dataset object. It then determines which GrapherWindow objects the dataset should
    be drawn on. i.e.:
    
        Without dataset overlaying (dwDict):
        
            [Dataset1] = [GrapherWindow1]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3]
                       .
                       .
                       .
    
        With dataset overlaying (dwDict):

            [Dataset1] = [GrapherWindow1, GrapherWindow3]
            [Dataset2] = [GrapherWindow2]
            [Dataset3] = [GrapherWindow3, GrapherWindow2]
                       .
                       .
                       .
    
    GrapherWindow objects are added and removed from the dictionary depending on factors
    such as overlaying datasets or closing windows.
    
    Note: the grapher will only plot datasets that possess the 'plotLive' parameter. This 
    parameter is checked for in the Dataset class. This prevents unwanted new datasets from being plotted
    Old datasets that are manually loaded from graph are exempt from this requirement.
    
    There is a main timer event that retrieves data from the Dataset buffer, sends it to
    the GrapherWindow, and calls on GrapherWindow to draw the plot. This ensures that all datasets
    are plotted constantly in order to maintain a live update.     

    '''

    def __init__(self, reactor, parent=None):
        super(CONNECTIONS, self).__init__()
        self.reactor = reactor
        self.dwDict = {} # dictionary relating Dataset and ApplicationWindow
        self.datasetDict = {} # dictionary relating a Dataset object with the dataset and directory 
        self.winList = []
        self.attemptLabRadConnect()               
        self.startTimer()

    def attemptLabRadConnect(self):
        from labrad.errors import LoginFailedError
        deferred = self.connect()
        def handleLabRadError(failure):
            if (failure.trap(ConnectionRefusedError)):
                self.retryLabradConnectDialog = RetryConnectingDialog(self)
                self.retryLabradConnectDialog.show()
        deferred.addErrback(handleLabRadError)

#    def attemptDataVaultConnect(self):
    
    # connect to the data vault    
    @inlineCallbacks    
    def connect(self):
        from labrad.wrappers import connectAsync
        from labrad.types import Error
        try: # if the connection failed and was retried, close the dialog
            self.retryLabradConnectDialog.close()
        except AttributeError:
            pass
        self.cxn = yield connectAsync()
        try:
            self.server = yield self.cxn.data_vault
            yield self.setupListeners()
            context = yield self.cxn.context() # create a new context
            self.introWindow = FirstWindow(self, context)
            self.introWindow.show()
            print 'Connection established: now listening dataset.'
        except AttributeError:
            print 'no data vault'
    # set up dataset listener    
    @inlineCallbacks
    def setupListeners(self):               
        yield self.server.signal__new_dataset_dir(99999)#, context = context)
        yield self.server.addListener(listener = self.updateDataset, source = None, ID = 99999)#, context = context)    
        yield self.server.signal__new_directory(77777)#, context = context)
        yield self.server.addListener(listener = self.addDirItem, source = None, ID = 77777)#, context = context)

    def addDirItem(self,x,y):
        #directory = tuple(eval(str(y))) 
        self.introWindow.datavaultwidget.populateList()
        for i in self.winList:
            i.datavaultwidget.populateList()
           
    # new dataset signal
    def updateDataset(self,x,y):
        dataset = int(y[0][0:5]) # retrieve dataset number
        directory = y[1] # retrieve directory
        itemLabel = y[0]
        self.addDatasetItem(itemLabel, directory)
        print directory
        print dataset
        manuallyLoaded = False # ensure that this dataset was not loaded manually
        self.newDataset(dataset, directory, manuallyLoaded)
 
    def addDatasetItem(self, itemLabel, directory):
        self.introWindow.datavaultwidget.addDatasetItem(itemLabel, directory)
        for i in self.winList:
            i.datavaultwidget.addDatasetItem(itemLabel, directory)
 
    # Creates a new Dataset object and checks if it has the 'plotLive' parameter
    @inlineCallbacks
    def newDataset(self, dataset, directory, manuallyLoaded):
        context = yield self.cxn.context() # create a new context
        datasetObject = Dataset(self.cxn, context, dataset, directory, self.reactor)
        self.datasetDict[dataset, directory] = datasetObject
        yield datasetObject.openDataset(context)
        yield datasetObject.setupParameterListener(context)
        yield datasetObject.checkForPlotParameter()
        datasetLabels = yield datasetObject.getYLabels()
        # if the dataset was loaded manually, it does not require the 'plotLive' parameter 
        if (manuallyLoaded == True):
            self.prepareDataset(datasetObject, dataset, directory, datasetLabels)#, context)
        else:        
            hasPlotParameter = yield datasetObject.listenForPlotParameter()
            if (hasPlotParameter == True):
                self.prepareDataset(datasetObject, dataset, directory, datasetLabels)#, context)
            else:
                # This data is not for plotting. Remove it.
                # There should be a cleaner way of doing this
                datasetObject.endTimer()
                del datasetObject

    # Prepare the dataset for plotting
    @inlineCallbacks
    def prepareDataset(self, datasetObject, dataset, directory, datasetLabels):#, context):
        #if windows request overlay, update those. else, create a new window.
        overlayWindows = self.getOverlayingWindows()
        if overlayWindows:
            self.dwDict[datasetObject] = overlayWindows
            for window in overlayWindows:
                window.qmc.initializeDataset(dataset, directory, datasetLabels)
                window.createDatasetCheckbox(dataset, directory) 
        else:
            context = yield self.cxn.context() # create a new context
            win = self.newGraph(context)
            yield deferToThread(time.sleep, .01)
            self.dwDict[datasetObject] = [win]
            win.qmc.initializeDataset(dataset, directory, datasetLabels)
            win.createDatasetCheckbox(dataset, directory) 

    # create a new graph window
    def newGraph(self, context):
        win = GrapherWindow(self, context)
        self.winList.append(win)
        win.show()
        return win
            
    def startTimer(self): 
        lc = LoopingCall(self.timerEvent)
        lc.start(GraphRefreshTime)
     
    # Main timer, cycles through dwDict. For each dataset, determines...
    # ... which windows to draw the dataset on. Then draws the plot.   
    @inlineCallbacks
    def timerEvent(self):
        print 'in connections: {0}'.format( len(self.dwDict.keys()) )
        for datasetObject in self.dwDict.keys():
            windowsToDrawOn = self.dwDict[datasetObject]
            if (datasetObject.data != None):
                data = datasetObject.data
                yield datasetObject.emptyDataBuffer()
                for i in windowsToDrawOn:
                    print 'still happening connections'
                    i.qmc.setPlotData(datasetObject.dataset, datasetObject.directory, data)
    
    # Cycles through the values in each key for checked Overlay boxes, returns the windows...
    # ...with the overlay button checked
    def getOverlayingWindows(self):
        self.overlaidWindows = []
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j.cb2.isChecked():
                    # skip duplicates
                    if j in self.overlaidWindows:
                        pass
                    else:
                        self.overlaidWindows.append(j)
        return self.overlaidWindows
    
    def getParameters(self, dataset, directory):
        parameters = self.datasetDict[dataset, directory].parameters
        return parameters
    
    # Datasets no longer need to be drawn on closed windows
    @inlineCallbacks
    def removeWindowFromDictionary(self, win):
        for i in self.dwDict.keys():
            values = self.dwDict[i]
            for j in values:
                if j == win:
                    # if the last window is being removed, delete the dataset object
                    # from the dictionary
                    if (len(values) == 1):
                        #self.dwDict[i].remove(j)
                        i.endTimer()
                        print 'disconnecting data signal'
                        yield i.disconnectDataSignal()
                        del self.dwDict[i]
                    else:
                        self.dwDict[i].remove(j)

        
    # Datavault widgets no longer need to be updated
    def removeWindowFromWinList(self, win):
        for i in self.winList:
            if i == win:
                self.winList.remove(i)