risk-network 0.0.3b1__py3-none-any.whl → 0.0.3b2__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
@@ -10,4 +10,4 @@ RISK: RISK Infers Spatial Kinship
10
10
 
11
11
  from risk.risk import RISK
12
12
 
13
- __version__ = "0.0.3-beta.1"
13
+ __version__ = "0.0.3-beta.2"
risk/stats/stats.py CHANGED
@@ -3,40 +3,14 @@ risk/stats/stats
3
3
  ~~~~~~~~~~~~~~~~
4
4
  """
5
5
 
6
- import sys
7
- from contextlib import contextmanager
8
- from multiprocessing import get_context, Lock
9
- from typing import Any, Callable, Generator, Union
6
+ from multiprocessing import get_context, Manager
7
+ from tqdm import tqdm
8
+ from typing import Any, Callable, Dict, Union
10
9
 
11
10
  import numpy as np
12
11
  from statsmodels.stats.multitest import fdrcorrection
13
12
  from threadpoolctl import threadpool_limits
14
13
 
15
-
16
- def _is_notebook() -> bool:
17
- """Determine the type of interactive environment and return it as a dictionary.
18
-
19
- Returns:
20
- bool: True if the environment is a Jupyter notebook, False otherwise.
21
- """
22
- try:
23
- shell = get_ipython().__class__.__name__
24
- if shell == "ZMQInteractiveShell":
25
- return True # Jupyter notebook or qtconsole
26
- elif shell == "TerminalInteractiveShell":
27
- return False # Terminal running IPython
28
- else:
29
- return False # Other types of shell
30
- except NameError:
31
- return False # Standard Python interpreter
32
-
33
-
34
- if _is_notebook():
35
- from tqdm.notebook import tqdm
36
- else:
37
- from tqdm import tqdm
38
-
39
-
40
14
  from risk.stats.permutation import (
41
15
  compute_neighborhood_score_by_sum,
42
16
  compute_neighborhood_score_by_stdev,
@@ -58,7 +32,7 @@ def compute_permutation(
58
32
  num_permutations: int = 1000,
59
33
  random_seed: int = 888,
60
34
  max_workers: int = 1,
61
- ) -> dict:
35
+ ) -> Dict[str, Any]:
62
36
  """Compute permutation test for enrichment and depletion in neighborhoods.
63
37
 
64
38
  Args:
@@ -78,6 +52,7 @@ def compute_permutation(
78
52
  annotations = annotations.astype(np.float32)
79
53
  # Retrieve the appropriate neighborhood score function based on the metric
80
54
  neighborhood_score_func = DISPATCH_PERMUTATION_TABLE[score_metric]
55
+
81
56
  # Run the permutation test to calculate depletion and enrichment counts
82
57
  counts_depletion, counts_enrichment = _run_permutation_test(
83
58
  neighborhoods=neighborhoods,
@@ -125,6 +100,7 @@ def _run_permutation_test(
125
100
  """
126
101
  # Set the random seed for reproducibility
127
102
  np.random.seed(random_seed)
103
+
128
104
  # Determine the indices to use based on the null distribution type
129
105
  if null_distribution == "network":
130
106
  idxs = range(annotations.shape[0])
@@ -135,6 +111,7 @@ def _run_permutation_test(
135
111
  annotations[np.isnan(annotations)] = 0
136
112
  annotation_matrix_obsv = annotations[idxs]
137
113
  neighborhoods_matrix_obsv = neighborhoods.T[idxs].T
114
+
138
115
  # Calculate observed neighborhood scores
139
116
  with np.errstate(invalid="ignore", divide="ignore"):
140
117
  observed_neighborhood_scores = neighborhood_score_func(
@@ -144,14 +121,21 @@ def _run_permutation_test(
144
121
  # Initialize count matrices for depletion and enrichment
145
122
  counts_depletion = np.zeros(observed_neighborhood_scores.shape)
146
123
  counts_enrichment = np.zeros(observed_neighborhood_scores.shape)
124
+
147
125
  # Determine the number of permutations to run in each worker process
148
126
  subset_size = num_permutations // max_workers
149
127
  remainder = num_permutations % max_workers
150
128
 
151
129
  # Use the spawn context for creating a new multiprocessing pool
152
130
  ctx = get_context("spawn")
153
- with ctx.Pool(max_workers, initializer=_init, initargs=(Lock(),)) as pool:
154
- with threadpool_limits(limits=1, user_api="blas"):
131
+ manager = Manager()
132
+ progress_counter = manager.Value("i", 0)
133
+ total_progress = num_permutations
134
+
135
+ # Execute the permutation test using multiprocessing
136
+ with ctx.Pool(max_workers) as pool:
137
+ with tqdm(total=total_progress, desc="Total progress", position=0) as progress:
138
+ # Prepare parameters for multiprocessing
155
139
  params_list = [
156
140
  (
157
141
  annotations,
@@ -160,14 +144,24 @@ def _run_permutation_test(
160
144
  observed_neighborhood_scores,
161
145
  neighborhood_score_func,
162
146
  subset_size + (1 if i < remainder else 0),
163
- i,
164
- max_workers,
165
- True,
147
+ progress_counter,
166
148
  )
167
149
  for i in range(max_workers)
168
150
  ]
169
- results = pool.starmap(_permutation_process_subset, params_list)
170
- for local_counts_depletion, local_counts_enrichment in results:
151
+
152
+ # Start the permutation process in parallel
153
+ results = pool.starmap_async(_permutation_process_subset, params_list)
154
+
155
+ # Update progress bar based on progress_counter
156
+ while not results.ready():
157
+ progress.update(progress_counter.value - progress.n)
158
+ results.wait(0.1)
159
+
160
+ # Ensure progress bar reaches 100%
161
+ progress.update(total_progress - progress.n)
162
+
163
+ # Accumulate results from each worker
164
+ for local_counts_depletion, local_counts_enrichment in results.get():
171
165
  counts_depletion = np.add(counts_depletion, local_counts_depletion)
172
166
  counts_enrichment = np.add(counts_enrichment, local_counts_enrichment)
173
167
 
@@ -181,9 +175,7 @@ def _permutation_process_subset(
181
175
  observed_neighborhood_scores: np.ndarray,
182
176
  neighborhood_score_func: Callable,
183
177
  subset_size: int,
184
- worker_id: int,
185
- max_workers: int,
186
- use_lock: bool,
178
+ progress_counter,
187
179
  ) -> tuple:
188
180
  """Process a subset of permutations for the permutation test.
189
181
 
@@ -194,9 +186,7 @@ def _permutation_process_subset(
194
186
  observed_neighborhood_scores (np.ndarray): Observed neighborhood scores.
195
187
  neighborhood_score_func (Callable): Function to calculate neighborhood scores.
196
188
  subset_size (int): Number of permutations to run in this subset.
197
- worker_id (int): ID of the worker process.
198
- max_workers (int): Number of worker processes.
199
- use_lock (bool): Whether to use a lock for multiprocessing synchronization.
189
+ progress_counter: Shared counter for tracking progress.
200
190
 
201
191
  Returns:
202
192
  tuple: Local counts of depletion and enrichment.
@@ -205,13 +195,7 @@ def _permutation_process_subset(
205
195
  local_counts_depletion = np.zeros(observed_neighborhood_scores.shape)
206
196
  local_counts_enrichment = np.zeros(observed_neighborhood_scores.shape)
207
197
 
208
- # Initialize progress bar for tracking permutation progress
209
- text = f"Worker {worker_id + 1} of {max_workers} progress"
210
- leave = worker_id == max_workers - 1 # Only leave the progress bar for the last worker
211
-
212
- with _tqdm_context(
213
- total=subset_size, desc=text, position=0, leave=leave, use_lock=use_lock
214
- ) as progress:
198
+ with threadpool_limits(limits=1, user_api="blas"):
215
199
  for _ in range(subset_size):
216
200
  # Permute the annotation matrix
217
201
  annotation_matrix_permut = annotation_matrix[np.random.permutation(idxs)]
@@ -228,72 +212,12 @@ def _permutation_process_subset(
228
212
  local_counts_enrichment,
229
213
  permuted_neighborhood_scores >= observed_neighborhood_scores,
230
214
  )
231
- # Update progress bar
232
- progress.update(1)
215
+ # Update the shared progress counter
216
+ progress_counter.value += 1
233
217
 
234
218
  return local_counts_depletion, local_counts_enrichment
235
219
 
236
220
 
237
- def _init(lock_: Any) -> None:
238
- """Initialize a global lock for multiprocessing.
239
-
240
- Args:
241
- lock_ (Any): A lock object to be used in multiprocessing.
242
- """
243
- global lock
244
- lock = lock_ # Assign the provided lock to a global variable
245
-
246
-
247
- @contextmanager
248
- def _tqdm_context(
249
- total: int, desc: str, position: int, leave: bool = False, use_lock: bool = False
250
- ) -> Generator:
251
- """A context manager for a `tqdm` progress bar.
252
-
253
- Args:
254
- total (int): The total number of iterations for the progress bar.
255
- desc (str): Description for the progress bar.
256
- position (int): The position of the progress bar (useful for multiple bars).
257
- leave (bool): Whether to leave the progress bar after completion.
258
- use_lock (bool): Whether to use a lock for multiprocessing synchronization.
259
-
260
- Yields:
261
- tqdm: A `tqdm` progress bar object.
262
- """
263
- # Set default parameters for the progress bar
264
- min_interval = 0.1
265
- # Use a lock for multiprocessing synchronization if specified
266
- if use_lock:
267
- with lock:
268
- # Create a progress bar with specified parameters and direct output to stderr
269
- progress = tqdm(
270
- total=total,
271
- desc=desc,
272
- position=position,
273
- leave=leave,
274
- mininterval=min_interval,
275
- file=sys.stderr,
276
- )
277
- try:
278
- yield progress # Yield the progress bar to the calling context
279
- finally:
280
- progress.close() # Ensure the progress bar is closed properly
281
- else:
282
- # Create a progress bar without using a lock
283
- progress = tqdm(
284
- total=total,
285
- desc=desc,
286
- position=position,
287
- leave=leave,
288
- mininterval=min_interval,
289
- file=sys.stderr,
290
- )
291
- try:
292
- yield progress # Yield the progress bar to the calling context
293
- finally:
294
- progress.close() # Ensure the progress bar is closed properly
295
-
296
-
297
221
  def calculate_significance_matrices(
298
222
  depletion_pvals: np.ndarray,
299
223
  enrichment_pvals: np.ndarray,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: risk-network
3
- Version: 0.0.3b1
3
+ Version: 0.0.3b2
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=YGLEEBwHyZBnVritQ0gJiaG6UyA7yTr-bRIl_zoG7uU,122
1
+ risk/__init__.py,sha256=H7Oal2XxdwvgwfVdxjsgEpAPdyruGRh2shgYLfJXFCs,122
2
2
  risk/constants.py,sha256=AICk3x5qRQhls_ijTb4VdbdxU6mZ1aLGbAjLEdBwfJI,550
3
3
  risk/risk.py,sha256=cWpYogZ-vma4ZZjewVNRMzb2TqHv8YABuzP2brXpOqo,16399
4
4
  risk/annotations/__init__.py,sha256=vUpVvMRE5if01Ic8QY6M2Ae3EFGJHdugEe9PdEkAW4Y,138
@@ -18,9 +18,9 @@ risk/network/io.py,sha256=KmdrsDZe-ZT4O59NYZM_nQd8Ew9qpbzQcqWS_PaE7eA,12559
18
18
  risk/network/plot.py,sha256=fy21X677xqJPFkn564Jegxy05C9x0pJXovd5fm3NZ4Q,34554
19
19
  risk/stats/__init__.py,sha256=4s9gdJo5B1G_cQc0iMoeIBt5OrQNXkdtNXkAMFQkLxc,103
20
20
  risk/stats/permutation.py,sha256=xgaZbaxo57t_FzPlpcb2nsq8oCzc_wj-zAm-xj3P2dA,3404
21
- risk/stats/stats.py,sha256=3elBwvHifYSjGwao8VdS6aP_nCWxT1R1hmvjuh66bzw,18394
22
- risk_network-0.0.3b1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
23
- risk_network-0.0.3b1.dist-info/METADATA,sha256=bevulqGzjR0_aXLvfIklxk64jYotkJb8e2qOTWoT20Q,43256
24
- risk_network-0.0.3b1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
25
- risk_network-0.0.3b1.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
26
- risk_network-0.0.3b1.dist-info/RECORD,,
21
+ risk/stats/stats.py,sha256=_3Fj5H8Nml4cExvLg7Mt_i1HCLAJJcJSDiiSzr3uFlo,15798
22
+ risk_network-0.0.3b2.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
23
+ risk_network-0.0.3b2.dist-info/METADATA,sha256=y75hZFuUFJ99JoFX2koM3Xf_aI28MKXxiFKHV8iV4yw,43256
24
+ risk_network-0.0.3b2.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
25
+ risk_network-0.0.3b2.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
26
+ risk_network-0.0.3b2.dist-info/RECORD,,