Пример #1
0
    def event_cut(self):
        # Get cutting parameters
        try:
            baseline = float(self.eventBaseline.text()) / self.dt
            duration = float(self.eventDuration.text()) / self.dt
        except NameError:
            aux.error_box('Invalid cutting value')

        # Cut out
        events, allAttrs = [], []
        for onset in self.xOnsets:
            eStart = onset - baseline
            eEnd = onset + duration
            eData = self.trace[eStart:eEnd]
            events.append(eData)
            attrs = {}
            attrs['dt'] = self.dt
            attrs['onset'] = onset
            allAttrs.append(attrs)

        # Store event waveforms in h5 data tree
        results = []
        #attrs = {}
        #attrs['dt'] = self.dt
        for e in np.arange(0, len(events)):
            #attrs['onset'] = self.xOnsets[e]
            results.append(['event' + str(e), events[e], allAttrs[e]])
        aux.save_results(self.browser, 'Events', results)
Пример #2
0
    def event_cut(self):       
        # Get cutting parameters
        try:        
            baseline = float(self.eventBaseline.text())/self.dt
            duration = float(self.eventDuration.text())/self.dt 
        except NameError:
            aux.error_box('Invalid cutting value')

        # Cut out
        events, allAttrs = [], []
        for onset in self.xOnsets:
            eStart = onset-baseline
            eEnd = onset+duration
            eData = self.trace[eStart:eEnd]
            events.append(eData)
            attrs = {}
            attrs['dt'] = self.dt
            attrs['onset'] = onset
            allAttrs.append(attrs)

        # Store event waveforms in h5 data tree
        results = []
        #attrs = {}
        #attrs['dt'] = self.dt 
        for e in np.arange(0, len(events)):
            #attrs['onset'] = self.xOnsets[e]
            results.append(['event'+str(e), events[e], allAttrs[e]])  
        aux.save_results(self.browser, 'Events', results)
Пример #3
0
    def event_cut(self):
        # Get trace and event onsets using stored dataIndex
        itrace = self.eventItemsIndex[0]
        trace = self.browser.ui.workingDataTree.dataItems[itrace]
        ionsets = self.eventItemsIndex[1]
        onsets = self.browser.ui.workingDataTree.dataItems[ionsets]   
        dt = float(trace.attrs['dt'])

        # Get cutting parameters
        baseline = float(self.eventBaseline.text())/dt
        duration = float(self.eventDuration.text())/dt 

        # Cut out
        events = []
        for onset in onsets.data:
            eStart = onset-baseline
            eEnd = onset+duration
            eData = trace.data[eStart:eEnd]
            events.append(eData)

        # Store event waveforms in h5 data tree
        results = []
        attrs = {}
        attrs['dt'] = dt 
        for e in np.arange(0, len(events)):
            results.append(['event'+str(e), events[e], attrs])  
        aux.save_results(self.browser, 'Events', results)
Пример #4
0
    def func(self, browser):
        """ Measure selected properties or statistics in the region defined
        by the data cursors.
    
        Options:
        1) create new entries in Working Data tree with the results
        """
    
        ############################################
        # ANALYSIS FUNCTION
       
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
        data = aux.get_data(browser)  
        c1, c2 = aux.get_cursors(plotWidget) 
        dataIndex = plotWidget.plotDataIndex     
        saveData = False

        # Get dt list
        dtList = aux.get_attr(plotWidget.plotDataItems, 'dt')

        # Go through data and check selected values to measure
        # Can probably do this in a more efficient way
        results = []
        for option in self.toolOptions:
            if option.isChecked():
                if option.text()=='Store result':
                    saveData = True        

                if option.text()=='Minimum':
                    dataMin = []
                    for t in range(len(data)):
                        dt = dtList[t]
                        y = np.min(data[t][c1/dt:c2/dt])
                        x = np.argmin(data[t][c1/dt:c2/dt])
                        dataMin.append(y)
                        aux.plot_point(plotWidget, c1/dt, x, y, dt)
                    results.append(['Minimum', dataMin])        

                if option.text()=='Maximum':
                    dataMax = []
                    for t in range(len(data)):
                        dt = dtList[t]
                        y = np.max(data[t][c1/dt:c2/dt])
                        x = np.argmax(data[t][c1/dt:c2/dt])
                        dataMax.append(y)
                        aux.plot_point(plotWidget, c1/dt, x, y, dt)
                    results.append(['Maximum', dataMax])    

                if option.text()=='Mean':
                    dataMean = []
                    for t in range(len(data)):
                        dt = dtList[t]
                        y = np.mean(data[t][c1/dt:c2/dt])
                        dataMean.append(y)
                        plotWidget.plot([c1,c2], [y,y], pen=pg.mkPen('#CF1C04', width=1))
                    results.append(['Mean', dataMean])

        # Store results
        if saveData: aux.save_results(browser, 'Measurements', results)             
Пример #5
0
    def func(self, browser):
        """ Filter traces
    
        Options:
        1) Filter type (currently Bessel only)
        2) Filter parameters
        
        Note: filter frequencies are in Hz, make sure dt is in seconds
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        btype = str(self.comboPass.currentText())
        if 'Low' in btype:
            btype = 'low'
        elif 'High' in btype:
            btype = 'high'
        try:    
            cutoff = float(self.filterCutoff.text())
            order = float(self.filterOrder.text())
        except ValueError:
            aux.error_box('Invalid Cut off or Order value')
            return
        bidir = self.filterDirection.isChecked()
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Filter data
        results, itemsToPlot = [], [] 
        for item in plotWidget.plotDataItems:  
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['filter_type'] = btype
            attrs['filter_cutoff'] = cutoff
            attrs['filter_order'] = order
        
            # Filter
            traceFilter = acq4filter.besselFilter(item.data, cutoff, order, float(item.attrs['dt'])/1000, btype, bidir)
            results.append([item.text(0), traceFilter, attrs])
        
            # Store filtered traces            
            filterItem = aux.make_h5item('filter', traceFilter, item.attrs)
            itemsToPlot.append(filterItem)

        # Plot results
        pgplot.plot_multipleData(browser, plotWidget, itemsToPlot, clear=False, color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText+'_filter', results)     
Пример #6
0
    def func(self, browser):
        """ Smooth traces
    
        Options:
        1) Window type
        2) Window length
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get options
        window = str(self.comboBox.currentText())
        try:
            window_len = float(self.smoothLength.text())
        except ValueError:
            aux.error_box('Invalid Window Length')
            return

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Smooth data
        results, itemsToPlot = [], []
        for item in plotWidget.plotDataItems:
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['smooth_window_type'] = window
            attrs['smooth_window_length'] = window_len

            # Smooth
            traceSmooth = smooth.smooth(item.data,
                                        window_len=window_len,
                                        window=window)
            results.append([item.text(0), traceSmooth, attrs])

            # Store smoothed item
            smoothItem = aux.make_h5item('smooth', traceSmooth, item.attrs)
            itemsToPlot.append(smoothItem)

        # Plot results
        pgplot.plot_multipleData(browser,
                                 plotWidget,
                                 itemsToPlot,
                                 clear=False,
                                 color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText + '_smooth', results)
Пример #7
0
    def func(self, browser):
        """ Remove a specific frequency from the data
    
        Options:
        1) Frequency
        2) Number of harmonics
        3) Number of FFT data samples to blank centered on the Frequency  
        4) Scale factor for how much the frequency is dampened (0<x<1)
        
        Note: frequencies are in Hz, make sure dt is in seconds
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get options
        frequency = float(self.freqRemoveFrequency.text())
        harmonics = int(self.freqRemoveHarmonics.text())
        samples = int(self.freqRemoveSamples.text())
        mag = float(self.freqRemoveMag.text())

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Remove frequency
        results = []
        for item in plotWidget.plotDataItems:
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['frequency_removed'] = frequency

            # Remove
            traceFilter = acq4filter.removePeriodic(
                item.data, frequency,
                float(item.attrs['dt']) / 1000, harmonics, samples, mag)
            results.append([item.text(0), traceFilter, attrs])

            # Store and plot filtered trace
            filterItem = aux.make_h5item('filter', traceFilter, item.attrs)
            pgplot.browse_singleData(browser,
                                     plotWidget,
                                     filterItem,
                                     clear=False,
                                     color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText + '_filter', results)
Пример #8
0
    def func(self, browser):
        """ Average trials for protocols with more than one sweep
        (e.g.: current or voltage steps)
    
        Options:
        1) Number of trials contained in the selected traces
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        try:
            numberOfTrials = int(self.trialsNumber.text())
        except ValueError:
            aux.error_box('Please input a valid number of trials')
            return
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Get data and attributes
        data = aux.get_data(self.browser)
        item = plotWidget.plotDataItems[0]
        
        # Reshape data and average
        try:
            data.shape = (numberOfTrials, data.shape[0]/numberOfTrials, data.shape[1])
            avg = data.mean(axis=0)
        
            # Make h5 items
            results, itemsToPlot = [], []        
            for sweep in avg:  
                #sweepItem = aux.make_h5item('sweep', sweep, item.attrs)
                results.append(['sweep', sweep, item.attrs])
        
                # Store average sweep            
                sweepItem = aux.make_h5item('sweep', sweep, item.attrs)
                itemsToPlot.append(sweepItem)

            # Plot results
            pgplot.plot_multipleData(browser, plotWidget, itemsToPlot, clear=False, color='#F2EF44')

            # Store results        
            aux.save_results(browser, parentText+'_trialsAvg', results)     
        
        except ValueError: 
            aux.error_box('The number of sweeps and trials do not match', sys.exc_info())          
Пример #9
0
    def func(self, browser):
        """ Downsample data by taking one point every N points
    
        Options:
        1) Number of points
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get options
        try:
            nPoints = int(self.points.text())
        except ValueError:
            aux.error_box('Invalid number of points')
            return

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Smooth data
        results, itemsToPlot = [], []
        for item in plotWidget.plotDataItems:
            # Copy attributes and add some new ones
            attrs = dict(item.attrs)
            attrs['dt'] = attrs['dt'] * nPoints

            # Downsample
            traceDsampled = item.data[0::nPoints]
            results.append([item.text(0), traceDsampled, attrs])

            # Store smoothed item
            dSampledItem = aux.make_h5item('smooth', traceDsampled, attrs)
            itemsToPlot.append(dSampledItem)

        # Plot results
        pgplot.plot_multipleData(browser,
                                 plotWidget,
                                 itemsToPlot,
                                 clear=False,
                                 color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText + '_dSample', results)
Пример #10
0
    def func(self, browser):
        """ Smooth traces
    
        Options:
        1) Window type
        2) Window length
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        window = str(self.comboBox.currentText())
        try:
            window_len = float(self.smoothLength.text())
        except ValueError:
            aux.error_box('Invalid Window Length')
            return
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Smooth data
        results, itemsToPlot = [], [] 
        for item in plotWidget.plotDataItems:  
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['smooth_window_type'] = window
            attrs['smooth_window_length'] = window_len
        
            # Smooth
            traceSmooth = smooth.smooth(item.data, window_len=window_len, window=window)
            results.append([item.text(0), traceSmooth, attrs])
        
            # Store smoothed item
            smoothItem = aux.make_h5item('smooth', traceSmooth, item.attrs)
            itemsToPlot.append(smoothItem)

        # Plot results
        pgplot.plot_multipleData(browser, plotWidget, itemsToPlot, clear=False, color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText+'_smooth', results)     
Пример #11
0
    def func(self, browser):
        """ Remove a specific frequency from the data
    
        Options:
        1) Frequency
        2) Number of harmonics
        3) Number of FFT data samples to blank centered on the Frequency  
        4) Scale factor for how much the frequency is dampened (0<x<1)
        
        Note: frequencies are in Hz, make sure dt is in seconds
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        frequency = float(self.freqRemoveFrequency.text())
        harmonics = int(self.freqRemoveHarmonics.text())
        samples = int(self.freqRemoveSamples.text())
        mag = float(self.freqRemoveMag.text())
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Remove frequency
        results = [] 
        for item in plotWidget.plotDataItems:  
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['frequency_removed'] = frequency
        
            # Remove
            traceFilter = acq4filter.removePeriodic(item.data, frequency,
                         float(item.attrs['dt'])/1000, harmonics, samples, mag)
            results.append([item.text(0), traceFilter, attrs])
        
            # Store and plot filtered trace            
            filterItem = aux.make_h5item('filter', traceFilter, item.attrs)
            pgplot.browse_singleData(browser, plotWidget, filterItem, clear=False, color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText+'_filter', results)     
Пример #12
0
    def func(self, browser):
        """ Downsample data by taking one point every N points
    
        Options:
        1) Number of points
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        try:
            nPoints = int(self.points.text())
        except ValueError:
            aux.error_box('Invalid number of points')
            return
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Smooth data
        results, itemsToPlot = [], [] 
        for item in plotWidget.plotDataItems:  
            # Copy attributes and add some new ones
            attrs = dict(item.attrs)
            attrs['dt'] = attrs['dt']*nPoints
        
            # Downsample
            traceDsampled = item.data[0::nPoints]
            results.append([item.text(0), traceDsampled, attrs])
        
            # Store smoothed item
            dSampledItem = aux.make_h5item('smooth', traceDsampled, attrs)
            itemsToPlot.append(dSampledItem)

        # Plot results
        pgplot.plot_multipleData(browser, plotWidget, itemsToPlot, clear=False, color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText+'_dSample', results)     
Пример #13
0
    def func(self, browser):
        """ Smooth traces
    
        Options:
        1) Window type
        2) Window length
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get options
        window = str(self.comboBox.currentText())
        window_len = float(self.smoothLength.text())
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Smooth data
        results = [] 
        for item in plotWidget.plotDataItems:  
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['smooth_window_type'] = window
            attrs['smooth_window_length'] = window_len
        
            # Smooth
            traceSmooth = smooth.smooth(item.data, window_len=window_len, window=window)
            results.append([item.text(0), traceSmooth, attrs])
        
            # Plot smoothed trace
            #x = np.arange(0, len(traceSmooth)*item.attrs['dt'], item.attrs['dt'])
            #plotWidget.plot(x, traceSmooth, pen=pg.mkPen('#F2EF44', width=1))
            
            smoothItem = aux.make_h5item('smooth', traceSmooth, item.attrs)
            pgplot.browse_singleData(browser, plotWidget, smoothItem, clear=False, color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText+'_smooth', results)     
Пример #14
0
    def func(self, browser):
        """ Calculate average trace from currently plotted traces.

        Options:
        1) create new entry in Working Data tree with the result
        2) plot average with orginal traces
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget   

        # Clear plot and get data
        plotWidget.clear()    
        data = aux.get_data(browser)
    
        # Get dt and 
        dt = aux.get_attr(plotWidget.plotDataItems, 'dt')[0]

        # Calculate average
        avgData = np.mean(data,0)

        # Check selected options
        for option in self.toolOptions:
            if option.isChecked():
                if option.text()=='Store result':
                    results = []                                    
                    # Get attributes from plotted items
                    item = plotWidget.plotDataItems[0]
                    attrs = item.attrs           
 
                    # Store data     
                    results.append(['avg_trace', avgData, attrs])
                    aux.save_results(browser, item.parent().text(0)+'_average', results) 
             
                if option.text()=='Show traces':
                    pgplot.replot(browser, plotWidget)

        # Plot average
        item = aux.make_h5item('avg', avgData, plotWidget.plotDataItems[0].attrs)
        pgplot.browse_singleData(browser, plotWidget, item, clear=False, color='r')
        if browser.ui.actionShowCursors.isChecked(): pgplot.replot_cursors(browser, plotWidget)      
Пример #15
0
    def event_cut(self, profile=False):

        # Read options 
        baseline = float(self.eventBaseline.text())
        duration = float(self.eventDuration.text())
    
        # Get plotted tracking data
        trackData = self.plotWidget.plotDataItems[0].data

        # Get selected trigger data
        item = self.browser.ui.workingDataTree.currentItem()
        triggers = item.data
        
        # Deal with dt
        dt = self.plotWidget.plotDataItems[0].attrs['dt']
        item.attrs['dt'] = dt

        # Extract events        
        events, stimProfiles = [], []
        for t in self.tevents:
            event = trackData[t-int(baseline/dt):t+int(duration/dt)]
            events.append(event)
            if profile:
                eventProfile = self.triggerProfileData[t-int(baseline/dt):t+int(duration/dt)]
                stimProfiles.append(eventProfile)                

        # Store data
        results = []
        attrs = {}
        attrs['dt'] = dt 
        attrs['t0'] = baseline  # in sampling points
        for e in np.arange(0, len(events)):
            attrs['trigger_time'] = self.tevents[e]  # in sampling points 
            results.append(['event'+str(e), events[e], attrs])  
        aux.save_results(self.browser, 'Events', results)
                
        if profile:
            results = []
            for e in np.arange(0, len(stimProfiles)):
                attrs['trigger_time'] = self.tevents[e]  # in sampling points 
                results.append(['stim'+str(e), stimProfiles[e], attrs])  
            aux.save_results(self.browser, 'Stimulation Profiles', results)     
    def func(self, browser):
        """ Analyse tracking data for user defined zones in
        the arena. Currently the two zones are defined by
        a divider on the X or Y coordinates.
        
        Properties measured:
        1 - time spent in each zone normalized to total time
        2 - number of zone transitions 

        Options:
        1) Position of the divider between the two zones
        """

        ############################################
        # ANALYSIS FUNCTION

        # Read options
        zoneDivider = float(self.plotWidget.zoneDividerCursorPos)

        # Get data and check cursors
        traces = self.plotWidget.plotDataItems
        dt = traces[0].attrs['dt']
        data, c1 = aux.get_dataRange(self.plotWidget, traces[0])

        # Get time in each zone
        zoneTime = []
        totalTime = float(len(data))
        zone1 = np.sum(data < zoneDivider)
        zone2 = totalTime - zone1
        zoneTime.append(zone1 / totalTime)
        zoneTime.append(zone2 / totalTime)

        # Get number of zone transitions
        transitions = np.sum(np.diff(data < zoneDivider))

        # Store data
        results = []
        results.append(['Time', zoneTime])
        results.append(['Transitions', [transitions]])
        aux.save_results(self.browser, 'Zone_analysis', results)
Пример #17
0
    def func(self, browser):
        """ Temporary event detection function using amplitude
        threshold only. Noise safety is for when coming down from
        peak, go down an extra amount from threshold before starting
        to search for the next event.
        """
        ############################################
        # ANALYSIS FUNCTION
 
        # Read detection options 
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return              

        try:
            noiseSafety = float(self.eventNoiseSafety.text())
            smoothFactor = float(self.eventSmooth.text())
            direction = str(self.eventDirection.currentText())
            minDuration = float(self.eventMinDuration.text())
            detectionTrace = str(self.detectionTrace.currentText())
            minInterval = float(self.eventMinInterval.text())
        except NameError:
            aux.error_box('Invalid detection value')
        bslWindow = 1.0
        slowestRise = 0.5
        #minEventInterval = 5000.0

        # Ensure that noise safety has the same sign as the threshold
        noiseSafety = np.sign(threshold) * abs(noiseSafety)

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget

        # Get dt list and attrs for use in concatenated data
        dtList = aux.get_attr(self.browser.ui.dataPlotsWidget.plotDataItems, 'dt')
        dt = dtList[0]
        self.dt = dt
        item = self.browser.ui.dataPlotsWidget.plotDataItems[0]
        attrs = item.attrs

        # Get data currently plotted and concatenate in a single sweep
        data = []
        for item in plotWidget.plotDataItems:
            trace, c1 = aux.get_dataRange(plotWidget, item)
            data.append(trace)
        data = np.array(data).ravel()

        # Get derivative trace and filter
        dtrace = None
        if detectionTrace=='derivative':
            print threshold
            dtrace = np.diff(data)
            dtrace = acq4filter.besselFilter(dtrace, 2000, 1, dt/1000, 'low', True)

        # Smooth
        self.trace = data
        if smoothFactor > 1:
            data = smooth.smooth(data, window_len=smoothFactor, window='hanning')

        # Comparison functions  
        if direction=='negative':
            comp = lambda a, b: a < b
        elif direction=='positive':
            comp = lambda a, b: a > b
            
        # Correct times for dt    
        minEventInterval = minInterval/dt
        minDuration = minDuration/dt
        bslWindow = bslWindow/dt
        slowestRise = slowestRise/dt
            
        # Run detection
        eventCounter,i = 0,0 #+bslWindow/dt+slowestRise/dt
        iLastDetection = 0
        self.xOnsets, self.yOnsets = [], []
        bsl = 0
        if dtrace is not  None:
            detectionData = dtrace
        else:
            detectionData = data
        while i<len(detectionData):
            # Sliding baseline
            #bsl = np.mean(data[i-bslWindow-slowestRise:i])   
            if comp(detectionData[i]-bsl,threshold):
              print i, i-iLastDetection
              if i-iLastDetection>minEventInterval:  # Min inter-event interval
                self.xOnsets.append(i)
                self.yOnsets.append(data[i])
                eventCounter+=1
                iLastDetection = i
                while i<len(detectionData) and comp(detectionData[i]-bsl,(threshold-noiseSafety)):
                    i+=1 # skip values if index in bounds AND until the value is below/above threshold again
                if i-iLastDetection < minDuration: # Event is too brief
                    self.xOnsets.pop()
                    self.yOnsets.pop()
                    eventCounter-=1
              else:
                i+=1   # for min event interval   
            else:
                i+=1

        frequency = eventCounter/(len(data)*dt)*1000   # in Hz
        print eventCounter, 'events detected at', frequency, 'Hz'

        # Store event onsets and peaks in h5 data tree
        results = []
        results.append(['trace', np.array(self.trace), attrs])
        results.append(['xOnsets', np.array(self.xOnsets)])
        results.append(['yOnsets', np.array(self.yOnsets)])
        results.append(['number', np.array([eventCounter])])
        results.append(['frequency', np.array([frequency])])
        aux.save_results(browser, 'Event_Detection', results)    

        # Plot results
        self.show_events(data, np.array(self.xOnsets), np.array(self.yOnsets), dt)

        # Turn cursors off (the plot has been cleared so there are no cursors displayed)    
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False          
Пример #18
0
    def func(self, browser):
        """ Temporary event detection function using amplitude
        threshold only. Noise safety is for when coming down from
        peak, go down an extra amount from threshold before starting
        to search for the next event.
        """
        ############################################
        # ANALYSIS FUNCTION
 
        # Read detection options 
        threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        noiseSafety = float(self.eventNoiseSafety.text())
        smoothFactor = float(self.eventSmooth.text())
        direction = str(self.eventDirection.currentText())
        c1, c2 = aux.get_cursors(self.browser.ui.dataPlotsWidget) 

        # Ensure that noise safety has the same sign as the threshold
        noiseSafety = np.sign(threshold) * abs(noiseSafety)

        # Get dt list and attrs for use in concatenated data
        dtList = aux.get_attr(self.browser.ui.dataPlotsWidget.plotDataItems, 'dt')
        dt = dtList[0]
        item = self.browser.ui.dataPlotsWidget.plotDataItems[0]
        attrs = item.attrs

        # Get data currently plotted within the cursors and concatenate in a single sweep
        data = aux.get_data(self.browser)
        if browser.ui.dataPlotsWidget.cursor1Pos: data = data[:,c1/dt:c2/dt]
        data = data.ravel()

        # Smooth
        original_data = data
        if smoothFactor > 1:
            data = smooth.smooth(data, window_len=smoothFactor, window='hanning')

        # Run detection  
        if direction=='negative':
            comp = lambda a, b: a < b
        elif direction=='positive':
            comp = lambda a, b: a > b
        eventCounter,i = 0,0
        xOnsets, yOnsets = [], []
        while i<len(data):
            if comp(data[i],threshold):
                xOnsets.append(i)
                yOnsets.append(data[i])
                eventCounter +=1
                while i<len(data) and comp(data[i],(threshold-noiseSafety)):
                    i+=1 # skip values if index in bounds AND until the value is below/above threshold again
            else:
                i+=1

        frequency = eventCounter/(len(data)*dt)*1000   # in Hz
        print eventCounter, 'events detected at', frequency, 'Hz'

        # Store event onsets and peaks in h5 data tree
        results = []
        results.append(['trace', np.array(original_data), attrs])
        results.append(['onsets', np.array(xOnsets)])
        results.append(['peaks', np.array(yOnsets)])
        results.append(['number', np.array([eventCounter])])
        results.append(['frequency', np.array([frequency])])
        listIndexes = aux.save_results(browser, 'Event_Detection', results)    

        # Store list indexes temporarily in stack widget list for further event analysis
        self.eventItemsIndex = listIndexes

        # Plot results
        self.show_events(data, np.array(xOnsets), np.array(yOnsets), dt)
Пример #19
0
    def func(self, browser):
        """ Temporary event detection function using amplitude
        threshold only. Noise safety is for when coming down from
        peak, go down an extra amount from threshold before starting
        to search for the next event.
        """
        ############################################
        # ANALYSIS FUNCTION

        # Read detection options
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return

        try:
            noiseSafety = float(self.eventNoiseSafety.text())
            smoothFactor = float(self.eventSmooth.text())
            direction = str(self.eventDirection.currentText())
            minDuration = float(self.eventMinDuration.text())
            detectionTrace = str(self.detectionTrace.currentText())
            minInterval = float(self.eventMinInterval.text())
        except NameError:
            aux.error_box('Invalid detection value')
        bslWindow = 1.0
        slowestRise = 0.5
        #minEventInterval = 5000.0

        # Ensure that noise safety has the same sign as the threshold
        noiseSafety = np.sign(threshold) * abs(noiseSafety)

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget

        # Get dt list and attrs for use in concatenated data
        dtList = aux.get_attr(self.browser.ui.dataPlotsWidget.plotDataItems,
                              'dt')
        dt = dtList[0]
        self.dt = dt
        item = self.browser.ui.dataPlotsWidget.plotDataItems[0]
        attrs = item.attrs

        # Get data currently plotted and concatenate in a single sweep
        data = []
        for item in plotWidget.plotDataItems:
            trace, c1 = aux.get_dataRange(plotWidget, item)
            data.append(trace)
        data = np.array(data).ravel()

        # Get derivative trace and filter
        dtrace = None
        if detectionTrace == 'derivative':
            print threshold
            dtrace = np.diff(data)
            dtrace = acq4filter.besselFilter(dtrace, 2000, 1, dt / 1000, 'low',
                                             True)

        # Smooth
        self.trace = data
        if smoothFactor > 1:
            data = smooth.smooth(data,
                                 window_len=smoothFactor,
                                 window='hanning')

        # Comparison functions
        if direction == 'negative':
            comp = lambda a, b: a < b
        elif direction == 'positive':
            comp = lambda a, b: a > b

        # Correct times for dt
        minEventInterval = minInterval / dt
        minDuration = minDuration / dt
        bslWindow = bslWindow / dt
        slowestRise = slowestRise / dt

        # Run detection
        eventCounter, i = 0, 0  #+bslWindow/dt+slowestRise/dt
        iLastDetection = 0
        self.xOnsets, self.yOnsets = [], []
        bsl = 0
        if dtrace is not None:
            detectionData = dtrace
        else:
            detectionData = data
        while i < len(detectionData):
            # Sliding baseline
            #bsl = np.mean(data[i-bslWindow-slowestRise:i])
            if comp(detectionData[i] - bsl, threshold):
                print i, i - iLastDetection
                if i - iLastDetection > minEventInterval:  # Min inter-event interval
                    self.xOnsets.append(i)
                    self.yOnsets.append(data[i])
                    eventCounter += 1
                    iLastDetection = i
                    while i < len(detectionData) and comp(
                            detectionData[i] - bsl, (threshold - noiseSafety)):
                        i += 1  # skip values if index in bounds AND until the value is below/above threshold again
                    if i - iLastDetection < minDuration:  # Event is too brief
                        self.xOnsets.pop()
                        self.yOnsets.pop()
                        eventCounter -= 1
                else:
                    i += 1  # for min event interval
            else:
                i += 1

        frequency = eventCounter / (len(data) * dt) * 1000  # in Hz
        print eventCounter, 'events detected at', frequency, 'Hz'

        # Store event onsets and peaks in h5 data tree
        results = []
        results.append(['trace', np.array(self.trace), attrs])
        results.append(['xOnsets', np.array(self.xOnsets)])
        results.append(['yOnsets', np.array(self.yOnsets)])
        results.append(['number', np.array([eventCounter])])
        results.append(['frequency', np.array([frequency])])
        aux.save_results(browser, 'Event_Detection', results)

        # Plot results
        self.show_events(data, np.array(self.xOnsets), np.array(self.yOnsets),
                         dt)

        # Turn cursors off (the plot has been cleared so there are no cursors displayed)
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False
Пример #20
0
    def func(self, browser):
        """ Calculate the probability of having an event per time bin
        Very simple threshold crossing event detection.    

        Options:
        1) Threshold for detecting spikes
        2) Time bin size (ms)
        3) Event direction
        """

        ############################################
        # ANALYSIS FUNCTION

        # Read detection options
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return
        try:
            timeBin = np.abs(float(self.timeBin.text()))
        except ValueError:
            aux.error_box('Invalid time bin')
            return
        direction = str(self.eventDirection.currentText())

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Detect events in each trace
        if direction == 'negative':
            comp = lambda a, b: a < b
        elif direction == 'positive':
            comp = lambda a, b: a > b

        # Check time bin (using the first plotted item)
        item = plotWidget.plotDataItems[0]
        dt = item.attrs['dt']
        data, c1 = aux.get_dataRange(plotWidget, item)
        if (timeBin / dt == 0) or (len(data) < timeBin / dt):
            aux.error_box(
                'Invalid time bin',
                infoText=
                'Make sure time bin is smaller than the selected data range')
            return

        # Detect events
        results = []
        plotWidget.clear()
        for item in plotWidget.plotDataItems:
            dt = item.attrs['dt']
            data, c1 = aux.get_dataRange(plotWidget, item)
            apCounter, i = 0, 0
            xOnsets, yOnsets = [], []
            while i < len(data):
                if comp(data[i], threshold):
                    xOnsets.append(i)
                    yOnsets.append(data[i])
                    apCounter += 1
                    while i < len(data) and comp(data[i], threshold):
                        i += 1  # skip values if index in bounds AND until the value is below/above threshold again
                else:
                    i += 1

            # Get events per time bin
            binSize = int(timeBin / dt)
            nbins = np.ceil(len(data) / binSize)
            eventCounter = []
            for b in np.arange(1, nbins + 1):
                count = np.sum((xOnsets > (b - 1) * binSize)
                               & (xOnsets < (b * binSize)))
                eventCounter.append(count)
            bins = np.arange(0 + binSize / 2., nbins * binSize + binSize / 2.,
                             binSize) * dt

            # Store data
            results.append(['event_counts', np.array(eventCounter)])

            # Plot detected events
            self.show_events(data, np.array(xOnsets), np.array(yOnsets), dt)

        # Turn cursors off (the plot has been cleared so there are no cursors displayed)
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False

        # Store results
        results.append(['time_bins', bins])
        aux.save_results(browser, parentText + '_eventProbability', results)
Пример #21
0
    def func(self, browser):
        """ Measure selected properties or statistics in the region defined
        by the data cursors.
    
        Rise time and onset are calculated by finding the peak and walking
        back until the limits are crossed. Onset limit is baseline mean; if
        no baseline has been set, it is taken as the mean value of the first
        1 ms of data.
    
        Options:
        1) create new entries in Working Data tree with the results
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Replot data to clear previous measure plot points
        pgplot.replot(browser, plotWidget)

        # Iterate through traces
        dataMin, dataMax, dataMean, dataMedian, dataSEM = [], [], [], [], []
        dataRiseTime, dataOnset, dataDecay = [], [], []
        for item in plotWidget.plotDataItems:
            
            # Get dt and data range
            dt = item.attrs['dt']
            data, c1, cx1, cx2 = aux.get_dataRange(plotWidget, item, cursors=True)

            # Check baseline
            if 'baselineStart' in item.analysis:
                bsl = 0  # the mean of the baseline will always be 0
            else:
                bsl = np.mean(data[0:round(1./dt)]) 
            
            # Measure selected parameters
            if self.minBox.isChecked():
                y = np.min(data)
                x = np.argmin(data)
                dataMin.append(y)
                aux.plot_point(plotWidget, c1, x, y, dt)                

            if self.maxBox.isChecked():
                y = np.max(data)
                x = np.argmax(data)
                dataMax.append(y)
                aux.plot_point(plotWidget, c1, x, y, dt)  

            if self.meanBox.isChecked():
                y = np.mean(data)
                dataMean.append(y)
                plotWidget.plot([cx1,cx2], [y,y], pen=pg.mkPen('#CF1C04', width=1))  

            if self.medianBox.isChecked():
                y = np.median(data)
                dataMedian.append(y)
                plotWidget.plot([cx1,cx2], [y,y], pen=pg.mkPen('#CF1C04', width=1))  

            if self.semBox.isChecked():
                y = np.std(data)/np.sqrt(len(data))
                dataSEM.append(y)
                plotWidget.plot([cx1,cx2], [y,y], pen=pg.mkPen('#CF1C04', width=1))  

            if self.riseTimeBox.isChecked():
                try:
                    lowerLimit = float(self.riseLowerLimit.text())/100
                    upperLimit = float(self.riseUpperLimit.text())/100
                except ValueError:
                    aux.error_box('Invalid limits')
                    return                                   
                # Get peak
                xPeak, yPeak = self.get_peak(data)
                # Get limits
                lowerLimit = lowerLimit*(yPeak-bsl)+bsl
                upperLimit = upperLimit*(yPeak-bsl)+bsl
                # Find limit crosses
                lowerCrossed, upperCrossed = False, False
                i = 0
                while lowerCrossed==False or upperCrossed==False:
                    if (upperCrossed==False) and self.comp(data[xPeak-i],upperLimit): 
                        xUpper = xPeak-i
                        upperCrossed = True
                    if self.comp(data[xPeak-i], lowerLimit):
                        xLower = xPeak-i
                        lowerCrossed = True
                    i+=1
                dataRiseTime.append((xUpper-xLower)*dt)
                # Plot points 
                aux.plot_point(plotWidget, c1, xLower, lowerLimit, dt) 
                aux.plot_point(plotWidget, c1, xUpper, upperLimit, dt)                 

            if self.onsetBox.isChecked():
                xPeak, yPeak = self.get_peak(data)
                bslCrossed = False
                i = 0
                while bslCrossed==False:
                    if self.comp(data[xPeak-i], bsl):
                        onset = xPeak-i
                        bslCrossed = True
                    i+=1
                aux.plot_point(plotWidget, c1, onset, bsl, dt)
                dataOnset.append(onset*dt)

            if self.decayTimeBox.isChecked():
                try:
                    decayLimit = float(self.decayLimit.text())/100
                except ValueError:
                    aux.error_box('Invalid limits')
                    return       
                xPeak, yPeak = self.get_peak(data)
                yDecay = decayLimit*(yPeak-bsl)+bsl
                decayCrossed = False
                i = 0
                while decayCrossed==False:
                    if self.comp(data[xPeak+i], yDecay):
                        decayTime = xPeak+i
                        decayCrossed = True
                    i+=1
                aux.plot_point(plotWidget, c1, decayTime, yDecay, dt)
                dataDecay.append(decayTime*dt)

        # Store results
        results = []
        if self.storeBox.isChecked():
            if self.minBox.isChecked(): results.append(['Minimum', np.array(dataMin)])
            if self.maxBox.isChecked(): results.append(['Maximum', np.array(dataMax)])
            if self.meanBox.isChecked(): results.append(['Mean', np.array(dataMean)])
            if self.medianBox.isChecked(): results.append(['Median', np.array(dataMedian)])
            if self.semBox.isChecked(): results.append(['SEM', np.array(dataSEM)])
            if self.riseTimeBox.isChecked(): results.append(['RiseTime', np.array(dataRiseTime)])
            if self.onsetBox.isChecked(): results.append(['Onset', np.array(dataOnset)])
            if self.decayTimeBox.isChecked(): results.append(['Decay', np.array(dataDecay)])
            aux.save_results(browser, 'Measurements', results)             
Пример #22
0
    def func(self, browser):
        """ Generate a FI curve from current steps
    
        Options:
        1) Threshold for detecting spikes
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Read detection options 
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return
    
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Detect APs in each trace
        comp = lambda a, b: a > b
        apNumber, apFrequency, results = [], [], []
        plotWidget.clear()        
        for item in plotWidget.plotDataItems:
            dt = item.attrs['dt']
            data, c1 = aux.get_dataRange(plotWidget, item)           
            apCounter, i = 0, 0
            xOnsets, yOnsets  = [], []
            while i<len(data):
                if comp(data[i],threshold):
                    xOnsets.append(i)
                    yOnsets.append(data[i])
                    apCounter+=1
                    while i<len(data) and comp(data[i],threshold):
                        i+=1 # skip values if index in bounds AND until the value is below/above threshold again
                else:
                    i+=1
            
            # Calculate AP frequency as 1/mean(ISI)
            isi = np.mean(np.diff(xOnsets))*dt # in ms
            if isi>0:
                freq = 1/(isi/1000.)
            else:
                freq = 0.0

            # Store number of APs and mean frequency
            apNumber.append(apCounter)
            apFrequency.append(freq)         

            # Plot detected APs
            self.show_events(data, np.array(xOnsets), np.array(yOnsets), dt)  
            
        # Turn cursors off (the plot has been cleared so there are no cursors displayed)    
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False       

        # Store results
        results.append(['AP_number', np.array(apNumber)])
        results.append(['AP_frequency', np.array(apFrequency)]) 
        aux.save_results(browser, parentText+'_FI', results)     
Пример #23
0
    def func(self, browser):
        """ Fit data traces within cursor-defined range
    
        Options:
        1) Equation
        2) Initial guesses
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Replot data to clear previous measure plot points
        pgplot.replot(browser, plotWidget)
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'

        # Get current function
        currentFuncmap = self.dataFit.fitfuncmap[str(self.comboBox.currentText())]

        # Read initial guesses
        pInit = []
        try:        
            nParam = len(currentFuncmap[2])
            for n in range(nParam): pInit.append(float(self.p[n].text()))
        except ValueError:
            aux.error_box('Invalid value in initial guess')
            return              

        # Fit data
        fitResults, fitTraces, fitTracesAttrs = [], [], []
        for item in plotWidget.plotDataItems:  

            # Get data range to fit        
            dt = item.attrs['dt']
            fitTracesAttrs.append(item.attrs)
            yData, c1, cx1, cx2 = aux.get_dataRange(plotWidget, item, cursors=True)
            xRange = pgplot.make_xvector(yData, dt)+cx1
            self.dataFit.c1 = cx1   

            # Fit
            func = currentFuncmap[0]
            fitParams = self.dataFit.fit(func, xRange, yData, pInit) 
            fitResults.append(fitParams)
            print fitParams            
        
            # Plot fitted function over trace
            if self.extendBox.isChecked():
                xRange = pgplot.make_xvector(item.data, dt)
                #xRange = np.arange(plotWidget.viewBox.viewRange()[0][0], plotWidget.viewBox.viewRange()[0][1], dt)
            fittedTrace = func(xRange, *fitParams)
            plotWidget.plot(xRange, fittedTrace, pen=pg.mkPen('r', width=1))
            fitTraces.append(fittedTrace)

        # Store results
        if self.storeBox.isChecked():
            fitResults = np.array(fitResults)
            results = []
            for n in range(np.shape(fitResults)[1]):    
                results.append([str(self.plabels[n].text()), fitResults[:,n]])
            for n in range(len(fitTraces)):
                results.append(['fitTraces_'+str(n), fitTraces[n], fitTracesAttrs[n]])     
            aux.save_results(browser, parentText+'_fit', results)     
Пример #24
0
    def func(self, browser):
        """ Calculate the probability of having an event per time bin
        Very simple threshold crossing event detection.    

        Options:
        1) Threshold for detecting spikes
        2) Time bin size (ms)
        3) Event direction
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        # Read detection options
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return         
        try:
            timeBin = np.abs(float(self.timeBin.text())) 
        except ValueError:
            aux.error_box('Invalid time bin')
            return              
        direction = str(self.eventDirection.currentText())
   
        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget
    
        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(0) # Assumes all plotted data have the same parent
        except AttributeError:   # Parent = None
            parentText = 'Data'
    
        # Detect events in each trace
        if direction=='negative':
            comp = lambda a, b: a < b
        elif direction=='positive':
            comp = lambda a, b: a > b
  
        # Check time bin (using the first plotted item)
        item = plotWidget.plotDataItems[0]
        dt = item.attrs['dt']
        data, c1 = aux.get_dataRange(plotWidget, item)
        if (timeBin/dt==0) or (len(data)<timeBin/dt):
            aux.error_box('Invalid time bin', infoText='Make sure time bin is smaller than the selected data range')
            return  
  
        # Detect events
        results = []        
        plotWidget.clear()
        for item in plotWidget.plotDataItems:
            dt = item.attrs['dt']
            data, c1 = aux.get_dataRange(plotWidget, item)
            apCounter, i = 0, 0
            xOnsets, yOnsets  = [], []
            while i<len(data):
                if comp(data[i],threshold):
                    xOnsets.append(i)
                    yOnsets.append(data[i])
                    apCounter+=1
                    while i<len(data) and comp(data[i],threshold):
                        i+=1 # skip values if index in bounds AND until the value is below/above threshold again
                else:
                    i+=1
            
            # Get events per time bin
            binSize = int(timeBin/dt)
            nbins = np.ceil(len(data)/binSize)
            eventCounter = []
            for b in np.arange(1, nbins+1):
                count = np.sum((xOnsets>(b-1)*binSize) & (xOnsets<(b*binSize)))
                eventCounter.append(count)
            bins = np.arange(0+binSize/2., nbins*binSize+binSize/2., binSize)*dt

            # Store data     
            results.append(['event_counts', np.array(eventCounter)]) 

            # Plot detected events
            self.show_events(data, np.array(xOnsets), np.array(yOnsets), dt)  

        # Turn cursors off (the plot has been cleared so there are no cursors displayed)    
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False       

        # Store results
        results.append(['time_bins', bins])
        aux.save_results(browser, parentText+'_eventProbability', results)     
Пример #25
0
    def func(self, browser):
        """ Get some properties of currently plotted tracking trigger events
        extracted with behaviour_triggerEvents.py module

        Properties measured:
        1 - failures to escape
        2 - latency to escape
        3 - time to reach the nest
        4 - average speed of escape
        5 - peak speed during escape

        Extracted events have useful attributes:
        t0 : data point of the trigger from the start of the event
        trigger_time : data point of the trigger from the start of the original
                       tracking trace

        Options:
        1) Threshold for the nest long-axis coordinate
        2) Threshold for the position derivative (to measure response latency)
        """

        ############################################
        # ANALYSIS FUNCTION      
    
        # Read options
        nestPos = float(self.plotWidget.nestCursorThsPos)
        derivativeThs = float(self.plotWidget.derivativeCursorThsPos)

        # Get plotted events
        events = self.plotWidget.plotDataItems
        
        # Go through events
        failures = []
        latencies, timeToNest, avgSpeed, maxSpeed = [], [], [], []
        comp = lambda a, b: a < b
        for event in events:
        
            # Get data range          
            #data, c1 = aux.get_dataRange(plotWidget, event)

            # Mark failures depending on position reached nest
            if np.sum(event.data<nestPos)==0:
                failures.append(1)
            else:
                failures.append(0)

                # Get latency to reaction
                t0 = event.attrs['t0']
                i = t0  # start from stimulus trigger
                dtrace = np.diff(event.data)
                while i<len(dtrace):
                    if comp(dtrace[i], derivativeThs):
                        latencies.append(i-t0)
                        break
                    i+=1     

                # Get latency to nest
                i = t0
                while i<len(event.data):
                    if comp(event.data[i], nestPos):
                        timeToNest.append(i-t0)
                        break
                    i+=1

                # Get other measures         
                avgSpeed.append(np.mean(dtrace[t0:i]))
                maxSpeed.append(dtrace[t0:i].min())

        # Store data
        results = []
        results.append(['Failures', failures])
        results.append(['Latencies', latencies])  
        results.append(['Time_to_nest', timeToNest])
        results.append(['Average_speed', avgSpeed])
        results.append(['Max_speed', maxSpeed])   
        aux.save_results(self.browser, 'Event_measurements', results)  
Пример #26
0
    def func(self, browser):
        """ Fit data traces within cursor-defined range
    
        Options:
        1) Equation
        2) Initial guesses
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Replot data to clear previous measure plot points
        pgplot.replot(browser, plotWidget)

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Get current function
        currentFuncmap = self.dataFit.fitfuncmap[str(
            self.comboBox.currentText())]

        # Read initial guesses
        pInit = []
        try:
            nParam = len(currentFuncmap[2])
            for n in range(nParam):
                pInit.append(float(self.p[n].text()))
        except ValueError:
            aux.error_box('Invalid value in initial guess')
            return

        # Fit data
        fitResults, fitTraces, fitTracesAttrs = [], [], []
        for item in plotWidget.plotDataItems:

            # Get data range to fit
            dt = item.attrs['dt']
            fitTracesAttrs.append(item.attrs)
            yData, c1, cx1, cx2 = aux.get_dataRange(plotWidget,
                                                    item,
                                                    cursors=True)
            xRange = pgplot.make_xvector(yData, dt) + cx1
            self.dataFit.c1 = cx1

            # Fit
            func = currentFuncmap[0]
            fitParams = self.dataFit.fit(func, xRange, yData, pInit)
            fitResults.append(fitParams)
            print fitParams

            # Plot fitted function over trace
            if self.extendBox.isChecked():
                xRange = pgplot.make_xvector(item.data, dt)
                #xRange = np.arange(plotWidget.viewBox.viewRange()[0][0], plotWidget.viewBox.viewRange()[0][1], dt)
            fittedTrace = func(xRange, *fitParams)
            plotWidget.plot(xRange, fittedTrace, pen=pg.mkPen('r', width=1))
            fitTraces.append(fittedTrace)

        # Store results
        if self.storeBox.isChecked():
            fitResults = np.array(fitResults)
            results = []
            for n in range(np.shape(fitResults)[1]):
                results.append([str(self.plabels[n].text()), fitResults[:, n]])
            for n in range(len(fitTraces)):
                results.append(
                    ['fitTraces_' + str(n), fitTraces[n], fitTracesAttrs[n]])
            aux.save_results(browser, parentText + '_fit', results)
Пример #27
0
    def func(self, browser):
        """ Generate a FI curve from current steps
    
        Options:
        1) Threshold for detecting spikes
        """

        ############################################
        # ANALYSIS FUNCTION

        # Read detection options
        try:
            threshold = float(self.browser.ui.dataPlotsWidget.cursorThsPos)
        except NameError:
            aux.error_box('No threshold selected')
            return

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Detect APs in each trace
        comp = lambda a, b: a > b
        apNumber, apFrequency, results = [], [], []
        plotWidget.clear()
        for item in plotWidget.plotDataItems:
            dt = item.attrs['dt']
            data, c1 = aux.get_dataRange(plotWidget, item)
            apCounter, i = 0, 0
            xOnsets, yOnsets = [], []
            while i < len(data):
                if comp(data[i], threshold):
                    xOnsets.append(i)
                    yOnsets.append(data[i])
                    apCounter += 1
                    while i < len(data) and comp(data[i], threshold):
                        i += 1  # skip values if index in bounds AND until the value is below/above threshold again
                else:
                    i += 1

            # Calculate AP frequency as 1/mean(ISI)
            isi = np.mean(np.diff(xOnsets)) * dt  # in ms
            if isi > 0:
                freq = 1 / (isi / 1000.)
            else:
                freq = 0.0

            # Store number of APs and mean frequency
            apNumber.append(apCounter)
            apFrequency.append(freq)

            # Plot detected APs
            self.show_events(data, np.array(xOnsets), np.array(yOnsets), dt)

        # Turn cursors off (the plot has been cleared so there are no cursors displayed)
        self.browser.ui.actionShowCursors.setChecked(False)
        plotWidget.cursor = False

        # Store results
        results.append(['AP_number', np.array(apNumber)])
        results.append(['AP_frequency', np.array(apFrequency)])
        aux.save_results(browser, parentText + '_FI', results)
Пример #28
0
    def func(self, browser):
        """ Measure selected properties or statistics in the region defined
        by the data cursors.
    
        Rise time and onset are calculated by finding the peak and walking
        back until the limits are crossed. Onset limit is baseline mean; if
        no baseline has been set, it is taken as the mean value of the first
        1 ms of data.
    
        Options:
        1) create new entries in Working Data tree with the results
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Replot data to clear previous measure plot points
        pgplot.replot(browser, plotWidget)

        # Iterate through traces
        dataMin, dataMax, dataMean, dataMedian, dataSEM = [], [], [], [], []
        dataRiseTime, dataOnset, dataDecay = [], [], []
        for item in plotWidget.plotDataItems:

            # Get dt and data range
            dt = item.attrs['dt']
            data, c1, cx1, cx2 = aux.get_dataRange(plotWidget,
                                                   item,
                                                   cursors=True)

            # Check baseline
            if 'baselineStart' in item.analysis:
                bsl = 0  # the mean of the baseline will always be 0
            else:
                bsl = np.mean(data[0:round(1. / dt)])

            # Measure selected parameters
            if self.minBox.isChecked():
                y = np.min(data)
                x = np.argmin(data)
                dataMin.append(y)
                aux.plot_point(plotWidget, c1, x, y, dt)

            if self.maxBox.isChecked():
                y = np.max(data)
                x = np.argmax(data)
                dataMax.append(y)
                aux.plot_point(plotWidget, c1, x, y, dt)

            if self.meanBox.isChecked():
                y = np.mean(data)
                dataMean.append(y)
                plotWidget.plot([cx1, cx2], [y, y],
                                pen=pg.mkPen('#CF1C04', width=1))

            if self.medianBox.isChecked():
                y = np.median(data)
                dataMedian.append(y)
                plotWidget.plot([cx1, cx2], [y, y],
                                pen=pg.mkPen('#CF1C04', width=1))

            if self.semBox.isChecked():
                y = np.std(data) / np.sqrt(len(data))
                dataSEM.append(y)
                plotWidget.plot([cx1, cx2], [y, y],
                                pen=pg.mkPen('#CF1C04', width=1))

            if self.riseTimeBox.isChecked():
                try:
                    lowerLimit = float(self.riseLowerLimit.text()) / 100
                    upperLimit = float(self.riseUpperLimit.text()) / 100
                except ValueError:
                    aux.error_box('Invalid limits')
                    return
                # Get peak
                xPeak, yPeak = self.get_peak(data)
                # Get limits
                lowerLimit = lowerLimit * (yPeak - bsl) + bsl
                upperLimit = upperLimit * (yPeak - bsl) + bsl
                # Find limit crosses
                lowerCrossed, upperCrossed = False, False
                i = 0
                while lowerCrossed == False or upperCrossed == False:
                    if (upperCrossed == False) and self.comp(
                            data[xPeak - i], upperLimit):
                        xUpper = xPeak - i
                        upperCrossed = True
                    if self.comp(data[xPeak - i], lowerLimit):
                        xLower = xPeak - i
                        lowerCrossed = True
                    i += 1
                dataRiseTime.append((xUpper - xLower) * dt)
                # Plot points
                aux.plot_point(plotWidget, c1, xLower, lowerLimit, dt)
                aux.plot_point(plotWidget, c1, xUpper, upperLimit, dt)

            if self.onsetBox.isChecked():
                xPeak, yPeak = self.get_peak(data)
                bslCrossed = False
                i = 0
                while bslCrossed == False:
                    if self.comp(data[xPeak - i], bsl):
                        onset = xPeak - i
                        bslCrossed = True
                    i += 1
                aux.plot_point(plotWidget, c1, onset, bsl, dt)
                dataOnset.append(onset * dt)

            if self.decayTimeBox.isChecked():
                try:
                    decayLimit = float(self.decayLimit.text()) / 100
                except ValueError:
                    aux.error_box('Invalid limits')
                    return
                xPeak, yPeak = self.get_peak(data)
                yDecay = decayLimit * (yPeak - bsl) + bsl
                decayCrossed = False
                i = 0
                while decayCrossed == False:
                    if self.comp(data[xPeak + i], yDecay):
                        decayTime = xPeak + i
                        decayCrossed = True
                    i += 1
                aux.plot_point(plotWidget, c1, decayTime, yDecay, dt)
                dataDecay.append(decayTime * dt)

        # Store results
        results = []
        if self.storeBox.isChecked():
            if self.minBox.isChecked():
                results.append(['Minimum', np.array(dataMin)])
            if self.maxBox.isChecked():
                results.append(['Maximum', np.array(dataMax)])
            if self.meanBox.isChecked():
                results.append(['Mean', np.array(dataMean)])
            if self.medianBox.isChecked():
                results.append(['Median', np.array(dataMedian)])
            if self.semBox.isChecked():
                results.append(['SEM', np.array(dataSEM)])
            if self.riseTimeBox.isChecked():
                results.append(['RiseTime', np.array(dataRiseTime)])
            if self.onsetBox.isChecked():
                results.append(['Onset', np.array(dataOnset)])
            if self.decayTimeBox.isChecked():
                results.append(['Decay', np.array(dataDecay)])
            aux.save_results(browser, 'Measurements', results)
Пример #29
0
    def func(self, browser):
        """ Filter traces
    
        Options:
        1) Filter type (currently Bessel only)
        2) Filter parameters
        
        Note: filter frequencies are in Hz, make sure dt is in seconds
        """

        ############################################
        # ANALYSIS FUNCTION

        # Get options
        btype = str(self.comboPass.currentText())
        if 'Low' in btype:
            btype = 'low'
        elif 'High' in btype:
            btype = 'high'
        try:
            cutoff = float(self.filterCutoff.text())
            order = float(self.filterOrder.text())
        except ValueError:
            aux.error_box('Invalid Cut off or Order value')
            return
        bidir = self.filterDirection.isChecked()

        # Get widgets
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget

        # Get parent text of plotted items
        try:
            parentText = plotWidget.plotDataItems[0].parent().text(
                0)  # Assumes all plotted data have the same parent
        except AttributeError:  # Parent = None
            parentText = 'Data'

        # Filter data
        results, itemsToPlot = [], []
        for item in plotWidget.plotDataItems:
            # Copy attributes and add some new ones
            attrs = item.attrs
            attrs['filter_type'] = btype
            attrs['filter_cutoff'] = cutoff
            attrs['filter_order'] = order

            # Filter
            traceFilter = acq4filter.besselFilter(
                item.data, cutoff, order,
                float(item.attrs['dt']) / 1000, btype, bidir)
            results.append([item.text(0), traceFilter, attrs])

            # Store filtered traces
            filterItem = aux.make_h5item('filter', traceFilter, item.attrs)
            itemsToPlot.append(filterItem)

        # Plot results
        pgplot.plot_multipleData(browser,
                                 plotWidget,
                                 itemsToPlot,
                                 clear=False,
                                 color='#F2EF44')

        # Store results
        aux.save_results(browser, parentText + '_filter', results)
Пример #30
0
    def func(self, browser):
        """ Calculate average trace from currently plotted traces. If cursors are
        selected the average is calculated for the range within the cursors.

        Options:
        1) create new entry in Working Data tree with the result
        2) plot average with orginal traces
        3) caclulate SD and SEM
        """
    
        ############################################
        # ANALYSIS FUNCTION
        
        plotWidget = browser.ui.dataPlotsWidget
        toolsWidget = browser.ui.oneDimToolStackedWidget   
        results = []

        # Get data and cursors
        data = []
        for item in plotWidget.plotDataItems:
            dt = item.attrs['dt']
            dataRange, c1 = aux.get_dataRange(plotWidget, item)    
            data.append(dataRange)   
        data = np.array(data)

        # Calculate average and make h5item for plotting
        try:
            #avgData = np.nanmean(data[:, c1:c2], 0)
            avgData = np.mean(data, 0)
            avgItem = aux.make_h5item('avg', avgData, plotWidget.plotDataItems[0].attrs)
            results.append(['avg_trace', avgData, item.attrs])  
        except ValueError:  
            aux.error_box('Cannot calculate average on data with different lengths', sys.exc_info(),
                          'Please ensure that all traces have the same length') 
            return

        # Calculate SD and SEM
        if self.sdBox.isChecked():
            #sdData = np.nanstd(data[:, c1:c2], 0)
            sdData = np.std(data, 0)            
            avgPlusSDItem = aux.make_h5item('avg+sd', avgData+sdData, plotWidget.plotDataItems[0].attrs)
            avgMinusSDItem = aux.make_h5item('avg-sd', avgData-sdData, plotWidget.plotDataItems[0].attrs)
            results.append(['avg+sd', avgData+sdData, item.attrs])  
            results.append(['avg-sd', avgData-sdData, item.attrs])  
 
        if self.semBox.isChecked():
            #semData = np.nanstd(data[:, c1:c2], 0)/np.sqrt(len(data))
            semData = np.std(data, 0)/np.sqrt(len(data))
            avgPlusSEMItem = aux.make_h5item('avg+sem', avgData+semData, plotWidget.plotDataItems[0].attrs)
            avgMinusSEMItem = aux.make_h5item('avg-sem', avgData-semData, plotWidget.plotDataItems[0].attrs)
            results.append(['avg+sem', avgData+semData, item.attrs])  
            results.append(['avg-sem', avgData-semData, item.attrs])  

        # Plot data
        if self.showTraces.isChecked(): 
            clear = False
        else:
            clear = True
        pgplot.browse_singleData(browser, plotWidget, avgItem, clear=clear, color='r')

        # Store data
        if self.storeResult.isChecked():     
            aux.save_results(browser, item.parent().text(0)+'_average', results)