bluecellulab 2.6.40__tar.gz → 2.6.41__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bluecellulab might be problematic. Click here for more details.

Files changed (107) hide show
  1. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/PKG-INFO +1 -1
  2. bluecellulab-2.6.41/bluecellulab/analysis/analysis.py +177 -0
  3. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/analysis/inject_sequence.py +69 -16
  4. bluecellulab-2.6.41/bluecellulab/analysis/plotting.py +57 -0
  5. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/core.py +64 -9
  6. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/tools.py +105 -13
  7. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab.egg-info/PKG-INFO +1 -1
  8. bluecellulab-2.6.40/bluecellulab/analysis/analysis.py +0 -63
  9. bluecellulab-2.6.40/bluecellulab/analysis/plotting.py +0 -25
  10. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.compile_mod.sh +0 -0
  11. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.gitattributes +0 -0
  12. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.github/dependabot.yml +0 -0
  13. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.github/workflows/release.yml +0 -0
  14. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.github/workflows/test.yml +0 -0
  15. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.gitignore +0 -0
  16. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.gitlab-ci.yml +0 -0
  17. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.readthedocs.yml +0 -0
  18. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/.zenodo.json +0 -0
  19. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/AUTHORS.txt +0 -0
  20. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/CHANGELOG.rst +0 -0
  21. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/CITATION.cff +0 -0
  22. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/CONTRIBUTING.rst +0 -0
  23. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/LICENSE +0 -0
  24. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/MANIFEST.in +0 -0
  25. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/Makefile +0 -0
  26. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/README.rst +0 -0
  27. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/__init__.py +0 -0
  28. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/analysis/__init__.py +0 -0
  29. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/__init__.py +0 -0
  30. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/ballstick/__init__.py +0 -0
  31. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/ballstick/emodel.hoc +0 -0
  32. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/ballstick/morphology.asc +0 -0
  33. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/cell_dict.py +0 -0
  34. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/injector.py +0 -0
  35. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/plotting.py +0 -0
  36. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/random.py +0 -0
  37. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/recording.py +0 -0
  38. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/section_distance.py +0 -0
  39. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/serialized_sections.py +0 -0
  40. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/sonata_proxy.py +0 -0
  41. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/stimuli_generator.py +0 -0
  42. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/cell/template.py +0 -0
  43. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/__init__.py +0 -0
  44. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/circuit_access/__init__.py +0 -0
  45. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/circuit_access/bluepy_circuit_access.py +0 -0
  46. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/circuit_access/definition.py +0 -0
  47. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/circuit_access/sonata_circuit_access.py +0 -0
  48. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/config/__init__.py +0 -0
  49. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/config/bluepy_simulation_config.py +0 -0
  50. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/config/definition.py +0 -0
  51. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/config/sections.py +0 -0
  52. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/config/sonata_simulation_config.py +0 -0
  53. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/format.py +0 -0
  54. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/iotools.py +0 -0
  55. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/node_id.py +0 -0
  56. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/simulation_access.py +0 -0
  57. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/synapse_properties.py +0 -0
  58. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit/validate.py +0 -0
  59. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/circuit_simulation.py +0 -0
  60. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/connection.py +0 -0
  61. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/dendrogram.py +0 -0
  62. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/exceptions.py +0 -0
  63. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/graph.py +0 -0
  64. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/hoc/Cell.hoc +0 -0
  65. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/hoc/RNGSettings.hoc +0 -0
  66. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/hoc/TDistFunc.hoc +0 -0
  67. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/hoc/TStim.hoc +0 -0
  68. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/hoc/fileUtils.hoc +0 -0
  69. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/importer.py +0 -0
  70. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/neuron_interpreter.py +0 -0
  71. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/plotwindow.py +0 -0
  72. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/psection.py +0 -0
  73. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/psegment.py +0 -0
  74. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/rngsettings.py +0 -0
  75. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/simulation/__init__.py +0 -0
  76. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/simulation/neuron_globals.py +0 -0
  77. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/simulation/parallel.py +0 -0
  78. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/simulation/simulation.py +0 -0
  79. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/stimulus/__init__.py +0 -0
  80. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/stimulus/circuit_stimulus_definitions.py +0 -0
  81. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/stimulus/factory.py +0 -0
  82. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/synapse/__init__.py +0 -0
  83. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/synapse/synapse_factory.py +0 -0
  84. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/synapse/synapse_types.py +0 -0
  85. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/type_aliases.py +0 -0
  86. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/utils.py +0 -0
  87. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab/verbosity.py +0 -0
  88. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab.egg-info/SOURCES.txt +0 -0
  89. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab.egg-info/dependency_links.txt +0 -0
  90. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab.egg-info/requires.txt +0 -0
  91. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/bluecellulab.egg-info/top_level.txt +0 -0
  92. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/Makefile +0 -0
  93. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/images/voltage-readme.png +0 -0
  94. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/make.bat +0 -0
  95. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/requirements_docs.txt +0 -0
  96. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/_static/.gitkeep +0 -0
  97. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/api.rst +0 -0
  98. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/changelog.rst +0 -0
  99. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/compiling-mechanisms.rst +0 -0
  100. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/conf.py +0 -0
  101. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/contributing.rst +0 -0
  102. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/index.rst +0 -0
  103. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/list_of_stim.rst +0 -0
  104. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/docs/source/logo/BlueCelluLabBanner.jpg +0 -0
  105. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/pyproject.toml +0 -0
  106. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/setup.cfg +0 -0
  107. {bluecellulab-2.6.40 → bluecellulab-2.6.41}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: bluecellulab
3
- Version: 2.6.40
3
+ Version: 2.6.41
4
4
  Summary: Biologically detailed neural network simulations and analysis.
5
5
  Author: Blue Brain Project, EPFL
6
6
  License: Apache2.0
@@ -0,0 +1,177 @@
1
+ """Module for analyzing cell simulation results."""
2
+ try:
3
+ import efel
4
+ except ImportError:
5
+ efel = None
6
+ import numpy as np
7
+
8
+ from bluecellulab.stimulus import StimulusFactory
9
+ from bluecellulab.tools import calculate_rheobase
10
+ from bluecellulab.analysis.inject_sequence import run_stimulus
11
+ from bluecellulab.analysis.plotting import plot_iv_curve, plot_fi_curve
12
+
13
+
14
+ def compute_plot_iv_curve(cell,
15
+ injecting_section="soma[0]",
16
+ injecting_segment=0.5,
17
+ recording_section="soma[0]",
18
+ recording_segment=0.5,
19
+ stim_start=100.0,
20
+ duration=500.0,
21
+ post_delay=100.0,
22
+ threshold_voltage=-30,
23
+ nb_bins=11):
24
+ """Compute and plot the Current-Voltage (I-V) curve for a given cell by
25
+ injecting a range of currents.
26
+
27
+ This function evaluates the relationship between the injected current amplitude and the resulting
28
+ steady-state membrane potential of a neuronal cell model. Currents are injected at a specified section
29
+ and segment, and the steady-state voltage at the recording location is used to construct the I-V curve.
30
+
31
+ Args:
32
+ cell (bluecellulab.cell.Cell): The initialized BlueCelluLab cell model.
33
+ injecting_section (str, optional): The name of the section where the stimulus is injected.
34
+ Default is "soma[0]".
35
+ injecting_segment (float, optional): The position along the injecting section (0.0 to 1.0)
36
+ where the stimulus is applied. Default is 0.5.
37
+ recording_section (str, optional): The name of the section where the voltage is recorded.
38
+ Default is "soma[0]".
39
+ recording_segment (float, optional): The position along the recording section (0.0 to 1.0)
40
+ where the voltage is recorded. Default is 0.5.
41
+ stim_start (float, optional): The start time of the current injection (in ms). Default is 100.0 ms.
42
+ duration (float, optional): The duration of the current injection (in ms). Default is 500.0 ms.
43
+ post_delay (float, optional): The delay after the stimulation ends before the simulation stops
44
+ (in ms). Default is 100.0 ms.
45
+ threshold_voltage (float, optional): The voltage threshold (in mV) for detecting a steady-state
46
+ response. Default is -30 mV.
47
+ nb_bins (int, optional): The number of discrete current levels between 0 and the maximum current.
48
+ Default is 11.
49
+
50
+ Returns:
51
+ tuple: A tuple containing:
52
+ - list_amp (np.ndarray): The injected current amplitudes (nA).
53
+ - steady_states (np.ndarray): The corresponding steady-state voltages (mV) recorded at the
54
+ specified location.
55
+
56
+ Raises:
57
+ ValueError: If the cell object is invalid, the specified sections/segments are not found, or if
58
+ the simulation results are inconsistent.
59
+ """
60
+ rheobase = calculate_rheobase(cell=cell, section=injecting_section, segx=injecting_segment)
61
+
62
+ list_amp = np.linspace(rheobase - 2, rheobase - 0.1, nb_bins) # [nA]
63
+
64
+ steps = []
65
+ times = []
66
+ voltages = []
67
+ # inject step current and record voltage response
68
+ stim_factory = StimulusFactory(dt=0.1)
69
+ for amp in list_amp:
70
+ step_stimulus = stim_factory.step(pre_delay=stim_start, duration=duration, post_delay=post_delay, amplitude=amp)
71
+ recording = run_stimulus(cell.template_params,
72
+ step_stimulus,
73
+ section=injecting_section,
74
+ segment=injecting_segment,
75
+ recording_section=recording_section,
76
+ recording_segment=recording_segment)
77
+ steps.append(step_stimulus)
78
+ times.append(recording.time)
79
+ voltages.append(recording.voltage)
80
+
81
+ steady_states = []
82
+ # compute steady state response
83
+ efel.set_setting('Threshold', threshold_voltage)
84
+ for voltage, t in zip(voltages, times):
85
+ trace = {
86
+ 'T': t,
87
+ 'V': voltage,
88
+ 'stim_start': [stim_start],
89
+ 'stim_end': [stim_start + duration]
90
+ }
91
+ features_results = efel.get_feature_values([trace], ['steady_state_voltage_stimend'])
92
+ steady_state = features_results[0]['steady_state_voltage_stimend']
93
+ steady_states.append(steady_state)
94
+
95
+ plot_iv_curve(list_amp,
96
+ steady_states,
97
+ injecting_section=injecting_section,
98
+ injecting_segment=injecting_segment,
99
+ recording_section=recording_section,
100
+ recording_segment=recording_segment)
101
+
102
+ return np.array(list_amp), np.array(steady_states)
103
+
104
+
105
+ def compute_plot_fi_curve(cell,
106
+ injecting_section="soma[0]",
107
+ injecting_segment=0.5,
108
+ recording_section="soma[0]",
109
+ recording_segment=0.5,
110
+ stim_start=100.0,
111
+ duration=500.0,
112
+ post_delay=100.0,
113
+ max_current=0.8,
114
+ nb_bins=11):
115
+ """Compute and plot the Frequency-Current (F-I) curve for a given cell by
116
+ injecting a range of currents.
117
+
118
+ This function evaluates the relationship between injected current amplitude and the firing rate
119
+ of a neuronal cell model. Currents are injected at a specified section and segment, and the number
120
+ of spikes recorded in the specified recording location is used to construct the F-I curve.
121
+
122
+ Args:
123
+ cell (bluecellulab.cell.Cell): The initialized BlueCelluLab cell model.
124
+ injecting_section (str, optional): The name of the section where the stimulus is injected.
125
+ Default is "soma[0]".
126
+ injecting_segment (float, optional): The position along the injecting section (0.0 to 1.0)
127
+ where the stimulus is applied. Default is 0.5.
128
+ recording_section (str, optional): The name of the section where spikes are recorded.
129
+ Default is "soma[0]".
130
+ recording_segment (float, optional): The position along the recording section (0.0 to 1.0)
131
+ where spikes are recorded. Default is 0.5.
132
+ stim_start (float, optional): The start time of the current injection (in ms). Default is 100.0 ms.
133
+ duration (float, optional): The duration of the current injection (in ms). Default is 500.0 ms.
134
+ post_delay (float, optional): The delay after the stimulation ends before the simulation stops
135
+ (in ms). Default is 100.0 ms.
136
+ max_current (float, optional): The maximum amplitude of the injected current (in nA).
137
+ Default is 0.8 nA.
138
+ nb_bins (int, optional): The number of discrete current levels between 0 and `max_current`.
139
+ Default is 11.
140
+
141
+ Returns:
142
+ tuple: A tuple containing:
143
+ - list_amp (np.ndarray): The injected current amplitudes (nA).
144
+ - spike_count (np.ndarray): The corresponding spike counts for each current amplitude.
145
+
146
+ Raises:
147
+ ValueError: If the cell object is invalid or the specified sections/segments are not found.
148
+ """
149
+ rheobase = calculate_rheobase(cell=cell, section=injecting_section, segx=injecting_segment)
150
+
151
+ list_amp = np.linspace(rheobase, max_current, nb_bins) # [nA]
152
+ steps = []
153
+ spikes = []
154
+ # inject step current and record spike response
155
+ stim_factory = StimulusFactory(dt=0.1)
156
+ for amp in list_amp:
157
+ step_stimulus = stim_factory.step(pre_delay=stim_start, duration=duration, post_delay=post_delay, amplitude=amp)
158
+ recording = run_stimulus(cell.template_params,
159
+ step_stimulus,
160
+ section=injecting_section,
161
+ segment=injecting_segment,
162
+ recording_section=recording_section,
163
+ recording_segment=recording_segment,
164
+ enable_spike_detection=True)
165
+ steps.append(step_stimulus)
166
+ spikes.append(recording.spike)
167
+
168
+ spike_count = [len(spike) for spike in spikes]
169
+
170
+ plot_fi_curve(list_amp,
171
+ spike_count,
172
+ injecting_section=injecting_section,
173
+ injecting_segment=injecting_segment,
174
+ recording_section=recording_section,
175
+ recording_segment=recording_segment)
176
+
177
+ return np.array(list_amp), np.array(spike_count)
@@ -1,7 +1,7 @@
1
1
  """Module for injecting a sequence of protocols to the cell."""
2
2
  from __future__ import annotations
3
3
  from enum import Enum, auto
4
- from typing import NamedTuple, Sequence, Dict
4
+ from typing import NamedTuple, Sequence, Dict, Optional
5
5
 
6
6
  import neuron
7
7
  import numpy as np
@@ -11,6 +11,7 @@ from bluecellulab.simulation.parallel import IsolatedProcess
11
11
  from bluecellulab.simulation.simulation import Simulation
12
12
  from bluecellulab.stimulus.circuit_stimulus_definitions import Hyperpolarizing
13
13
  from bluecellulab.stimulus.factory import Stimulus, StimulusFactory
14
+ from bluecellulab.tools import validate_section_and_segment
14
15
 
15
16
 
16
17
  class StimulusName(Enum):
@@ -24,10 +25,12 @@ class StimulusName(Enum):
24
25
 
25
26
 
26
27
  class Recording(NamedTuple):
27
- """A tuple of the current, voltage and time recordings."""
28
+ """A tuple of the current, voltage and time recordings with optional spike
29
+ recordings."""
28
30
  current: np.ndarray
29
31
  voltage: np.ndarray
30
32
  time: np.ndarray
33
+ spike: np.ndarray | None
31
34
 
32
35
 
33
36
  StimulusRecordings = Dict[str, Recording]
@@ -40,41 +43,91 @@ def run_stimulus(
40
43
  segment: float,
41
44
  cvode: bool = True,
42
45
  add_hypamp: bool = True,
46
+ recording_section: str = "soma[0]",
47
+ recording_segment: float = 0.5,
48
+ enable_spike_detection: bool = False,
49
+ threshold_spike_detection: float = -30,
43
50
  ) -> Recording:
44
- """Creates a cell and stimulates it with a given stimulus.
51
+ """Creates a cell from template parameters, applies a stimulus, and records
52
+ the response.
53
+
54
+ This function simulates the electrical activity of a neuronal cell model by injecting
55
+ a stimulus into a specified section and segment, recording the voltage response, and
56
+ optionally detecting spikes.
45
57
 
46
58
  Args:
47
- template_params: The parameters to create the cell from a template.
48
- stimulus: The input stimulus to inject into the cell.
49
- section: Name of the section of cell where the stimulus is to be injected.
50
- segment: The segment of the section where the stimulus is to be injected.
51
- cvode: True to use variable time-steps. False for fixed time-steps.
59
+ template_params (TemplateParams): Parameters required to create the cell from a
60
+ specified template, including morphology and mechanisms.
61
+ stimulus (Stimulus): The stimulus waveform to inject, defined by time and current arrays.
62
+ section (str): Name of the section of the cell where the stimulus is applied.
63
+ (e.g. soma[0])
64
+ segment (float): The normalized position (0.0 to 1.0) along the injecting
65
+ section where the stimulus is applied.
66
+ cvode (bool, optional): Whether to use variable time-step integration. Defaults to True.
67
+ add_hypamp (bool, optional): If True, adds a hyperpolarizing stimulus before applying
68
+ the main stimulus. Defaults to True.
69
+ recording_section (str): Name of the section of the cell where voltage is recorded.
70
+ recording_segment (float): The normalized position (0.0 to 1.0) along the recording
71
+ section where voltage is recorded.
72
+ enable_spike_detection (bool, optional): If True, enables spike detection at the
73
+ recording location. Defaults to False.
74
+ threshold_spike_detection (float, optional): The voltage threshold (mV) for spike detection.
75
+ Defaults to -30 mV.
52
76
 
53
77
  Returns:
54
- The voltage-time recording at the specified location.
78
+ Recording: A `Recording` object containing the following:
79
+ - `current` (np.ndarray): The injected current waveform (nA).
80
+ - `voltage` (np.ndarray): The recorded membrane potential (mV) over time.
81
+ - `time` (np.ndarray): The simulation time points (ms).
82
+ - `spike` (np.ndarray or None): The detected spikes, if spike detection is enabled.
55
83
 
56
84
  Raises:
57
- ValueError: If the time and voltage arrays are not the same length.
85
+ ValueError: If the time, current, and voltage arrays do not have the same length,
86
+ or if the specified sections or segments are not found in the cell model.
58
87
  """
59
88
  cell = Cell.from_template_parameters(template_params)
60
- neuron_section = cell.sections[section]
89
+
90
+ validate_section_and_segment(cell, section, segment)
91
+ validate_section_and_segment(cell, recording_section, recording_segment)
92
+
61
93
  if add_hypamp:
62
94
  hyp_stim = Hyperpolarizing(target="", delay=0.0, duration=stimulus.stimulus_time)
63
95
  cell.add_replay_hypamp(hyp_stim)
64
- cell.add_voltage_recording(neuron_section, segment)
96
+
97
+ cell.add_voltage_recording(cell.sections[recording_section], recording_segment)
98
+
99
+ # Set up spike detection if enabled
100
+ spikes: Optional[np.ndarray] = None
101
+ if enable_spike_detection:
102
+ recording_location = f"{recording_section}({str(recording_segment)})"
103
+ cell.start_recording_spikes(None, location=recording_location, threshold=threshold_spike_detection)
104
+
105
+ # Inject the stimulus and run the simulation
65
106
  iclamp, _ = cell.inject_current_waveform(
66
- stimulus.time, stimulus.current, section=neuron_section, segx=segment
107
+ stimulus.time, stimulus.current, section=cell.sections[section], segx=segment
67
108
  )
68
109
  current_vector = neuron.h.Vector()
69
110
  current_vector.record(iclamp._ref_i)
111
+
70
112
  simulation = Simulation(cell)
71
113
  simulation.run(stimulus.stimulus_time, cvode=cvode)
114
+
115
+ # Retrieve simulation results
72
116
  current = np.array(current_vector.to_python())
73
- voltage = cell.get_voltage_recording(neuron_section, segment)
117
+ voltage = cell.get_voltage_recording(cell.sections[recording_section], recording_segment)
74
118
  time = cell.get_time()
119
+
75
120
  if len(time) != len(voltage) or len(time) != len(current):
76
- raise ValueError("Time, current and voltage arrays are not the same length")
77
- return Recording(current, voltage, time)
121
+ raise ValueError("Time, current, and voltage arrays are not the same length")
122
+
123
+ if enable_spike_detection:
124
+ results = cell.get_recorded_spikes(location=recording_location, threshold=threshold_spike_detection)
125
+ if results is not None:
126
+ spikes = np.array(results)
127
+ else:
128
+ spikes = None
129
+
130
+ return Recording(current=current, voltage=voltage, time=time, spike=spikes)
78
131
 
79
132
 
80
133
  def apply_multiple_stimuli(
@@ -0,0 +1,57 @@
1
+ """Module for plotting analysis results of cell simulations."""
2
+
3
+ import matplotlib.pyplot as plt
4
+
5
+
6
+ def plot_iv_curve(currents, voltages, injecting_section, injecting_segment, recording_section, recording_segment):
7
+ """Plots the IV curve.
8
+
9
+ Args:
10
+ currents (list): The injected current levels (nA).
11
+ voltages (list): The corresponding steady-state voltages (mV).
12
+ injecting_section (str): The section in the cell where the current was injected.
13
+ injecting_segment (float): The segment position (0.0 to 1.0) where the current was injected.
14
+ recording_section (str): The section in the cell where spikes were recorded.
15
+ recording_segment (float): The segment position (0.0 to 1.0) where spikes were recorded.
16
+
17
+ Raises:
18
+ ValueError: If the lengths of currents and voltages do not match.
19
+ """
20
+ if len(currents) != len(voltages):
21
+ raise ValueError("currents and voltages must have the same length")
22
+
23
+ plt.figure(figsize=(10, 6))
24
+ plt.plot(currents, voltages, marker='o', linestyle='-', color='b')
25
+ plt.title("I-V Curve")
26
+ plt.xlabel(f"Injected Current [nA] at {injecting_section}({injecting_segment:.2f})")
27
+ plt.ylabel(f"Steady state voltage [mV] at {recording_section}({recording_segment:.2f})")
28
+ plt.grid(True)
29
+ plt.tight_layout()
30
+ plt.show()
31
+
32
+
33
+ def plot_fi_curve(currents, spike_count, injecting_section, injecting_segment, recording_section, recording_segment):
34
+ """Plots the F-I (Frequency-Current) curve.
35
+
36
+ Args:
37
+ currents (list): The injected current levels (nA).
38
+ spike_count (list): The number of spikes recorded for each current level.
39
+ injecting_section (str): The section in the cell where the current was injected.
40
+ injecting_segment (float): The segment position (0.0 to 1.0) where the current was injected.
41
+ recording_section (str): The section in the cell where spikes were recorded.
42
+ recording_segment (float): The segment position (0.0 to 1.0) where spikes were recorded.
43
+
44
+ Raises:
45
+ ValueError: If the lengths of currents and spike counts do not match.
46
+ """
47
+ if len(currents) != len(spike_count):
48
+ raise ValueError("currents and spike count must have the same length")
49
+
50
+ plt.figure(figsize=(10, 6))
51
+ plt.plot(currents, spike_count, marker='o')
52
+ plt.title("F-I Curve")
53
+ plt.xlabel(f"Injected Current [nA] at {injecting_section}({injecting_segment:.2f})")
54
+ plt.ylabel(f"Spike Count recorded at {recording_section}({recording_segment:.2f})")
55
+ plt.grid(True)
56
+ plt.tight_layout()
57
+ plt.show()
@@ -25,6 +25,7 @@ from typing_extensions import deprecated
25
25
  import neuron
26
26
  import numpy as np
27
27
  import pandas as pd
28
+ import re
28
29
 
29
30
  import bluecellulab
30
31
  from bluecellulab.cell.recording import section_to_voltage_recording_str
@@ -376,7 +377,11 @@ class Cell(InjectableMixin, PlottableMixin):
376
377
 
377
378
  def get_recording(self, var_name: str) -> np.ndarray:
378
379
  """Get recorded values."""
379
- return np.array(self.recordings[var_name].to_python())
380
+ try:
381
+ res = np.array(self.recordings[var_name].to_python())
382
+ except KeyError as e:
383
+ raise ValueError(f"No recording for '{var_name}' was found.") from e
384
+ return res
380
385
 
381
386
  def add_replay_synapse(self,
382
387
  synapse_id: SynapseID,
@@ -432,19 +437,42 @@ class Cell(InjectableMixin, PlottableMixin):
432
437
  def create_netcon_spikedetector(self, target: HocObjectType, location: str, threshold: float = -30.0) -> HocObjectType:
433
438
  """Add and return a spikedetector.
434
439
 
435
- This is a NetCon that detects spike in the current cell, and that
436
- connects to target
440
+ This function creates a NetCon object that detects spikes at a specific
441
+ location in the current cell and connects to the provided target point process.
442
+ The location can be specified as a predefined site ('soma' or 'AIS') or as a
443
+ custom location in the format `section[index](position)`. Custom locations
444
+ allow fine-grained control of the spike detection site within the cell's sections.
437
445
 
438
446
  Args:
439
- target: target point process
440
- location: the spike detection location
441
- threshold: spike detection threshold
447
+ target: A NEURON point process object (e.g., synapse) that the NetCon connects to.
448
+ location: The spike detection location. Acceptable formats include:
449
+
450
+ - `"soma"`: Detect spikes in the soma section at the distal end.
451
+
452
+ - `"AIS"`: Detect spikes in the axon initial segment at the midpoint.
442
453
 
443
- Returns: Neuron netcon object
454
+ - `"section[index](position)"`: Custom location specifying:
455
+
456
+ - `section`: The name of the section (e.g., 'soma', 'axon').
457
+ - `[index]` (optional): Segment index within a section array (e.g., 'soma[0]').
458
+ - `(position)` (optional): Normalized position along the section length (0 to 1).
459
+ Defaults to 0.5 if not provided.
460
+
461
+ threshold: The voltage threshold for spike detection (default: -30.0 mV).
462
+
463
+ Returns:
464
+ A NEURON `NetCon` object configured for spike detection at the specified location.
444
465
 
445
466
  Raises:
446
- ValueError: If the spike detection location is not 'soma' or 'AIS'.
467
+ ValueError: If:
468
+
469
+ - The `location` is not 'soma', 'AIS', or a valid custom format.
470
+
471
+ - The specified section or segment index does not exist.
472
+
473
+ - The position is out of bounds (e.g., negative or greater than 1.0).
447
474
  """
475
+
448
476
  if location == "soma":
449
477
  sec = public_hoc_cell(self.cell).soma[0]
450
478
  source = sec(1)._ref_v
@@ -452,7 +480,34 @@ class Cell(InjectableMixin, PlottableMixin):
452
480
  sec = public_hoc_cell(self.cell).axon[1]
453
481
  source = sec(0.5)._ref_v
454
482
  else:
455
- raise ValueError("Spike detection location must be soma or AIS")
483
+ # Parse custom location (e.g., 'soma[0](0.3)')
484
+ pattern = r'^([a-zA-Z_]+)(?:\[(\d+)\])?(?:\((-?\d+\.\d+)\))?$'
485
+ match = re.search(pattern, location)
486
+
487
+ # Extract the value if a match is found
488
+ if match:
489
+ section_name = match.group(1)
490
+ segment_index = match.group(2)
491
+ pos = match.group(3)
492
+ if pos is None:
493
+ pos = 0.5
494
+ else:
495
+ pos = float(pos)
496
+
497
+ else:
498
+ raise ValueError(f"Invalid location format: {location}")
499
+
500
+ try:
501
+ # Handle section arrays (e.g., soma[0])
502
+ if segment_index is not None:
503
+ sec = getattr(public_hoc_cell(self.cell), section_name)[int(segment_index)]
504
+ else:
505
+ sec = getattr(public_hoc_cell(self.cell), section_name)
506
+
507
+ source = sec(pos)._ref_v
508
+ except (AttributeError, ValueError, IndexError) as e:
509
+ raise ValueError(f"Invalid spike detection location: {location}") from e
510
+
456
511
  netcon = neuron.h.NetCon(source, target, sec=sec)
457
512
  netcon.threshold = threshold
458
513
  return netcon
@@ -28,6 +28,8 @@ from bluecellulab.circuit.circuit_access import EmodelProperties
28
28
  from bluecellulab.exceptions import UnsteadyCellError
29
29
  from bluecellulab.simulation.parallel import IsolatedProcess
30
30
  from bluecellulab.utils import CaptureOutput
31
+ from bluecellulab.type_aliases import NeuronSection
32
+
31
33
 
32
34
  logger = logging.getLogger(__name__)
33
35
 
@@ -38,10 +40,13 @@ def calculate_input_resistance(
38
40
  template_format: str,
39
41
  emodel_properties: EmodelProperties | None,
40
42
  current_delta: float = 0.01,
43
+ section: str = "soma[0]",
44
+ segx: float = 0.5
41
45
  ) -> float:
42
46
  """Calculate the input resistance at rest of the cell."""
43
47
  rest_voltage = calculate_SS_voltage(
44
- template_path, morphology_path, template_format, emodel_properties, 0.0
48
+ template_path, morphology_path, template_format, emodel_properties, 0.0,
49
+ section=section, segx=segx
45
50
  )
46
51
  step_voltage = calculate_SS_voltage(
47
52
  template_path,
@@ -49,6 +54,8 @@ def calculate_input_resistance(
49
54
  template_format,
50
55
  emodel_properties,
51
56
  current_delta,
57
+ section=section,
58
+ segx=segx
52
59
  )
53
60
 
54
61
  voltage_delta = step_voltage - rest_voltage
@@ -64,6 +71,8 @@ def calculate_SS_voltage(
64
71
  step_level: float,
65
72
  check_for_spiking=False,
66
73
  spike_threshold=-20.0,
74
+ section: str = "soma[0]",
75
+ segx: float = 0.5
67
76
  ) -> float:
68
77
  """Calculate the steady state voltage at a certain current step."""
69
78
  with IsolatedProcess() as runner:
@@ -77,6 +86,8 @@ def calculate_SS_voltage(
77
86
  step_level,
78
87
  check_for_spiking,
79
88
  spike_threshold,
89
+ section,
90
+ segx
80
91
  ],
81
92
  )
82
93
  return SS_voltage
@@ -90,6 +101,8 @@ def calculate_SS_voltage_subprocess(
90
101
  step_level: float,
91
102
  check_for_spiking: bool,
92
103
  spike_threshold: float,
104
+ section: str = "soma[0]",
105
+ segx: float = 0.5
93
106
  ) -> float:
94
107
  """Subprocess wrapper of calculate_SS_voltage.
95
108
 
@@ -104,11 +117,15 @@ def calculate_SS_voltage_subprocess(
104
117
  template_format=template_format,
105
118
  emodel_properties=emodel_properties,
106
119
  )
107
- cell.add_ramp(500, 5000, step_level, step_level)
120
+
121
+ sec = get_section(cell, section)
122
+ neuron_section = sec
123
+ cell.add_voltage_recording(cell.sections[section], segx)
124
+ cell.add_ramp(500, 5000, step_level, step_level, section=neuron_section, segx=segx)
108
125
  simulation = bluecellulab.Simulation()
109
126
  simulation.run(1000, cvode=template_accepts_cvode(template_path))
110
127
  time = cell.get_time()
111
- voltage = cell.get_soma_voltage()
128
+ voltage = cell.get_voltage_recording(section=neuron_section, segx=segx)
112
129
  SS_voltage = np.mean(voltage[np.where((time < 1000) & (time > 800))])
113
130
  cell.delete()
114
131
 
@@ -250,6 +267,8 @@ def detect_spike_step(
250
267
  inj_start: float,
251
268
  inj_stop: float,
252
269
  step_level: float,
270
+ section: str = "soma[0]",
271
+ segx: float = 0.5
253
272
  ) -> bool:
254
273
  """Detect if there is a spike at a certain step level."""
255
274
  with IsolatedProcess() as runner:
@@ -264,6 +283,8 @@ def detect_spike_step(
264
283
  inj_start,
265
284
  inj_stop,
266
285
  step_level,
286
+ section,
287
+ segx
267
288
  ],
268
289
  )
269
290
  return spike_detected
@@ -277,7 +298,9 @@ def detect_spike_step_subprocess(
277
298
  hyp_level: float,
278
299
  inj_start: float,
279
300
  inj_stop: float,
280
- step_level: float
301
+ step_level: float,
302
+ section: str = "soma[0]",
303
+ segx: float = 0.5
281
304
  ) -> bool:
282
305
  """Detect if there is a spike at a certain step level."""
283
306
  cell = bluecellulab.Cell(
@@ -285,13 +308,18 @@ def detect_spike_step_subprocess(
285
308
  morphology_path=morphology_path,
286
309
  template_format=template_format,
287
310
  emodel_properties=emodel_properties)
288
- cell.add_ramp(0, 5000, hyp_level, hyp_level)
289
- cell.add_ramp(inj_start, inj_stop, step_level, step_level)
311
+
312
+ sec = get_section(cell, section)
313
+ cell.add_voltage_recording(cell.sections[section], segx)
314
+
315
+ neuron_section = sec
316
+ cell.add_ramp(0, 5000, hyp_level, hyp_level, section=neuron_section, segx=segx)
317
+ cell.add_ramp(inj_start, inj_stop, step_level, step_level, section=neuron_section, segx=segx)
290
318
  simulation = bluecellulab.Simulation()
291
319
  simulation.run(int(inj_stop), cvode=template_accepts_cvode(template_path))
292
320
 
293
321
  time = cell.get_time()
294
- voltage = cell.get_soma_voltage()
322
+ voltage = cell.get_voltage_recording(section=neuron_section, segx=segx)
295
323
  voltage_step = voltage[np.where((time > inj_start) & (time < inj_stop))]
296
324
  spike_detected = detect_spike(voltage_step)
297
325
 
@@ -319,6 +347,8 @@ def search_threshold_current(
319
347
  min_current: float,
320
348
  max_current: float,
321
349
  current_precision: float = 0.01,
350
+ section: str = "soma[0]",
351
+ segx: float = 0.5
322
352
  ):
323
353
  """Search current necessary to reach threshold."""
324
354
  if abs(max_current - min_current) < current_precision:
@@ -328,7 +358,8 @@ def search_threshold_current(
328
358
 
329
359
  spike_detected = detect_spike_step(
330
360
  template_name, morphology_path, template_format, emodel_properties,
331
- hyp_level, inj_start, inj_stop, med_current
361
+ hyp_level, inj_start, inj_stop, med_current,
362
+ section=section, segx=segx
332
363
  )
333
364
  logger.info("Spike threshold detection at: %f nA" % med_current)
334
365
 
@@ -337,13 +368,15 @@ def search_threshold_current(
337
368
  template_format, emodel_properties,
338
369
  hyp_level, inj_start, inj_stop,
339
370
  min_current, med_current,
340
- current_precision)
371
+ current_precision,
372
+ section=section, segx=segx)
341
373
  else:
342
374
  return search_threshold_current(template_name, morphology_path,
343
375
  template_format, emodel_properties,
344
376
  hyp_level, inj_start, inj_stop,
345
377
  med_current, max_current,
346
- current_precision)
378
+ current_precision,
379
+ section=section, segx=segx)
347
380
 
348
381
 
349
382
  def check_empty_topology() -> bool:
@@ -354,12 +387,17 @@ def check_empty_topology() -> bool:
354
387
  return stdout == ['', '']
355
388
 
356
389
 
357
- def calculate_max_thresh_current(cell: Cell, threshold_voltage: float = -30.0) -> float:
390
+ def calculate_max_thresh_current(cell: Cell,
391
+ threshold_voltage: float = -30.0,
392
+ section: str = "soma[0]",
393
+ segx: float = 0.5) -> float:
358
394
  """Calculate the upper bound threshold current.
359
395
 
360
396
  Args:
361
397
  cell (bluecellulab.cell.Cell): The initialized cell model.
362
398
  threshold_voltage (float, optional): Voltage threshold for spike detection. Default is -30.0 mV.
399
+ section (str, optional): The section where current is injected.
400
+ segx (float, optional): Fractional location within the section for current injection.
363
401
 
364
402
  Returns:
365
403
  float: The upper bound threshold current.
@@ -371,6 +409,8 @@ def calculate_max_thresh_current(cell: Cell, threshold_voltage: float = -30.0) -
371
409
  template_format=cell.template_params.template_format,
372
410
  emodel_properties=cell.template_params.emodel_properties,
373
411
  step_level=0.0,
412
+ section=section,
413
+ segx=segx
374
414
  )
375
415
 
376
416
  # Calculate input resistance (rin)
@@ -379,6 +419,8 @@ def calculate_max_thresh_current(cell: Cell, threshold_voltage: float = -30.0) -
379
419
  morphology_path=cell.template_params.morph_filepath,
380
420
  template_format=cell.template_params.template_format,
381
421
  emodel_properties=cell.template_params.emodel_properties,
422
+ section=section,
423
+ segx=segx
382
424
  )
383
425
 
384
426
  # Calculate upperbound threshold current
@@ -391,7 +433,9 @@ def calculate_max_thresh_current(cell: Cell, threshold_voltage: float = -30.0) -
391
433
  def calculate_rheobase(cell: Cell,
392
434
  threshold_voltage: float = -30.0,
393
435
  threshold_search_stim_start: float = 300.0,
394
- threshold_search_stim_stop: float = 1000.0) -> float:
436
+ threshold_search_stim_stop: float = 1000.0,
437
+ section: str = "soma[0]",
438
+ segx: float = 0.5) -> float:
395
439
  """Calculate the rheobase by first computing the upper bound threshold
396
440
  current.
397
441
 
@@ -400,6 +444,8 @@ def calculate_rheobase(cell: Cell,
400
444
  threshold_voltage (float, optional): Voltage threshold for spike detection. Default is -30.0 mV.
401
445
  threshold_search_stim_start (float, optional): Start time for threshold search stimulation (in ms). Default is 300.0 ms.
402
446
  threshold_search_stim_stop (float, optional): Stop time for threshold search stimulation (in ms). Default is 1000.0 ms.
447
+ section (str, optional): The section where current is injected.
448
+ segx (float, optional): Fractional location within the section for current injection.
403
449
 
404
450
  Returns:
405
451
  float: The rheobase current.
@@ -408,7 +454,12 @@ def calculate_rheobase(cell: Cell,
408
454
  raise ValueError("emodel_properties cannot be None")
409
455
 
410
456
  # Calculate upper bound threshold current
411
- upperbound_threshold_current = calculate_max_thresh_current(cell, threshold_voltage)
457
+ upperbound_threshold_current = calculate_max_thresh_current(
458
+ cell,
459
+ threshold_voltage,
460
+ section,
461
+ segx
462
+ )
412
463
 
413
464
  # Compute rheobase
414
465
  rheobase = search_threshold_current(
@@ -422,6 +473,47 @@ def calculate_rheobase(cell: Cell,
422
473
  min_current=cell.template_params.emodel_properties.holding_current,
423
474
  max_current=upperbound_threshold_current,
424
475
  current_precision=0.005,
476
+ section=section,
477
+ segx=segx
425
478
  )
426
479
 
427
480
  return rheobase
481
+
482
+
483
+ def validate_section_and_segment(cell: Cell, section_name: str, segment_position: float):
484
+ """Validate a single section and segment position.
485
+
486
+ Args:
487
+ cell: The cell model to validate against.
488
+ section_name: The name of the section to validate (e.g., 'soma', 'axon[1]').
489
+ segment_position: The position within the section (e.g., 0.5 for the middle).
490
+
491
+ Raises:
492
+ ValueError: If the section or position is invalid.
493
+ """
494
+ # Validate the section
495
+ if section_name not in cell.sections:
496
+ raise ValueError(f"Section '{section_name}' not found in the cell model.")
497
+
498
+ # Validate the segment position
499
+ if not (0.0 <= segment_position <= 1.0):
500
+ raise ValueError(f"Segment position must be between 0.0 and 1.0, got {segment_position}.")
501
+
502
+
503
+ def get_section(cell: Cell, section_name: str) -> NeuronSection:
504
+ """Retrieve a NEURON section from the cell by its name.
505
+
506
+ Args:
507
+ cell (Cell): The cell object containing the sections.
508
+ section_name (str): The name of the section to retrieve.
509
+
510
+ Returns:
511
+ NeuronSection: The NEURON section corresponding to the provided name.
512
+
513
+ Raises:
514
+ ValueError: If the section with the specified name does not exist.
515
+ """
516
+ try:
517
+ return cell.sections[section_name]
518
+ except KeyError:
519
+ raise ValueError(f"Section '{section_name}' not found in the cell.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: bluecellulab
3
- Version: 2.6.40
3
+ Version: 2.6.41
4
4
  Summary: Biologically detailed neural network simulations and analysis.
5
5
  Author: Blue Brain Project, EPFL
6
6
  License: Apache2.0
@@ -1,63 +0,0 @@
1
- """Module for analyzing cell simulation results."""
2
- try:
3
- import efel
4
- except ImportError:
5
- efel = None
6
- import numpy as np
7
-
8
- from bluecellulab.stimulus import StimulusFactory
9
- from bluecellulab.tools import calculate_rheobase
10
- from bluecellulab.analysis.inject_sequence import run_stimulus
11
- from bluecellulab.analysis.plotting import plot_iv_curve
12
-
13
-
14
- def compute_plot_iv_curve(cell, stim_start=100.0, duration=500.0, post_delay=100.0, threshold_voltage=-30, nb_bins=11):
15
- """Compute and plot the IV curve from a given cell by injecting a
16
- predefined range of currents.
17
-
18
- Args:
19
- cell (bluecellulab.cell.Cell): The initialized cell model.
20
- stim_start (float): Start time for current injection (in ms). Default is 100.0 ms.
21
- duration (float): Duration of current injection (in ms). Default is 500.0 ms.
22
- post_delay (float): Delay after the stimulation ends (in ms). Default is 100.0 ms.
23
- nb_bins (int): Number of current injection levels. Default is 11.
24
-
25
- Returns:
26
- tuple: A tuple containing:
27
- - list_amp (np.ndarray): The predefined injected step current levels (nA).
28
- - steady_states (np.ndarray): The corresponding steady-state voltages (mV).
29
- """
30
- rheobase = calculate_rheobase(cell)
31
-
32
- list_amp = np.linspace(rheobase - 2, rheobase - 0.1, nb_bins) # [nA]
33
-
34
- steps = []
35
- times = []
36
- voltages = []
37
- # inject step current and record voltage response
38
- for amp in list_amp:
39
- stim_factory = StimulusFactory(dt=0.1)
40
- step_stimulus = stim_factory.step(pre_delay=stim_start, duration=duration, post_delay=post_delay, amplitude=amp)
41
- recording = run_stimulus(cell.template_params, step_stimulus, section="soma[0]", segment=0.5)
42
- steps.append(step_stimulus)
43
- times.append(recording.time)
44
- voltages.append(recording.voltage)
45
-
46
- steady_states = []
47
- # compute steady state response
48
- efel.set_setting('Threshold', threshold_voltage)
49
- for voltage, t in zip(voltages, times):
50
- trace = {
51
- 'T': t,
52
- 'V': voltage,
53
- 'stim_start': [stim_start],
54
- 'stim_end': [stim_start + duration]
55
- }
56
- features_results = efel.get_feature_values([trace], ['steady_state_voltage_stimend'])
57
- steady_state = features_results[0]['steady_state_voltage_stimend']
58
- steady_states.append(steady_state)
59
-
60
- # plot I-V curve
61
- plot_iv_curve(list_amp, steady_states)
62
-
63
- return np.array(list_amp), np.array(steady_states)
@@ -1,25 +0,0 @@
1
- """Module for plotting analysis results of cell simulations."""
2
-
3
- import matplotlib.pyplot as plt
4
-
5
-
6
- def plot_iv_curve(currents, voltages):
7
- """Plots the IV curve.
8
-
9
- Args:
10
- currents (iterable): The injected current levels (nA).
11
- voltages (iterable): The corresponding steady-state voltages (mV).
12
- Raises:
13
- ValueError: If the lengths of currents and voltages do not match.
14
- """
15
- if len(currents) != len(voltages):
16
- raise ValueError("currents and voltages must have the same length")
17
-
18
- # Plotting
19
- plt.figure(figsize=(10, 6))
20
- plt.plot(voltages, currents, marker='o', linestyle='-', color='b')
21
- plt.title("I-V Curve")
22
- plt.ylabel("Injected current [nA]")
23
- plt.xlabel("Steady state voltage [mV]")
24
- plt.tight_layout()
25
- plt.show()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes