def plotClicked(plt, pts): pt = pts[0] #(id, fn, time) = pt.data #[['SourceFile', 'ProtocolSequenceDir', 'fitTime']] #fh = db.getDir('ProtocolSequence', id)[fn] fh = pt.data()['SourceFile'] id = pt.data()['ProtocolSequenceDir'] time = pt.data()['fitTime'] data = fh.read()['Channel':'primary'] data = fn.besselFilter(data, 8e3) p = pw2.plot(data, clear=True) pos = time / data.xvals('Time')[-1] arrow = pg.CurveArrow(p, pos=pos) xr = pw2.viewRect().left(), pw2.viewRect().right() if time < xr[0] or time > xr[1]: w = xr[1]-xr[0] pw2.setXRange(time-w/5., time+4*w/5., padding=0) fitLen = pt.data()['fitDecayTau']*pt.data()['fitLengthOverDecay'] x = np.linspace(time, time+fitLen, fitLen * 50e3) v = [pt.data()['fitAmplitude'], pt.data()['fitTime'], pt.data()['fitRiseTau'], pt.data()['fitDecayTau']] y = fn.pspFunc(v, x, risePower=2.0) + data[np.argwhere(data.xvals('Time')>time)[0]-1] pw2.plot(x, y, pen='b')
def processEventFits(events, startEvent, stopEvent, opts): ## This function does all the processing work for EventFitter. dt = opts['dt'] origTau = opts['tau'] multiFit = opts['multiFit'] waveform = opts['waveform'] tvals = opts['tvals'] nFields = len(events.dtype.fields) dtype = [(n, events[n].dtype) for n in events.dtype.names] output = np.empty(len(events), dtype=dtype + [ ('fitAmplitude', float), ('fitTime', float), ('fitRiseTau', float), ('fitDecayTau', float), ('fitTimeToPeak', float), ('fitError', float), ('fitFractionalError', float), ('fitLengthOverDecay', float), ]) offset = 0 ## not all input events will produce output events; offset keeps track of the difference. outputState = { 'guesses': [], 'eventData': [], 'indexes': [], 'xVals': [], 'yVals': [] } for i in range(startEvent, stopEvent): start = events[i]['time'] #sliceLen = 50e-3 sliceLen = dt*300. ## Ca2+ events are much longer than 50ms if i+1 < len(events): nextStart = events[i+1]['time'] sliceLen = min(sliceLen, nextStart-start) guessLen = events[i]['len']*dt tau = origTau if tau is not None: guessLen += tau*2. #print i, guessLen, tau, events[i]['len']*dt #sliceLen = 50e-3 sliceLen = guessLen if i+1 < len(events): ## cut slice back if there is another event coming up nextStart = events[i+1]['time'] sliceLen = min(sliceLen, nextStart-start) ## Figure out from where to pull waveform data that will be fitted startIndex = np.argwhere(tvals>=start)[0][0] stopIndex = startIndex + int(sliceLen/dt) eventData = waveform[startIndex:stopIndex] times = tvals[startIndex:stopIndex] #print i, startIndex, stopIndex, dt if len(times) < 4: ## PSP fit requires at least 4 points; skip this one offset += 1 continue ## reconvolve this chunk of the signal if it was previously deconvolved if tau is not None: eventData = functions.expReconvolve(eventData, tau=tau, dt=dt) #print i, len(eventData) ## Make guesses as to the shape of the event mx = eventData.max() mn = eventData.min() if mx > -mn: peakVal = mx else: peakVal = mn guessAmp = peakVal * 2 ## fit converges more reliably if we start too large guessRise = guessLen/4. guessDecay = guessLen/2. guessStart = times[0] zc = functions.zeroCrossingEvents(eventData - (peakVal/3.)) ## eliminate events going the wrong direction if len(zc) > 0: if guessAmp > 0: zc = zc[zc['peak']>0] else: zc = zc[zc['peak']<0] #print zc ## measure properties for the largest event within 10ms of start zc = zc[zc['index'] < 10e-3/dt] if len(zc) > 0: if guessAmp > 0: zcInd = np.argmax(zc['sum']) ## the largest event in this clip else: zcInd = np.argmin(zc['sum']) ## the largest event in this clip zcEv = zc[zcInd] #guessLen = dt*zc[zcInd]['len'] guessRise = .1e-3 #dt*zcEv['len'] * 0.2 guessDecay = dt*zcEv['len'] * 0.8 guessStart = times[0] + dt*zcEv['index'] - guessRise*3. ## cull down the data set if possible cullLen = zcEv['index'] + zcEv['len']*3 if len(eventData) > cullLen: eventData = eventData[:cullLen] times = times[:cullLen] ## fitting to exponential rise * decay ## parameters are [amplitude, x-offset, rise tau, fall tau] guess = [guessAmp, guessStart, guessRise, guessDecay] #guess = [amp, times[0], guessLen/4., guessLen/2.] ## careful! bounds = [ sorted((guessAmp * 0.1, guessAmp)), sorted((guessStart-min(guessRise, 0.01), guessStart+guessRise*2)), sorted((dt*0.5, guessDecay)), sorted((dt*0.5, guessDecay * 50.)) ] yVals = eventData.view(np.ndarray) fit = functions.fitPsp(times, yVals, guess=guess, bounds=bounds, multiFit=multiFit) computed = functions.pspFunc(fit, times) peakTime = functions.pspMaxTime(fit[2], fit[3]) diff = (yVals - computed) err = (diff**2).sum() fracError = diff.std() / computed.std() lengthOverDecay = (times[-1] - fit[1]) / fit[3] # ratio of (length of data that was fit : decay constant) output[i-offset] = tuple(events[i]) + tuple(fit) + (peakTime, err, fracError, lengthOverDecay) #output['fitTime'] += output['time'] #print fit #self.events.append(eventData) outputState['guesses'].append(guess) outputState['eventData'].append(eventData) outputState['indexes'].append(i) outputState['xVals'].append(times) outputState['yVals'].append(computed) if offset > 0: output = output[:-offset] outputState['output'] = output return outputState
def process(self, waveform, events, display=True): self.deletedFits = [] for item in self.plotItems: try: item.sigClicked.disconnect(self.fitClicked) except: pass self.plotItems = [] tau = waveform.infoCopy(-1).get('expDeconvolveTau', None) dt = waveform.xvals(0)[1] - waveform.xvals(0)[0] opts = { 'dt': dt, 'tau': tau, 'multiFit': self.ctrls['multiFit'].isChecked(), 'waveform': waveform.view(np.ndarray), 'tvals': waveform.xvals('Time'), } #if not self.ctrls['parallel'].isChecked(): output = processEventFits(events, startEvent=0, stopEvent=len(events), opts=opts) guesses = output['guesses'] eventData = output['eventData'] indexes = output['indexes'] xVals = output['xVals'] yVals = output['yVals'] output = output['output'] #else: #print "parallel:", self.pool, self.poolSize #results = [] #nProcesses = self.ctrls['nProcesses'].value() #evPerProcess = int(len(events) / nProcesses) #start = 0 #for i in range(nProcesses): #stop = start + evPerProcess #if stop > len(events): #stop = len(events) #args = (events, start, stop, opts) #results.append(self.pool.apply_async(processEventFits, args)) #print "started process", start, stop #start = stop #data = [] #guesses = [] #eventData = [] #indexes = [] #xVals = [] #yVals = [] #for res in results: ## reconstruct results here #print "getting result", res #output = res.get(10) #data.append(output['output']) #guesses.extend(output['guesses']) #eventData.extend(output['eventData']) #indexes.extend(output['indexes']) #xVals.extend(output['xVals']) #yVals.extend(output['yVals']) #output = np.concatenate(data) for i in range(len(indexes)): if display and self['plot'].isConnected(): if self.ctrls['plotFits'].isChecked(): item = pg.PlotDataItem(x=xVals[i], y=yVals[i], pen=(0, 0, 255), clickable=True) item.setZValue(100) self.plotItems.append(item) item.eventIndex = indexes[i] item.sigClicked.connect(self.fitClicked) item.deleted = False if self.ctrls['plotGuess'].isChecked(): item2 = pg.PlotDataItem(x=xVals[i], y=functions.pspFunc(guesses[i], xVals[i]), pen=(255, 0, 0)) item2.setZValue(100) self.plotItems.append(item2) if self.ctrls['plotEvents'].isChecked(): item2 = pg.PlotDataItem(x=xVals[i], y=eventData[i], pen=(0, 255, 0)) item2.setZValue(100) self.plotItems.append(item2) #plot = self.plot.connections().keys()[0].node().getPlot() #plot.addItem(item) self.outputData = output return {'output': output, 'plot': self.plotItems}
def displayData(self, fh, plot, pen, evTime=None, eventFilter=None): """ Display data for a single site in a plot--ephys trace, detected events Returns all items added to the plot. """ pen = pg.mkPen(pen) items = [] if isinstance(fh, basestring): fh = self.source()[fh] if fh.isDir(): fh = self.dataModel.getClampFile(fh) ## plot all data, incl. events data = fh.read()['primary'] data = fn.besselFilter(data, 4e3) pc = plot.plot(data, pen=pen, clear=False) items.append(pc) ## mark location of event if an event index was given if evTime is not None: #pos = float(index)/len(data) pos = evTime / data.xvals('Time')[-1] #print evTime, data.xvals('Time')[-1], pos #print index arrow = pg.CurveArrow(pc, pos=pos) plot.addItem(arrow) items.append(arrow) events = self.getEvents(fh)['events'] if eventFilter is not None: events = eventFilter(events) ## draw ticks over all detected events if len(events) > 0: if 'fitTime' in events.dtype.names: times = events['fitTime'] ticks = pg.VTickGroup(times, [0.9, 1.0], pen=pen) plot.addItem(ticks) items.append(ticks) #self.mapTicks.append(ticks) ## draw event fits evPen = pg.mkPen(pen) c = evPen.color() c.setAlpha(c.alpha()/2) evPen.setColor(c) for ev in events: time = ev['fitTime'] try: fitLen = ev['fitDecayTau']*ev['fitLengthOverDecay'] except IndexError: fitLen = ev['fitDecayTau']*4. x = np.linspace(time, time+fitLen, fitLen * 50e3) v = [ev['fitAmplitude'], ev['fitTime'], ev['fitRiseTau'], ev['fitDecayTau']] y = fn.pspFunc(v, x, risePower=2.0) + data[np.argwhere(data.xvals('Time')>time)[0]-1] evc = plot.plot(x, y, pen=evPen) evc.setZValue(pc.zValue()-100) return items