def analyze_response_strength(rec, source, remove_artifacts=False, deconvolve=True, lpf=True, bsub=True, lowpass=1000): """Perform a standardized strength analysis on a record selected by response_query or baseline_query. 1. Determine timing of presynaptic stimulus pulse edges and spike 2. Measure peak deflection on raw trace 3. Apply deconvolution / artifact removal / lpf 4. Measure peak deflection on deconvolved trace """ data = TSeries(rec.data, sample_rate=db.default_sample_rate) if source == 'pulse_response': # Find stimulus pulse edges for artifact removal start = rec.pulse_start - rec.rec_start pulse_times = [start, start + rec.pulse_dur] if rec.spike_time is None: # these pulses failed QC, but we analyze them anyway to make all data visible spike_time = 11e-3 else: spike_time = rec.spike_time - rec.rec_start elif source == 'baseline': # Fake stimulus information to ensure that background data receives # the same filtering / windowing treatment pulse_times = [10e-3, 12e-3] spike_time = 11e-3 else: raise ValueError("Invalid source %s" % source) results = {} results['raw_trace'] = data results['pulse_times'] = pulse_times results['spike_time'] = spike_time # Measure crosstalk from pulse onset p1 = data.time_slice(pulse_times[0] - 200e-6, pulse_times[0]).median() p2 = data.time_slice(pulse_times[0], pulse_times[0] + 200e-6).median() results['crosstalk'] = p2 - p1 # crosstalk artifacts in VC are removed before deconvolution if rec.clamp_mode == 'vc' and remove_artifacts is True: data = remove_crosstalk_artifacts(data, pulse_times) remove_artifacts = False # Measure deflection on raw data results['pos_amp'], _ = measure_peak(data, '+', spike_time, pulse_times) results['neg_amp'], _ = measure_peak(data, '-', spike_time, pulse_times) # Deconvolution / artifact removal / filtering if deconvolve: tau = 15e-3 if rec.clamp_mode == 'ic' else 5e-3 else: tau = None dec_data = deconv_filter(data, pulse_times, tau=tau, lpf=lpf, remove_artifacts=remove_artifacts, bsub=bsub, lowpass=lowpass) results['dec_trace'] = dec_data # Measure deflection on deconvolved data results['pos_dec_amp'], results['pos_dec_latency'] = measure_peak( dec_data, '+', spike_time, pulse_times) results['neg_dec_amp'], results['neg_dec_latency'] = measure_peak( dec_data, '-', spike_time, pulse_times) return results
def set_data(self, data, show_spikes=False, subtract_baseline=True): self.spike_plot.setVisible(show_spikes) self.spike_plot.enableAutoRange(False, False) self.data_plot.enableAutoRange(False, False) psp = StackedPsp() for recording in data: pulses = sorted(list(data[recording].keys())) for pulse_n in pulses: rec = data[recording][pulse_n] # spike-align pulse + offset for pulse number spike_t = rec.StimPulse.first_spike_time if spike_t is None: spike_t = rec.StimPulse.onset_time + 1e-3 qc_pass = rec.PulseResponse.in_qc_pass if rec.Synapse.synapse_type == 'in' else rec.PulseResponse.ex_qc_pass pen = (255, 255, 255, 100) if qc_pass else (200, 50, 0, 100) t0 = rec.PulseResponse.data_start_time - spike_t ts = TSeries(data=rec.data, t0=t0, sample_rate=db.default_sample_rate) c = self.data_plot.plot(ts.time_values, ts.data, pen=pen) # arrange plots nicely y0 = 0 if not subtract_baseline else ts.time_slice(None, 0).median() shift = (pulse_n * 35e-3 + (30e-3 if pulse_n > 8 else 0), -y0) zval = 0 if qc_pass else -10 c.setPos(*shift) c.setZValue(zval) if show_spikes: t0 = rec.spike_data_start_time - spike_t spike_ts = TSeries(data=rec.spike_data, t0=t0, sample_rate=db.default_sample_rate) c = self.spike_plot.plot(spike_ts.time_values, spike_ts.data, pen=pen) c.setPos(*shift) c.setZValue(zval) # evaluate recorded fit for this response fit_par = rec.PulseResponseFit if fit_par.fit_amp is None: continue fit = psp.eval( x=ts.time_values, exp_amp=fit_par.fit_exp_amp, exp_tau=fit_par.fit_decay_tau, amp=fit_par.fit_amp, rise_time=fit_par.fit_rise_time, decay_tau=fit_par.fit_decay_tau, xoffset=fit_par.fit_latency, yoffset=fit_par.fit_yoffset, rise_power=2, ) pen = (0, 255, 0, 100) if qc_pass else (50, 150, 0, 100) c = self.data_plot.plot(ts.time_values, fit, pen=pen) c.setZValue(10) c.setPos(*shift) if not qc_pass: print( "qc fail: ", rec.PulseResponse.meta.get('qc_failures', 'no qc failures recorded')) self.spike_plot.enableAutoRange(True, True) self.data_plot.enableAutoRange(True, True)