bmtool 0.7.1.6__tar.gz → 0.7.1.7__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.
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/PKG-INFO +1 -1
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/analysis/entrainment.py +33 -33
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/analysis/spikes.py +4 -2
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/entrainment.py +168 -2
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/synapses.py +76 -25
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/PKG-INFO +1 -1
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/setup.py +1 -1
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/LICENSE +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/README.md +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/SLURM.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/__main__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/analysis/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/analysis/lfp.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/analysis/netcon_reports.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/connections.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/lfp.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/netcon_reports.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/bmplot/spikes.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/connectors.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/debug/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/debug/commands.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/debug/debug.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/graphs.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/manage.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/plot_commands.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/singlecell.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/util/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/util/commands.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/util/neuron/__init__.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/util/neuron/celltuner.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool/util/util.py +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/SOURCES.txt +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/dependency_links.txt +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/entry_points.txt +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/requires.txt +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/bmtool.egg-info/top_level.txt +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/pyproject.toml +0 -0
- {bmtool-0.7.1.6 → bmtool-0.7.1.7}/setup.cfg +0 -0
@@ -636,26 +636,26 @@ def calculate_entrainment_per_cell(
|
|
636
636
|
|
637
637
|
|
638
638
|
def calculate_spike_rate_power_correlation(
|
639
|
-
spike_rate,
|
640
|
-
lfp_data,
|
641
|
-
fs,
|
642
|
-
pop_names,
|
643
|
-
filter_method="wavelet",
|
644
|
-
bandwidth=2.0,
|
645
|
-
lowcut=None,
|
646
|
-
highcut=None,
|
647
|
-
freq_range=(10, 100),
|
648
|
-
freq_step=5,
|
639
|
+
spike_rate: xr.DataArray,
|
640
|
+
lfp_data: np.ndarray,
|
641
|
+
fs: float,
|
642
|
+
pop_names: list,
|
643
|
+
filter_method: str = "wavelet",
|
644
|
+
bandwidth: float = 2.0,
|
645
|
+
lowcut: float = None,
|
646
|
+
highcut: float = None,
|
647
|
+
freq_range: tuple = (10, 100),
|
648
|
+
freq_step: float = 5,
|
649
|
+
type_name: str = "raw", # 'raw' or 'smoothed'
|
649
650
|
):
|
650
651
|
"""
|
651
|
-
Calculate correlation between population spike rates and LFP power across frequencies
|
652
|
-
using wavelet filtering. This function assumes the fs of the spike_rate and lfp are the same.
|
652
|
+
Calculate correlation between population spike rates (xarray) and LFP power across frequencies.
|
653
653
|
|
654
|
-
Parameters
|
655
|
-
|
656
|
-
spike_rate :
|
657
|
-
|
658
|
-
lfp_data : np.
|
654
|
+
Parameters
|
655
|
+
----------
|
656
|
+
spike_rate : xr.DataArray
|
657
|
+
Population spike rates with dimensions (time, population[, type])
|
658
|
+
lfp_data : np.ndarray
|
659
659
|
LFP data
|
660
660
|
fs : float
|
661
661
|
Sampling frequency
|
@@ -673,19 +673,17 @@ def calculate_spike_rate_power_correlation(
|
|
673
673
|
Min and max frequency to analyze (default: (10, 100))
|
674
674
|
freq_step : float, optional
|
675
675
|
Step size for frequency analysis (default: 5)
|
676
|
+
type_name : str, optional
|
677
|
+
Which type of spike rate to use if 'type' dimension exists (default: 'raw')
|
676
678
|
|
677
|
-
Returns
|
678
|
-
|
679
|
+
Returns
|
680
|
+
-------
|
679
681
|
correlation_results : dict
|
680
682
|
Dictionary with correlation results for each population and frequency
|
681
683
|
frequencies : array
|
682
684
|
Array of frequencies analyzed
|
683
685
|
"""
|
684
|
-
|
685
|
-
# Define frequency bands to analyze
|
686
686
|
frequencies = np.arange(freq_range[0], freq_range[1] + 1, freq_step)
|
687
|
-
|
688
|
-
# Dictionary to store results
|
689
687
|
correlation_results = {pop: {} for pop in pop_names}
|
690
688
|
|
691
689
|
# Calculate power at each frequency band using specified filter
|
@@ -695,20 +693,22 @@ def calculate_spike_rate_power_correlation(
|
|
695
693
|
lfp_data, freq, fs, filter_method, lowcut=lowcut, highcut=highcut, bandwidth=bandwidth
|
696
694
|
)
|
697
695
|
|
698
|
-
#
|
696
|
+
# For each population, extract the correct spike rate
|
699
697
|
for pop in pop_names:
|
700
|
-
#
|
701
|
-
|
698
|
+
# If 'type' dimension exists, select the type
|
699
|
+
if "type" in spike_rate.dims:
|
700
|
+
pop_rate = spike_rate.sel(population=pop, type=type_name).values
|
701
|
+
else:
|
702
|
+
pop_rate = spike_rate.sel(population=pop).values
|
702
703
|
|
703
704
|
# Calculate correlation with power at each frequency
|
704
705
|
for freq in frequencies:
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
)
|
710
|
-
|
711
|
-
corr, p_val = stats.spearmanr(pop_rate, power_by_freq[freq])
|
706
|
+
lfp_power = power_by_freq[freq]
|
707
|
+
# Ensure lengths match
|
708
|
+
min_len = min(len(pop_rate), len(lfp_power))
|
709
|
+
if len(pop_rate) != len(lfp_power):
|
710
|
+
print(f"Warning: Length mismatch for {pop} at {freq} Hz, truncating to {min_len}")
|
711
|
+
corr, p_val = stats.spearmanr(pop_rate[:min_len], lfp_power[:min_len])
|
712
712
|
correlation_results[pop][freq] = {"correlation": corr, "p_value": p_val}
|
713
713
|
|
714
714
|
return correlation_results, frequencies
|
@@ -282,9 +282,11 @@ def get_population_spike_rate(
|
|
282
282
|
|
283
283
|
if config is None:
|
284
284
|
print(
|
285
|
-
"Note: Node number is obtained by counting unique node spikes in the network.\nIf the network did not run for a sufficient duration,
|
285
|
+
"Note: Node number is obtained by counting unique node spikes in the network.\nIf the network did not run for a sufficient duration, or not all cells fired,\nthen this count will not include all nodes so the firing rate will not be of the whole population!"
|
286
|
+
)
|
287
|
+
print(
|
288
|
+
"You can provide a config to calculate the correct amount of nodes! for a true population rate."
|
286
289
|
)
|
287
|
-
print("You can provide a config to calculate the correct amount of nodes!")
|
288
290
|
|
289
291
|
if config:
|
290
292
|
if not network_name:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import matplotlib.pyplot as plt
|
2
2
|
import numpy as np
|
3
|
+
import pandas as pd
|
3
4
|
import seaborn as sns
|
4
5
|
from matplotlib.gridspec import GridSpec
|
5
6
|
from scipy import stats
|
@@ -55,7 +56,7 @@ def plot_spike_power_correlation(correlation_results, frequencies, pop_names):
|
|
55
56
|
|
56
57
|
def plot_cycle_with_spike_histograms(phase_data, bins=36, pop_name=None):
|
57
58
|
"""
|
58
|
-
Plot an idealized
|
59
|
+
Plot an idealized cycle with spike histograms for different neuron populations.
|
59
60
|
|
60
61
|
Parameters:
|
61
62
|
-----------
|
@@ -120,7 +121,7 @@ def plot_cycle_with_spike_histograms(phase_data, bins=36, pop_name=None):
|
|
120
121
|
plt.show()
|
121
122
|
|
122
123
|
|
123
|
-
def
|
124
|
+
def plot_entrainment_by_population(ppc_dict, pop_names, freqs, figsize=(15, 8), title=None):
|
124
125
|
"""
|
125
126
|
Plot PPC for all node populations on one graph with mean and standard error.
|
126
127
|
|
@@ -200,3 +201,168 @@ def plot_ppc_by_population(ppc_dict, pop_names, freqs, figsize=(15, 8), title=No
|
|
200
201
|
# Adjust layout and save
|
201
202
|
plt.tight_layout()
|
202
203
|
plt.show()
|
204
|
+
|
205
|
+
|
206
|
+
def plot_entrainment_swarm_plot(ppc_dict, pop_names, freq, save_path=None, title=None):
|
207
|
+
"""
|
208
|
+
Plot a swarm plot of the entrainment for different populations at a single frequency.
|
209
|
+
|
210
|
+
Parameters:
|
211
|
+
-----------
|
212
|
+
ppc_dict : dict
|
213
|
+
Dictionary containing PPC values organized by population, node, and frequency
|
214
|
+
pop_names : list
|
215
|
+
List of population names to include in the plot
|
216
|
+
freq : float or int
|
217
|
+
The specific frequency to plot
|
218
|
+
save_path : str, optional
|
219
|
+
Path to save the figure. If None, figure is just displayed.
|
220
|
+
|
221
|
+
Returns:
|
222
|
+
--------
|
223
|
+
matplotlib.figure.Figure
|
224
|
+
The figure object for further customization if needed
|
225
|
+
"""
|
226
|
+
# Set the style
|
227
|
+
sns.set_style("whitegrid")
|
228
|
+
|
229
|
+
# Prepare data for the swarm plot
|
230
|
+
data_list = []
|
231
|
+
|
232
|
+
for pop in pop_names:
|
233
|
+
values = []
|
234
|
+
node_ids = []
|
235
|
+
|
236
|
+
for node in ppc_dict[pop]:
|
237
|
+
if freq in ppc_dict[pop][node] and ppc_dict[pop][node][freq] is not None:
|
238
|
+
data_list.append(
|
239
|
+
{"Population": pop, "Node": node, "PPC Difference": ppc_dict[pop][node][freq]}
|
240
|
+
)
|
241
|
+
|
242
|
+
# Create DataFrame in long format
|
243
|
+
df = pd.DataFrame(data_list)
|
244
|
+
|
245
|
+
if df.empty:
|
246
|
+
print(f"No data available for frequency {freq}.")
|
247
|
+
return None
|
248
|
+
|
249
|
+
# Print mean PPC change for each population)
|
250
|
+
for pop in pop_names:
|
251
|
+
subset = df[df["Population"] == pop]
|
252
|
+
if not subset.empty:
|
253
|
+
mean_val = subset["PPC Difference"].mean()
|
254
|
+
std_val = subset["PPC Difference"].std()
|
255
|
+
n = len(subset)
|
256
|
+
sem_val = std_val / np.sqrt(n) # Standard error of the mean
|
257
|
+
print(f"{pop}: {mean_val:.4f} ± {sem_val:.4f} (n={n})")
|
258
|
+
|
259
|
+
# Create figure
|
260
|
+
plt.figure(figsize=(max(8, len(pop_names) * 1.5), 8))
|
261
|
+
|
262
|
+
# Create swarm plot
|
263
|
+
ax = sns.swarmplot(
|
264
|
+
x="Population",
|
265
|
+
y="PPC Difference",
|
266
|
+
data=df,
|
267
|
+
size=3,
|
268
|
+
# palette='Set2'
|
269
|
+
)
|
270
|
+
|
271
|
+
# Add sample size annotations
|
272
|
+
for i, pop in enumerate(pop_names):
|
273
|
+
subset = df[df["Population"] == pop]
|
274
|
+
if not subset.empty:
|
275
|
+
n = len(subset)
|
276
|
+
y_min = subset["PPC Difference"].min()
|
277
|
+
y_max = subset["PPC Difference"].max()
|
278
|
+
|
279
|
+
# Position annotation below the lowest point
|
280
|
+
plt.annotate(
|
281
|
+
f"n={n}", (i, y_min - 0.05 * (y_max - y_min) - 0.05), ha="center", fontsize=10
|
282
|
+
)
|
283
|
+
|
284
|
+
# Add reference line at y=0
|
285
|
+
plt.axhline(y=0, color="black", linestyle="-", linewidth=0.5, alpha=0.7)
|
286
|
+
|
287
|
+
# Add horizontal lines for mean values
|
288
|
+
for i, pop in enumerate(pop_names):
|
289
|
+
subset = df[df["Population"] == pop]
|
290
|
+
if not subset.empty:
|
291
|
+
mean_val = subset["PPC Difference"].mean()
|
292
|
+
plt.plot([i - 0.25, i + 0.25], [mean_val, mean_val], "r-", linewidth=2)
|
293
|
+
|
294
|
+
# Calculate and display statistics
|
295
|
+
if len(pop_names) > 1:
|
296
|
+
# Print statistical test results
|
297
|
+
print(f"\nMann-Whitney U Test Results at {freq} Hz:")
|
298
|
+
print("-" * 60)
|
299
|
+
|
300
|
+
# Add p-values for pairwise comparisons
|
301
|
+
y_max = df["PPC Difference"].max()
|
302
|
+
y_min = df["PPC Difference"].min()
|
303
|
+
y_range = y_max - y_min
|
304
|
+
|
305
|
+
# Perform t-tests between populations if there are at least 2
|
306
|
+
for i in range(len(pop_names)):
|
307
|
+
for j in range(i + 1, len(pop_names)):
|
308
|
+
pop1 = pop_names[i]
|
309
|
+
pop2 = pop_names[j]
|
310
|
+
|
311
|
+
vals1 = df[df["Population"] == pop1]["PPC Difference"].values
|
312
|
+
vals2 = df[df["Population"] == pop2]["PPC Difference"].values
|
313
|
+
|
314
|
+
if len(vals1) > 1 and len(vals2) > 1:
|
315
|
+
# Perform Mann-Whitney U test (non-parametric)
|
316
|
+
u_stat, p_val = stats.mannwhitneyu(vals1, vals2, alternative="two-sided")
|
317
|
+
|
318
|
+
# Add significance markers
|
319
|
+
sig_str = "ns"
|
320
|
+
if p_val < 0.05:
|
321
|
+
sig_str = "*"
|
322
|
+
if p_val < 0.01:
|
323
|
+
sig_str = "**"
|
324
|
+
if p_val < 0.001:
|
325
|
+
sig_str = "***"
|
326
|
+
|
327
|
+
# Position the significance bar
|
328
|
+
bar_height = y_max + 0.1 * y_range * (1 + (j - i - 1) * 0.5)
|
329
|
+
|
330
|
+
# Draw the bar
|
331
|
+
plt.plot([i, j], [bar_height, bar_height], "k-")
|
332
|
+
plt.plot([i, i], [bar_height - 0.02 * y_range, bar_height], "k-")
|
333
|
+
plt.plot([j, j], [bar_height - 0.02 * y_range, bar_height], "k-")
|
334
|
+
|
335
|
+
# Add significance marker
|
336
|
+
plt.text(
|
337
|
+
(i + j) / 2,
|
338
|
+
bar_height + 0.01 * y_range,
|
339
|
+
sig_str,
|
340
|
+
ha="center",
|
341
|
+
va="bottom",
|
342
|
+
fontsize=12,
|
343
|
+
)
|
344
|
+
|
345
|
+
# Print the statistical comparison
|
346
|
+
print(f"{pop1} vs {pop2}: U={u_stat:.1f}, p={p_val:.4f} {sig_str}")
|
347
|
+
|
348
|
+
# Add labels and title
|
349
|
+
plt.xlabel("Population", fontsize=14)
|
350
|
+
plt.ylabel("PPC", fontsize=14)
|
351
|
+
if title:
|
352
|
+
plt.title(title, fontsize=16)
|
353
|
+
|
354
|
+
# Adjust y-axis limits to make room for annotations
|
355
|
+
y_min, y_max = plt.ylim()
|
356
|
+
plt.ylim(y_min - 0.15 * (y_max - y_min), y_max + 0.25 * (y_max - y_min))
|
357
|
+
|
358
|
+
# Add gridlines
|
359
|
+
plt.grid(True, linestyle="--", alpha=0.7, axis="y")
|
360
|
+
|
361
|
+
# Adjust layout
|
362
|
+
plt.tight_layout()
|
363
|
+
|
364
|
+
# Save figure if path is provided
|
365
|
+
if save_path:
|
366
|
+
plt.savefig(f"{save_path}/ppc_change_swarm_plot_{freq}Hz.png", dpi=300, bbox_inches="tight")
|
367
|
+
|
368
|
+
plt.show()
|
@@ -18,15 +18,18 @@ from scipy.optimize import curve_fit, minimize, minimize_scalar
|
|
18
18
|
from scipy.signal import find_peaks
|
19
19
|
from tqdm.notebook import tqdm
|
20
20
|
|
21
|
+
from bmtool.util.util import load_mechanisms_from_config, load_templates_from_config
|
22
|
+
|
21
23
|
|
22
24
|
class SynapseTuner:
|
23
25
|
def __init__(
|
24
26
|
self,
|
25
|
-
mechanisms_dir: str,
|
26
|
-
templates_dir: str,
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
mechanisms_dir: str = None,
|
28
|
+
templates_dir: str = None,
|
29
|
+
config: str = None,
|
30
|
+
conn_type_settings: dict = None,
|
31
|
+
connection: str = None,
|
32
|
+
general_settings: dict = None,
|
30
33
|
json_folder_path: str = None,
|
31
34
|
current_name: str = "i",
|
32
35
|
other_vars_to_record: list = None,
|
@@ -57,8 +60,18 @@ class SynapseTuner:
|
|
57
60
|
List of synaptic variables you would like sliders set up for the STP sliders method by default will use all parameters in spec_syn_param.
|
58
61
|
|
59
62
|
"""
|
60
|
-
|
61
|
-
|
63
|
+
if config is None and (mechanisms_dir is None or templates_dir is None):
|
64
|
+
raise ValueError(
|
65
|
+
"Either a config file or both mechanisms_dir and templates_dir must be provided."
|
66
|
+
)
|
67
|
+
|
68
|
+
if config is None:
|
69
|
+
neuron.load_mechanisms(mechanisms_dir)
|
70
|
+
h.load_file(templates_dir)
|
71
|
+
else:
|
72
|
+
load_mechanisms_from_config(config)
|
73
|
+
load_templates_from_config(config)
|
74
|
+
|
62
75
|
self.conn_type_settings = conn_type_settings
|
63
76
|
if json_folder_path:
|
64
77
|
print(f"updating settings from json path {json_folder_path}")
|
@@ -939,10 +952,11 @@ class SynapseTuner:
|
|
939
952
|
class GapJunctionTuner:
|
940
953
|
def __init__(
|
941
954
|
self,
|
942
|
-
mechanisms_dir: str,
|
943
|
-
templates_dir: str,
|
944
|
-
|
945
|
-
|
955
|
+
mechanisms_dir: str = None,
|
956
|
+
templates_dir: str = None,
|
957
|
+
config: str = None,
|
958
|
+
general_settings: dict = None,
|
959
|
+
conn_type_settings: dict = None,
|
946
960
|
):
|
947
961
|
"""
|
948
962
|
Initialize the GapJunctionTuner class.
|
@@ -953,13 +967,24 @@ class GapJunctionTuner:
|
|
953
967
|
Directory path containing the compiled mod files needed for NEURON mechanisms.
|
954
968
|
templates_dir : str
|
955
969
|
Directory path containing cell template files (.hoc or .py) loaded into NEURON.
|
970
|
+
config : str
|
971
|
+
Path to a BMTK config.json file. Can be used to load mechanisms, templates, and other settings.
|
956
972
|
general_settings : dict
|
957
973
|
General settings dictionary including parameters like simulation time step, duration, and temperature.
|
958
974
|
conn_type_settings : dict
|
959
975
|
A dictionary containing connection-specific settings for gap junctions.
|
960
976
|
"""
|
961
|
-
|
962
|
-
|
977
|
+
if config is None and (mechanisms_dir is None or templates_dir is None):
|
978
|
+
raise ValueError(
|
979
|
+
"Either a config file or both mechanisms_dir and templates_dir must be provided."
|
980
|
+
)
|
981
|
+
|
982
|
+
if config is None:
|
983
|
+
neuron.load_mechanisms(mechanisms_dir)
|
984
|
+
h.load_file(templates_dir)
|
985
|
+
else:
|
986
|
+
load_mechanisms_from_config(config)
|
987
|
+
load_templates_from_config(config)
|
963
988
|
|
964
989
|
self.general_settings = general_settings
|
965
990
|
self.conn_type_settings = conn_type_settings
|
@@ -1049,7 +1074,6 @@ class GapJunctionTuner:
|
|
1049
1074
|
plt.xlabel("Time (ms)")
|
1050
1075
|
plt.ylabel("Membrane Voltage (mV)")
|
1051
1076
|
plt.legend()
|
1052
|
-
plt.show()
|
1053
1077
|
|
1054
1078
|
def coupling_coefficient(self, t, v1, v2, t_start, t_end, dt=h.dt):
|
1055
1079
|
"""
|
@@ -1085,28 +1109,55 @@ class GapJunctionTuner:
|
|
1085
1109
|
|
1086
1110
|
def InteractiveTuner(self):
|
1087
1111
|
w_run = widgets.Button(description="Run", icon="history", button_style="primary")
|
1088
|
-
values = [i * 10**-4 for i in range(1,
|
1112
|
+
values = [i * 10**-4 for i in range(1, 1001)] # From 1e-4 to 1e-1
|
1089
1113
|
|
1090
1114
|
# Create the SelectionSlider widget with appropriate formatting
|
1091
|
-
resistance = widgets.
|
1092
|
-
|
1093
|
-
|
1115
|
+
resistance = widgets.FloatLogSlider(
|
1116
|
+
value=0.001,
|
1117
|
+
base=10,
|
1118
|
+
min=-4, # max exponent of base
|
1119
|
+
max=-1, # min exponent of base
|
1120
|
+
step=0.1, # exponent step
|
1094
1121
|
description="Resistance: ",
|
1095
1122
|
continuous_update=True,
|
1096
1123
|
)
|
1097
1124
|
|
1098
1125
|
ui = VBox([w_run, resistance])
|
1126
|
+
|
1127
|
+
# Create an output widget to control what gets cleared
|
1128
|
+
output = widgets.Output()
|
1129
|
+
|
1099
1130
|
display(ui)
|
1131
|
+
display(output)
|
1100
1132
|
|
1101
1133
|
def on_button(*args):
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1134
|
+
with output:
|
1135
|
+
# Clear only the output widget, not the entire cell
|
1136
|
+
output.clear_output(wait=True)
|
1137
|
+
|
1138
|
+
resistance_for_gap = resistance.value
|
1139
|
+
print(f"Running simulation with resistance: {resistance_for_gap}")
|
1140
|
+
|
1141
|
+
try:
|
1142
|
+
self.model(resistance_for_gap)
|
1143
|
+
self.plot_model()
|
1144
|
+
|
1145
|
+
# Convert NEURON vectors to numpy arrays
|
1146
|
+
t_array = np.array(self.t_vec)
|
1147
|
+
v1_array = np.array(self.soma_v_1)
|
1148
|
+
v2_array = np.array(self.soma_v_2)
|
1149
|
+
|
1150
|
+
cc = self.coupling_coefficient(t_array, v1_array, v2_array, 500, 1000)
|
1151
|
+
print(f"coupling_coefficient is {cc:0.4f}")
|
1152
|
+
plt.show()
|
1153
|
+
|
1154
|
+
except Exception as e:
|
1155
|
+
print(f"Error during simulation or analysis: {e}")
|
1156
|
+
import traceback
|
1157
|
+
|
1158
|
+
traceback.print_exc()
|
1109
1159
|
|
1160
|
+
# Run once initially
|
1110
1161
|
on_button()
|
1111
1162
|
w_run.on_click(on_button)
|
1112
1163
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|