dendrotweaks 0.4.5__py3-none-any.whl → 0.4.6__py3-none-any.whl
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.
- dendrotweaks/__init__.py +1 -1
- dendrotweaks/analysis/ephys_analysis.py +63 -39
- dendrotweaks/biophys/default_mod/vecstim.mod +1 -11
- dendrotweaks/biophys/distributions.py +3 -3
- dendrotweaks/biophys/io/converter.py +4 -0
- dendrotweaks/biophys/mechanisms.py +11 -1
- dendrotweaks/model.py +143 -1087
- dendrotweaks/model_io.py +736 -39
- dendrotweaks/model_simulation.py +326 -0
- dendrotweaks/morphology/io/reader.py +2 -2
- dendrotweaks/path_manager.py +2 -2
- dendrotweaks/prerun.py +63 -0
- dendrotweaks/utils.py +114 -29
- {dendrotweaks-0.4.5.dist-info → dendrotweaks-0.4.6.dist-info}/METADATA +1 -1
- {dendrotweaks-0.4.5.dist-info → dendrotweaks-0.4.6.dist-info}/RECORD +18 -16
- {dendrotweaks-0.4.5.dist-info → dendrotweaks-0.4.6.dist-info}/WHEEL +0 -0
- {dendrotweaks-0.4.5.dist-info → dendrotweaks-0.4.6.dist-info}/licenses/LICENSE +0 -0
- {dendrotweaks-0.4.5.dist-info → dendrotweaks-0.4.6.dist-info}/top_level.txt +0 -0
dendrotweaks/__init__.py
CHANGED
@@ -257,7 +257,7 @@ def plot_somatic_spikes(data, ax=None, show_metrics=False):
|
|
257
257
|
ax.plot([t - 10*w/2, t + 10*w/2], [v - a/2, v - a/2], color='lawngreen', linestyle='--')
|
258
258
|
|
259
259
|
|
260
|
-
def calculate_fI_curve(model, duration=1000, min_amp=0, max_amp=1, n=5, **kwargs):
|
260
|
+
def calculate_fI_curve(model, duration=1000, prerun_time=0, min_amp=0, max_amp=1, n=5, **kwargs):
|
261
261
|
"""
|
262
262
|
Calculate the frequency-current (f-I) curve of the neuron model.
|
263
263
|
|
@@ -289,7 +289,7 @@ def calculate_fI_curve(model, duration=1000, min_amp=0, max_amp=1, n=5, **kwargs
|
|
289
289
|
vs = {}
|
290
290
|
for amp in amps:
|
291
291
|
iclamp.amp = amp
|
292
|
-
model.
|
292
|
+
model.run(duration=duration, prerun_time=prerun_time)
|
293
293
|
spike_data = detect_somatic_spikes(model, **kwargs)
|
294
294
|
n_spikes = len(spike_data['spike_times'])
|
295
295
|
rate = n_spikes / iclamp.dur * 1000
|
@@ -304,7 +304,22 @@ def calculate_fI_curve(model, duration=1000, min_amp=0, max_amp=1, n=5, **kwargs
|
|
304
304
|
}
|
305
305
|
|
306
306
|
|
307
|
-
def plot_fI_curve(data, ax=None, **kwargs):
|
307
|
+
def plot_fI_curve(data, ax=None, vshift=200, **kwargs):
|
308
|
+
"""
|
309
|
+
Plot the f-I curve and somatic voltage traces.
|
310
|
+
|
311
|
+
Parameters
|
312
|
+
----------
|
313
|
+
data : dict
|
314
|
+
A dictionary containing the current amplitudes, firing rates, and voltages.
|
315
|
+
Can be obtained from `calculate_fI_curve`.
|
316
|
+
ax : matplotlib.axes.Axes, optional
|
317
|
+
The axes to plot on. If two axes are provided, the first will show the somatic voltage traces and the second will show the f-I curve.
|
318
|
+
If a single axis is provided, it will show the f-I curve only.
|
319
|
+
If None, a new figure will be created.
|
320
|
+
vshift : int, optional
|
321
|
+
The vertical shift for the somatic voltage traces. Default is 200.
|
322
|
+
"""
|
308
323
|
|
309
324
|
if ax is None:
|
310
325
|
_, ax = plt.subplots(1, 2, figsize=(5, 5))
|
@@ -314,25 +329,20 @@ def plot_fI_curve(data, ax=None, **kwargs):
|
|
314
329
|
vs = data['voltages']
|
315
330
|
t = data['time']
|
316
331
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
ax[0].spines['right'].set_visible(False)
|
325
|
-
ax[0].spines['bottom'].set_visible(False)
|
326
|
-
ax[0].spines['left'].set_visible(False)
|
327
|
-
ax[0].set_xticks([])
|
328
|
-
ax[0].set_yticks([])
|
332
|
+
if isinstance(ax, (list, np.ndarray)):
|
333
|
+
for i, (amp, v) in enumerate(vs.items()):
|
334
|
+
ax[0].plot(t, np.array(v) - i*vshift, label=f'{amp} nA')
|
335
|
+
ax[0].set_title('Somatic spikes')
|
336
|
+
ax[0].legend()
|
337
|
+
ax[0].axis('off')
|
338
|
+
ax = ax[1]
|
329
339
|
|
330
|
-
ax
|
340
|
+
ax.plot(amps, rates, color='gray', zorder=0)
|
331
341
|
for a, r in zip(amps, rates):
|
332
|
-
ax
|
333
|
-
ax
|
334
|
-
ax
|
335
|
-
ax
|
342
|
+
ax.plot(a, r, 'o', zorder=1)
|
343
|
+
ax.set_xlabel('Current (nA)')
|
344
|
+
ax.set_ylabel('Firing rate (Hz)')
|
345
|
+
ax.set_title('f-I curve')
|
336
346
|
|
337
347
|
|
338
348
|
# =============================================================================
|
@@ -416,7 +426,7 @@ def plot_voltage_attenuation(data, ax=None):
|
|
416
426
|
ax.set_ylabel('Voltage attenuation')
|
417
427
|
ax.set_title('Voltage attenuation')
|
418
428
|
|
419
|
-
def calculate_dendritic_nonlinearity(model, duration=1000, max_weight=None, n=None):
|
429
|
+
def calculate_dendritic_nonlinearity(model, duration=1000, prerun_time=0, max_weight=None, n=None):
|
420
430
|
"""Calculate the expected and observed voltage changes for a range of synaptic weights.
|
421
431
|
|
422
432
|
Parameters
|
@@ -460,7 +470,7 @@ def calculate_dendritic_nonlinearity(model, duration=1000, max_weight=None, n=No
|
|
460
470
|
|
461
471
|
for w in weights:
|
462
472
|
population.update_input_params(weight=w)
|
463
|
-
model.
|
473
|
+
model.run(duration=duration, prerun_time=prerun_time)
|
464
474
|
v = np.array(model.simulator.recordings['v'][seg])
|
465
475
|
v_start = v[start_ts]
|
466
476
|
v_max = np.max(v[start_ts:])
|
@@ -479,7 +489,22 @@ def calculate_dendritic_nonlinearity(model, duration=1000, max_weight=None, n=No
|
|
479
489
|
}
|
480
490
|
|
481
491
|
|
482
|
-
def plot_dendritic_nonlinearity(data, ax=None, **kwargs):
|
492
|
+
def plot_dendritic_nonlinearity(data, ax=None, vshift=200, **kwargs):
|
493
|
+
"""
|
494
|
+
Plot the dendritic nonlinearity based on expected and observed voltage changes.
|
495
|
+
|
496
|
+
Parameters
|
497
|
+
----------
|
498
|
+
data : dict
|
499
|
+
A dictionary containing the expected and observed voltage changes.
|
500
|
+
Can be obtained from `calculate_dendritic_nonlinearity`.
|
501
|
+
ax : matplotlib.axes.Axes, optional
|
502
|
+
The axes to plot on. If two axes are provided, the first will show the voltage traces and the second will show the dendritic nonlinearity.
|
503
|
+
If a single axis is provided, it will show the dendritic nonlinearity only.
|
504
|
+
If None, a new figure will be created.
|
505
|
+
vshift : int, optional
|
506
|
+
The vertical shift for the voltage traces.
|
507
|
+
"""
|
483
508
|
|
484
509
|
if ax is None:
|
485
510
|
_, ax = plt.subplots(1, 2, figsize=(10, 5))
|
@@ -489,22 +514,21 @@ def plot_dendritic_nonlinearity(data, ax=None, **kwargs):
|
|
489
514
|
vs = data['voltages']
|
490
515
|
t = data['time']
|
491
516
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
ax
|
501
|
-
ax
|
502
|
-
|
503
|
-
|
504
|
-
ax
|
505
|
-
ax
|
506
|
-
ax
|
507
|
-
ax[1].set_title('Dendritic nonlinearity')
|
517
|
+
if isinstance(ax, (list, np.ndarray)):
|
518
|
+
for i, (weight, v) in enumerate(vs.items()):
|
519
|
+
ax[0].plot(t, np.array(v) - i*vshift, label=f'{weight} synapses')
|
520
|
+
ax[0].set_title('Voltage traces')
|
521
|
+
ax[0].legend()
|
522
|
+
ax[0].axis('off')
|
523
|
+
ax = ax[1]
|
524
|
+
|
525
|
+
ax.plot(expected_delta_vs, delta_vs, zorder=1)
|
526
|
+
ax.plot(expected_delta_vs, expected_delta_vs, color='gray', linestyle='--', zorder=0)
|
527
|
+
for ep, ob in zip(expected_delta_vs, delta_vs):
|
528
|
+
ax.plot(ep, ob, 'o', zorder=2)
|
529
|
+
ax.set_xlabel('Expected voltage change (mV)')
|
530
|
+
ax.set_ylabel('Observed voltage change (mV)')
|
531
|
+
ax.set_title('Dendritic nonlinearity')
|
508
532
|
|
509
533
|
|
510
534
|
def calculate_sag_ratio(model):
|
@@ -1,6 +1,7 @@
|
|
1
1
|
: Vector stream of events
|
2
2
|
|
3
3
|
NEURON {
|
4
|
+
THREADSAFE
|
4
5
|
ARTIFICIAL_CELL VecStim
|
5
6
|
RANGE delay
|
6
7
|
}
|
@@ -12,13 +13,8 @@ ASSIGNED {
|
|
12
13
|
delay
|
13
14
|
}
|
14
15
|
|
15
|
-
PARAMETER {
|
16
|
-
:delay = 0.0
|
17
|
-
}
|
18
|
-
|
19
16
|
INITIAL {
|
20
17
|
index = 0
|
21
|
-
:delay = 0
|
22
18
|
element()
|
23
19
|
if (index > 0) {
|
24
20
|
net_send(delay + etime - t, 1)
|
@@ -35,12 +31,6 @@ NET_RECEIVE (w) {
|
|
35
31
|
}
|
36
32
|
}
|
37
33
|
|
38
|
-
VERBATIM
|
39
|
-
extern double* vector_vec();
|
40
|
-
extern int vector_capacity();
|
41
|
-
extern void* vector_arg();
|
42
|
-
ENDVERBATIM
|
43
|
-
|
44
34
|
PROCEDURE element() {
|
45
35
|
VERBATIM
|
46
36
|
{ void* vv; int i, size; double* px;
|
@@ -131,16 +131,16 @@ def gaussian(distance: float, amplitude: float, mean: float, std: float) -> floa
|
|
131
131
|
return amplitude * exp(-((distance - mean) ** 2) / (2 * std ** 2))
|
132
132
|
|
133
133
|
|
134
|
-
def step(distance: float,
|
134
|
+
def step(distance: float, start: float, end: float, min_value: float, max_value: float) -> float:
|
135
135
|
"""
|
136
136
|
Step distribution function.
|
137
137
|
|
138
138
|
Args:
|
139
139
|
distance (float): The distance parameter.
|
140
|
-
min_value (float): The minimum value parameter.
|
141
|
-
max_value (float): The maximum value parameter.
|
142
140
|
start (float): The start parameter.
|
143
141
|
end (float): The end parameter.
|
142
|
+
min_value (float): The minimum value parameter.
|
143
|
+
max_value (float): The maximum value parameter.
|
144
144
|
|
145
145
|
Returns:
|
146
146
|
The result of the step equation: min_value if distance < start, max_value if distance > end, and a linear interpolation between min_value and max_value if start <= distance <= end.
|
@@ -94,6 +94,10 @@ class MODFileConverter():
|
|
94
94
|
self.reader.read_file(path_to_mod_file)
|
95
95
|
self.reader.preprocess()
|
96
96
|
blocks = self.reader.get_blocks(verbose)
|
97
|
+
if blocks.get('KINETIC'):
|
98
|
+
raise NotImplementedError(
|
99
|
+
"Conversion aborted: MOD files containing KINETIC blocks are not supported by DendroTweaks."
|
100
|
+
)
|
97
101
|
|
98
102
|
if verbose: print(f"\nPARSING")
|
99
103
|
self.parser.parse(blocks, verbose)
|
@@ -575,4 +575,14 @@ class CaDynamics(Mechanism):
|
|
575
575
|
'gamma': 0.05,
|
576
576
|
'kt': 0.0,
|
577
577
|
'kd': 0.0
|
578
|
-
}
|
578
|
+
}
|
579
|
+
|
580
|
+
|
581
|
+
class FallbackChannel(IonChannel):
|
582
|
+
"""
|
583
|
+
Fallback channel class in case of import failure.
|
584
|
+
"""
|
585
|
+
def __init__(self, name):
|
586
|
+
super().__init__(name=name)
|
587
|
+
self.params = {'gbar': 0.0}
|
588
|
+
self.range_params = {'gbar': 0.0}
|