Evaluating biophysically detailed multi-compartmental models¶
Tutorial 1.1: Simulating biophysically detailed multi-compartmental models outlined how to run 5 stimulus protocols (\(bAP\), \(BAC\) and \(3\) step currents) in silico.
This tutorial will show how to use ISF in order to compare the cell’s in silico response to an empirical distribution of electrophysiological parameters, i.e. the simulation objectives. Quantifying how far off the responses are compared to this distribution will be done with the Evaluator object.
In addition to quantifying the response and comparing it to empirical values, this tutorial will also show how to visually inspect simulations using the visualize package.
To get started, adapt the path below to your desired output directory:
[1]:
from pathlib import Path
tutorial_output_dir = f"{Path.home()}/isf_tutorial_output" # <-- Change this to your desired output directory
[2]:
import Interface as I
%matplotlib inline
db = I.DataBase(tutorial_output_dir).create_sub_db("neuron_modeling")
[INFO] ISF: Current version: heads/data+0.g1077bcf8.dirty
[INFO] ISF: Current pid: 227965
[INFO] ISF: Loading mechanisms:
Warning: no DISPLAY environment variable.
--No graphics will be displayed.
[ATTENTION] ISF: The source folder has uncommited changes!
[INFO] ISF: Loaded modules with __version__ attribute are:
IPython: 8.12.2, Interface: heads/data+0.g1077bcf8.dirty, PIL: 10.4.0, _brotli: 1.0.9, _csv: 1.0, _ctypes: 1.1.0, _curses: b'2.2', _decimal: 1.70, argparse: 1.1, backcall: 0.2.0, blosc: 1.11.1, bluepyopt: 1.9.126, brotli: 1.0.9, certifi: 2024.08.30, cffi: 1.17.0, charset_normalizer: 3.4.0, click: 7.1.2, cloudpickle: 3.1.0, colorama: 0.4.6, comm: 0.2.2, csv: 1.0, ctypes: 1.1.0, cycler: 0.12.1, cytoolz: 0.12.3, dash: 2.18.2, dask: 2.30.0, dateutil: 2.9.0, deap: 1.4, debugpy: 1.8.5, decimal: 1.70, decorator: 5.1.1, defusedxml: 0.7.1, distributed: 2.30.0, distutils: 3.8.20, django: 1.8.19, entrypoints: 0.4, executing: 2.1.0, fasteners: 0.17.3, flask: 1.1.4, fsspec: 2024.10.0, future: 1.0.0, greenlet: 3.1.1, idna: 3.10, ipaddress: 1.0, ipykernel: 6.29.5, ipywidgets: 8.1.5, isf_pandas_msgpack: 0.2.3, itsdangerous: 1.1.0, jedi: 0.19.1, jinja2: 2.11.3, joblib: 1.4.2, json: 2.0.9, jupyter_client: 7.3.4, jupyter_core: 5.7.2, kiwisolver: 1.4.5, logging: 0.5.1.2, markupsafe: 2.0.1, matplotlib: 3.5.1, msgpack: 1.0.8, neuron: 7.8.2+, numcodecs: 0.12.1, numexpr: 2.8.6, numpy: 1.19.2, packaging: 25.0, pandas: 1.1.3, parameters: 0.2.1, parso: 0.8.4, past: 1.0.0, pexpect: 4.9.0, pickleshare: 0.7.5, platform: 1.0.8, platformdirs: 4.3.6, plotly: 5.24.1, prompt_toolkit: 3.0.48, psutil: 6.0.0, ptyprocess: 0.7.0, pure_eval: 0.2.3, pydevd: 2.9.5, pygments: 2.18.0, pyparsing: 3.1.4, pytz: 2024.2, re: 2.2.1, requests: 2.32.3, scandir: 1.10.0, scipy: 1.5.2, seaborn: 0.12.2, six: 1.16.0, sklearn: 0.23.2, socketserver: 0.4, socks: 1.7.1, sortedcontainers: 2.4.0, stack_data: 0.6.2, statsmodels: 0.13.2, sumatra: 0.7.4, tables: 3.8.0, tblib: 3.0.0, tlz: 0.12.3, toolz: 1.0.0, tqdm: 4.67.1, traitlets: 5.14.3, urllib3: 2.2.3, wcwidth: 0.2.13, werkzeug: 1.0.1, yaml: 5.3.1, zarr: 2.15.0, zlib: 1.0, zmq: 26.2.0, zstandard: 0.19.0
The previous tutorial showed how to set up a Simulator object, which we saved to re-use here. Let’s load it back in to evaluate how well these models have performed
[3]:
simulator = db['simulator']
voltage_traces = db['voltage_traces']
The ISF Evaluator¶
ISF implements an Evaluator object to evaluate voltage traces. It can be configured once with empirical values on voltage traces and re-used afterwards.
[4]:
from biophysics_fitting.hay.default_setup import get_Evaluator
evaluator = get_Evaluator(step=True, interpolate_voltage_trace=False)
[5]:
evaluation = evaluator.evaluate(voltage_traces)
evaluation
[5]:
{'BAC_APheight.check_1AP': 'True',
'BAC_APheight.raw': array([33.66002227, 29.8688259 , 23.41371875]),
'BAC_APheight.normalized': 1.0076752949319177,
'BAC_APheight': 1.0076752949319177,
'BAC_ISI.check_2_or_3_APs': 'True',
'BAC_ISI.check_repolarization': 'True',
'BAC_ISI.raw': 9.936833063034726,
'BAC_ISI.normalized': 0.04207239994684291,
'BAC_ISI': 0.04207239994684291,
'BAC_caSpike_height.check_1_Ca_AP': 'True',
'BAC_caSpike_height.check_>=2_Na_AP': 'True',
'BAC_caSpike_height.check_ca_max_after_nth_somatic_spike': 'True',
'BAC_caSpike_height.raw': 8.413835125674638,
'BAC_caSpike_height.normalized': 0.6629272148325343,
'BAC_caSpike_height': 0.6629272148325343,
'BAC_caSpike_width.check_1_Ca_AP': 'True',
'BAC_caSpike_width.raw': 38.31055111593054,
'BAC_caSpike_width.normalized': 0.6933473353783755,
'BAC_caSpike_width': 0.6933473353783755,
'BAC_spikecount.raw': 3,
'BAC_spikecount.normalized': 0.0,
'BAC_spikecount': 0.0,
'BAC_ahpdepth.check_2AP': 'True',
'BAC_ahpdepth.raw': array([-65.68694881, -65.42729689]),
'BAC_ahpdepth.normalized': 0.1392807122615114,
'BAC_ahpdepth': 0.1392807122615114,
'BAC.err': 143.74912826015054,
'BAC.check_minspikenum': 'True',
'BAC.check_returning_to_rest': 'True',
'BAC.check_no_spike_before_stimulus': 'True',
'BAC.check_last_spike_before_deadline': 'True',
'BAC.check_max_prestim_dendrite_depo': nan,
'bAP_spikecount.raw': 1,
'bAP_spikecount.normalized': 0.0,
'bAP_spikecount': 0.0,
'bAP_APheight.check_1AP': 'True',
'bAP_APheight.raw': array([33.65989277]),
'bAP_APheight.normalized': 1.7319785547438031,
'bAP_APheight': 1.7319785547438031,
'bAP_APwidth.check_1AP': 'True',
'bAP_APwidth.raw': array([0.98336221]),
'bAP_APwidth.normalized': 2.0332755883802065,
'bAP_APwidth': 2.0332755883802065,
'bAP_att2.raw': 32.61344140808186,
'bAP_att2.check_1_AP': 'True',
'bAP_att2.check_relative_height': 'True',
'bAP_att2.normalized': 1.2386558591918138,
'bAP_att2': 1.2386558591918138,
'bAP_att3.raw': 21.018319507819953,
'bAP_att3.check_1_AP': 'True',
'bAP_att3.check_relative_height': 'True',
'bAP_att3.normalized': 1.6057535361393405,
'bAP_att3': 1.6057535361393405,
'bAP.err': 248.30532972531503,
'bAP.check_minspikenum': 'True',
'bAP.check_returning_to_rest': 'True',
'bAP.check_no_spike_before_stimulus': 'True',
'bAP.check_last_spike_before_deadline': 'True',
'bAP.check_max_prestim_dendrite_depo': nan,
'mf1.check_1AP': 21,
'mf1.raw': 10.5,
'mf1.normalized': 1.7045454545454546,
'mf1': 1.7045454545454546,
'AI1.check_2ISI': 21,
'AI1.raw': 0.008210116836947173,
'AI1.normalized': 0.5066062458183707,
'AI1': 0.5066062458183707,
'ISIcv1.check_2ISI': 21,
'ISIcv1.raw': 0.07166545818156783,
'ISIcv1.normalized': 1.518210025496329,
'ISIcv1': 1.518210025496329,
'DI1.check_2ISI': 21,
'DI1.raw': 43.55860401502662,
'DI1.normalized': 0.42387682153444994,
'DI1': 0.42387682153444994,
'TTFS1.check_1AP': 21,
'TTFS1.raw': 31.83428349013741,
'TTFS1.normalized': 1.5595241133692064,
'TTFS1': 1.5595241133692064,
'APh1.check_1AP': 'True',
'APh1.raw': array([24.09137071, 22.99574218, 22.78835239, 22.69107345, 22.68429012,
22.67564812, 22.6771194 , 22.52439294, 22.60587203, 22.56109392,
22.51164211, 22.4663929 , 22.52556049, 22.46631672, 22.40467648,
22.40949821, 22.42663761, 22.33953598, 22.30147383, 22.33121202,
22.36159536]),
'APh1.normalized': 0.7275205487209074,
'APh1': 0.7275205487209074,
'fAHPd1.check_2AP': 'True',
'fAHPd1.raw': array([-63.07277651, -62.78005906, -62.6583248 , -62.53651584,
-62.52194432, -62.43449412, -62.32089897, -62.39006 ,
-62.31048539, -62.33128433, -62.28978495, -62.31658177,
-62.28410763, -62.30394597, -62.3336867 , -62.30956485,
-62.31995899, -62.31292736, -62.3652368 ]),
'fAHPd1.normalized': 1.8003008765264834,
'fAHPd1': 1.8003008765264834,
'sAHPd1.check_2AP': 'True',
'sAHPd1.raw': array([-62.67978109, -63.10984807, -63.25590053, -63.21579511,
-63.11367589, -63.00336828, -62.86072748, -62.80277767,
-62.68235573, -62.62529579, -62.56086612, -62.52874268,
-62.48671966, -62.43637328, -62.41316377, -62.38445205,
-62.35582907, -62.33716901, -62.35128974]),
'sAHPd1.normalized': 1.0151163975923705,
'sAHPd1': 1.0151163975923705,
'sAHPt1.check_2AP': 'True',
'sAHPt1.raw': array([0.21629595, 0.19349339, 0.21138262, 0.21059077, 0.21985869,
0.22330926, 0.226997 , 0.2386829 , 0.24629334, 0.23097281,
0.24412891, 0.2647404 , 0.24537822, 0.25003761, 0.24583298,
0.24744496, 0.25608634, 0.26335499, 0.25594333]),
'sAHPt1.normalized': 0.5495925224841391,
'sAHPt1': 0.5495925224841391,
'APw1.check_1AP': 'True',
'APw1.raw': array([0.96198111, 0.93800774, 0.97709169, 0.94631752, 0.97689972,
0.95077889, 0.97062854, 0.9449781 , 0.94071347, 0.95432122,
0.95311969, 0.932242 , 0.98678948, 0.93568953, 0.95748403,
0.96239958, 0.95148441, 0.96229513, 0.95876679, 0.95203888,
0.94387863]),
'APw1.normalized': 2.117487156301,
'APw1': 2.117487156301,
'StepOne.err': 186.063249205872,
'StepOne.check_minspikenum': 'True',
'StepOne.check_returning_to_rest': 'True',
'StepOne.check_no_spike_before_stimulus': 'True',
'StepOne.check_last_spike_before_deadline': 'True',
'StepOne.check_max_prestim_dendrite_depo': nan,
'mf2.check_1AP': 29,
'mf2.raw': 14.5,
'mf2.normalized': 0.0,
'mf2': 0.0,
'AI2.check_2ISI': 29,
'AI2.raw': 0.01302293276553171,
'AI2.normalized': 1.9148094224163767,
'AI2': 1.9148094224163767,
'ISIcv2.check_2ISI': 29,
'ISIcv2.raw': 0.1270919522564917,
'ISIcv2.normalized': 0.5106508765351007,
'ISIcv2': 0.5106508765351007,
'DI2.check_2ISI': 29,
'DI2.raw': 19.335769758475635,
'DI2.normalized': 1.4694531512688596,
'DI2': 1.4694531512688596,
'TTFS2.check_1AP': 29,
'TTFS2.raw': 20.04291489923446,
'TTFS2.normalized': 0.125569753657245,
'TTFS2': 0.125569753657245,
'APh2.check_1AP': 'True',
'APh2.raw': array([25.289338 , 22.91487818, 23.00459579, 22.49166693, 22.29761099,
22.21175384, 22.25860675, 22.2450473 , 22.26937709, 22.14045844,
22.22940218, 22.18828798, 22.08730248, 22.09746412, 22.02329864,
22.00543709, 22.02109181, 21.95402584, 22.0333001 , 22.00324597,
21.94894466, 21.94920213, 21.92281833, 21.88771034, 21.88948634,
21.84765357, 21.89441045, 21.77926653, 21.82714999]),
'APh2.normalized': 0.9342151521837061,
'APh2': 0.9342151521837061,
'fAHPd2.check_2AP': 'True',
'fAHPd2.raw': array([-63.31954044, -62.99594263, -62.62724758, -62.40615908,
-62.20911732, -62.17715377, -62.09167612, -62.07826386,
-61.96563229, -62.0238239 , -62.00215742, -61.93515078,
-61.90298672, -61.90306708, -61.89143113, -61.89131561,
-61.89810665, -61.95373015, -61.93932434, -61.9037699 ,
-61.95375415, -61.95347455, -61.93760715, -61.94996851,
-61.95934734, -61.99514349, -61.95610612]),
'fAHPd2.normalized': 1.4198796199388009,
'fAHPd2': 1.4198796199388009,
'sAHPd2.check_2AP': 'True',
'sAHPd2.raw': array([-62.69571127, -62.50916915, -62.79705684, -62.91073606,
-62.7546071 , -62.61809871, -62.47858224, -62.35608982,
-62.23057261, -62.10762341, -62.06436578, -61.98290703,
-61.93966353, -61.85511224, -61.81083838, -61.76599192,
-61.73416086, -61.72949083, -61.69477853, -61.65643276,
-61.64104844, -61.61903164, -61.58479313, -61.58183362,
-61.55295009, -61.55902855, -61.52938553]),
'sAHPd2.normalized': 0.3243466774696222,
'sAHPd2': 0.3243466774696222,
'sAHPt2.check_2AP': 'True',
'sAHPt2.raw': array([0.14440786, 0.10149109, 0.23006425, 0.23913882, 0.23972689,
0.22124587, 0.26057754, 0.26478589, 0.26298941, 0.27062517,
0.2596264 , 0.26580278, 0.2734945 , 0.28501231, 0.26285161,
0.28442103, 0.27858236, 0.26828522, 0.29121099, 0.28293423,
0.27761429, 0.29550939, 0.26738561, 0.28966649, 0.25861875,
0.27133896, 0.29678496]),
'sAHPt2.normalized': 1.01641064338122,
'sAHPt2': 1.01641064338122,
'APw2.check_1AP': 'True',
'APw2.raw': array([0.94586939, 0.91959924, 0.94497682, 0.94000711, 0.97506431,
0.96358534, 0.94363674, 0.93621152, 0.95582546, 0.95260643,
0.97758583, 0.94832052, 0.93123934, 0.9398469 , 0.93592603,
0.93713813, 0.94962583, 0.96446361, 0.93927337, 0.9493291 ,
0.9349232 , 0.96418846, 0.94105855, 0.9350136 , 0.95549361,
0.96590542, 0.94363678, 0.93346691, 0.95732679]),
'APw2.normalized': 1.5324457777590226,
'APw2': 1.5324457777590226,
'StepTwo.err': 183.82534769658955,
'StepTwo.check_minspikenum': 'True',
'StepTwo.check_returning_to_rest': 'True',
'StepTwo.check_no_spike_before_stimulus': 'True',
'StepTwo.check_last_spike_before_deadline': 'True',
'StepTwo.check_max_prestim_dendrite_depo': nan,
'mf3.check_1AP': 55,
'mf3.raw': 27.5,
'mf3.normalized': 2.2500225002250023,
'mf3': 2.2500225002250023,
'AI3.check_2ISI': 55,
'AI3.raw': 0.009023622914987494,
'AI3.normalized': 1.701393428841344,
'AI3': 1.701393428841344,
'ISIcv3.check_2ISI': 55,
'ISIcv3.raw': 0.15152925677739668,
'ISIcv3.normalized': 4.009232626956906,
'ISIcv3': 4.009232626956906,
'DI3.check_2ISI': 55,
'DI3.raw': 7.828677080833472,
'DI3.normalized': 2.950213350401774,
'DI3': 2.950213350401774,
'TTFS3.check_1AP': 55,
'TTFS3.raw': 7.333930069455391,
'TTFS3.normalized': 0.08393006945539128,
'TTFS3': 0.08393006945539128,
'APh3.check_1AP': 'True',
'APh3.raw': array([31.06548527, 25.12701956, 23.61311489, 22.73688262, 22.21078341,
21.57937786, 21.04672383, 20.76563028, 20.64813921, 20.55610157,
20.42377868, 20.4599674 , 20.45969288, 20.43528102, 20.174338 ,
20.30478441, 20.35465197, 20.28209844, 20.22536986, 20.27072808,
20.15914034, 20.19224602, 20.15232081, 20.14372265, 20.13439816,
20.07233316, 20.11473716, 20.03663349, 20.0170812 , 20.05731578,
20.03805308, 20.00040917, 19.95123863, 19.94288751, 19.95577528,
19.95158293, 19.93562061, 19.92758261, 19.78689311, 19.87964998,
19.87197628, 19.83337694, 19.81677821, 19.84509897, 19.72888495,
19.79162615, 19.76673602, 19.77400936, 19.76127948, 19.80455543,
19.74585616, 19.75381166, 19.72279777, 19.77130918, 19.69740275]),
'APh3.normalized': 0.592363621161479,
'APh3': 0.592363621161479,
'fAHPd3.check_2AP': 'True',
'fAHPd3.raw': array([-64.49147803, -63.19511496, -62.72814944, -62.28446636,
-61.75978386, -61.31762381, -61.01314808, -60.81151239,
-60.67912156, -60.52746746, -60.53372268, -60.48151412,
-60.44317895, -60.18392669, -60.31955776, -60.34059709,
-60.298159 , -60.263136 , -60.28501073, -60.1924222 ,
-60.25948116, -60.24707285, -60.21552421, -60.22883443,
-60.2118771 , -60.244356 , -60.18499324, -60.2022267 ,
-60.23005033, -60.25431815, -60.26227308, -60.23695933,
-60.22131564, -60.26720735, -60.29679708, -60.27592727,
-60.29552467, -60.22672025, -60.29066048, -60.313126 ,
-60.31248887, -60.2925893 , -60.3463166 , -60.25238435,
-60.3302365 , -60.35249597, -60.37554333, -60.36903818,
-60.38429871, -60.39394615, -60.37696266, -60.39843727,
-60.45272127]),
'fAHPd3.normalized': 1.1277531070124256,
'fAHPd3': 1.1277531070124256,
'sAHPd3.check_2AP': 'True',
'sAHPd3.raw': array([-62.3132864 , -61.88864277, -61.77676612, -61.69415586,
-61.30304238, -60.98434918, -60.72257492, -60.51480139,
-60.46581423, -60.27360188, -60.30502217, -60.21105122,
-60.18140053, -59.9297075 , -60.08423894, -60.03726704,
-60.01453674, -59.98993216, -59.93277795, -59.89552556,
-59.91701656, -59.92733511, -59.86207856, -59.79412642,
-59.77317544, -59.86225267, -59.76805902, -59.80739407,
-59.8257073 , -59.77714064, -59.74146828, -59.73339037,
-59.83316817, -59.84775185, -59.85289352, -59.8342664 ,
-59.86712761, -59.73352912, -59.73979828, -59.84408651,
-59.77256854, -59.81154729, -59.80507675, -59.78089181,
-59.76471253, -59.79733875, -59.74039751, -59.80519001,
-59.83571012, -59.7251643 , -59.81061982, -59.81074666,
-59.82644007]),
'sAHPd3.normalized': 0.09246104391805444,
'sAHPd3': 0.09246104391805444,
'sAHPt3.check_2AP': 'True',
'sAHPt3.raw': array([0.36279071, 0.30161064, 0.2484799 , 0.19095867, 0.16237276,
0.13911125, 0.12780075, 0.12544222, 0.11718686, 0.12136835,
0.11837248, 0.12196111, 0.12127243, 0.12714399, 0.121469 ,
0.12636774, 0.12568368, 0.12529812, 0.13047645, 0.12941498,
0.13028479, 0.12950152, 0.13214559, 0.13703346, 0.13802471,
0.13345267, 0.13726805, 0.13487522, 0.13450501, 0.13951205,
0.14203114, 0.14143575, 0.13531704, 0.13557297, 0.13556914,
0.13666068, 0.13540744, 0.14145944, 0.14279928, 0.13822604,
0.14193758, 0.13887647, 0.14073416, 0.13959887, 0.14259464,
0.14216232, 0.14713721, 0.14205005, 0.14046243, 0.14771324,
0.14297933, 0.14214369, 0.14378104]),
'sAHPt3.normalized': 2.109119864685762,
'sAHPt3': 2.109119864685762,
'APw3.check_1AP': 'True',
'APw3.raw': array([0.98531213, 0.91123546, 0.94754453, 0.92717859, 0.92242316,
0.95287909, 0.92477266, 0.92511115, 0.95809013, 0.93476667,
0.94955365, 0.94920487, 0.93034679, 0.95285811, 0.93205066,
0.94868883, 0.93788963, 0.94364911, 0.93710963, 0.94210618,
0.96209178, 0.93310596, 0.96895262, 0.94518157, 0.95295191,
0.93313142, 0.93405116, 0.95356331, 0.94557525, 0.95123666,
0.9397376 , 0.94528431, 0.94698763, 0.96069676, 0.95914107,
0.95262626, 0.95051096, 0.929552 , 0.93727957, 0.92652508,
0.96162485, 0.94524348, 0.92878712, 0.92922577, 0.95214297,
0.95807564, 0.95623037, 0.95059179, 0.94546294, 0.94579291,
0.94372633, 0.9617165 , 0.9415482 , 0.94118213, 0.933252 ]),
'APw3.normalized': 2.234564571206278,
'APw3': 2.234564571206278,
'StepThree.err': 179.370143914727,
'StepThree.check_minspikenum': 'True',
'StepThree.check_returning_to_rest': 'True',
'StepThree.check_no_spike_before_stimulus': 'True',
'StepThree.check_last_spike_before_deadline': 'True',
'StepThree.check_max_prestim_dendrite_depo': nan}
evaluation
contains a lot of information. Most are self-explanatory, but not all, so here is a small overview.
Suffix |
Meaning |
---|---|
|
Check if certain conditions are met before moving on to evaluation. E.g. it does not make sense to measure the AP height of the second AP during the BAC stimulus, if there is no burst firing at all. |
|
The measured values for all objectives are saved under |
|
Scales objective between \(0\) and \(1\). |
No suffix |
The objective in units of \(\sigma\) relative to the empirically observed mean \(\mu\). |
The step current objectives have some cryptic acronyms as well:
Acronym |
Meaning |
---|---|
|
Spike frequency |
|
Adaptation Index |
|
Interspike Interval Coefficient of Variation |
|
Initial burst ISI |
|
First spike latency |
|
AP peak |
|
Fast AHP Depth |
|
Slow AHP Depth |
|
Slow AHP Time |
|
AP half-width |
Exactly how much each objective is allowed to deviate from its empirical mean is defined in each evaluator class, associated with a stimulu protocol. See for example the BAC
class in biophysics_fitting.hay.evaluation
Let’s clean up this data a bit and plot out their deviation from the mean.
[6]:
# only plot out sigma from mean, not raw or normalized values - also no checks.
sigma_mean = {k: v for k, v in evaluation.items() if \
not k.endswith('.raw') and \
not k.endswith('.normalized') and \
not 'check' in k and \
not k.endswith('err') and\
not "1BAC" in k}
sigma_mean
[6]:
{'BAC_APheight': 1.0076752949319177,
'BAC_ISI': 0.04207239994684291,
'BAC_caSpike_height': 0.6629272148325343,
'BAC_caSpike_width': 0.6933473353783755,
'BAC_spikecount': 0.0,
'BAC_ahpdepth': 0.1392807122615114,
'bAP_spikecount': 0.0,
'bAP_APheight': 1.7319785547438031,
'bAP_APwidth': 2.0332755883802065,
'bAP_att2': 1.2386558591918138,
'bAP_att3': 1.6057535361393405,
'mf1': 1.7045454545454546,
'AI1': 0.5066062458183707,
'ISIcv1': 1.518210025496329,
'DI1': 0.42387682153444994,
'TTFS1': 1.5595241133692064,
'APh1': 0.7275205487209074,
'fAHPd1': 1.8003008765264834,
'sAHPd1': 1.0151163975923705,
'sAHPt1': 0.5495925224841391,
'APw1': 2.117487156301,
'mf2': 0.0,
'AI2': 1.9148094224163767,
'ISIcv2': 0.5106508765351007,
'DI2': 1.4694531512688596,
'TTFS2': 0.125569753657245,
'APh2': 0.9342151521837061,
'fAHPd2': 1.4198796199388009,
'sAHPd2': 0.3243466774696222,
'sAHPt2': 1.01641064338122,
'APw2': 1.5324457777590226,
'mf3': 2.2500225002250023,
'AI3': 1.701393428841344,
'ISIcv3': 4.009232626956906,
'DI3': 2.950213350401774,
'TTFS3': 0.08393006945539128,
'APh3': 0.592363621161479,
'fAHPd3': 1.1277531070124256,
'sAHPd3': 0.09246104391805444,
'sAHPt3': 2.109119864685762,
'APw3': 2.234564571206278}
[7]:
def translate_objective(objective):
"""
A simple map between objective acronyms and their full name
"""
step_map = {
'mf': "Spike frequency",
'AI': 'Adaptation Index',
'ISIcv': "Interspike Interval \n Coefficient of Variation",
'DI': "Initial burst ISI",
'TTFS': "First spike latency",
'APh': "AP peak",
'fAHPd': "Fast AHP Depth",
'sAHPd': "Slow AHP Depth",
'sAHPt': "Slow AHP Time",
'APw': "AP half-width",
}
if not "bAP" in objective and not "BAC" in objective:
# must be step current objective
t = step_map[objective[:-1]]
else:
t = objective
return t
[8]:
from collections import OrderedDict
I.plt.style.use("fivethirtyeight")
colors = I.plt.rcParams['axes.prop_cycle'].by_key()['color']
fig = I.plt.figure(figsize=(10, 10))
gs = fig.add_gridspec(2,2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, :])
for k, v in sigma_mean.items():
if "BAC" in k:
c = colors[0]
ax = ax1
label="BAC"
elif 'bAP' in k:
c = colors[1]
ax = ax2
label="bAP"
else:
label = "Step current {}".format(k[-1])
c = colors[int(k[-1])+1]
ax = ax3
ax.barh(y=translate_objective(k), width=v, zorder=5-v, label=label, color=c)
ax1.vlines(3.2, ymin=-.5, ymax=5.5, color='k')
ax2.vlines(3.2, ymin=-.5, ymax=4.5, color='k')
ax3.vlines(4.5, ymin=-.5, ymax=9.5, color='k')
ax1.set_title("bAP stimulus")
ax2.set_title("BAC stimulus")
ax3.set_title("Step current stimuli")
ax3.set_xlabel("Sigma from mean")
handles, labels = I.plt.gca().get_legend_handles_labels()
by_label = OrderedDict(zip(labels, handles))
I.plt.legend(by_label.values(), by_label.keys(), loc="best")
fig.tight_layout()
I.plt.show()

All objectives are well within the pre-defined bounds. most are even under \(2 \sigma\) from the mean!
Visualization¶
How much did current ended up flowing through the ion channels? Let’s plot out a spatial integration of all the current types in the apical dendrite. Let’s take a \(BAC\) current injection as an example simulation.
[9]:
from getting_started import example_data_dir
model_db = I.DataBase(I.os.path.join(example_data_dir, "simulation_data", "biophysics"))
example_models = model_db['example_models']
biophysical_parameter_names = [e for e in example_models.columns if "ephys" in e or e == "scale_apical.scale"]
params = example_models[biophysical_parameter_names].iloc[0]
In order to know which currents flow through the membrane, we need to record this. We can configure the simulator to record range variables
with a cell_modify_function
:
[10]:
cell, biophysical_parameters = simulator.setup.get(params)
record_vars = [
'NaTa_t.ina',
'Ca_HVA.ica',
'Ca_LVAst.ica',
'SKv3_1.ik',
'SK_E2.ik',
'Ih.ihcn',
'Im.ik'
]
def record_rangevars(cell, params):
for rv in record_vars:
cell.record_range_var(rv)
return cell
simulator.setup.cell_modify_funs.append(('BAC.record_range_vars', record_rangevars))
cell, _ = simulator.get_simulated_cell(biophysical_parameters, stim="BAC")
[11]:
from visualize.current_visualizer import CurrentAnalysis
ca = CurrentAnalysis(cell, rangeVars = record_vars)
fig = ca.plot_areas(plot_voltage = True, t_stim=295)
fig.set_size_inches(8,6)
for ax in fig.axes: ax.grid(False)

The black and orange line denote membrane voltage at the soma and dendritic recording location respectively. The filled in areas are a spatial sum of ionic current across time: \(I_{ion}(t) = \sum_{dendrites} \int_x I_{ion} dx\)
Animating the membrane voltage¶
So far, we have only visualized the somatic membrane potential. Now, we create a short animation, where the whole dendrite is visualized.
[12]:
if not 'burst_trail_video' in db.keys():
I.cell_to_animation(
cell,
xlim = [0,1500],
ylim = [-90, 50],
tstart = 295,
tend = 350,
tstep = 0.2,
outdir = db.create_managed_folder('burst_trail_video'))
I.display_animation(db['burst_trail_video'].join('*', '*.png'), embedded=True);
If you want to visualize the entire dendritic tree, that’s also possible, although a bit slower. Here, we use Dask to parallellize frame generation of the membrane voltage across the entire dendritic tree. You can use the +/- buttons to cycle through the frames faster or slower. Alternatively, you play around with the t_step
parameter to create mre or less frames per time interval.
[13]:
client = I.get_client()
outdir = I.os.path.join(db.basedir, 'burst_trail_video_3d')
cmv = I.CellMorphologyVisualizer(
cell,
t_start=295, # Don't load all simulation data, only the interesting part
t_stop=350, # these are in [ms]
t_step=1)
cmv.animation(
images_path=outdir,
show_legend=True,
color="voltage",
client=client,
overwrite_frames=True);
These visualization aren’t limited to just the membrane voltage either! Let’s visualize some current flowing through one specific ion channel.
Animating ion currents¶
We can also visualize current through ion channels. Let’s have a look at the calcium current through low voltage activated calcium channels:
[14]:
# # to re-create this video, comment out below
# del db['burst_trail_ca_current_video']
range_var = 'Ca_LVAst.ica'
if not 'burst_trail_ca_current_video' in db.keys():
I.cell_to_animation(
cell,
xlim = [0,1500],
ylim = [-0.3, 0.1],
tstart = 295,
tend = 350,
tstep = 0.2,
outdir = db.create_managed_folder('burst_trail_ca_current_video'),
range_vars = range_var)
print("{} membrane current".format(range_var))
I.display_animation(db['burst_trail_ca_current_video'].join('*', '*png'), embedded = True);
Ca_LVAst.ica membrane current
[15]:
outdir = I.os.path.join(db.basedir, 'Ca_LVAst_video_3d')
cmv.set_cmap("RdBu", vmin=-2e-1, vmax=2e-1) # more visible
cmv.animation(
images_path=outdir,
color="Ca_LVAst.ica",
show_legend=True,
client=client,
overwrite_frames=True);
In the visualization above, not all dendrites are shown, because not all dendrites contain this ion channel.
Recap¶
We have seen how to run simulations in Tutorial 1.3 and how to evaluate the results of these simulation here. Now, we have all the necessary tools to start building neuron models from scratch. This will be shown in the next tutorial.