bmtool 0.5.8__tar.gz → 0.5.9.5__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.5.8 → bmtool-0.5.9.5}/PKG-INFO +1 -1
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/bmplot.py +134 -28
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/connectors.py +15 -8
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/PKG-INFO +1 -1
- {bmtool-0.5.8 → bmtool-0.5.9.5}/setup.py +1 -1
- {bmtool-0.5.8 → bmtool-0.5.9.5}/LICENSE +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/README.md +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/SLURM.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/__init__.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/__main__.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/debug/__init__.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/debug/commands.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/debug/debug.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/graphs.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/manage.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/plot_commands.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/singlecell.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/synapses.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/util/__init__.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/util/commands.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/util/neuron/__init__.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/util/neuron/celltuner.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool/util/util.py +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/SOURCES.txt +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/dependency_links.txt +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/entry_points.txt +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/requires.txt +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/bmtool.egg-info/top_level.txt +0 -0
- {bmtool-0.5.8 → bmtool-0.5.9.5}/setup.cfg +0 -0
@@ -405,6 +405,76 @@ def connection_histogram(config=None,nodes=None,edges=None,sources=[],targets=[]
|
|
405
405
|
tids = []
|
406
406
|
util.relation_matrix(config,nodes,edges,sources,targets,sids,tids,prepend_pop,relation_func=connection_pair_histogram,synaptic_info=synaptic_info)
|
407
407
|
|
408
|
+
def connection_distance(config: str,source: str,target: str,
|
409
|
+
source_cell_id: int,target_id_type: str) -> None:
|
410
|
+
"""
|
411
|
+
Plots the 3D spatial distribution of target nodes relative to a source node
|
412
|
+
and a histogram of distances from the source node to each target node.
|
413
|
+
|
414
|
+
Parameters:
|
415
|
+
----------
|
416
|
+
config: (str) A BMTK simulation config
|
417
|
+
sources: (str) network name(s) to plot
|
418
|
+
targets: (str) network name(s) to plot
|
419
|
+
source_cell_id : (int) ID of the source cell for calculating distances to target nodes.
|
420
|
+
target_id_type : (str) A string to filter target nodes based off the target_query.
|
421
|
+
|
422
|
+
"""
|
423
|
+
if not config:
|
424
|
+
raise Exception("config not defined")
|
425
|
+
if not source or not target:
|
426
|
+
raise Exception("Sources or targets not defined")
|
427
|
+
#if source != target:
|
428
|
+
#raise Exception("Code is setup for source and target to be the same! Look at source code for function to add feature")
|
429
|
+
|
430
|
+
# Load nodes and edges based on config file
|
431
|
+
nodes, edges = util.load_nodes_edges_from_config(config)
|
432
|
+
|
433
|
+
edge_network = source + "_to_" + target
|
434
|
+
node_network = source
|
435
|
+
|
436
|
+
# Filter edges to obtain connections originating from the source node
|
437
|
+
edge = edges[edge_network]
|
438
|
+
edge = edge[edge['source_node_id'] == source_cell_id]
|
439
|
+
if target_id_type:
|
440
|
+
edge = edge[edge['target_query'].str.contains(target_id_type, na=False)]
|
441
|
+
|
442
|
+
target_node_ids = edge['target_node_id']
|
443
|
+
|
444
|
+
# Filter nodes to obtain only the target and source nodes
|
445
|
+
node = nodes[node_network]
|
446
|
+
target_nodes = node.loc[node.index.isin(target_node_ids)]
|
447
|
+
source_node = node.loc[node.index == source_cell_id]
|
448
|
+
|
449
|
+
# Calculate distances between source node and each target node
|
450
|
+
target_positions = target_nodes[['pos_x', 'pos_y', 'pos_z']].values
|
451
|
+
source_position = np.array([source_node['pos_x'], source_node['pos_y'], source_node['pos_z']]).ravel() # Ensure 1D shape
|
452
|
+
distances = np.linalg.norm(target_positions - source_position, axis=1)
|
453
|
+
|
454
|
+
# Plot positions of source and target nodes in 3D space
|
455
|
+
fig = plt.figure(figsize=(8, 6))
|
456
|
+
ax = fig.add_subplot(111, projection='3d')
|
457
|
+
|
458
|
+
ax.scatter(target_nodes['pos_x'], target_nodes['pos_y'], target_nodes['pos_z'], c='blue', label="target cells")
|
459
|
+
ax.scatter(source_node['pos_x'], source_node['pos_y'], source_node['pos_z'], c='red', label="source cell")
|
460
|
+
|
461
|
+
# Optional: Add text annotations for distances
|
462
|
+
# for i, distance in enumerate(distances):
|
463
|
+
# ax.text(target_nodes['pos_x'].iloc[i], target_nodes['pos_y'].iloc[i], target_nodes['pos_z'].iloc[i],
|
464
|
+
# f'{distance:.2f}', color='black', fontsize=8, ha='center')
|
465
|
+
|
466
|
+
plt.legend()
|
467
|
+
plt.show()
|
468
|
+
|
469
|
+
# Plot distances in a separate 2D plot
|
470
|
+
plt.figure(figsize=(8, 6))
|
471
|
+
plt.hist(distances, bins=20, color='blue', edgecolor='black')
|
472
|
+
plt.xlabel("Distance")
|
473
|
+
plt.ylabel("Count")
|
474
|
+
plt.title("Distance from Source Node to Each Target Node")
|
475
|
+
plt.grid(True)
|
476
|
+
plt.show()
|
477
|
+
|
408
478
|
def edge_histogram_matrix(config=None,sources = None,targets=None,sids=None,tids=None,no_prepend_pop=None,edge_property = None,time = None,time_compare = None,report=None,title=None,save_file=None):
|
409
479
|
"""
|
410
480
|
write about function here
|
@@ -480,8 +550,14 @@ def plot_connection_info(text, num, source_labels,target_labels, title, syn_info
|
|
480
550
|
# Loop over data dimensions and create text annotations.
|
481
551
|
for i in range(num_source):
|
482
552
|
for j in range(num_target):
|
483
|
-
edge_info = text[i,j]
|
484
|
-
|
553
|
+
edge_info = text[i, j]
|
554
|
+
|
555
|
+
# Initialize the dictionary for the source node if not already done
|
556
|
+
if source_labels[i] not in graph_dict:
|
557
|
+
graph_dict[source_labels[i]] = {}
|
558
|
+
|
559
|
+
# Add edge info for the target node
|
560
|
+
graph_dict[source_labels[i]][target_labels[j]] = edge_info
|
485
561
|
if syn_info =='2' or syn_info =='3':
|
486
562
|
if num_source > 8 and num_source <20:
|
487
563
|
fig_text = ax1.text(j, i, edge_info,
|
@@ -726,71 +802,101 @@ def plot_spikes(nodes, spikes_file,save_file=None):
|
|
726
802
|
|
727
803
|
return
|
728
804
|
|
729
|
-
def plot_3d_positions(config=None,populations_list=None,group_by=None,title=None,save_file=None):
|
805
|
+
def plot_3d_positions(config=None, populations_list=None, group_by=None, title=None, save_file=None, subset=None):
|
730
806
|
"""
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
807
|
+
Plots a 3D graph of all cells with x, y, z location.
|
808
|
+
|
809
|
+
Parameters:
|
810
|
+
- config: A BMTK simulation config
|
811
|
+
- populations_list: Which network(s) to plot
|
812
|
+
- group_by: How to name cell groups
|
813
|
+
- title: Plot title
|
814
|
+
- save_file: If plot should be saved
|
815
|
+
- subset: Take every Nth row. This will make plotting large network graphs easier to see.
|
737
816
|
"""
|
738
817
|
|
739
818
|
if not config:
|
740
819
|
raise Exception("config not defined")
|
741
|
-
|
820
|
+
|
821
|
+
if populations_list is None:
|
742
822
|
populations_list = "all"
|
823
|
+
|
824
|
+
# Set group keys (e.g., node types)
|
743
825
|
group_keys = group_by
|
744
|
-
if title
|
826
|
+
if title is None:
|
745
827
|
title = "3D positions"
|
746
828
|
|
829
|
+
# Load nodes from the configuration
|
747
830
|
nodes = util.load_nodes_from_config(config)
|
748
831
|
|
832
|
+
# Get the list of populations to plot
|
749
833
|
if 'all' in populations_list:
|
750
834
|
populations = list(nodes)
|
751
835
|
else:
|
752
836
|
populations = populations_list.split(",")
|
753
|
-
|
837
|
+
|
838
|
+
# Split group_by into list
|
754
839
|
group_keys = group_keys.split(",")
|
755
|
-
group_keys += (len(populations)-len(group_keys)) * ["node_type_id"]
|
756
|
-
|
840
|
+
group_keys += (len(populations) - len(group_keys)) * ["node_type_id"] # Extend the array to default values if not enough given
|
841
|
+
if len(group_keys) > 1:
|
842
|
+
raise Exception("Only one group by is supported currently!")
|
843
|
+
|
844
|
+
fig = plt.figure(figsize=(10, 10))
|
757
845
|
ax = fig.add_subplot(projection='3d')
|
758
846
|
handles = []
|
759
|
-
for nodes_key,group_key in zip(list(nodes),group_keys):
|
760
|
-
if 'all' not in populations and nodes_key not in populations:
|
761
|
-
continue
|
762
|
-
|
763
|
-
nodes_df = nodes[nodes_key]
|
764
847
|
|
848
|
+
for pop in (list(nodes)):
|
849
|
+
|
850
|
+
if 'all' not in populations and pop not in populations:
|
851
|
+
continue
|
852
|
+
|
853
|
+
nodes_df = nodes[pop]
|
854
|
+
group_key = group_keys[0]
|
855
|
+
|
856
|
+
# If group_key is provided, ensure the column exists in the dataframe
|
765
857
|
if group_key is not None:
|
766
858
|
if group_key not in nodes_df:
|
767
|
-
raise Exception(
|
859
|
+
raise Exception(f"Could not find column '{group_key}' in {pop}")
|
860
|
+
|
768
861
|
groupings = nodes_df.groupby(group_key)
|
769
|
-
|
770
862
|
n_colors = nodes_df[group_key].nunique()
|
771
|
-
color_norm = colors.Normalize(vmin=0, vmax=(n_colors-1))
|
863
|
+
color_norm = colors.Normalize(vmin=0, vmax=(n_colors - 1))
|
772
864
|
scalar_map = cmx.ScalarMappable(norm=color_norm, cmap='hsv')
|
773
|
-
color_map = [scalar_map.to_rgba(i) for i in range(
|
865
|
+
color_map = [scalar_map.to_rgba(i) for i in range(n_colors)]
|
774
866
|
else:
|
775
867
|
groupings = [(None, nodes_df)]
|
776
868
|
color_map = ['blue']
|
777
869
|
|
870
|
+
# Loop over groupings and plot
|
778
871
|
for color, (group_name, group_df) in zip(color_map, groupings):
|
779
|
-
if "pos_x" not in group_df
|
780
|
-
|
781
|
-
|
872
|
+
if "pos_x" not in group_df or "pos_y" not in group_df or "pos_z" not in group_df:
|
873
|
+
print(f"Warning: Missing position columns in group '{group_name}' for {pop}. Skipping this group.")
|
874
|
+
continue # Skip if position columns are missing
|
875
|
+
|
876
|
+
# Subset the dataframe by taking every Nth row if subset is provided
|
877
|
+
if subset is not None:
|
878
|
+
group_df = group_df.iloc[::subset]
|
879
|
+
|
880
|
+
h = ax.scatter(group_df["pos_x"], group_df["pos_y"], group_df["pos_z"], color=color, label=group_name)
|
782
881
|
handles.append(h)
|
882
|
+
|
783
883
|
if not handles:
|
884
|
+
print("No data to plot.")
|
784
885
|
return
|
886
|
+
|
887
|
+
# Set plot title and legend
|
785
888
|
plt.title(title)
|
786
889
|
plt.legend(handles=handles)
|
787
890
|
|
891
|
+
# Draw the plot
|
788
892
|
plt.draw()
|
789
893
|
|
894
|
+
# Save the plot if save_file is provided
|
790
895
|
if save_file:
|
791
896
|
plt.savefig(save_file)
|
792
|
-
|
793
|
-
if
|
897
|
+
|
898
|
+
# Show the plot if running outside of a notebook
|
899
|
+
if not is_notebook:
|
794
900
|
plt.show()
|
795
901
|
|
796
902
|
return
|
@@ -580,9 +580,11 @@ class ReciprocalConnector(AbstractConnector):
|
|
580
580
|
self.source = source
|
581
581
|
self.target = target
|
582
582
|
if self.source is None or len(self.source) == 0:
|
583
|
-
|
583
|
+
src_str, trg_str = self.get_nodes_info()
|
584
|
+
raise ValueError(f"{src_str} nodes do not exists")
|
584
585
|
if self.target is None or len(self.target) == 0:
|
585
|
-
|
586
|
+
src_str, trg_str = self.get_nodes_info()
|
587
|
+
raise ValueError(f"{trg_str} nodes do not exists")
|
586
588
|
|
587
589
|
# Setup nodes
|
588
590
|
self.recurrent = is_same_pop(self.source, self.target, quick=self.quick)
|
@@ -1130,9 +1132,11 @@ class UnidirectionConnector(AbstractConnector):
|
|
1130
1132
|
self.source = source
|
1131
1133
|
self.target = target
|
1132
1134
|
if self.source is None or len(self.source) == 0:
|
1133
|
-
|
1135
|
+
src_str, trg_str = self.get_nodes_info()
|
1136
|
+
raise ValueError(f"{src_str} nodes do not exists")
|
1134
1137
|
if self.target is None or len(self.target) == 0:
|
1135
|
-
|
1138
|
+
src_str, trg_str = self.get_nodes_info()
|
1139
|
+
raise ValueError(f"{trg_str} nodes do not exists")
|
1136
1140
|
self.n_pair = len(self.source) * len(self.target)
|
1137
1141
|
|
1138
1142
|
def edge_params(self):
|
@@ -1179,6 +1183,7 @@ class UnidirectionConnector(AbstractConnector):
|
|
1179
1183
|
+ src_str + "\n to " + trg_str,flush=True)
|
1180
1184
|
|
1181
1185
|
# Make random connections
|
1186
|
+
|
1182
1187
|
p_arg = self.p_arg(source, target)
|
1183
1188
|
p = self.p(p_arg)
|
1184
1189
|
possible = p > 0
|
@@ -1274,8 +1279,9 @@ class GapJunction(UnidirectionConnector):
|
|
1274
1279
|
def setup_nodes(self, source=None, target=None):
|
1275
1280
|
super().setup_nodes(source=source, target=target)
|
1276
1281
|
if len(self.source) != len(self.target):
|
1277
|
-
|
1278
|
-
|
1282
|
+
src_str, trg_str = self.get_nodes_info()
|
1283
|
+
raise ValueError(f"Source and target must be the same for "
|
1284
|
+
f"gap junction. Nodes are {src_str} and {trg_str}")
|
1279
1285
|
self.n_source = len(self.source)
|
1280
1286
|
|
1281
1287
|
def make_connection(self, source, target, *args, **kwargs):
|
@@ -1500,8 +1506,9 @@ class OneToOneSequentialConnector(AbstractConnector):
|
|
1500
1506
|
source, target = target, source
|
1501
1507
|
if self.target_count == 0:
|
1502
1508
|
if source is None or len(source) == 0:
|
1503
|
-
|
1504
|
-
|
1509
|
+
src_str, trg_str = self.get_nodes_info()
|
1510
|
+
raise ValueError((f"{trg_str}" if self.partition_source else
|
1511
|
+
f"{src_str}") + " nodes do not exists")
|
1505
1512
|
self.source = source
|
1506
1513
|
self.n_source = len(source)
|
1507
1514
|
if target is None or len(target) == 0:
|
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
|