Example #1
0
    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)
Example #3
0
    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)
Example #4
0
    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)
Example #6
0
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())
Example #7
0
    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)
Example #8
0
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))