risk-network 0.0.7b12__py3-none-any.whl → 0.0.8b1__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.
risk/__init__.py CHANGED
@@ -7,4 +7,4 @@ RISK: RISK Infers Spatial Kinships
7
7
 
8
8
  from risk.risk import RISK
9
9
 
10
- __version__ = "0.0.7-beta.12"
10
+ __version__ = "0.0.8-beta.1"
risk/network/io.py CHANGED
@@ -153,8 +153,10 @@ class NetworkIO:
153
153
  params.log_network(filetype=filetype)
154
154
  self._log_loading(filetype)
155
155
 
156
+ # Important: Make a copy of the network to avoid modifying the original
157
+ network_copy = network.copy()
156
158
  # Initialize the graph
157
- return self._initialize_graph(network)
159
+ return self._initialize_graph(network_copy)
158
160
 
159
161
  @staticmethod
160
162
  def load_cytoscape_network(
@@ -475,16 +477,50 @@ class NetworkIO:
475
477
  logger.debug(f"Total edges missing weights: {missing_weights}")
476
478
 
477
479
  def _validate_nodes(self, G: nx.Graph) -> None:
478
- """Validate the graph structure and attributes.
480
+ """Validate the graph structure and attributes with attribute fallback for positions and labels.
479
481
 
480
482
  Args:
481
483
  G (nx.Graph): A NetworkX graph object.
482
484
  """
485
+ # Keep track of nodes missing labels
486
+ nodes_with_missing_labels = []
487
+
483
488
  for node, attrs in G.nodes(data=True):
484
- assert (
485
- "x" in attrs and "y" in attrs
486
- ), f"Node {node} is missing 'x' or 'y' position attributes."
487
- assert "label" in attrs, f"Node {node} is missing a 'label' attribute."
489
+ # Attribute fallback for 'x' and 'y' attributes
490
+ if "x" not in attrs or "y" not in attrs:
491
+ if (
492
+ "pos" in attrs
493
+ and isinstance(attrs["pos"], (tuple, list))
494
+ and len(attrs["pos"]) >= 2
495
+ ):
496
+ attrs["x"], attrs["y"] = attrs["pos"][
497
+ :2
498
+ ] # Use only x and y, ignoring z if present
499
+ else:
500
+ raise ValueError(
501
+ f"Node {node} is missing 'x', 'y', and a valid 'pos' attribute."
502
+ )
503
+
504
+ # Attribute fallback for 'label' attribute
505
+ if "label" not in attrs:
506
+ # Try alternative attribute names for label
507
+ if "name" in attrs:
508
+ attrs["label"] = attrs["name"]
509
+ elif "id" in attrs:
510
+ attrs["label"] = attrs["id"]
511
+ else:
512
+ # Collect nodes with missing labels
513
+ nodes_with_missing_labels.append(node)
514
+ attrs["label"] = str(node) # Use node ID as the label
515
+
516
+ # Issue a single warning if any labels were missing
517
+ if nodes_with_missing_labels:
518
+ total_nodes = len(G.nodes)
519
+ fraction_missing_labels = len(nodes_with_missing_labels) / total_nodes
520
+ logger.warning(
521
+ f"{len(nodes_with_missing_labels)} out of {total_nodes} nodes "
522
+ f"({fraction_missing_labels:.2%}) were missing 'label' attributes and were assigned node IDs."
523
+ )
488
524
 
489
525
  def _assign_edge_lengths(self, G: nx.Graph) -> None:
490
526
  """Prepare the network by adjusting surface depth and calculating edge lengths.
@@ -133,6 +133,7 @@ def _run_permutation_test(
133
133
  observed_neighborhood_scores,
134
134
  neighborhood_score_func,
135
135
  subset_size + (1 if i < remainder else 0),
136
+ num_permutations,
136
137
  progress_counter,
137
138
  max_workers,
138
139
  rng, # Pass the random number generator to each worker
@@ -144,11 +145,9 @@ def _run_permutation_test(
144
145
  results = pool.starmap_async(_permutation_process_subset, params_list, chunksize=1)
145
146
 
146
147
  # Update progress bar based on progress_counter
147
- # NOTE: Waiting for results to be ready while updating progress bar gives a big improvement
148
- # in performance, especially for large number of permutations and workers
149
148
  while not results.ready():
150
149
  progress.update(progress_counter.value - progress.n)
151
- results.wait(0.05) # Wait for 50ms
150
+ results.wait(0.1) # Wait for 100ms
152
151
  # Ensure progress bar reaches 100%
153
152
  progress.update(total_progress - progress.n)
154
153
 
@@ -167,6 +166,7 @@ def _permutation_process_subset(
167
166
  observed_neighborhood_scores: np.ndarray,
168
167
  neighborhood_score_func: Callable,
169
168
  subset_size: int,
169
+ num_permutations: int,
170
170
  progress_counter: ValueProxy,
171
171
  max_workers: int,
172
172
  rng: np.random.Generator,
@@ -180,6 +180,7 @@ def _permutation_process_subset(
180
180
  observed_neighborhood_scores (np.ndarray): Observed neighborhood scores.
181
181
  neighborhood_score_func (Callable): Function to calculate neighborhood scores.
182
182
  subset_size (int): Number of permutations to run in this subset.
183
+ num_permutations (int): Number of total permutations across all subsets.
183
184
  progress_counter (multiprocessing.managers.ValueProxy): Shared counter for tracking progress.
184
185
  max_workers (int): Number of workers for multiprocessing.
185
186
  rng (np.random.Generator): Random number generator object.
@@ -190,11 +191,15 @@ def _permutation_process_subset(
190
191
  # Initialize local count matrices for this worker
191
192
  local_counts_depletion = np.zeros(observed_neighborhood_scores.shape)
192
193
  local_counts_enrichment = np.zeros(observed_neighborhood_scores.shape)
194
+
193
195
  # NOTE: Limit the number of threads used by NumPy's BLAS implementation to 1 when more than one worker is used.
194
- # This can help prevent oversubscription of CPU resources during multiprocessing, ensuring that each process
195
- # doesn't use more than one CPU core.
196
196
  limits = None if max_workers == 1 else 1
197
197
  with threadpool_limits(limits=limits, user_api="blas"):
198
+ # Initialize a local counter for batched progress updates
199
+ local_progress = 0
200
+ # Calculate the modulo value based on total permutations for 1/100th frequency updates
201
+ modulo_value = max(1, num_permutations // 100)
202
+
198
203
  for _ in range(subset_size):
199
204
  # Permute the annotation matrix using the RNG
200
205
  annotation_matrix_permut = annotation_matrix[rng.permutation(idxs)]
@@ -212,7 +217,15 @@ def _permutation_process_subset(
212
217
  local_counts_enrichment,
213
218
  permuted_neighborhood_scores >= observed_neighborhood_scores,
214
219
  )
215
- # Update the shared progress counter
216
- progress_counter.value += 1
220
+
221
+ # Update local progress counter
222
+ local_progress += 1
223
+ # Update shared progress counter every 1/100th of total permutations
224
+ if local_progress % modulo_value == 0:
225
+ progress_counter.value += modulo_value
226
+
227
+ # Final progress update for any remaining iterations
228
+ if local_progress % modulo_value != 0:
229
+ progress_counter.value += modulo_value
217
230
 
218
231
  return local_counts_depletion, local_counts_enrichment
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: risk-network
3
- Version: 0.0.7b12
3
+ Version: 0.0.8b1
4
4
  Summary: A Python package for biological network analysis
5
5
  Author: Ira Horecka
6
6
  Author-email: Ira Horecka <ira89@icloud.com>
@@ -1,4 +1,4 @@
1
- risk/__init__.py,sha256=b9WNiI1lQZaEaH5NHdgQdLB2MS9EUzlVycFh2JpNEJs,113
1
+ risk/__init__.py,sha256=UNSdF3ch5eG5kY1NsOrjzDZOS-HRak9ASoBVXBkvCAM,112
2
2
  risk/constants.py,sha256=XInRaH78Slnw_sWgAsBFbUHkyA0h0jL0DKGuQNbOvjM,550
3
3
  risk/risk.py,sha256=FaQhDCBZxZSAXJsScH0rSbjjCTNZA5vgf9rJj1GHW44,20924
4
4
  risk/annotations/__init__.py,sha256=vUpVvMRE5if01Ic8QY6M2Ae3EFGJHdugEe9PdEkAW4Y,138
@@ -14,17 +14,17 @@ risk/neighborhoods/neighborhoods.py,sha256=M-wL4xB_BUTlSZg90swygO5NdrZ6hFUFqs6js
14
14
  risk/network/__init__.py,sha256=iEPeJdZfqp0toxtbElryB8jbz9_t_k4QQ3iDvKE8C_0,126
15
15
  risk/network/geometry.py,sha256=H1yGVVqgbfpzBzJwEheDLfvGLSA284jGQQTn612L4Vc,6759
16
16
  risk/network/graph.py,sha256=_LEoom4EEowGALuJKSXcev9RAAHu2FqIeq3u7mkifW0,16479
17
- risk/network/io.py,sha256=ASoKG4vkCC_aHwxlF4502W_SyaaCrRnHsTmRwL00spI,21266
17
+ risk/network/io.py,sha256=kY7HqmL3wa1NnqHu61_G8IpT21qpBijpAZ4ixmsseJA,22911
18
18
  risk/network/plot.py,sha256=9GcLKkH3CMEtraYnfdLXNJCi04rBQCjw4T6Q8k5yNOI,67091
19
19
  risk/stats/__init__.py,sha256=WcgoETQ-hS0LQqKRsAMIPtP15xZ-4eul6VUBuUx4Wzc,220
20
20
  risk/stats/hypergeom.py,sha256=o6Qnj31gCAKxr2uQirXrbv7XvdDJGEq69MFW-ubx_hA,2272
21
21
  risk/stats/poisson.py,sha256=8x9hB4DCukq4gNIlIKO-c_jYG1-BTwTX53oLauFyfj8,1793
22
22
  risk/stats/stats.py,sha256=kvShov-94W6ffgDUTb522vB9hDJQSyTsYif_UIaFfSM,7059
23
23
  risk/stats/permutation/__init__.py,sha256=neJp7FENC-zg_CGOXqv-iIvz1r5XUKI9Ruxhmq7kDOI,105
24
- risk/stats/permutation/permutation.py,sha256=kmSZ7bQ-AD0TFiQDgIwfxTeqHa4pjp7fIcOzAqyhUNY,9714
24
+ risk/stats/permutation/permutation.py,sha256=D84Rcpt6iTQniK0PfQGcw9bLcHbMt9p-ARcurUnIXZQ,10095
25
25
  risk/stats/permutation/test_functions.py,sha256=lftOude6hee0pyR80HlBD32522JkDoN5hrKQ9VEbuoY,2345
26
- risk_network-0.0.7b12.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
27
- risk_network-0.0.7b12.dist-info/METADATA,sha256=BHkHe5vNDc1pLERmMqrAQhO0I-DAeQbF8g44BRd1k1I,43143
28
- risk_network-0.0.7b12.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
29
- risk_network-0.0.7b12.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
30
- risk_network-0.0.7b12.dist-info/RECORD,,
26
+ risk_network-0.0.8b1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
27
+ risk_network-0.0.8b1.dist-info/METADATA,sha256=E0T1xFQXaQfe3oH0ZW7fAukDoB3QbvzswcLc0oczpqA,43142
28
+ risk_network-0.0.8b1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
29
+ risk_network-0.0.8b1.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
30
+ risk_network-0.0.8b1.dist-info/RECORD,,