Example #1
0
    def __init__(self):
        # set up simulation in remote process
        self.dt = 25*us
        self.proc = mp.QtProcess(debug=False)
        ndemo = self.proc._import('neurodemo')
        self.sim = ndemo.Sim(temp=6.3, dt=self.dt)
        self.sim._setProxyOptions(deferGetattr=True)
        self.neuron = ndemo.Section(name='soma')
        self.sim.add(self.neuron)
        
        self.hhna = self.neuron.add(ndemo.HHNa())
        self.leak = self.neuron.add(ndemo.Leak())
        self.hhk = self.neuron.add(ndemo.HHK())
        self.dexh = self.neuron.add(ndemo.IH())
        self.dexh.enabled = False
        
        self.clamp = self.neuron.add(ndemo.PatchClamp(mode='ic'))
        #cmd = np.zeros(int(1/self.dt))
        #cmd[int(0.4/self.dt):int(0.8/self.dt)] = 200e-12
        #self.clamp.set_command(cmd, dt=self.dt)
        
        mechanisms = [self.clamp, self.hhna, self.leak, self.hhk, self.dexh]

        # loop to run the simulation indefinitely
        self.runner = ndemo.SimRunner(self.sim)
        #self.runner.add_request('soma.Vm') 
        self.runner.add_request('t') 
        self.runner.new_result.connect(mp.proxy(self.new_result, autoProxy=False, callSync='off'))

        
        # set up GUI
        QtGui.QWidget.__init__(self)
        self.fullscreen_widget = None
        self.resize(1024, 768)
        self.layout = QtGui.QGridLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        
        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
        self.layout.addWidget(self.splitter, 0, 0)
        
        self.ptree = pt.ParameterTree(showHeader=False)
        self.splitter.addWidget(self.ptree)
        
        self.plot_splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
        self.splitter.addWidget(self.plot_splitter)
        
        self.neuronview = NeuronView(self.neuron, mechanisms)
        self.plot_splitter.addWidget(self.neuronview)
        
        #self.vm_plot = ScrollingPlot(dt=self.dt, npts=int(1.0/self.dt),
                                         #parent=self, labels={'left': ('Membrane Potential', 'V'), 
                                                              #'bottom': ('Time', 's')})
        #self.vm_plot.setYRange(-90*mV, 50*mV)
        #self.vm_plot.setXRange(-1000*ms, 0*ms)
        #self.vm_plot.addLine(y=self.neuron.ek)
        #self.vm_plot.addLine(y=self.neuron.ena)
        #self.plot_splitter.addWidget(self.vm_plot)
        self.channel_plots = {}
        
        
        self.channel_params = [
            ChannelParameter(self.leak),
            ChannelParameter(self.hhna),
            ChannelParameter(self.hhk),
            ChannelParameter(self.dexh),
        ]
        for ch in self.channel_params:
            ch.plots_changed.connect(self.plots_changed)

        self.clamp_param = ClampParameter(self.clamp, self)
        self.clamp_param.plots_changed.connect(self.plots_changed)


        self.vm_plot = self.add_plot('soma.V', 'Membrane Potential', 'V')
        
        self.splitter.setSizes([350, 650])

        self.show()

        
        self.params = pt.Parameter.create(name='params', type='group', children=[
            dict(name='Preset', type='list', values=['', 'Passive Membrane', 'Action Potential']),
            dict(name='Run', type='bool', value=True),
            dict(name='Speed', type='float', value=0.3, limits=[0, 10], step=1, dec=True),
            dict(name='Temp', type='float', value=self.sim.temp, suffix='C', step=1.0),
            dict(name='Capacitance', type='float', value=self.neuron.cap, suffix='F', siPrefix=True, dec=True),
            dict(name='Cell Schematic', type='bool', value=True, children=[
                dict(name='Show Circuit', type='bool', value=False),
            ]),
            self.clamp_param,
            dict(name='Ion Channels', type='group', children=self.channel_params),
        ])
        self.ptree.setParameters(self.params)
        self.params.sigTreeStateChanged.connect(self.params_changed)
        
        self.start()

        self.clamp_param['Plot Current'] = True
        self.plot_splitter.setSizes([300, 500, 200])
        
        self.pause_shortcut = QtGui.QShortcut(QtGui.QKeySequence('Space'), self)
        self.pause_shortcut.activated.connect(self.pause)
        self.slow_shortcut = QtGui.QShortcut(QtGui.QKeySequence('-'), self)
        self.slow_shortcut.activated.connect(self.slower)
        self.fast_shortcut = QtGui.QShortcut(QtGui.QKeySequence('='), self)
        self.fast_shortcut.activated.connect(self.faster)
        self.fullscreen_shortcut = QtGui.QShortcut(QtGui.QKeySequence('F11'), self)
        self.fullscreen_shortcut.activated.connect(self.fullscreen)
        self.fullscreen_shortcut.setContext(QtCore.Qt.ApplicationShortcut)
Example #2
0
class DemoWindow(QtGui.QWidget):
    def __init__(self):
        # set up simulation in remote process
        self.dt = 25*us
        self.proc = mp.QtProcess(debug=False)
        ndemo = self.proc._import('neurodemo')
        self.sim = ndemo.Sim(temp=6.3, dt=self.dt)
        self.sim._setProxyOptions(deferGetattr=True)
        self.neuron = ndemo.Section(name='soma')
        self.sim.add(self.neuron)
        
        self.hhna = self.neuron.add(ndemo.HHNa())
        self.leak = self.neuron.add(ndemo.Leak())
        self.hhk = self.neuron.add(ndemo.HHK())
        self.dexh = self.neuron.add(ndemo.IH())
        self.dexh.enabled = False
        
        self.clamp = self.neuron.add(ndemo.PatchClamp(mode='ic'))
        #cmd = np.zeros(int(1/self.dt))
        #cmd[int(0.4/self.dt):int(0.8/self.dt)] = 200e-12
        #self.clamp.set_command(cmd, dt=self.dt)
        
        mechanisms = [self.clamp, self.hhna, self.leak, self.hhk, self.dexh]

        # loop to run the simulation indefinitely
        self.runner = ndemo.SimRunner(self.sim)
        #self.runner.add_request('soma.Vm') 
        self.runner.add_request('t') 
        self.runner.new_result.connect(mp.proxy(self.new_result, autoProxy=False, callSync='off'))

        
        # set up GUI
        QtGui.QWidget.__init__(self)
        self.fullscreen_widget = None
        self.resize(1024, 768)
        self.layout = QtGui.QGridLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)
        
        self.splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
        self.layout.addWidget(self.splitter, 0, 0)
        
        self.ptree = pt.ParameterTree(showHeader=False)
        self.splitter.addWidget(self.ptree)
        
        self.plot_splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
        self.splitter.addWidget(self.plot_splitter)
        
        self.neuronview = NeuronView(self.neuron, mechanisms)
        self.plot_splitter.addWidget(self.neuronview)
        
        #self.vm_plot = ScrollingPlot(dt=self.dt, npts=int(1.0/self.dt),
                                         #parent=self, labels={'left': ('Membrane Potential', 'V'), 
                                                              #'bottom': ('Time', 's')})
        #self.vm_plot.setYRange(-90*mV, 50*mV)
        #self.vm_plot.setXRange(-1000*ms, 0*ms)
        #self.vm_plot.addLine(y=self.neuron.ek)
        #self.vm_plot.addLine(y=self.neuron.ena)
        #self.plot_splitter.addWidget(self.vm_plot)
        self.channel_plots = {}
        
        
        self.channel_params = [
            ChannelParameter(self.leak),
            ChannelParameter(self.hhna),
            ChannelParameter(self.hhk),
            ChannelParameter(self.dexh),
        ]
        for ch in self.channel_params:
            ch.plots_changed.connect(self.plots_changed)

        self.clamp_param = ClampParameter(self.clamp, self)
        self.clamp_param.plots_changed.connect(self.plots_changed)


        self.vm_plot = self.add_plot('soma.V', 'Membrane Potential', 'V')
        
        self.splitter.setSizes([350, 650])

        self.show()

        
        self.params = pt.Parameter.create(name='params', type='group', children=[
            dict(name='Preset', type='list', values=['', 'Passive Membrane', 'Action Potential']),
            dict(name='Run', type='bool', value=True),
            dict(name='Speed', type='float', value=0.3, limits=[0, 10], step=1, dec=True),
            dict(name='Temp', type='float', value=self.sim.temp, suffix='C', step=1.0),
            dict(name='Capacitance', type='float', value=self.neuron.cap, suffix='F', siPrefix=True, dec=True),
            dict(name='Cell Schematic', type='bool', value=True, children=[
                dict(name='Show Circuit', type='bool', value=False),
            ]),
            self.clamp_param,
            dict(name='Ion Channels', type='group', children=self.channel_params),
        ])
        self.ptree.setParameters(self.params)
        self.params.sigTreeStateChanged.connect(self.params_changed)
        
        self.start()

        self.clamp_param['Plot Current'] = True
        self.plot_splitter.setSizes([300, 500, 200])
        
        self.pause_shortcut = QtGui.QShortcut(QtGui.QKeySequence('Space'), self)
        self.pause_shortcut.activated.connect(self.pause)
        self.slow_shortcut = QtGui.QShortcut(QtGui.QKeySequence('-'), self)
        self.slow_shortcut.activated.connect(self.slower)
        self.fast_shortcut = QtGui.QShortcut(QtGui.QKeySequence('='), self)
        self.fast_shortcut.activated.connect(self.faster)
        self.fullscreen_shortcut = QtGui.QShortcut(QtGui.QKeySequence('F11'), self)
        self.fullscreen_shortcut.activated.connect(self.fullscreen)
        self.fullscreen_shortcut.setContext(QtCore.Qt.ApplicationShortcut)

    def params_changed(self, root, changes):
        for param, change, val in changes:
            if change != 'value':
                continue
            if param is self.params.child('Run'):
                if val:
                    self.start()
                else:
                    self.stop()
            elif param is self.params.child('Speed'):
                self.runner.set_speed(val)
            elif param is self.params.child('Temp'):
                self.sim.temp = val
            elif param is self.params.child('Capacitance'):
                self.neuron.cap = val
            elif param is self.params.child('Preset'):
                self.load_preset(val)
            elif param is self.params.child('Cell Schematic'):
                self.neuronview.setVisible(val)
            elif param is self.params.child('Cell Schematic', 'Show Circuit'):
                self.neuronview.show_circuit(val)
        
    def plots_changed(self, param, channel, name, plot):
        key = channel.name + '.' + name
        if plot:
            self.add_plot(key, param.name(), name)
        else:
            self.remove_plot(key)

    def add_plot(self, key, pname, name):
        # decide on y range, label, and units for new plot
        yranges = {
            'V': (-100*mV, 50*mV),
            'I': (-1*nA, 1*nA),
            'G': (0, 100*nS),
            'OP': (0, 1),
            'm': (0, 1),
            'h': (0, 1),
            'n': (0, 1),
        }
        color = {'I': 'c', 'G': 'y', 'OP': 'g', 'V': 'w'}.get(name, 0.7)
        units = {'I': 'A', 'G': 'S', 'V': 'V'}
        label = pname + ' ' + name
        if name in units:
            label = (label, units[name])
            
        # create new plot
        plt = ScrollingPlot(dt=self.dt, npts=int(1.0 / self.dt),
                            labels={'left': label}, pen=color)
        if hasattr(self, 'vm_plot'):
            plt.setXLink(self.vm_plot)
        else:
            plt.setXRange(-1, 0)
        plt.setYRange(*yranges.get(name, (0, 1)))
        
        # register this plot for later..
        self.channel_plots[key] = plt
        self.runner.add_request(key)
        
        # add new plot to splitter and resize all accordingly
        sizes = self.plot_splitter.sizes()
        self.plot_splitter.addWidget(plt)
        size = self.plot_splitter.height() / (len(sizes) + 1.)
        r = len(sizes) / (len(sizes)+1)
        sizes = [s * r for s in sizes] + [size]
        self.plot_splitter.setSizes(sizes)
        
        # Ask sequence plotter to update as well
        self.clamp_param.add_plot(key, label)
        return plt
            
    def remove_plot(self, key):
        plt = self.channel_plots.pop(key)
        self.runner.remove_request(key)
        self.clamp_param.remove_plot(key)
        plt.setParent(None)
        plt.close()
        
    def start(self):
        self.runner.start(blocksize=100)
        
    def stop(self):
        self.runner.stop()
        
    def pause(self):
        self.params['Run'] = not self.params['Run']

    def slower(self):
        self.params['Speed'] *= 0.5
        
    def faster(self):
        self.params['Speed'] = min(self.params['Speed'] * 2.0, 10)

    def fullscreen(self):
        if self.fullscreen_widget is None:
            w = QtGui.QApplication.focusWidget()
            ind = self.plot_splitter.indexOf(w)
            if ind < 0:
                return
            self.fs_widget_index = ind
            w.setParent(None)
            w.showFullScreen()
            self.fullscreen_widget = w
        else:
            self.fullscreen_widget.showNormal()
            self.plot_splitter.insertWidget(self.fs_widget_index, self.fullscreen_widget)
            self.fullscreen_widget = None
        
    def new_result(self, final_state, result):
        for k, plt in self.channel_plots.items():
            if k not in result:
                continue
            plt.append(result[k][1:])
            
        # Let the clamp decide which triggered regions of the data to extract
        # for pulse plots
        self.clamp_param.new_result(result)
        
        # update the schematic
        self.neuronview.update_state(final_state)

    def load_preset(self, preset):
        if preset == 'Passive Membrane':
            self.params['Temp'] = 6.3
            self.params['Speed'] = 0.05
            self.params['Patch Clamp', 'Plot Current'] = False
            self.params['Patch Clamp', 'Plot Voltage'] = False
            chans = self.params.child('Ion Channels')
            chans['soma.Ileak'] = True
            chans['soma.Ileak', 'Erev'] = 0
            chans['soma.INa'] = False
            chans['soma.IK'] = False
            chans['soma.IH'] = False
        elif preset == 'Action Potential':
            self.params['Temp'] = 6.3
            self.params['Speed'] = 0.05
            chans = self.params.child('Ion Channels')
            chans['soma.Ileak'] = True
            chans['soma.Ileak', 'Erev'] = -55*mV
            chans['soma.INa'] = True
            chans['soma.IK'] = True
            chans['soma.IH'] = False
            
        self.params['Preset'] = ''

    def closeEvent(self, ev):
        self.runner.stop()
        self.proc.close()
        QtGui.QApplication.instance().quit()