def __init__(self): pg.QtCore.QObject.__init__(self) # global session for querying from DB self.session = db.session() win = pg.QtGui.QSplitter() win.setOrientation(pg.QtCore.Qt.Horizontal) win.resize(1000, 800) win.show() b = ExperimentBrowser() b.populate() win.addWidget(b) rs_plots = ResponseStrengthPlots(self.session) win.addWidget(rs_plots) b.itemSelectionChanged.connect(self._selected) b.doubleClicked.connect(self._dbl_clicked) self.win = win self.rs_plots = rs_plots self.browser = b self.nwb_viewer = MultipatchNwbViewer()
def __init__(self): pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.browser = ExperimentBrowser() self.addWidget(self.browser) self.plots = PlotGrid() self.addWidget(self.plots) self.browser.itemSelectionChanged.connect(self.browser_item_selected)
def __init__(self): self.loaded_pair = None pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.ctrl_split = pg.QtGui.QSplitter(pg.QtCore.Qt.Vertical) self.addWidget(self.ctrl_split) self.browser = ExperimentBrowser() self.ctrl_split.addWidget(self.browser) self.ptree = pg.parametertree.ParameterTree() self.ctrl_split.addWidget(self.ptree) self.params = pg.parametertree.Parameter.create( name='params', type='group', children=[ { 'name': 'show spikes', 'type': 'bool', 'value': True }, { 'name': 'subtract baseline', 'type': 'bool', 'value': True }, { 'name': 'stimulus filter', 'type': 'group' }, ]) self.ptree.setParameters(self.params) self.scroll_area = pg.QtGui.QScrollArea() self.addWidget(self.scroll_area) self.view = pg.GraphicsLayoutWidget() self.scroll_area.setWidget(self.view) self.resize(1600, 1000) self.plots = [] self.browser.itemSelectionChanged.connect(self.browser_item_selected) self.params.sigTreeStateChanged.connect(self.plot_all)
def __init__(self): self.ctrl_panel = ControlPanel() self.latency_superline = SuperLine() self.latency_superline.sigPositionChanged.connect(self.ctrl_panel.set_latency) self.ic_plot = TSeriesPlot('Current Clamp', 'V') for plot in self.ic_plot.trace_plots: plot.addItem(self.latency_superline.new_line(default_latency)) self.vc_plot = TSeriesPlot('Voltage Clamp', 'A') for plot in self.vc_plot.trace_plots: plot.addItem(self.latency_superline.new_line(default_latency)) self.user_latency = self.ctrl_panel.user_latency self.user_latency.sigValueChanged.connect(self.latency_superline.set_value_from_ctrl_panel) self.ctrl_panel.output_params.child('Fit parameters').sigTreeStateChanged.connect(self.colorize_fit) self.experiment_browser = ExperimentBrowser() self.fit_compare = pg.DiffTreeWidget() self.meta_compare = pg.DiffTreeWidget() self.nrmse_thresh = 4 self.sorted_responses = None self.signs = { 'vc': { -55: {'ex': -1, 'in': 1}, -70: {'ex': -1, 'in': 0}, }, 'ic':{ -55: {'ex': 1, 'in': -1}, -70: {'ex': 1, 'in': 0}, }, } self.fit_precision = { 'amp': {'vc': 14, 'ic': 8}, 'exp_amp': {'vc': 14, 'ic': 8}, 'exp_tau': {'vc': 8, 'ic': 8}, 'decay_tau': {'vc': 8, 'ic': 8}, 'nrmse': {'vc': 2, 'ic': 2}, 'rise_time': {'vc': 7, 'ic': 6}, 'rise_power': {'vc': 0, 'ic': 0}, 'xoffset': {'vc': 7, 'ic': 7}, 'yoffset': {'vc': 5, 'ic': 14}, }
class DynamicsWindow(pg.QtGui.QSplitter): def __init__(self): pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.browser = ExperimentBrowser() self.addWidget(self.browser) self.plots = PlotGrid() self.addWidget(self.plots) self.browser.itemSelectionChanged.connect(self.browser_item_selected) def browser_item_selected(self): with pg.BusyCursor(): selected = self.browser.selectedItems() if len(selected) != 1: return item = selected[0] if not hasattr(item, 'pair'): return pair = item.pair self.load_pair(pair) def load_pair(self, pair): print("Loading:", pair) q = pulse_response_query(pair, data=True) self.sorted_recs = sorted_pulse_responses(q.all()) self.plot_all() def plot_all(self): self.plots.clear() self.plots.set_shape(len(self.sorted_recs), 1) psp = StackedPsp() stim_keys = sorted(list(self.sorted_recs.keys())) for i, stim_key in enumerate(stim_keys): prs = self.sorted_recs[stim_key] plt = self.plots[i, 0] plt.setTitle("%s %0.0f Hz %0.2f s" % stim_key) for recording in prs: pulses = sorted(list(prs[recording].keys())) for pulse_n in pulses: rec = prs[recording][pulse_n] # spike-align pulse + offset for pulse number spike_t = rec.stim_pulse.first_spike_time if spike_t is None: spike_t = rec.stim_pulse.onset_time + 1e-3 qc_pass = rec.pulse_response.in_qc_pass if rec.synapse.synapse_type == 'in' else rec.pulse_response.ex_qc_pass pen = (255, 255, 255, 100) if qc_pass else (100, 0, 0, 100) t0 = rec.pulse_response.data_start_time - spike_t ts = TSeries(data=rec.data, t0=t0, sample_rate=db.default_sample_rate) c = plt.plot(ts.time_values, ts.data, pen=pen) # arrange plots nicely shift = (pulse_n * 35e-3 + (30e-3 if pulse_n > 8 else 0), 0) c.setPos(*shift) if not qc_pass: c.setZValue(-10) continue # evaluate recorded fit for this response fit_par = rec.pulse_response_fit 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, ) c = plt.plot(ts.time_values, fit, pen=(0, 255, 0, 100)) c.setZValue(10) c.setPos(*shift)
class DynamicsWindow(pg.QtGui.QSplitter): def __init__(self): self.loaded_pair = None pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.ctrl_split = pg.QtGui.QSplitter(pg.QtCore.Qt.Vertical) self.addWidget(self.ctrl_split) self.browser = ExperimentBrowser() self.ctrl_split.addWidget(self.browser) self.ptree = pg.parametertree.ParameterTree() self.ctrl_split.addWidget(self.ptree) self.params = pg.parametertree.Parameter.create( name='params', type='group', children=[ { 'name': 'show spikes', 'type': 'bool', 'value': True }, { 'name': 'subtract baseline', 'type': 'bool', 'value': True }, { 'name': 'stimulus filter', 'type': 'group' }, ]) self.ptree.setParameters(self.params) self.scroll_area = pg.QtGui.QScrollArea() self.addWidget(self.scroll_area) self.view = pg.GraphicsLayoutWidget() self.scroll_area.setWidget(self.view) self.resize(1600, 1000) self.plots = [] self.browser.itemSelectionChanged.connect(self.browser_item_selected) self.params.sigTreeStateChanged.connect(self.plot_all) def clear(self): for plt in self.plots: self.view.removeItem(plt) self.plots = [] def browser_item_selected(self): with pg.BusyCursor(): selected = self.browser.selectedItems() if len(selected) != 1: return item = selected[0] if not hasattr(item, 'pair'): return pair = item.pair self.load_pair(pair) def load_pair(self, pair): if pair is not self.loaded_pair: print("Loading:", pair) q = pulse_response_query(pair, data=True, spike_data=True) self.sorted_recs = sorted_pulse_responses(q.all()) self.stim_keys = sorted(list(self.sorted_recs.keys())) self.update_params() self.loaded_pair = pair self.plot_all() def update_params(self): with pg.SignalBlock(self.params.sigTreeStateChanged, self.plot_all): stim_param = self.params.child('stimulus filter') for ch in stim_param.children(): stim_param.removeChild(ch) for k in self.stim_keys: param = pg.parametertree.Parameter.create(name=str(k), type="bool", value="True") stim_param.addChild(param) def plot_all(self): with pg.BusyCursor(): self.clear() show_spikes = self.params['show spikes'] for i, stim_key in enumerate(self.stim_keys): if self.params['stimulus filter', str(stim_key)] is False: continue plt = DynamicsPlot() self.plots.append(plt) self.view.addItem(plt) self.view.nextRow() plt.set_title("%s %0.0f Hz %0.2f s" % stim_key) prs = self.sorted_recs[stim_key] plt.set_data( prs, show_spikes=show_spikes, subtract_baseline=self.params['subtract baseline']) plt_height = max(400 if show_spikes else 250, self.scroll_area.height() / len(self.stim_keys)) self.view.setFixedHeight(plt_height * len(self.plots)) self.view.setFixedWidth( self.scroll_area.width() - self.scroll_area.verticalScrollBar().width())
def __init__(self): self.loaded_pair = None pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.ctrl_split = pg.QtGui.QSplitter(pg.QtCore.Qt.Vertical) self.addWidget(self.ctrl_split) self.browser = ExperimentBrowser() self.ctrl_split.addWidget(self.browser) self.scatter_plot = pg.ScatterPlotWidget() self.ctrl_split.addWidget(self.scatter_plot.ctrlPanel) self.addWidget(self.scatter_plot.plot) # Select all fields to be displayed fields = { 'pulse_response_id': { 'column': db.PulseResponse.id, 'mode': 'range', 'dtype': int }, 'clamp_mode': { 'column': db.PatchClampRecording.clamp_mode, 'mode': 'enum', 'values': ['ic', 'vc'], 'dtype': object }, 'pulse_number': { 'column': db.StimPulse.pulse_number, 'mode': 'enum', 'values': list(range(1, 13)), 'dtype': int }, 'induction_frequency': { 'column': db.MultiPatchProbe.induction_frequency, 'mode': 'range', 'dtype': float }, 'recovery_delay': { 'column': db.MultiPatchProbe.recovery_delay, 'mode': 'range', 'dtype': float }, 'baseline_current': { 'column': db.PatchClampRecording.baseline_current, 'mode': 'range', 'dtype': float }, 'baseline_potential': { 'column': db.PatchClampRecording.baseline_potential, 'mode': 'range', 'dtype': float }, 'baseline_rms_noise': { 'column': db.PatchClampRecording.baseline_rms_noise, 'mode': 'range', 'dtype': float }, 'recording_qc_pass': { 'column': db.PatchClampRecording.qc_pass, 'mode': 'enum', 'values': [True, False], 'dtype': bool }, } for table, prefix in [(db.PulseResponse, ''), (db.PulseResponseFit, ''), (db.PulseResponseStrength, '')]: for name, col in table.__table__.c.items(): if name.endswith('_id'): continue colname = name if name == 'id': name = table.__table__.name + '_id' else: name = prefix + name if isinstance( col.type, (sqltypes.Integer, sqltypes.Float, database.FloatType)): fields[name] = {'mode': 'range', 'dtype': float} elif isinstance(col.type, sqltypes.String): fields[name] = {'mode': 'enum', 'dtype': object} elif isinstance(col.type, sqltypes.Boolean): fields[name] = { 'mode': 'enum', 'values': [True, False], 'dtype': bool } else: continue fields[name]['column'] = getattr(table, colname) self.fields = fields # set up scatter plot fields sp_fields = [] self.dtype = [] for name, spec in fields.items(): if spec['mode'] == 'enum': sp_fields.append((name, { 'mode': 'enum', 'values': spec['values'] })) else: sp_fields.append((name, {'mode': 'range'})) self.dtype.append((name, spec['dtype'])) self.scatter_plot.setFields(sp_fields) # default filter for IC data cm_filter = self.scatter_plot.filter.addNew('clamp_mode') cm_filter['vc'] = False # default color by nrmse nrmse_color = self.scatter_plot.colorMap.addNew('fit_nrmse') qc_color = self.scatter_plot.colorMap.addNew('ex_qc_pass') qc_color['Values', 'True'] = (255, 255, 255) qc_color['Values', 'False'] = (0, 0, 0) qc_color['Operation'] = 'Multiply' self.view = pg.GraphicsLayoutWidget() self.addWidget(self.view) self.spike_plots = [ self.view.addPlot(row=0, col=0), self.view.addPlot(row=0, col=1) ] self.data_plots = [ self.view.addPlot(row=1, col=0), self.view.addPlot(row=1, col=1) ] self.dec_plots = [ self.view.addPlot(row=2, col=0), self.view.addPlot(row=2, col=1) ] for col in (0, 1): self.spike_plots[col].setXLink(self.data_plots[0]) self.data_plots[col].setXLink(self.data_plots[0]) self.dec_plots[col].setXLink(self.data_plots[0]) self.spike_plots[1].setYLink(self.spike_plots[0]) self.data_plots[1].setYLink(self.data_plots[0]) self.dec_plots[1].setYLink(self.dec_plots[0]) self.resize(1600, 1000) self.browser.itemSelectionChanged.connect(self.browser_item_selected) self.scatter_plot.sigScatterPlotClicked.connect( self.scatter_plot_clicked)
class SynapseEventWindow(pg.QtGui.QSplitter): def __init__(self): self.loaded_pair = None pg.QtGui.QSplitter.__init__(self, pg.QtCore.Qt.Horizontal) self.ctrl_split = pg.QtGui.QSplitter(pg.QtCore.Qt.Vertical) self.addWidget(self.ctrl_split) self.browser = ExperimentBrowser() self.ctrl_split.addWidget(self.browser) self.scatter_plot = pg.ScatterPlotWidget() self.ctrl_split.addWidget(self.scatter_plot.ctrlPanel) self.addWidget(self.scatter_plot.plot) # Select all fields to be displayed fields = { 'pulse_response_id': { 'column': db.PulseResponse.id, 'mode': 'range', 'dtype': int }, 'clamp_mode': { 'column': db.PatchClampRecording.clamp_mode, 'mode': 'enum', 'values': ['ic', 'vc'], 'dtype': object }, 'pulse_number': { 'column': db.StimPulse.pulse_number, 'mode': 'enum', 'values': list(range(1, 13)), 'dtype': int }, 'induction_frequency': { 'column': db.MultiPatchProbe.induction_frequency, 'mode': 'range', 'dtype': float }, 'recovery_delay': { 'column': db.MultiPatchProbe.recovery_delay, 'mode': 'range', 'dtype': float }, 'baseline_current': { 'column': db.PatchClampRecording.baseline_current, 'mode': 'range', 'dtype': float }, 'baseline_potential': { 'column': db.PatchClampRecording.baseline_potential, 'mode': 'range', 'dtype': float }, 'baseline_rms_noise': { 'column': db.PatchClampRecording.baseline_rms_noise, 'mode': 'range', 'dtype': float }, 'recording_qc_pass': { 'column': db.PatchClampRecording.qc_pass, 'mode': 'enum', 'values': [True, False], 'dtype': bool }, } for table, prefix in [(db.PulseResponse, ''), (db.PulseResponseFit, ''), (db.PulseResponseStrength, '')]: for name, col in table.__table__.c.items(): if name.endswith('_id'): continue colname = name if name == 'id': name = table.__table__.name + '_id' else: name = prefix + name if isinstance( col.type, (sqltypes.Integer, sqltypes.Float, database.FloatType)): fields[name] = {'mode': 'range', 'dtype': float} elif isinstance(col.type, sqltypes.String): fields[name] = {'mode': 'enum', 'dtype': object} elif isinstance(col.type, sqltypes.Boolean): fields[name] = { 'mode': 'enum', 'values': [True, False], 'dtype': bool } else: continue fields[name]['column'] = getattr(table, colname) self.fields = fields # set up scatter plot fields sp_fields = [] self.dtype = [] for name, spec in fields.items(): if spec['mode'] == 'enum': sp_fields.append((name, { 'mode': 'enum', 'values': spec['values'] })) else: sp_fields.append((name, {'mode': 'range'})) self.dtype.append((name, spec['dtype'])) self.scatter_plot.setFields(sp_fields) # default filter for IC data cm_filter = self.scatter_plot.filter.addNew('clamp_mode') cm_filter['vc'] = False # default color by nrmse nrmse_color = self.scatter_plot.colorMap.addNew('fit_nrmse') qc_color = self.scatter_plot.colorMap.addNew('ex_qc_pass') qc_color['Values', 'True'] = (255, 255, 255) qc_color['Values', 'False'] = (0, 0, 0) qc_color['Operation'] = 'Multiply' self.view = pg.GraphicsLayoutWidget() self.addWidget(self.view) self.spike_plots = [ self.view.addPlot(row=0, col=0), self.view.addPlot(row=0, col=1) ] self.data_plots = [ self.view.addPlot(row=1, col=0), self.view.addPlot(row=1, col=1) ] self.dec_plots = [ self.view.addPlot(row=2, col=0), self.view.addPlot(row=2, col=1) ] for col in (0, 1): self.spike_plots[col].setXLink(self.data_plots[0]) self.data_plots[col].setXLink(self.data_plots[0]) self.dec_plots[col].setXLink(self.data_plots[0]) self.spike_plots[1].setYLink(self.spike_plots[0]) self.data_plots[1].setYLink(self.data_plots[0]) self.dec_plots[1].setYLink(self.dec_plots[0]) self.resize(1600, 1000) self.browser.itemSelectionChanged.connect(self.browser_item_selected) self.scatter_plot.sigScatterPlotClicked.connect( self.scatter_plot_clicked) def browser_item_selected(self): with pg.BusyCursor(): selected = self.browser.selectedItems() if len(selected) != 1: return item = selected[0] if not hasattr(item, 'pair'): return pair = item.pair self.load_pair(pair) def load_pair(self, pair): if pair is not self.loaded_pair: print("Loading:", pair) self.loaded_pair = pair # Load data for scatter plot cols = [ spec['column'].label(name) for name, spec in self.fields.items() ] q = db.query(*cols) q = q.outerjoin( db.PulseResponseFit, db.PulseResponseFit.pulse_response_id == db.PulseResponse.id) q = q.outerjoin( db.PulseResponseStrength, db.PulseResponseStrength.pulse_response_id == db.PulseResponse.id) q = q.join(db.StimPulse, db.PulseResponse.stim_pulse) q = q.join(db.Recording, db.PulseResponse.recording_id == db.Recording.id) q = q.join(db.PatchClampRecording, db.PatchClampRecording.recording_id == db.Recording.id) q = q.join(db.MultiPatchProbe) q = q.filter(db.PulseResponse.pair_id == pair.id) recs = q.all() print("loaded %d/%s pulse responses" % (len(recs), len(pair.pulse_responses))) self.loaded_recs = recs data = np.empty(len(recs), dtype=self.dtype) for i, rec in enumerate(recs): for name, spec in self.dtype: data[i][name] = getattr(rec, name) self.loaded_data = data self.scatter_plot.setData(data) def scatter_plot_clicked(self, plt, points): for plt in self.data_plots + self.dec_plots + self.spike_plots: plt.clear() # query raw data for selected points ids = [int(pt.data()['pulse_response_id']) for pt in points] q = db.query(db.PulseResponse, db.PulseResponse.data, db.PulseResponseFit).outerjoin( db.PulseResponseFit).filter( db.PulseResponse.id.in_(ids)) recs = q.all() print("Selected pulse responses:") for rec in recs: print(rec.PulseResponse.id, rec.PulseResponse.meta) self._plot_pulse_response(rec) self.scatter_plot.setSelectedPoints(points) def _plot_pulse_response(self, rec): pr = rec.PulseResponse base_ts = pr.get_tseries('baseline', align_to='spike') if base_ts is not None: self.data_plots[1].plot(base_ts.time_values, base_ts.data) pre_ts = pr.get_tseries('pre', align_to='spike') # If there is no presynaptic spike time, plot spike in red and bail out if pre_ts is None: pre_ts = pr.get_tseries('pre', align_to='pulse') self.spike_plots[0].plot(pre_ts.time_values, pre_ts.data, pen=(255, 0, 0, 100)) return post_ts = pr.get_tseries('post', align_to='spike') self.spike_plots[0].plot(pre_ts.time_values, pre_ts.data) self.data_plots[0].plot(post_ts.time_values, post_ts.data) # evaluate recorded fit for this response fit_par = rec.PulseResponseFit # If there is no fit, bail out here if fit_par is None: return spsp = StackedPsp() fit = spsp.eval( x=post_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, ) self.data_plots[0].plot(post_ts.time_values, fit, pen=(0, 255, 0, 100)) # plot with reconvolved amplitude fit = spsp.eval( x=post_ts.time_values, exp_amp=fit_par.fit_exp_amp, exp_tau=fit_par.fit_decay_tau, amp=fit_par.dec_fit_reconv_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, ) self.data_plots[0].plot(post_ts.time_values, fit, pen=(200, 255, 0, 100)) # plot deconvolution clamp_mode = pr.recording.patch_clamp_recording.clamp_mode if clamp_mode == 'ic': decay_tau = self.loaded_pair.synapse.psp_decay_tau lowpass = 2000 else: decay_tau = self.loaded_pair.synapse.psc_decay_tau lowpass = 6000 dec = deconv_filter(post_ts, None, tau=decay_tau, lowpass=lowpass, remove_artifacts=False, bsub=True) self.dec_plots[0].plot(dec.time_values, dec.data) # plot deconvolution fit psp = Psp() fit = psp.eval( x=dec.time_values, exp_tau=fit_par.dec_fit_decay_tau, amp=fit_par.dec_fit_amp, rise_time=fit_par.dec_fit_rise_time, decay_tau=fit_par.dec_fit_decay_tau, xoffset=fit_par.dec_fit_latency, yoffset=fit_par.dec_fit_yoffset, rise_power=1, ) self.dec_plots[0].plot(dec.time_values, fit, pen=(0, 255, 0, 100))