bmtool 0.7.5.1__py3-none-any.whl → 0.7.7__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.
- bmtool/bmplot/connections.py +11 -5
- bmtool/connectors.py +386 -0
- bmtool/singlecell.py +429 -31
- bmtool/synapses.py +369 -45
- bmtool/util/util.py +69 -17
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/METADATA +1 -1
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/RECORD +11 -11
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/WHEEL +0 -0
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/entry_points.txt +0 -0
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/licenses/LICENSE +0 -0
- {bmtool-0.7.5.1.dist-info → bmtool-0.7.7.dist-info}/top_level.txt +0 -0
bmtool/singlecell.py
CHANGED
@@ -769,7 +769,7 @@ class FI(object):
|
|
769
769
|
--------
|
770
770
|
tuple
|
771
771
|
(current_amplitudes, spike_counts) where:
|
772
|
-
- current_amplitudes: List of current injection amplitudes (
|
772
|
+
- current_amplitudes: List of current injection amplitudes (pA)
|
773
773
|
- spike_counts: List of spike counts corresponding to each amplitude
|
774
774
|
"""
|
775
775
|
print("Running simulations for FI curve...")
|
@@ -781,14 +781,14 @@ class FI(object):
|
|
781
781
|
print()
|
782
782
|
print("Results")
|
783
783
|
# lets make a df so the results line up nice
|
784
|
-
data = {"Injection (
|
784
|
+
data = {"Injection (pA):": [amp * 1000 for amp in self.amps], "number of spikes": self.nspks}
|
785
785
|
df = pd.DataFrame(data)
|
786
786
|
print(df)
|
787
|
-
# print(f'Injection (
|
787
|
+
# print(f'Injection (pA): ' + ', '.join(f'{x:g}' for x in self.amps))
|
788
788
|
# print(f'Number of spikes: ' + ', '.join(f'{x:d}' for x in self.nspks))
|
789
789
|
print()
|
790
790
|
|
791
|
-
return self.amps, self.nspks
|
791
|
+
return [amp * 1000 for amp in self.amps], self.nspks
|
792
792
|
|
793
793
|
|
794
794
|
class ZAP(CurrentClamp):
|
@@ -1040,6 +1040,8 @@ class Profiler:
|
|
1040
1040
|
# initialize to None and then prefer config-derived paths if provided
|
1041
1041
|
self.template_dir = None
|
1042
1042
|
self.mechanism_dir = None
|
1043
|
+
self.templates = None # Initialize templates attribute
|
1044
|
+
self.config = config # Store config path
|
1043
1045
|
|
1044
1046
|
# If a BMTK config is provided, load mechanisms/templates from it
|
1045
1047
|
if config is not None:
|
@@ -1067,7 +1069,7 @@ class Profiler:
|
|
1067
1069
|
load_templates_from_config(config)
|
1068
1070
|
except Exception:
|
1069
1071
|
# fall back to explicit dirs if config parsing/loading fails
|
1070
|
-
|
1072
|
+
print('failed')
|
1071
1073
|
|
1072
1074
|
else:
|
1073
1075
|
# fall back to explicit args if not set by config
|
@@ -1091,30 +1093,54 @@ class Profiler:
|
|
1091
1093
|
|
1092
1094
|
def load_templates(self, hoc_template_file=None):
|
1093
1095
|
if self.templates is None: # Can really only do this once
|
1094
|
-
if
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1096
|
+
# Check if we have a config file - if so, extract templates from node configs
|
1097
|
+
if hasattr(self, 'config') and self.config is not None:
|
1098
|
+
try:
|
1099
|
+
from bmtool.util.util import load_nodes_from_config
|
1100
|
+
nodes_networks = load_nodes_from_config(config=self.config)
|
1101
|
+
template_names = set()
|
1102
|
+
for nodes in nodes_networks:
|
1103
|
+
try:
|
1104
|
+
cell_template_names = nodes_networks[nodes]['model_template'].unique()
|
1105
|
+
# Clean up template names (remove 'hoc:' prefix if present)
|
1106
|
+
for template in cell_template_names:
|
1107
|
+
if isinstance(template, str):
|
1108
|
+
# Remove 'hoc:' prefix if present
|
1109
|
+
clean_name = template.replace('hoc:', '') if template.startswith('hoc:') else template
|
1110
|
+
template_names.add(clean_name)
|
1111
|
+
except:
|
1112
|
+
# If fails, means no model_templates in that network
|
1113
|
+
pass
|
1114
|
+
|
1115
|
+
self.templates = sorted(list(template_names))
|
1116
|
+
self.hoc_templates = [] # Templates loaded via config, not hoc files
|
1117
|
+
|
1118
|
+
except Exception as e:
|
1119
|
+
print(f"Failed to load templates from config: {e}")
|
1108
1120
|
else:
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1121
|
+
# Traditional loading with template_dir and mechanism_dir
|
1122
|
+
if (
|
1123
|
+
self.mechanism_dir != "./"
|
1124
|
+
and self.mechanism_dir != "."
|
1125
|
+
and self.mechanism_dir != "././"
|
1126
|
+
):
|
1127
|
+
neuron.load_mechanisms(self.mechanism_dir)
|
1128
|
+
h_base = set(dir(h))
|
1129
|
+
|
1130
|
+
cwd = os.getcwd()
|
1131
|
+
os.chdir(self.template_dir)
|
1132
|
+
if not hoc_template_file:
|
1133
|
+
self.hoc_templates = glob.glob("*.hoc")
|
1134
|
+
for hoc_template in self.hoc_templates:
|
1135
|
+
h.load_file(str(hoc_template))
|
1136
|
+
else:
|
1137
|
+
self.hoc_templates = [hoc_template_file]
|
1138
|
+
h.load_file(hoc_template_file)
|
1139
|
+
|
1140
|
+
os.chdir(cwd)
|
1141
|
+
|
1142
|
+
h_loaded = dir(h)
|
1143
|
+
self.templates = [x for x in h_loaded if x not in h_base]
|
1118
1144
|
|
1119
1145
|
return self.templates
|
1120
1146
|
|
@@ -1163,10 +1189,16 @@ class Profiler:
|
|
1163
1189
|
|
1164
1190
|
if plot:
|
1165
1191
|
plt.figure()
|
1166
|
-
|
1192
|
+
t_array = np.array(time)
|
1193
|
+
amp_array = np.array(amp)
|
1194
|
+
t_idx = (t_array >= passive.inj_delay) & (t_array <= passive.inj_delay + passive.inj_dur)
|
1195
|
+
plt.plot(t_array[t_idx], amp_array[t_idx])
|
1167
1196
|
if passive.method == "exp2":
|
1168
1197
|
plt.plot(*passive.double_exponential_fit(), "r:", label="double exponential fit")
|
1169
1198
|
plt.legend()
|
1199
|
+
elif passive.method == "exp":
|
1200
|
+
plt.plot(*passive.single_exponential_fit(), "r:", label="single exponential fit")
|
1201
|
+
plt.legend()
|
1170
1202
|
plt.title("Passive Cell Current Injection")
|
1171
1203
|
plt.xlabel("Time (ms)")
|
1172
1204
|
plt.ylabel("Membrane Potential (mV)")
|
@@ -1228,7 +1260,7 @@ class Profiler:
|
|
1228
1260
|
plot: bool
|
1229
1261
|
automatically plot an fi curve
|
1230
1262
|
|
1231
|
-
Returns the injection amplitudes (
|
1263
|
+
Returns the injection amplitudes (pA) used, number of spikes per amplitude supplied
|
1232
1264
|
list(amps), list(# of spikes)
|
1233
1265
|
"""
|
1234
1266
|
fi = FI(
|
@@ -1244,7 +1276,7 @@ class Profiler:
|
|
1244
1276
|
plt.figure()
|
1245
1277
|
plt.plot(amp, nspk)
|
1246
1278
|
plt.title("FI Curve")
|
1247
|
-
plt.xlabel("Injection (
|
1279
|
+
plt.xlabel("Injection (pA)")
|
1248
1280
|
plt.ylabel("# Spikes")
|
1249
1281
|
plt.show()
|
1250
1282
|
|
@@ -1301,6 +1333,372 @@ class Profiler:
|
|
1301
1333
|
|
1302
1334
|
return time, amp
|
1303
1335
|
|
1336
|
+
def interactive_runner(self):
|
1337
|
+
"""Interactive runner for single cell profiling with GUI widgets.
|
1338
|
+
|
1339
|
+
This method creates an interactive interface using ipywidgets that allows
|
1340
|
+
users to select templates and analysis methods, adjust parameters, and run
|
1341
|
+
simulations with real-time plotting.
|
1342
|
+
"""
|
1343
|
+
try:
|
1344
|
+
import ipywidgets as widgets
|
1345
|
+
from IPython.display import display, clear_output
|
1346
|
+
import matplotlib.pyplot as plt
|
1347
|
+
except ImportError:
|
1348
|
+
raise ImportError("ipywidgets and matplotlib are required for interactive mode. Install with: pip install ipywidgets matplotlib")
|
1349
|
+
|
1350
|
+
# Get available templates
|
1351
|
+
available_templates = self.load_templates()
|
1352
|
+
|
1353
|
+
# Check what NEURON objects are available
|
1354
|
+
import neuron
|
1355
|
+
h = neuron.h
|
1356
|
+
|
1357
|
+
# Create widgets
|
1358
|
+
template_dropdown = widgets.Dropdown(
|
1359
|
+
options=available_templates,
|
1360
|
+
value=available_templates[0] if available_templates else None,
|
1361
|
+
description='Template:',
|
1362
|
+
style={'description_width': '80px'},
|
1363
|
+
layout=widgets.Layout(width='300px')
|
1364
|
+
)
|
1365
|
+
|
1366
|
+
method_dropdown = widgets.Dropdown(
|
1367
|
+
options=['passive_properties', 'current_injection', 'fi_curve', 'impedance_amplitude_profile'],
|
1368
|
+
value='passive_properties',
|
1369
|
+
description='Method:',
|
1370
|
+
style={'description_width': '80px'},
|
1371
|
+
layout=widgets.Layout(width='300px')
|
1372
|
+
)
|
1373
|
+
|
1374
|
+
# Default values based on method - from basic_settings in single_cell_tuning.ipynb
|
1375
|
+
method_defaults = {
|
1376
|
+
'passive_properties': {
|
1377
|
+
'inj_amp': -20.0,
|
1378
|
+
'inj_delay': 1500.0,
|
1379
|
+
'inj_dur': 1000.0,
|
1380
|
+
'tstop': 2500.0,
|
1381
|
+
'tau_method': 'exp2'
|
1382
|
+
},
|
1383
|
+
'current_injection': {
|
1384
|
+
'inj_amp': 50.0,
|
1385
|
+
'inj_delay': 1500.0,
|
1386
|
+
'inj_dur': 1000.0,
|
1387
|
+
'tstop': 3000.0
|
1388
|
+
},
|
1389
|
+
'fi_curve': {
|
1390
|
+
'i_start': -100.0,
|
1391
|
+
'i_stop': 800.0,
|
1392
|
+
'i_increment': 20.0,
|
1393
|
+
'inj_delay': 1500.0,
|
1394
|
+
'inj_dur': 1000.0
|
1395
|
+
},
|
1396
|
+
'impedance_amplitude_profile': {
|
1397
|
+
'inj_amp': 100.0,
|
1398
|
+
'inj_delay': 1000.0,
|
1399
|
+
'inj_dur': 15000.0,
|
1400
|
+
'tstop': 15500.0,
|
1401
|
+
'fstart': 0.0,
|
1402
|
+
'fend': 15.0,
|
1403
|
+
'chirp_type': 'linear'
|
1404
|
+
}
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
# Common parameters - always plot results, no need for toggle
|
1408
|
+
|
1409
|
+
# Method-specific parameters - styled like synapses.py sliders
|
1410
|
+
slider_style = {'description_width': 'initial'}
|
1411
|
+
slider_layout = None # Use default width for longer sliders
|
1412
|
+
text_style = {'description_width': 'initial'}
|
1413
|
+
text_layout = widgets.Layout(width='200px')
|
1414
|
+
|
1415
|
+
# Initialize sliders with default values for passive_properties (initial method)
|
1416
|
+
defaults = method_defaults['passive_properties']
|
1417
|
+
|
1418
|
+
inj_amp_slider = widgets.FloatSlider(value=defaults['inj_amp'], min=-500.0, max=1000.0, step=10.0, description='Injection Amp (pA):', style=slider_style)
|
1419
|
+
inj_delay_slider = widgets.FloatSlider(value=defaults['inj_delay'], min=0.0, max=3000.0, step=10.0, description='Injection Delay (ms):', style=slider_style)
|
1420
|
+
inj_dur_slider = widgets.FloatSlider(value=defaults['inj_dur'], min=100.0, max=20000.0, step=100.0, description='Injection Duration (ms):', style=slider_style)
|
1421
|
+
tstop_slider = widgets.FloatSlider(value=defaults['tstop'], min=500.0, max=25000.0, step=100.0, description='Total Time (ms):', style=slider_style)
|
1422
|
+
|
1423
|
+
# FI curve specific
|
1424
|
+
fi_defaults = method_defaults['fi_curve']
|
1425
|
+
i_start_slider = widgets.FloatSlider(value=fi_defaults['i_start'], min=-500.0, max=500.0, step=10.0, description='I Start (pA):', style=slider_style)
|
1426
|
+
i_stop_slider = widgets.FloatSlider(value=fi_defaults['i_stop'], min=0.0, max=2000.0, step=50.0, description='I Stop (pA):', style=slider_style)
|
1427
|
+
i_increment_slider = widgets.FloatSlider(value=fi_defaults['i_increment'], min=10.0, max=500.0, step=10.0, description='I Increment (pA):', style=slider_style)
|
1428
|
+
|
1429
|
+
# ZAP specific
|
1430
|
+
zap_defaults = method_defaults['impedance_amplitude_profile']
|
1431
|
+
fstart_slider = widgets.FloatSlider(value=zap_defaults['fstart'], min=0.0, max=50.0, step=1.0, description='Start Freq (Hz):', style=slider_style)
|
1432
|
+
fend_slider = widgets.FloatSlider(value=zap_defaults['fend'], min=1.0, max=100.0, step=1.0, description='End Freq (Hz):', style=slider_style)
|
1433
|
+
chirp_dropdown = widgets.Dropdown(options=['linear', 'exponential'], value=zap_defaults['chirp_type'], description='Chirp Type:', style=slider_style)
|
1434
|
+
|
1435
|
+
# Passive properties specific
|
1436
|
+
tau_method_dropdown = widgets.Dropdown(
|
1437
|
+
options=['simple', 'exp', 'exp2'],
|
1438
|
+
value=defaults['tau_method'],
|
1439
|
+
description='Tau Method:',
|
1440
|
+
style=slider_style
|
1441
|
+
)
|
1442
|
+
|
1443
|
+
# Sections
|
1444
|
+
record_sec_text = widgets.Text(value='soma', description='Record Section:', style=text_style, layout=text_layout)
|
1445
|
+
inj_sec_text = widgets.Text(value='soma', description='Injection Section:', style=text_style, layout=text_layout)
|
1446
|
+
|
1447
|
+
# Post init function
|
1448
|
+
post_init_text = widgets.Text(value='', description='Post Init Function:', placeholder='e.g., insert_mechs(123)', style={'description_width': 'initial'}, layout=widgets.Layout(width='300px'))
|
1449
|
+
|
1450
|
+
run_button = widgets.Button(
|
1451
|
+
description='Run Analysis',
|
1452
|
+
button_style='primary',
|
1453
|
+
icon='play',
|
1454
|
+
layout=widgets.Layout(width='140px')
|
1455
|
+
)
|
1456
|
+
|
1457
|
+
reset_button = widgets.Button(
|
1458
|
+
description='Reset to Defaults',
|
1459
|
+
button_style='warning',
|
1460
|
+
icon='refresh',
|
1461
|
+
layout=widgets.Layout(width='150px')
|
1462
|
+
)
|
1463
|
+
|
1464
|
+
output_area = widgets.Output(
|
1465
|
+
layout=widgets.Layout(border='1px solid #ccc', padding='10px', margin='10px 0 0 0')
|
1466
|
+
)
|
1467
|
+
|
1468
|
+
# Layout containers - organized like synapse tuner
|
1469
|
+
# Top row - template and method selection
|
1470
|
+
selection_row = widgets.HBox([
|
1471
|
+
template_dropdown,
|
1472
|
+
method_dropdown
|
1473
|
+
], layout=widgets.Layout(margin='0 0 10px 0'))
|
1474
|
+
|
1475
|
+
# Button row - main controls
|
1476
|
+
button_row = widgets.HBox([
|
1477
|
+
run_button,
|
1478
|
+
reset_button
|
1479
|
+
], layout=widgets.Layout(margin='0 0 10px 0'))
|
1480
|
+
|
1481
|
+
# Section row - recording and injection sections
|
1482
|
+
section_row = widgets.HBox([
|
1483
|
+
record_sec_text,
|
1484
|
+
inj_sec_text,
|
1485
|
+
post_init_text
|
1486
|
+
], layout=widgets.Layout(margin='0 0 10px 0'))
|
1487
|
+
|
1488
|
+
# Parameter columns - organized in columns like synapse tuner
|
1489
|
+
injection_params_col1 = widgets.VBox([
|
1490
|
+
inj_amp_slider,
|
1491
|
+
inj_delay_slider
|
1492
|
+
], layout=widgets.Layout(margin='0 10px 0 0'))
|
1493
|
+
|
1494
|
+
injection_params_col2 = widgets.VBox([
|
1495
|
+
inj_dur_slider,
|
1496
|
+
tstop_slider
|
1497
|
+
], layout=widgets.Layout(margin='0 0 0 10px'))
|
1498
|
+
|
1499
|
+
# Passive properties specific columns
|
1500
|
+
passive_params_col1 = widgets.VBox([
|
1501
|
+
inj_amp_slider,
|
1502
|
+
inj_delay_slider
|
1503
|
+
], layout=widgets.Layout(margin='0 10px 0 0'))
|
1504
|
+
|
1505
|
+
passive_params_col2 = widgets.VBox([
|
1506
|
+
inj_dur_slider,
|
1507
|
+
tstop_slider,
|
1508
|
+
tau_method_dropdown
|
1509
|
+
], layout=widgets.Layout(margin='0 0 0 10px'))
|
1510
|
+
|
1511
|
+
fi_params_col1 = widgets.VBox([
|
1512
|
+
i_start_slider,
|
1513
|
+
i_stop_slider
|
1514
|
+
], layout=widgets.Layout(margin='0 10px 0 0'))
|
1515
|
+
|
1516
|
+
fi_params_col2 = widgets.VBox([
|
1517
|
+
i_increment_slider,
|
1518
|
+
inj_dur_slider # Use duration for FI curve too
|
1519
|
+
], layout=widgets.Layout(margin='0 0 0 10px'))
|
1520
|
+
|
1521
|
+
zap_params_col1 = widgets.VBox([
|
1522
|
+
inj_amp_slider,
|
1523
|
+
inj_delay_slider,
|
1524
|
+
inj_dur_slider
|
1525
|
+
], layout=widgets.Layout(margin='0 10px 0 0'))
|
1526
|
+
|
1527
|
+
zap_params_col2 = widgets.VBox([
|
1528
|
+
tstop_slider,
|
1529
|
+
fstart_slider,
|
1530
|
+
fend_slider,
|
1531
|
+
chirp_dropdown
|
1532
|
+
], layout=widgets.Layout(margin='0 0 0 10px'))
|
1533
|
+
|
1534
|
+
# Function to update slider values based on method defaults
|
1535
|
+
def update_slider_values(method):
|
1536
|
+
"""Update slider values to match the defaults for the selected method"""
|
1537
|
+
if method in method_defaults:
|
1538
|
+
defaults = method_defaults[method]
|
1539
|
+
|
1540
|
+
# Update common sliders if they exist in defaults
|
1541
|
+
if 'inj_amp' in defaults:
|
1542
|
+
inj_amp_slider.value = defaults['inj_amp']
|
1543
|
+
if 'inj_delay' in defaults:
|
1544
|
+
inj_delay_slider.value = defaults['inj_delay']
|
1545
|
+
if 'inj_dur' in defaults:
|
1546
|
+
inj_dur_slider.value = defaults['inj_dur']
|
1547
|
+
if 'tstop' in defaults:
|
1548
|
+
tstop_slider.value = defaults['tstop']
|
1549
|
+
|
1550
|
+
# Update method-specific sliders
|
1551
|
+
if method == 'fi_curve':
|
1552
|
+
if 'i_start' in defaults:
|
1553
|
+
i_start_slider.value = defaults['i_start']
|
1554
|
+
if 'i_stop' in defaults:
|
1555
|
+
i_stop_slider.value = defaults['i_stop']
|
1556
|
+
if 'i_increment' in defaults:
|
1557
|
+
i_increment_slider.value = defaults['i_increment']
|
1558
|
+
|
1559
|
+
elif method == 'impedance_amplitude_profile':
|
1560
|
+
if 'fstart' in defaults:
|
1561
|
+
fstart_slider.value = defaults['fstart']
|
1562
|
+
if 'fend' in defaults:
|
1563
|
+
fend_slider.value = defaults['fend']
|
1564
|
+
if 'chirp_type' in defaults:
|
1565
|
+
chirp_dropdown.value = defaults['chirp_type']
|
1566
|
+
|
1567
|
+
elif method == 'passive_properties':
|
1568
|
+
if 'tau_method' in defaults:
|
1569
|
+
tau_method_dropdown.value = defaults['tau_method']
|
1570
|
+
|
1571
|
+
|
1572
|
+
# Function to update parameter visibility based on selected method
|
1573
|
+
def update_params(*args):
|
1574
|
+
method = method_dropdown.value
|
1575
|
+
|
1576
|
+
# Update slider values to defaults for the selected method
|
1577
|
+
update_slider_values(method)
|
1578
|
+
|
1579
|
+
# Update parameter column visibility
|
1580
|
+
if method == 'passive_properties':
|
1581
|
+
param_columns.children = [widgets.HBox([passive_params_col1, passive_params_col2])]
|
1582
|
+
elif method == 'current_injection':
|
1583
|
+
param_columns.children = [widgets.HBox([injection_params_col1, injection_params_col2])]
|
1584
|
+
elif method == 'fi_curve':
|
1585
|
+
param_columns.children = [widgets.HBox([fi_params_col1, fi_params_col2])]
|
1586
|
+
elif method == 'impedance_amplitude_profile':
|
1587
|
+
param_columns.children = [widgets.HBox([zap_params_col1, zap_params_col2])]
|
1588
|
+
|
1589
|
+
method_dropdown.observe(update_params, 'value')
|
1590
|
+
|
1591
|
+
# Initialize parameter columns container
|
1592
|
+
param_columns = widgets.VBox([widgets.HBox([passive_params_col1, passive_params_col2])])
|
1593
|
+
|
1594
|
+
# Run function
|
1595
|
+
def run_analysis(b):
|
1596
|
+
output_area.clear_output() # Clear immediately on click
|
1597
|
+
with output_area:
|
1598
|
+
|
1599
|
+
template = template_dropdown.value
|
1600
|
+
method = method_dropdown.value
|
1601
|
+
record_sec = record_sec_text.value
|
1602
|
+
inj_sec = inj_sec_text.value
|
1603
|
+
post_init = post_init_text.value if post_init_text.value else None
|
1604
|
+
|
1605
|
+
kwargs = {
|
1606
|
+
'record_sec': record_sec,
|
1607
|
+
'inj_sec': inj_sec,
|
1608
|
+
'plot': True # Always plot results
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
if post_init:
|
1612
|
+
kwargs['post_init_function'] = post_init
|
1613
|
+
|
1614
|
+
# Add method-specific parameters
|
1615
|
+
if method == 'passive_properties':
|
1616
|
+
kwargs.update({
|
1617
|
+
'inj_amp': inj_amp_slider.value,
|
1618
|
+
'inj_delay': inj_delay_slider.value,
|
1619
|
+
'inj_dur': inj_dur_slider.value,
|
1620
|
+
'tstop': tstop_slider.value,
|
1621
|
+
'method': tau_method_dropdown.value
|
1622
|
+
})
|
1623
|
+
elif method == 'current_injection':
|
1624
|
+
kwargs.update({
|
1625
|
+
'inj_amp': inj_amp_slider.value,
|
1626
|
+
'inj_delay': inj_delay_slider.value,
|
1627
|
+
'inj_dur': inj_dur_slider.value,
|
1628
|
+
'tstop': tstop_slider.value
|
1629
|
+
})
|
1630
|
+
elif method == 'fi_curve':
|
1631
|
+
kwargs.update({
|
1632
|
+
'i_start': i_start_slider.value,
|
1633
|
+
'i_stop': i_stop_slider.value,
|
1634
|
+
'i_increment': i_increment_slider.value,
|
1635
|
+
'tstart': inj_delay_slider.value,
|
1636
|
+
'tdur': inj_dur_slider.value
|
1637
|
+
})
|
1638
|
+
elif method == 'impedance_amplitude_profile':
|
1639
|
+
kwargs.update({
|
1640
|
+
'inj_amp': inj_amp_slider.value,
|
1641
|
+
'inj_delay': inj_delay_slider.value,
|
1642
|
+
'inj_dur': inj_dur_slider.value,
|
1643
|
+
'tstop': tstop_slider.value,
|
1644
|
+
'fstart': fstart_slider.value,
|
1645
|
+
'fend': fend_slider.value,
|
1646
|
+
'chirp_type': chirp_dropdown.value
|
1647
|
+
})
|
1648
|
+
|
1649
|
+
print("="*60)
|
1650
|
+
print(f"Running {method} for template: {template}")
|
1651
|
+
print("="*60)
|
1652
|
+
print("Parameters:")
|
1653
|
+
for key, value in kwargs.items():
|
1654
|
+
print(f" {key}: {value}")
|
1655
|
+
print("-"*60)
|
1656
|
+
|
1657
|
+
try:
|
1658
|
+
if method == 'passive_properties':
|
1659
|
+
result = self.passive_properties(template, **kwargs)
|
1660
|
+
|
1661
|
+
elif method == 'current_injection':
|
1662
|
+
result = self.current_injection(template, **kwargs)
|
1663
|
+
elif method == 'fi_curve':
|
1664
|
+
result = self.fi_curve(template, **kwargs)
|
1665
|
+
elif method == 'impedance_amplitude_profile':
|
1666
|
+
result = self.impedance_amplitude_profile(template, **kwargs)
|
1667
|
+
|
1668
|
+
|
1669
|
+
except Exception as e:
|
1670
|
+
print("="*60)
|
1671
|
+
print(f"✗ Error running analysis: {e}")
|
1672
|
+
print("="*60)
|
1673
|
+
import traceback
|
1674
|
+
traceback.print_exc()
|
1675
|
+
|
1676
|
+
# Reset function
|
1677
|
+
def reset_to_defaults(b):
|
1678
|
+
output_area.clear_output() # Clear immediately on click
|
1679
|
+
with output_area:
|
1680
|
+
method = method_dropdown.value
|
1681
|
+
update_slider_values(method)
|
1682
|
+
print(f"Reset all parameters to defaults for {method}")
|
1683
|
+
|
1684
|
+
run_button.on_click(run_analysis)
|
1685
|
+
reset_button.on_click(reset_to_defaults)
|
1686
|
+
|
1687
|
+
# Create main UI layout - matching synapse tuner structure
|
1688
|
+
ui = widgets.VBox([
|
1689
|
+
selection_row,
|
1690
|
+
button_row,
|
1691
|
+
section_row,
|
1692
|
+
param_columns
|
1693
|
+
], layout=widgets.Layout(padding='10px'))
|
1694
|
+
|
1695
|
+
# Display the interface - UI on top, output below (like synapse tuner)
|
1696
|
+
display(ui)
|
1697
|
+
display(output_area)
|
1698
|
+
|
1699
|
+
# Initial update
|
1700
|
+
update_params()
|
1701
|
+
|
1304
1702
|
|
1305
1703
|
# Example usage
|
1306
1704
|
# profiler = Profiler('./temp/templates', './temp/mechanisms/modfiles')
|