You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
10 KiB
313 lines
10 KiB
2 years ago
|
#!/usr/bin/python
|
||
|
"""
|
||
|
Basic test of initialization of multiple cells in the model, and running multiple cells at one time.
|
||
|
Plots the resposnes to a series of current injections for most implemented baseic cell types in
|
||
|
in cnmodel.
|
||
|
|
||
|
Usage:
|
||
|
python examples/toy_model.py (no arguments)
|
||
|
|
||
|
"""
|
||
|
|
||
|
from __future__ import print_function
|
||
|
|
||
|
|
||
|
import sys
|
||
|
from neuron import h
|
||
|
import numpy as np
|
||
|
import cnmodel.cells as cells
|
||
|
from cnmodel.protocols import Protocol
|
||
|
from cnmodel.util import custom_init
|
||
|
from collections import OrderedDict
|
||
|
import re
|
||
|
import pyqtgraph.exporters
|
||
|
from cnmodel.util import pyqtgraphPlotHelpers as PH
|
||
|
from cnmodel.protocols import IVCurve
|
||
|
|
||
|
|
||
|
try: # check for pyqtgraph install
|
||
|
import pyqtgraph as pg
|
||
|
except ImportError:
|
||
|
raise ImportError("This model requires pyqtgraph")
|
||
|
|
||
|
from cnmodel.util.stim import make_pulse
|
||
|
|
||
|
|
||
|
def autorowcol(n):
|
||
|
"""
|
||
|
return a reasonable layout (cols, rows) for n plots on a page
|
||
|
up to 16.
|
||
|
Otherwise return floor(sqrt(n)) + 1 for both r and c.
|
||
|
"""
|
||
|
nmap = {
|
||
|
1: (1, 1),
|
||
|
2: (2, 1),
|
||
|
3: (3, 1),
|
||
|
4: (2, 2),
|
||
|
5: (3, 2),
|
||
|
6: (3, 2),
|
||
|
7: (3, 3),
|
||
|
8: (3, 3),
|
||
|
9: (3, 3),
|
||
|
10: (3, 4),
|
||
|
11: (3, 4),
|
||
|
12: (3, 4),
|
||
|
13: (4, 4),
|
||
|
14: (4, 4),
|
||
|
15: (4, 4),
|
||
|
16: (4, 4),
|
||
|
}
|
||
|
if n <= 16:
|
||
|
return nmap[n][0], nmap[n][1]
|
||
|
else:
|
||
|
nx = np.floor(np.sqrt(n)) + 1
|
||
|
return nx, nx
|
||
|
|
||
|
|
||
|
def makeLayout(cols=1, rows=1, letters=True, margins=4, spacing=4, nmax=None):
|
||
|
"""
|
||
|
Create a multipanel plot, returning the various pyptgraph elements.
|
||
|
The layout is always a rectangular grid with shape (cols, rows)
|
||
|
if letters is true, then the plot is labeled "A, B, C..."
|
||
|
margins sets the margins around the outside of the plot
|
||
|
spacing sets the spacing between the elements of the grid
|
||
|
"""
|
||
|
import string
|
||
|
|
||
|
letters = string.ascii_uppercase
|
||
|
widget = pg.QtGui.QWidget()
|
||
|
gridLayout = pg.QtGui.QGridLayout()
|
||
|
widget.setLayout(gridLayout)
|
||
|
gridLayout.setContentsMargins(margins, margins, margins, margins)
|
||
|
gridLayout.setSpacing(spacing)
|
||
|
plots = [[0 for x in range(cols)] for x in range(rows)]
|
||
|
i = 0
|
||
|
for c in range(cols):
|
||
|
for r in range(rows):
|
||
|
plots[r][c] = pg.PlotWidget()
|
||
|
gridLayout.addWidget(plots[r][c], r, c)
|
||
|
# labelUp(plots[r][c], 'T(s)', 'Y', title = letters[i])
|
||
|
i += 1
|
||
|
if i > 25:
|
||
|
i = 0
|
||
|
if nmax is not None and i >= nmax:
|
||
|
break # that's all - leave out empty plots
|
||
|
|
||
|
return (plots, widget, gridLayout)
|
||
|
|
||
|
|
||
|
def getnextrowcol(plx, row, col, cols):
|
||
|
col += 1
|
||
|
if col >= cols:
|
||
|
col = 0
|
||
|
row += 1
|
||
|
return (plx[row][col], row, col)
|
||
|
|
||
|
|
||
|
class Toy(Protocol):
|
||
|
"""
|
||
|
Calls to encapsulate the model runs
|
||
|
Run a set of cells with defined parameters to show excitability patterns.
|
||
|
Note that cells from Rothman and Manis are run at 22C; others at various
|
||
|
temperatures depending on how they were initially measured and defined.
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self):
|
||
|
super(Toy, self).__init__()
|
||
|
|
||
|
def current_name(self, name, n):
|
||
|
"""
|
||
|
From the name of the current model, get the current injection information
|
||
|
|
||
|
Parameters
|
||
|
---------
|
||
|
name : str (no default)
|
||
|
name of the cell type
|
||
|
n : int (no default)
|
||
|
"""
|
||
|
if len(self.celltypes[name][3]) > 2:
|
||
|
injs = self.celltypes[name][3]
|
||
|
injarr = np.linspace(injs[0], injs[1], injs[2], endpoint=True)
|
||
|
return "%.3f" % injarr[n]
|
||
|
else:
|
||
|
return "%.3f" % self.celltypes[name][3][n]
|
||
|
|
||
|
def getname(self, cell, ninj):
|
||
|
name = self.make_name(cell)
|
||
|
iname = self.current_name(name, ninj)
|
||
|
nname = name + " " + iname
|
||
|
return name, nname
|
||
|
|
||
|
def make_name(self, cell):
|
||
|
return cell + ", " + self.celltypes[cell][1] + ":"
|
||
|
|
||
|
def run(self):
|
||
|
sre = re.compile(
|
||
|
"(?P<cell>\w+)(?:[, ]*)(?P<type>[\w-]*)(?:[, ]*)(?P<species>[\w-]*)"
|
||
|
) # regex for keys in cell types
|
||
|
self.celltypes = OrderedDict(
|
||
|
[
|
||
|
("Bushy, II", (cells.Bushy, "II", "guineapig", (-0.5, 0.5, 11), 22)),
|
||
|
(
|
||
|
"Bushy, II-I",
|
||
|
(cells.Bushy, "II-I", "guineapig", (-0.5, 0.5, 11), 22),
|
||
|
),
|
||
|
(
|
||
|
"DStellate, I-II",
|
||
|
(cells.DStellate, "I-II", "guineapig", (-0.3, 0.3, 9), 22),
|
||
|
),
|
||
|
(
|
||
|
"TStellate, I-c",
|
||
|
(cells.TStellate, "I-c", "guineapig", (-0.15, 0.15, 9), 22),
|
||
|
),
|
||
|
(
|
||
|
"TStellate, I-t",
|
||
|
(cells.TStellate, "I-t", "guineapig", (-0.15, 0.15, 9), 22),
|
||
|
),
|
||
|
(
|
||
|
"Octopus, II-o",
|
||
|
(cells.Octopus, "II-o", "guineapig", (-2.5, 2.5, 11), 22),
|
||
|
),
|
||
|
("Bushy, II, Mouse", (cells.Bushy, "II", "mouse", (-1, 1.2, 13), 34)),
|
||
|
(
|
||
|
"TStellate, I-c, Mouse",
|
||
|
(cells.TStellate, "I-c", "mouse", (-1, 1, 9), 34),
|
||
|
),
|
||
|
(
|
||
|
"DStellate, I-II, Mouse",
|
||
|
(cells.DStellate, "I-II", "mouse", (-0.5, 0.5, 9), 34),
|
||
|
),
|
||
|
(
|
||
|
"Pyramidal, I, Rat",
|
||
|
(cells.Pyramidal, "I", "rat", (-0.3, 0.4, 11), 34),
|
||
|
),
|
||
|
(
|
||
|
"Cartwheel, I, Mouse",
|
||
|
(cells.Cartwheel, "I", "mouse", (-0.5, 0.5, 9), 34),
|
||
|
),
|
||
|
(
|
||
|
"Tuberculoventral, I, Mouse",
|
||
|
(cells.Tuberculoventral, "I", "mouse", (-0.35, 1, 11), 34),
|
||
|
),
|
||
|
("SGC, bm, Mouse", (cells.SGC, "bm", "mouse", (-0.2, 0.6, 9), 34)),
|
||
|
("SGC, a, Mouse", (cells.SGC, "a", "mouse", (-0.2, 0.6, 9), 34)),
|
||
|
]
|
||
|
)
|
||
|
|
||
|
dt = 0.025
|
||
|
h.dt = dt
|
||
|
h.celsius = 22
|
||
|
|
||
|
stim = {"NP": 1, "delay": 10, "dur": 100, "amp": 0.0, "dt": h.dt}
|
||
|
tend = stim["delay"] + stim["dur"] + 20.0
|
||
|
|
||
|
netcells = {}
|
||
|
for c in list(self.celltypes.keys()):
|
||
|
g = sre.match(c)
|
||
|
cellname = g.group("cell")
|
||
|
modelType = g.group("type")
|
||
|
species = self.celltypes[c][2]
|
||
|
if g.group("type") == "":
|
||
|
netcells[c] = self.celltypes[c][0].create()
|
||
|
else:
|
||
|
netcells[c] = self.celltypes[c][0].create(
|
||
|
modelType=modelType, species=species, debug=False
|
||
|
)
|
||
|
# dicts to hold data
|
||
|
pl = OrderedDict([])
|
||
|
pl2 = OrderedDict([])
|
||
|
rvec = OrderedDict([])
|
||
|
vec = OrderedDict([])
|
||
|
istim = OrderedDict([])
|
||
|
ncells = len(list(self.celltypes.keys()))
|
||
|
#
|
||
|
# build plotting area
|
||
|
#
|
||
|
app = pg.mkQApp()
|
||
|
self.win = pg.GraphicsWindow()
|
||
|
self.win.setBackground("w")
|
||
|
self.win.resize(800, 600)
|
||
|
cols, rows = autorowcol(ncells)
|
||
|
|
||
|
row = 0
|
||
|
col = 0
|
||
|
labelStyle = {"color": "#000", "font-size": "9pt", "weight": "normal"}
|
||
|
tickStyle = pg.QtGui.QFont("Arial", 9, pg.QtGui.QFont.Light)
|
||
|
self.iv = IVCurve() # use standard IVCurve here...
|
||
|
for n, name in enumerate(self.celltypes.keys()):
|
||
|
nrn_cell = netcells[
|
||
|
name
|
||
|
] # get the Neuron object we are using for this cell class
|
||
|
injcmds = list(self.celltypes[name][3]) # list of injections
|
||
|
injcmds[2] = (injcmds[1] - injcmds[0]) / (
|
||
|
float(injcmds[2] - 1)
|
||
|
) # convert to pulse format for IVCurve
|
||
|
temperature = self.celltypes[name][4]
|
||
|
nrn_cell.set_temperature(float(temperature))
|
||
|
ninjs = len(injcmds)
|
||
|
print("cell: ", name)
|
||
|
# print( 'injs: ', injcmds)
|
||
|
pl[name] = self.win.addPlot(
|
||
|
labels={"left": "V (mV)", "bottom": "Time (ms)"}
|
||
|
)
|
||
|
PH.nice_plot(pl[name])
|
||
|
pl[name].setTitle(title=name, font=pg.QtGui.QFont("Arial", 10))
|
||
|
col += 1
|
||
|
if col >= cols:
|
||
|
col = 0
|
||
|
self.win.nextRow()
|
||
|
row += 1
|
||
|
self.iv.reset()
|
||
|
self.iv.run(
|
||
|
{"pulse": [injcmds]},
|
||
|
nrn_cell,
|
||
|
durs=(stim["delay"], stim["dur"], 20.0),
|
||
|
sites=None,
|
||
|
reppulse=None,
|
||
|
temp=float(temperature),
|
||
|
)
|
||
|
for k in range(len(self.iv.voltage_traces)):
|
||
|
pl[name].plot(
|
||
|
self.iv.time_values,
|
||
|
self.iv.voltage_traces[k],
|
||
|
pen=pg.mkPen("k", width=0.75),
|
||
|
)
|
||
|
pl[name].setRange(xRange=(0.0, 130.0), yRange=(-160.0, 40.0))
|
||
|
PH.noaxes(pl[name])
|
||
|
PH.calbar(
|
||
|
pl[list(self.celltypes.keys())[0]],
|
||
|
calbar=[0, -120.0, 10.0, 20.0],
|
||
|
unitNames={"x": "ms", "y": "mV"},
|
||
|
)
|
||
|
|
||
|
text = u"{0:2d}\u00b0C {1:.2f}-{2:.2f} nA".format(
|
||
|
int(temperature),
|
||
|
np.min(self.iv.current_cmd),
|
||
|
np.max(self.iv.current_cmd),
|
||
|
)
|
||
|
ti = pg.TextItem(text, anchor=(1, 0))
|
||
|
ti.setFont(pg.QtGui.QFont("Arial", 9))
|
||
|
ti.setPos(120.0, -120.0)
|
||
|
pl[name].addItem(ti)
|
||
|
# get overall Rin, etc; need to initialize all cells
|
||
|
nrn_cell.cell_initialize()
|
||
|
for n, name in enumerate(self.celltypes.keys()):
|
||
|
nrn_cell = netcells[name]
|
||
|
nrn_cell.vm0 = nrn_cell.soma.v
|
||
|
pars = nrn_cell.compute_rmrintau(auto_initialize=False)
|
||
|
print(
|
||
|
"{0:>14s} [{1:>24s}] *** Rin = {2:6.1f} M\ohm Tau = {3:6.1f} ms Vm = {4:6.1f} mV".format(
|
||
|
nrn_cell.status["name"], name, pars["Rin"], pars["tau"], pars["v"]
|
||
|
)
|
||
|
)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
t = Toy()
|
||
|
t.run()
|
||
|
if sys.flags.interactive == 0:
|
||
|
pg.QtGui.QApplication.exec_()
|
||
|
# exporter = pg.exporters.ImageExporter(t.win.scene())
|
||
|
# exporter.export('~/Desktop/Model_Figure2.svg')
|