bmtool 0.8.1__tar.gz → 0.8.2__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.
Files changed (45) hide show
  1. {bmtool-0.8.1 → bmtool-0.8.2}/PKG-INFO +1 -1
  2. bmtool-0.8.2/bmtool/analysis/netcon_reports.py +228 -0
  3. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/connections.py +15 -2
  4. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/util/util.py +6 -0
  5. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/PKG-INFO +1 -1
  6. {bmtool-0.8.1 → bmtool-0.8.2}/setup.py +1 -1
  7. bmtool-0.8.1/bmtool/analysis/netcon_reports.py +0 -94
  8. {bmtool-0.8.1 → bmtool-0.8.2}/LICENSE +0 -0
  9. {bmtool-0.8.1 → bmtool-0.8.2}/README.md +0 -0
  10. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/SLURM.py +0 -0
  11. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/__init__.py +0 -0
  12. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/__main__.py +0 -0
  13. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/analysis/__init__.py +0 -0
  14. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/analysis/entrainment.py +0 -0
  15. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/analysis/lfp.py +0 -0
  16. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/analysis/spikes.py +0 -0
  17. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/__init__.py +0 -0
  18. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/entrainment.py +0 -0
  19. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/lfp.py +0 -0
  20. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/netcon_reports.py +0 -0
  21. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/bmplot/spikes.py +0 -0
  22. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/connectors.py +0 -0
  23. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/debug/__init__.py +0 -0
  24. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/debug/commands.py +0 -0
  25. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/debug/debug.py +0 -0
  26. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/graphs.py +0 -0
  27. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/manage.py +0 -0
  28. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/plot_commands.py +0 -0
  29. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/singlecell.py +0 -0
  30. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/stimulus/__init__.py +0 -0
  31. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/stimulus/assemblies.py +0 -0
  32. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/stimulus/core.py +0 -0
  33. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/stimulus/generators.py +0 -0
  34. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/synapses.py +0 -0
  35. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/util/__init__.py +0 -0
  36. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/util/commands.py +0 -0
  37. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/util/neuron/__init__.py +0 -0
  38. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool/util/neuron/celltuner.py +0 -0
  39. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/SOURCES.txt +0 -0
  40. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/dependency_links.txt +0 -0
  41. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/entry_points.txt +0 -0
  42. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/requires.txt +0 -0
  43. {bmtool-0.8.1 → bmtool-0.8.2}/bmtool.egg-info/top_level.txt +0 -0
  44. {bmtool-0.8.1 → bmtool-0.8.2}/pyproject.toml +0 -0
  45. {bmtool-0.8.1 → bmtool-0.8.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bmtool
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -0,0 +1,228 @@
1
+ import h5py
2
+ import numpy as np
3
+ import xarray as xr
4
+ from typing import Union, List, Dict, Any
5
+
6
+ from ..util.util import load_nodes_from_config
7
+
8
+
9
+ def load_synapse_report(
10
+ h5_file_path: str,
11
+ config_path: str,
12
+ edge_name: str,
13
+ source_groupby: Union[str, List[str]],
14
+ target_groupby: Union[str, List[str]],
15
+ ) -> xr.Dataset:
16
+ """
17
+ Load and process a synapse report from a bmtk simulation into an xarray.
18
+
19
+ Parameters:
20
+ -----------
21
+ h5_file_path : str
22
+ Path to the h5 file containing the synapse report
23
+ config_path : str
24
+ Path to the simulation configuration file
25
+ edge_name : str
26
+ Edge name in format 'source_to_target' (e.g., 'thalamic_tone_to_LA')
27
+ This determines which source and target networks to load for population mapping
28
+ source_groupby : str or List[str]
29
+ Node property column name(s) to use for labeling source synapses.
30
+ Examples: 'pop_name', ['pop_name', 'model_type']
31
+ target_groupby : str or List[str]
32
+ Node property column name(s) to use for labeling target synapses.
33
+ Examples: 'pop_name', ['pop_name', 'model_type']
34
+
35
+ Returns:
36
+ --------
37
+ xarray.Dataset
38
+ An xarray containing the synapse report data with proper population labeling.
39
+ For each column in source_groupby/target_groupby, separate coordinates are created:
40
+ 'source_{column}', 'target_{column}', etc.
41
+ A 'connection_label' coordinate is also created with pipe-delimited values
42
+ (e.g., 'Pyr|biophys->PV|biophys').
43
+
44
+ Examples:
45
+ ---------
46
+ # Group by single column (default behavior):
47
+ ds = load_synapse_report(
48
+ h5_file_path='output/synapse_report.h5',
49
+ config_path='simulation_config.json',
50
+ edge_name='LA_to_LA',
51
+ source_groupby='pop_name',
52
+ target_groupby='pop_name'
53
+ )
54
+
55
+ # Group by multiple columns:
56
+ ds = load_synapse_report(
57
+ h5_file_path='output/synapse_report.h5',
58
+ config_path='simulation_config.json',
59
+ edge_name='LA_to_LA',
60
+ source_groupby=['pop_name', 'model_type'],
61
+ target_groupby=['pop_name', 'model_type']
62
+ )
63
+ # Returns dataset with coordinates:
64
+ # source_pop_name, source_model_type, target_pop_name, target_model_type, connection_label
65
+ """
66
+ # Normalize groupby parameters to lists
67
+ if isinstance(source_groupby, str):
68
+ source_groupby = [source_groupby]
69
+ if isinstance(target_groupby, str):
70
+ target_groupby = [target_groupby]
71
+
72
+ # Parse edge_name to extract source and target networks
73
+ if "_to_" not in edge_name:
74
+ raise ValueError(
75
+ f"Invalid edge_name format: '{edge_name}'. Expected format: 'source_to_target' "
76
+ "(e.g., 'thalamic_tone_to_LA')"
77
+ )
78
+
79
+ source_network, target_network = edge_name.split("_to_")
80
+
81
+ # Load the h5 file to get synapse mapping data
82
+ with h5py.File(h5_file_path, "r") as file:
83
+ # Get the first (and typically only) network key in the report
84
+ report_networks = list(file["report"].keys())
85
+ if not report_networks:
86
+ raise ValueError(f"No report networks found in {h5_file_path}")
87
+
88
+ # Use the first available network in the h5 file
89
+ report_network = report_networks[0]
90
+ report = file["report"][report_network]
91
+ mapping = report["mapping"]
92
+
93
+ # Get the data - shape is (n_timesteps, n_synapses)
94
+ data = report["data"][:]
95
+
96
+ # Get time information
97
+ time_info = mapping["time"][:] # [start_time, end_time, dt]
98
+ start_time = time_info[0]
99
+ end_time = time_info[1]
100
+ dt = time_info[2]
101
+
102
+ # Create time array
103
+ n_steps = data.shape[0]
104
+ time = np.linspace(start_time, start_time + (n_steps - 1) * dt, n_steps)
105
+
106
+ # Get mapping information
107
+ src_ids = mapping["src_ids"][:]
108
+ trg_ids = mapping["trg_ids"][:]
109
+ sec_id = mapping["element_ids"][:]
110
+ sec_x = mapping["element_pos"][:]
111
+
112
+ # Load node information for both source and target networks
113
+ all_nodes = load_nodes_from_config(config_path)
114
+
115
+ # Get the source and target node dataframes
116
+ if source_network not in all_nodes:
117
+ raise ValueError(
118
+ f"Source network '{source_network}' not found in config. "
119
+ f"Available networks: {list(all_nodes.keys())}"
120
+ )
121
+ if target_network not in all_nodes:
122
+ raise ValueError(
123
+ f"Target network '{target_network}' not found in config. "
124
+ f"Available networks: {list(all_nodes.keys())}"
125
+ )
126
+
127
+ source_nodes = all_nodes[source_network]
128
+ target_nodes = all_nodes[target_network]
129
+
130
+ # Validate that requested groupby columns exist in node dataframes
131
+ missing_src_cols = [col for col in source_groupby if col not in source_nodes.columns]
132
+ if missing_src_cols:
133
+ raise KeyError(
134
+ f"Columns {missing_src_cols} not found in source network '{source_network}'. "
135
+ f"Available columns: {list(source_nodes.columns)}"
136
+ )
137
+
138
+ missing_trg_cols = [col for col in target_groupby if col not in target_nodes.columns]
139
+ if missing_trg_cols:
140
+ raise KeyError(
141
+ f"Columns {missing_trg_cols} not found in target network '{target_network}'. "
142
+ f"Available columns: {list(target_nodes.columns)}"
143
+ )
144
+
145
+ # Create mappings from node IDs to groupby column values
146
+ # source_mappings[col] = {node_id: column_value}
147
+ source_mappings: Dict[str, Dict[int, Any]] = {}
148
+ for col in source_groupby:
149
+ source_mappings[col] = dict(zip(source_nodes.index, source_nodes[col]))
150
+
151
+ target_mappings: Dict[str, Dict[int, Any]] = {}
152
+ for col in target_groupby:
153
+ target_mappings[col] = dict(zip(target_nodes.index, target_nodes[col]))
154
+
155
+ # Determine default values for external inputs (src_id = -1)
156
+ # Get the most common value or "unknown" if heterogeneous
157
+ src_external_values = {}
158
+ for col in source_groupby:
159
+ unique_vals = source_nodes[col].unique()
160
+ if len(unique_vals) == 1:
161
+ src_external_values[col] = unique_vals[0]
162
+ else:
163
+ src_external_values[col] = "unknown"
164
+
165
+ # Get the number of synapses
166
+ n_synapses = data.shape[1]
167
+
168
+ # Create arrays to hold the groupby values for each synapse
169
+ # synapse_values[col] = [val_for_synapse_0, val_for_synapse_1, ...]
170
+ source_values: Dict[str, List[Any]] = {col: [] for col in source_groupby}
171
+ target_values: Dict[str, List[Any]] = {col: [] for col in target_groupby}
172
+ connection_labels = []
173
+
174
+ # Process each synapse
175
+ for i in range(n_synapses):
176
+ src_id = src_ids[i]
177
+ trg_id = trg_ids[i]
178
+
179
+ # Get source groupby values
180
+ src_label_parts = []
181
+ for col in source_groupby:
182
+ if src_id == -1:
183
+ # External input: use default value for this column
184
+ val = src_external_values[col]
185
+ else:
186
+ val = source_mappings[col].get(src_id, f"unknown_{src_id}")
187
+ source_values[col].append(val)
188
+ src_label_parts.append(str(val))
189
+
190
+ # Get target groupby values
191
+ trg_label_parts = []
192
+ for col in target_groupby:
193
+ val = target_mappings[col].get(trg_id, f"unknown_{trg_id}")
194
+ target_values[col].append(val)
195
+ trg_label_parts.append(str(val))
196
+
197
+ # Create connection label with pipe-delimited format
198
+ src_label = "|".join(src_label_parts)
199
+ trg_label = "|".join(trg_label_parts)
200
+ connection_labels.append(f"{src_label}->{trg_label}")
201
+
202
+ # Create coordinates dictionary dynamically based on groupby columns
203
+ coords = {
204
+ "time": time,
205
+ "synapse": np.arange(n_synapses),
206
+ "source_id": ("synapse", src_ids),
207
+ "target_id": ("synapse", trg_ids),
208
+ "sec_id": ("synapse", sec_id),
209
+ "sec_x": ("synapse", sec_x),
210
+ "connection_label": ("synapse", connection_labels),
211
+ }
212
+
213
+ # Add source groupby coordinates
214
+ for col in source_groupby:
215
+ coords[f"source_{col}"] = ("synapse", source_values[col])
216
+
217
+ # Add target groupby coordinates
218
+ for col in target_groupby:
219
+ coords[f"target_{col}"] = ("synapse", target_values[col])
220
+
221
+ # Create xarray dataset
222
+ ds = xr.Dataset(
223
+ data_vars={"synapse_value": (["time", "synapse"], data)},
224
+ coords=coords,
225
+ attrs={"description": "Synapse report data from bmtk simulation"},
226
+ )
227
+
228
+ return ds
@@ -193,7 +193,11 @@ def percent_connection_matrix(
193
193
  no_prepend_pop : bool, optional
194
194
  If True, population name is not displayed before sid or tid in the plot. Default is False.
195
195
  method : str, optional
196
- Method for calculating percent connectivity. Options: 'total', 'uni', 'bi'.
196
+ Method for calculating percent connectivity. Options:
197
+ - 'total': Pairwise connection probability (connections / (sources * targets) * 100)
198
+ - 'uni': Unidirectional connection probability
199
+ - 'bi': Bidirectional connection probability
200
+ - 'innervation': Percentage of target neurons receiving at least one connection
197
201
  Default is 'total'.
198
202
  include_gap : bool, optional
199
203
  If True, include gap junctions in analysis. If False, only include chemical synapses.
@@ -249,7 +253,16 @@ def percent_connection_matrix(
249
253
  include_gap=include_gap,
250
254
  )
251
255
  if title is None or title == "":
252
- title = "Percent Connectivity"
256
+ if method == "uni":
257
+ title = "Unidirectional Percent Connectivity"
258
+ elif method == "bi":
259
+ title = "Bidirectional Percent Connectivity"
260
+ elif method == "total":
261
+ title = "Total Percent Connectivity"
262
+ elif method == "innervation":
263
+ title = "Percentage of target neurons receiving at least one connection"
264
+ else:
265
+ title = "Percent Connectivity"
253
266
 
254
267
  if return_dict:
255
268
  result_dict = plot_connection_info(
@@ -1240,12 +1240,18 @@ def percent_connections(
1240
1240
  uni = round(num_uni / (num_sources * num_targets) * 100, 2)
1241
1241
  bi = round(num_bi / (num_sources * num_targets) * 100, 2)
1242
1242
 
1243
+ # Calculate innervation percentage (% of target neurons receiving at least one connection)
1244
+ unique_target_nodes = cons['target_node_id'].nunique()
1245
+ innervation = round(unique_target_nodes / num_targets * 100, 2)
1246
+
1243
1247
  if method == "total":
1244
1248
  return total
1245
1249
  if method == "uni":
1246
1250
  return uni
1247
1251
  if method == "bi":
1248
1252
  return bi
1253
+ if method == "innervation":
1254
+ return innervation
1249
1255
 
1250
1256
  return relation_matrix(
1251
1257
  config, nodes, edges, sources, targets, sids, tids, prepend_pop, relation_func=precent_func
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bmtool
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: BMTool
5
5
  Home-page: https://github.com/cyneuro/bmtool
6
6
  Download-URL:
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setup(
7
7
  name="bmtool",
8
- version="0.8.1",
8
+ version="0.8.2",
9
9
  author="Neural Engineering Laboratory at the University of Missouri",
10
10
  author_email="gregglickert@mail.missouri.edu",
11
11
  description="BMTool",
@@ -1,94 +0,0 @@
1
- import h5py
2
- import numpy as np
3
- import xarray as xr
4
-
5
- from ..util.util import load_nodes_from_config
6
-
7
-
8
- def load_synapse_report(h5_file_path, config_path, network):
9
- """
10
- Load and process a synapse report from a bmtk simulation into an xarray.
11
-
12
- Parameters:
13
- -----------
14
- h5_file_path : str
15
- Path to the h5 file containing the synapse report
16
- config_path : str
17
- Path to the simulation configuration file
18
-
19
- Returns:
20
- --------
21
- xarray.Dataset
22
- An xarray containing the synapse report data with proper population labeling
23
- """
24
- # Load the h5 file
25
- with h5py.File(h5_file_path, "r") as file:
26
- # Get the report data
27
- report = file["report"][network]
28
- mapping = report["mapping"]
29
-
30
- # Get the data - shape is (n_timesteps, n_synapses)
31
- data = report["data"][:]
32
-
33
- # Get time information
34
- time_info = mapping["time"][:] # [start_time, end_time, dt]
35
- start_time = time_info[0]
36
- end_time = time_info[1]
37
- dt = time_info[2]
38
-
39
- # Create time array
40
- n_steps = data.shape[0]
41
- time = np.linspace(start_time, start_time + (n_steps - 1) * dt, n_steps)
42
-
43
- # Get mapping information
44
- src_ids = mapping["src_ids"][:]
45
- trg_ids = mapping["trg_ids"][:]
46
- sec_id = mapping["element_ids"][:]
47
- sec_x = mapping["element_pos"][:]
48
-
49
- # Load node information
50
- nodes = load_nodes_from_config(config_path)
51
- nodes = nodes[network]
52
-
53
- # Create a mapping from node IDs to population names
54
- node_to_pop = dict(zip(nodes.index, nodes["pop_name"]))
55
-
56
- # Get the number of synapses
57
- n_synapses = data.shape[1]
58
-
59
- # Create arrays to hold the source and target populations for each synapse
60
- source_pops = []
61
- target_pops = []
62
- connection_labels = []
63
-
64
- # Process each synapse
65
- for i in range(n_synapses):
66
- src_id = src_ids[i]
67
- trg_id = trg_ids[i]
68
-
69
- # Get population names (with fallback for unknown IDs)
70
- src_pop = node_to_pop.get(src_id, f"unknown_{src_id}")
71
- trg_pop = node_to_pop.get(trg_id, f"unknown_{trg_id}")
72
-
73
- source_pops.append(src_pop)
74
- target_pops.append(trg_pop)
75
- connection_labels.append(f"{src_pop}->{trg_pop}")
76
-
77
- # Create xarray dataset
78
- ds = xr.Dataset(
79
- data_vars={"synapse_value": (["time", "synapse"], data)},
80
- coords={
81
- "time": time,
82
- "synapse": np.arange(n_synapses),
83
- "source_pop": ("synapse", source_pops),
84
- "target_pop": ("synapse", target_pops),
85
- "source_id": ("synapse", src_ids),
86
- "target_id": ("synapse", trg_ids),
87
- "sec_id": ("synapse", sec_id),
88
- "sec_x": ("synapse", sec_x),
89
- "connection_label": ("synapse", connection_labels),
90
- },
91
- attrs={"description": "Synapse report data from bmtk simulation"},
92
- )
93
-
94
- return ds
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