risk-network 0.0.9b23__py3-none-any.whl → 0.0.9b25__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.
Files changed (40) hide show
  1. risk/__init__.py +1 -1
  2. risk/annotations/__init__.py +2 -2
  3. risk/annotations/annotations.py +9 -9
  4. risk/annotations/io.py +0 -2
  5. risk/log/__init__.py +2 -2
  6. risk/neighborhoods/__init__.py +3 -5
  7. risk/neighborhoods/api.py +446 -0
  8. risk/neighborhoods/community.py +4 -2
  9. risk/neighborhoods/domains.py +28 -1
  10. risk/network/__init__.py +1 -3
  11. risk/network/graph/__init__.py +1 -1
  12. risk/network/graph/api.py +194 -0
  13. risk/network/graph/summary.py +6 -2
  14. risk/network/io.py +0 -2
  15. risk/network/plotter/__init__.py +6 -0
  16. risk/network/plotter/api.py +54 -0
  17. risk/network/{plot → plotter}/canvas.py +3 -3
  18. risk/network/{plot → plotter}/contour.py +2 -2
  19. risk/network/{plot → plotter}/labels.py +3 -3
  20. risk/network/{plot → plotter}/network.py +136 -3
  21. risk/network/{plot → plotter}/utils/colors.py +15 -6
  22. risk/risk.py +10 -483
  23. risk/stats/__init__.py +8 -4
  24. risk/stats/binom.py +51 -0
  25. risk/stats/chi2.py +69 -0
  26. risk/stats/hypergeom.py +27 -17
  27. risk/stats/permutation/__init__.py +1 -1
  28. risk/stats/permutation/permutation.py +44 -55
  29. risk/stats/permutation/test_functions.py +25 -17
  30. risk/stats/poisson.py +15 -9
  31. risk/stats/zscore.py +68 -0
  32. {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/METADATA +1 -1
  33. risk_network-0.0.9b25.dist-info/RECORD +44 -0
  34. risk/network/plot/__init__.py +0 -6
  35. risk/network/plot/plotter.py +0 -143
  36. risk_network-0.0.9b23.dist-info/RECORD +0 -39
  37. /risk/network/{plot → plotter}/utils/layout.py +0 -0
  38. {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/LICENSE +0 -0
  39. {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/WHEEL +0 -0
  40. {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/top_level.txt +0 -0
risk/stats/hypergeom.py CHANGED
@@ -6,44 +6,54 @@ risk/stats/hypergeom
6
6
  from typing import Any, Dict
7
7
 
8
8
  import numpy as np
9
+ from scipy.sparse import csr_matrix
9
10
  from scipy.stats import hypergeom
10
11
 
11
12
 
12
13
  def compute_hypergeom_test(
13
- neighborhoods: np.ndarray, annotations: np.ndarray, null_distribution: str = "network"
14
+ neighborhoods: csr_matrix,
15
+ annotations: csr_matrix,
16
+ null_distribution: str = "network",
14
17
  ) -> Dict[str, Any]:
15
- """Compute hypergeometric test for enrichment and depletion in neighborhoods with selectable null distribution.
18
+ """
19
+ Compute hypergeometric test for enrichment and depletion in neighborhoods with selectable null distribution.
16
20
 
17
21
  Args:
18
- neighborhoods (np.ndarray): Binary matrix representing neighborhoods.
19
- annotations (np.ndarray): Binary matrix representing annotations.
22
+ neighborhoods (csr_matrix): Sparse binary matrix representing neighborhoods.
23
+ annotations (csr_matrix): Sparse binary matrix representing annotations.
20
24
  null_distribution (str, optional): Type of null distribution ('network' or 'annotations'). Defaults to "network".
21
25
 
22
26
  Returns:
23
27
  Dict[str, Any]: Dictionary containing depletion and enrichment p-values.
24
28
  """
25
29
  # Get the total number of nodes in the network
26
- total_node_count = neighborhoods.shape[0]
30
+ total_nodes = neighborhoods.shape[1]
31
+
32
+ # Compute sums
33
+ neighborhood_sums = neighborhoods.sum(axis=0).A.flatten() # Convert to dense array
34
+ annotation_sums = annotations.sum(axis=0).A.flatten() # Convert to dense array
27
35
 
28
36
  if null_distribution == "network":
29
- # Case 1: Use all nodes as the background
30
- background_population = total_node_count
31
- neighborhood_sums = np.sum(neighborhoods, axis=0, keepdims=True).T
32
- annotation_sums = np.sum(annotations, axis=0, keepdims=True)
37
+ background_population = total_nodes
33
38
  elif null_distribution == "annotations":
34
- # Case 2: Only consider nodes with at least one annotation
35
- annotated_nodes = np.sum(annotations, axis=1) > 0
36
- background_population = np.sum(annotated_nodes)
37
- neighborhood_sums = np.sum(neighborhoods[annotated_nodes], axis=0, keepdims=True).T
38
- annotation_sums = np.sum(annotations[annotated_nodes], axis=0, keepdims=True)
39
+ annotated_nodes = annotations.sum(axis=1).A.flatten() > 0 # Boolean mask
40
+ background_population = annotated_nodes.sum()
41
+ neighborhood_sums = neighborhoods[annotated_nodes].sum(axis=0).A.flatten()
42
+ annotation_sums = annotations[annotated_nodes].sum(axis=0).A.flatten()
39
43
  else:
40
44
  raise ValueError(
41
45
  "Invalid null_distribution value. Choose either 'network' or 'annotations'."
42
46
  )
43
47
 
44
- # Matrix multiplication for annotated nodes in each neighborhood
45
- annotated_in_neighborhood = neighborhoods.T @ annotations
46
- # Calculate depletion and enrichment p-values using the hypergeometric distribution
48
+ # Observed counts
49
+ annotated_in_neighborhood = neighborhoods.T @ annotations # Sparse result
50
+ annotated_in_neighborhood = annotated_in_neighborhood.toarray() # Convert to dense
51
+ # Align shapes for broadcasting
52
+ neighborhood_sums = neighborhood_sums.reshape(-1, 1)
53
+ annotation_sums = annotation_sums.reshape(1, -1)
54
+ background_population = np.array(background_population).reshape(1, 1)
55
+
56
+ # Compute hypergeometric p-values
47
57
  depletion_pvals = hypergeom.cdf(
48
58
  annotated_in_neighborhood, background_population, annotation_sums, neighborhood_sums
49
59
  )
@@ -3,4 +3,4 @@ risk/stats/permutation
3
3
  ~~~~~~~~~~~~~~~~~~~~~~
4
4
  """
5
5
 
6
- from .permutation import compute_permutation_test
6
+ from risk.stats.permutation.permutation import compute_permutation_test
@@ -3,11 +3,12 @@ risk/stats/permutation/permutation
3
3
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
4
  """
5
5
 
6
- from multiprocessing import get_context, shared_memory, Manager
6
+ from multiprocessing import get_context, Manager
7
7
  from multiprocessing.managers import ValueProxy
8
8
  from typing import Any, Callable, Dict, List, Tuple, Union
9
9
 
10
10
  import numpy as np
11
+ from scipy.sparse import csr_matrix
11
12
  from threadpoolctl import threadpool_limits
12
13
  from tqdm import tqdm
13
14
 
@@ -15,8 +16,8 @@ from risk.stats.permutation.test_functions import DISPATCH_TEST_FUNCTIONS
15
16
 
16
17
 
17
18
  def compute_permutation_test(
18
- neighborhoods: np.ndarray,
19
- annotations: np.ndarray,
19
+ neighborhoods: csr_matrix,
20
+ annotations: csr_matrix,
20
21
  score_metric: str = "sum",
21
22
  null_distribution: str = "network",
22
23
  num_permutations: int = 1000,
@@ -26,9 +27,9 @@ def compute_permutation_test(
26
27
  """Compute permutation test for enrichment and depletion in neighborhoods.
27
28
 
28
29
  Args:
29
- neighborhoods (np.ndarray): Binary matrix representing neighborhoods.
30
- annotations (np.ndarray): Binary matrix representing annotations.
31
- score_metric (str, optional): Metric to use for scoring ('sum', 'mean', etc.). Defaults to "sum".
30
+ neighborhoods (csr_matrix): Sparse binary matrix representing neighborhoods.
31
+ annotations (csr_matrix): Sparse binary matrix representing annotations.
32
+ score_metric (str, optional): Metric to use for scoring ('sum' or 'stdev'). Defaults to "sum".
32
33
  null_distribution (str, optional): Type of null distribution ('network' or 'annotations'). Defaults to "network".
33
34
  num_permutations (int, optional): Number of permutations to run. Defaults to 1000.
34
35
  random_seed (int, optional): Seed for random number generation. Defaults to 888.
@@ -66,19 +67,19 @@ def compute_permutation_test(
66
67
 
67
68
 
68
69
  def _run_permutation_test(
69
- neighborhoods: np.ndarray,
70
- annotations: np.ndarray,
70
+ neighborhoods: csr_matrix,
71
+ annotations: csr_matrix,
71
72
  neighborhood_score_func: Callable,
72
73
  null_distribution: str = "network",
73
74
  num_permutations: int = 1000,
74
75
  random_seed: int = 888,
75
76
  max_workers: int = 4,
76
77
  ) -> tuple:
77
- """Run a permutation test to calculate enrichment and depletion counts.
78
+ """Run the permutation test to calculate depletion and enrichment counts.
78
79
 
79
80
  Args:
80
- neighborhoods (np.ndarray): The neighborhood matrix.
81
- annotations (np.ndarray): The annotation matrix.
81
+ neighborhoods (csr_matrix): Sparse binary matrix representing neighborhoods.
82
+ annotations (csr_matrix): Sparse binary matrix representing annotations.
82
83
  neighborhood_score_func (Callable): Function to calculate neighborhood scores.
83
84
  null_distribution (str, optional): Type of null distribution ('network' or 'annotations'). Defaults to "network".
84
85
  num_permutations (int, optional): Number of permutations. Defaults to 1000.
@@ -100,8 +101,8 @@ def _run_permutation_test(
100
101
  "Invalid null_distribution value. Choose either 'network' or 'annotations'."
101
102
  )
102
103
 
103
- # Replace NaNs with zeros in the annotations matrix
104
- annotations[np.isnan(annotations)] = 0
104
+ # Replace NaNs with zeros in the sparse annotations matrix
105
+ annotations.data[np.isnan(annotations.data)] = 0
105
106
  annotation_matrix_obsv = annotations[idxs]
106
107
  neighborhoods_matrix_obsv = neighborhoods.T[idxs].T
107
108
  # Calculate observed neighborhood scores
@@ -131,45 +132,33 @@ def _run_permutation_test(
131
132
  permutations[i * batch_size : (i + 1) * batch_size] for i in range(max_workers)
132
133
  ]
133
134
 
134
- # Create shared memory for annotations
135
- shm_annotations = shared_memory.SharedMemory(create=True, size=annotations.nbytes)
136
- shared_annotations = np.ndarray(
137
- annotations.shape, dtype=annotations.dtype, buffer=shm_annotations.buf
138
- )
139
- np.copyto(shared_annotations, annotations)
140
-
141
135
  # Execute the permutation test using multiprocessing
142
- try:
143
- with ctx.Pool(max_workers) as pool:
144
- with tqdm(total=total_progress, desc="Total progress", position=0) as progress:
145
- # Prepare parameters for multiprocessing
146
- params_list = [
147
- (
148
- permutation_batches[i], # Pass the batch of precomputed permutations
149
- annotations,
150
- neighborhoods_matrix_obsv,
151
- observed_neighborhood_scores,
152
- neighborhood_score_func,
153
- num_permutations,
154
- progress_counter,
155
- max_workers,
156
- )
157
- for i in range(max_workers)
158
- ]
159
-
160
- # Start the permutation process in parallel
161
- results = pool.starmap_async(_permutation_process_batch, params_list, chunksize=1)
162
-
163
- # Update progress bar based on progress_counter
164
- while not results.ready():
165
- progress.update(progress_counter.value - progress.n)
166
- results.wait(0.1) # Wait for 100ms
167
- # Ensure progress bar reaches 100%
168
- progress.update(total_progress - progress.n)
169
- finally:
170
- # Clean up shared memory
171
- shm_annotations.close()
172
- shm_annotations.unlink()
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
139
+ params_list = [
140
+ (
141
+ permutation_batches[i], # Pass the batch of precomputed permutations
142
+ annotations,
143
+ neighborhoods_matrix_obsv,
144
+ observed_neighborhood_scores,
145
+ neighborhood_score_func,
146
+ num_permutations,
147
+ progress_counter,
148
+ max_workers,
149
+ )
150
+ for i in range(max_workers)
151
+ ]
152
+
153
+ # Start the permutation process in parallel
154
+ results = pool.starmap_async(_permutation_process_batch, params_list, chunksize=1)
155
+
156
+ # Update progress bar based on progress_counter
157
+ while not results.ready():
158
+ progress.update(progress_counter.value - progress.n)
159
+ results.wait(0.1) # Wait for 100ms
160
+ # Ensure progress bar reaches 100%
161
+ progress.update(total_progress - progress.n)
173
162
 
174
163
  # Accumulate results from each worker
175
164
  for local_counts_depletion, local_counts_enrichment in results.get():
@@ -181,8 +170,8 @@ def _run_permutation_test(
181
170
 
182
171
  def _permutation_process_batch(
183
172
  permutations: Union[List, Tuple, np.ndarray],
184
- annotation_matrix: np.ndarray,
185
- neighborhoods_matrix_obsv: np.ndarray,
173
+ annotation_matrix: csr_matrix,
174
+ neighborhoods_matrix_obsv: csr_matrix,
186
175
  observed_neighborhood_scores: np.ndarray,
187
176
  neighborhood_score_func: Callable,
188
177
  num_permutations: int,
@@ -193,8 +182,8 @@ def _permutation_process_batch(
193
182
 
194
183
  Args:
195
184
  permutations (Union[List, Tuple, np.ndarray]): Permutation batch to process.
196
- annotation_matrix (np.ndarray): The annotation matrix.
197
- neighborhoods_matrix_obsv (np.ndarray): Observed neighborhoods matrix.
185
+ annotation_matrix (csr_matrix): Sparse binary matrix representing annotations.
186
+ neighborhoods_matrix_obsv (csr_matrix): Sparse binary matrix representing observed neighborhoods.
198
187
  observed_neighborhood_scores (np.ndarray): Observed neighborhood scores.
199
188
  neighborhood_score_func (Callable): Function to calculate neighborhood scores.
200
189
  num_permutations (int): Number of total permutations across all subsets.
@@ -4,6 +4,7 @@ risk/stats/permutation/test_functions
4
4
  """
5
5
 
6
6
  import numpy as np
7
+ from scipy.sparse import csr_matrix
7
8
 
8
9
  # Note: Cython optimizations provided minimal performance benefits.
9
10
  # The final version with Cython is archived in the `cython_permutation` branch.
@@ -11,46 +12,53 @@ import numpy as np
11
12
 
12
13
 
13
14
  def compute_neighborhood_score_by_sum(
14
- neighborhoods_matrix: np.ndarray, annotation_matrix: np.ndarray
15
+ neighborhoods_matrix: csr_matrix, annotation_matrix: csr_matrix
15
16
  ) -> np.ndarray:
16
- """Compute the sum of attribute values for each neighborhood.
17
+ """Compute the sum of attribute values for each neighborhood using sparse matrices.
17
18
 
18
19
  Args:
19
- neighborhoods_matrix (np.ndarray): Binary matrix representing neighborhoods.
20
- annotation_matrix (np.ndarray): Matrix representing annotation values.
20
+ neighborhoods_matrix (csr_matrix): Sparse binary matrix representing neighborhoods.
21
+ annotation_matrix (csr_matrix): Sparse matrix representing annotation values.
21
22
 
22
23
  Returns:
23
- np.ndarray: Sum of attribute values for each neighborhood.
24
+ np.ndarray: Dense array of summed attribute values for each neighborhood.
24
25
  """
25
26
  # Calculate the neighborhood score as the dot product of neighborhoods and annotations
26
- neighborhood_sum = np.dot(neighborhoods_matrix, annotation_matrix)
27
- return neighborhood_sum
27
+ neighborhood_score = neighborhoods_matrix @ annotation_matrix # Sparse matrix multiplication
28
+ # Convert the result to a dense array for downstream calculations
29
+ neighborhood_score_dense = neighborhood_score.toarray()
30
+ return neighborhood_score_dense
28
31
 
29
32
 
30
33
  def compute_neighborhood_score_by_stdev(
31
- neighborhoods_matrix: np.ndarray, annotation_matrix: np.ndarray
34
+ neighborhoods_matrix: csr_matrix, annotation_matrix: csr_matrix
32
35
  ) -> np.ndarray:
33
- """Compute the standard deviation of neighborhood scores.
36
+ """Compute the standard deviation of neighborhood scores for sparse matrices.
34
37
 
35
38
  Args:
36
- neighborhoods_matrix (np.ndarray): Binary matrix representing neighborhoods.
37
- annotation_matrix (np.ndarray): Matrix representing annotation values.
39
+ neighborhoods_matrix (csr_matrix): Sparse binary matrix representing neighborhoods.
40
+ annotation_matrix (csr_matrix): Sparse matrix representing annotation values.
38
41
 
39
42
  Returns:
40
43
  np.ndarray: Standard deviation of the neighborhood scores.
41
44
  """
42
45
  # Calculate the neighborhood score as the dot product of neighborhoods and annotations
43
- neighborhood_score = np.dot(neighborhoods_matrix, annotation_matrix)
44
- # Calculate the number of elements in each neighborhood
45
- N = np.sum(neighborhoods_matrix, axis=1)
46
+ neighborhood_score = neighborhoods_matrix @ annotation_matrix # Sparse matrix multiplication
47
+ # Calculate the number of elements in each neighborhood (sum of rows)
48
+ N = neighborhoods_matrix.sum(axis=1).A.flatten() # Convert to 1D array
49
+ # Avoid division by zero by replacing zeros in N with np.nan temporarily
50
+ N[N == 0] = np.nan
46
51
  # Compute the mean of the neighborhood scores
47
- M = neighborhood_score / N[:, None]
52
+ M = neighborhood_score.multiply(1 / N[:, None]).toarray() # Sparse element-wise division
48
53
  # Compute the mean of squares (EXX) directly using squared annotation matrix
49
- EXX = np.dot(neighborhoods_matrix, annotation_matrix**2) / N[:, None]
54
+ annotation_squared = annotation_matrix.multiply(annotation_matrix) # Element-wise squaring
55
+ EXX = (neighborhoods_matrix @ annotation_squared).multiply(1 / N[:, None]).toarray()
50
56
  # Calculate variance as EXX - M^2
51
- variance = EXX - M**2
57
+ variance = EXX - np.power(M, 2)
52
58
  # Compute the standard deviation as the square root of the variance
53
59
  neighborhood_stdev = np.sqrt(variance)
60
+ # Replace np.nan back with zeros in case N was 0 (no elements in the neighborhood)
61
+ neighborhood_stdev[np.isnan(neighborhood_stdev)] = 0
54
62
  return neighborhood_stdev
55
63
 
56
64
 
risk/stats/poisson.py CHANGED
@@ -6,39 +6,45 @@ risk/stats/poisson
6
6
  from typing import Any, Dict
7
7
 
8
8
  import numpy as np
9
+ from scipy.sparse import csr_matrix
9
10
  from scipy.stats import poisson
10
11
 
11
12
 
12
13
  def compute_poisson_test(
13
- neighborhoods: np.ndarray, annotations: np.ndarray, null_distribution: str = "network"
14
+ neighborhoods: csr_matrix,
15
+ annotations: csr_matrix,
16
+ null_distribution: str = "network",
14
17
  ) -> Dict[str, Any]:
15
- """Compute Poisson test for enrichment and depletion in neighborhoods with selectable null distribution.
18
+ """
19
+ Compute Poisson test for enrichment and depletion in neighborhoods with selectable null distribution.
16
20
 
17
21
  Args:
18
- neighborhoods (np.ndarray): Binary matrix representing neighborhoods.
19
- annotations (np.ndarray): Binary matrix representing annotations.
22
+ neighborhoods (csr_matrix): Sparse binary matrix representing neighborhoods.
23
+ annotations (csr_matrix): Sparse binary matrix representing annotations.
20
24
  null_distribution (str, optional): Type of null distribution ('network' or 'annotations'). Defaults to "network".
21
25
 
22
26
  Returns:
23
27
  Dict[str, Any]: Dictionary containing depletion and enrichment p-values.
24
28
  """
25
29
  # Matrix multiplication to get the number of annotated nodes in each neighborhood
26
- annotated_in_neighborhood = neighborhoods @ annotations
30
+ annotated_in_neighborhood = neighborhoods @ annotations # Sparse result
31
+ # Convert annotated counts to dense for downstream calculations
32
+ annotated_in_neighborhood_dense = annotated_in_neighborhood.toarray()
27
33
 
28
34
  # Compute lambda_expected based on the chosen null distribution
29
35
  if null_distribution == "network":
30
36
  # Use the mean across neighborhoods (axis=1)
31
- lambda_expected = np.mean(annotated_in_neighborhood, axis=1, keepdims=True)
37
+ lambda_expected = np.mean(annotated_in_neighborhood_dense, axis=1, keepdims=True)
32
38
  elif null_distribution == "annotations":
33
39
  # Use the mean across annotations (axis=0)
34
- lambda_expected = np.mean(annotated_in_neighborhood, axis=0, keepdims=True)
40
+ lambda_expected = np.mean(annotated_in_neighborhood_dense, axis=0, keepdims=True)
35
41
  else:
36
42
  raise ValueError(
37
43
  "Invalid null_distribution value. Choose either 'network' or 'annotations'."
38
44
  )
39
45
 
40
46
  # Compute p-values for enrichment and depletion using Poisson distribution
41
- enrichment_pvals = 1 - poisson.cdf(annotated_in_neighborhood - 1, lambda_expected)
42
- depletion_pvals = poisson.cdf(annotated_in_neighborhood, lambda_expected)
47
+ enrichment_pvals = 1 - poisson.cdf(annotated_in_neighborhood_dense - 1, lambda_expected)
48
+ depletion_pvals = poisson.cdf(annotated_in_neighborhood_dense, lambda_expected)
43
49
 
44
50
  return {"enrichment_pvals": enrichment_pvals, "depletion_pvals": depletion_pvals}
risk/stats/zscore.py ADDED
@@ -0,0 +1,68 @@
1
+ """
2
+ risk/stats/zscore
3
+ ~~~~~~~~~~~~~~~~~~
4
+ """
5
+
6
+ from typing import Any, Dict
7
+
8
+ import numpy as np
9
+ from scipy.sparse import csr_matrix
10
+ from scipy.stats import norm
11
+
12
+
13
+ def compute_zscore_test(
14
+ neighborhoods: csr_matrix,
15
+ annotations: csr_matrix,
16
+ null_distribution: str = "network",
17
+ ) -> Dict[str, Any]:
18
+ """
19
+ Compute Z-score test for enrichment and depletion in neighborhoods with selectable null distribution.
20
+
21
+ Args:
22
+ neighborhoods (csr_matrix): Sparse binary matrix representing neighborhoods.
23
+ annotations (csr_matrix): Sparse binary matrix representing annotations.
24
+ null_distribution (str, optional): Type of null distribution ('network' or 'annotations'). Defaults to "network".
25
+
26
+ Returns:
27
+ Dict[str, Any]: Dictionary containing depletion and enrichment p-values.
28
+ """
29
+ # Total number of nodes in the network
30
+ total_node_count = neighborhoods.shape[1]
31
+
32
+ # Compute sums
33
+ if null_distribution == "network":
34
+ background_population = total_node_count
35
+ neighborhood_sums = neighborhoods.sum(axis=0).A.flatten() # Dense column sums
36
+ annotation_sums = annotations.sum(axis=0).A.flatten() # Dense row sums
37
+ elif null_distribution == "annotations":
38
+ annotated_nodes = annotations.sum(axis=1).A.flatten() > 0 # Dense boolean mask
39
+ background_population = annotated_nodes.sum()
40
+ neighborhood_sums = neighborhoods[annotated_nodes].sum(axis=0).A.flatten()
41
+ annotation_sums = annotations[annotated_nodes].sum(axis=0).A.flatten()
42
+ else:
43
+ raise ValueError(
44
+ "Invalid null_distribution value. Choose either 'network' or 'annotations'."
45
+ )
46
+
47
+ # Observed values
48
+ observed = (neighborhoods.T @ annotations).toarray() # Convert sparse result to dense
49
+ # Expected values under the null
50
+ neighborhood_sums = neighborhood_sums.reshape(-1, 1) # Ensure correct shape
51
+ annotation_sums = annotation_sums.reshape(1, -1) # Ensure correct shape
52
+ expected = (neighborhood_sums @ annotation_sums) / background_population
53
+
54
+ # Standard deviation under the null
55
+ std_dev = np.sqrt(
56
+ expected
57
+ * (1 - annotation_sums / background_population)
58
+ * (1 - neighborhood_sums / background_population)
59
+ )
60
+ std_dev[std_dev == 0] = np.nan # Avoid division by zero
61
+ # Compute Z-scores
62
+ z_scores = (observed - expected) / std_dev
63
+
64
+ # Convert Z-scores to depletion and enrichment p-values
65
+ enrichment_pvals = norm.sf(z_scores) # Upper tail
66
+ depletion_pvals = norm.cdf(z_scores) # Lower tail
67
+
68
+ return {"depletion_pvals": depletion_pvals, "enrichment_pvals": enrichment_pvals}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: risk-network
3
- Version: 0.0.9b23
3
+ Version: 0.0.9b25
4
4
  Summary: A Python package for biological network analysis
5
5
  Author: Ira Horecka
6
6
  Author-email: Ira Horecka <ira89@icloud.com>
@@ -0,0 +1,44 @@
1
+ risk/__init__.py,sha256=Rgsnt64VMhbyTleA_DXr5VcFJG6748i86zd0VZHy9r4,127
2
+ risk/constants.py,sha256=XInRaH78Slnw_sWgAsBFbUHkyA0h0jL0DKGuQNbOvjM,550
3
+ risk/risk.py,sha256=s827_lRknFseOP9O4zW8sP-IcCd2EzrpV_tnVY_tz5s,1104
4
+ risk/annotations/__init__.py,sha256=parsbcux1U4urpUqh9AdzbDWuLj9HlMidycMPkpSQFo,179
5
+ risk/annotations/annotations.py,sha256=XmVuLL5NFAj6F30fZY22N8nb4LK6sig7fE0NXL1iZp8,14497
6
+ risk/annotations/io.py,sha256=z1AJySsU-KL_IYuHa7j3nvuczmOHgK3WfaQ4TRunvrA,10499
7
+ risk/log/__init__.py,sha256=7LxDysQu7doi0LAvlY2YbjN6iJH0fNknqy8lSLgeljo,217
8
+ risk/log/console.py,sha256=PgjyEvyhYLUSHXPUKEqOmxsDsfrjPICIgqo_cAHq0N8,4575
9
+ risk/log/parameters.py,sha256=VtwfMzLU1xI4yji3-Ch5vHjH-KdwTfwaEMmi7hFQTs0,5716
10
+ risk/neighborhoods/__init__.py,sha256=Q74HwTH7okI-vaskJPy2bYwb5sNjGASTzJ6m8V8arCU,234
11
+ risk/neighborhoods/api.py,sha256=KdUouMHJPwvePJGdz7Ck1GWYhN96QDb_SuPyTt3KwAc,23515
12
+ risk/neighborhoods/community.py,sha256=VIDvB-SsMDDvWkUaYXf_E-gcg0HELMVv2MKshPwJAFQ,15480
13
+ risk/neighborhoods/domains.py,sha256=MufM4cbvP3HrJyESOuGT0wYD_cz3rjT0SGqEnbytkh8,12523
14
+ risk/neighborhoods/neighborhoods.py,sha256=bBUY7hXqcsOoAEkPdRoRNuj36WsllXicmz_LxZfEuyw,21186
15
+ risk/network/__init__.py,sha256=oVi3FA1XXKD84014Cykq-9bpX4_s0F3aAUfNOU-07Qw,73
16
+ risk/network/geometry.py,sha256=omyb9afSKMUtQ-RKVHUoRyxJifOW0ASenHjyCjg43kg,6836
17
+ risk/network/io.py,sha256=JV5hqf1oIwWUVw07BjhD0qACQGbtIeA8NSMDcFql88k,23465
18
+ risk/network/graph/__init__.py,sha256=ziGJew3yhtqvrb9LUuneDu_LwW2Wa9vd4UuhoL5l1CA,91
19
+ risk/network/graph/api.py,sha256=Ag4PjFTX6BUvmW7ZdfIgwdsr8URigX9jD9yEFRXUxrU,8220
20
+ risk/network/graph/network.py,sha256=KdIBM_-flHMWcBK4RUjU_QRfOZIf_yv9fv4L7AOLkqU,12199
21
+ risk/network/graph/summary.py,sha256=8IenFZfhyzcg5aGNJp7Zjb0Umy0mFNmJlfwXcO7y8MU,10311
22
+ risk/network/plotter/__init__.py,sha256=ixXQxpBVpNIz1y9tUHZ7CiJmGfewvbvjuB1LQ-AIf1s,93
23
+ risk/network/plotter/api.py,sha256=cLZHq-rn_5FJwIWM5hYlQMobPmaxCE-P2iqgxTDIOTQ,1860
24
+ risk/network/plotter/canvas.py,sha256=l-Se86DMDJMHh8Yn-_hsl0_ipoazHLJGRCqXcc9HK4M,13498
25
+ risk/network/plotter/contour.py,sha256=svi76suYlVYq2VoDQxXmun8Hmo0lI2CQRjAyHg0qdhk,15490
26
+ risk/network/plotter/labels.py,sha256=QesD1ybseA6ldLmWMqVaAqSPR34yVEgEzXzg1AKQD6o,45513
27
+ risk/network/plotter/network.py,sha256=wcBf1GaM1wPzW-iXTrLzOmlG2_9wwfll_hJUzUO2u2Y,19917
28
+ risk/network/plotter/utils/colors.py,sha256=EFlIUZ3MGSKoHeZi9cgR6uLKK5GGJ4QzE6lmnrHViLw,18967
29
+ risk/network/plotter/utils/layout.py,sha256=2P4Bqi1dGiX9KsriLYqiq1KlHpsMdZemAUza4WcYoNA,3634
30
+ risk/stats/__init__.py,sha256=1CPRtT1LDwudrvFgkVtSom8cp4cM7b4X6b4fHPaNHw0,405
31
+ risk/stats/binom.py,sha256=8Qwcxnq1u-AycwQs_sQxwuxgkgDpES-A-kIcj4fRc3g,2032
32
+ risk/stats/chi2.py,sha256=MGFNrWP40i9TxnMsZYbDgqdMrN_Fe0xFsnWU8xNsVSs,3046
33
+ risk/stats/hypergeom.py,sha256=VfQBtpgSGG826uBP1WyBMavP3ylZnhponUZ2rHFdGAE,2502
34
+ risk/stats/poisson.py,sha256=_KHe9g8XNRD4-Q486zx2UgHCO2QyvBOiHuX3hRZLEqc,2050
35
+ risk/stats/stats.py,sha256=y2DMJF3uKRIWRyYiCd2Kwxa-EqOzX5HsMBms_Vw6wK8,7322
36
+ risk/stats/zscore.py,sha256=Jx9cLKAHiDnrgW_Su9KZYYQiTVsuyJMC7vXBusnEI-c,2648
37
+ risk/stats/permutation/__init__.py,sha256=OLmYLm2uj96hPsSaUs0vUqFYw6Thwch_aHtpL7L0ZFw,127
38
+ risk/stats/permutation/permutation.py,sha256=693DyWPNz6L_wCL06F7gj2u1df0qVc4F3Na36jCLYMI,10577
39
+ risk/stats/permutation/test_functions.py,sha256=D3XMPM8CasUNytWSRce22TI6KK6XulYn5uGG4lWxaHs,3120
40
+ risk_network-0.0.9b25.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
41
+ risk_network-0.0.9b25.dist-info/METADATA,sha256=XJSNAooxsGNwoMnp-6Nx0YCnp1zBWVm9ej2yjtUUPDg,47627
42
+ risk_network-0.0.9b25.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
43
+ risk_network-0.0.9b25.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
44
+ risk_network-0.0.9b25.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- """
2
- risk/network/plot
3
- ~~~~~~~~~~~~~~~~~
4
- """
5
-
6
- from risk.network.plot.plotter import NetworkPlotter
@@ -1,143 +0,0 @@
1
- """
2
- risk/network/plot/plotter
3
- ~~~~~~~~~~~~~~~~~~~~~~~~~
4
- """
5
-
6
- from typing import List, Tuple, Union
7
-
8
- import matplotlib.pyplot as plt
9
- import numpy as np
10
-
11
- from risk.log import params
12
- from risk.network.graph import NetworkGraph
13
- from risk.network.plot.canvas import Canvas
14
- from risk.network.plot.contour import Contour
15
- from risk.network.plot.labels import Labels
16
- from risk.network.plot.network import Network
17
- from risk.network.plot.utils.colors import to_rgba
18
- from risk.network.plot.utils.layout import calculate_bounding_box
19
-
20
-
21
- class NetworkPlotter(Canvas, Network, Contour, Labels):
22
- """A class for visualizing network graphs with customizable options.
23
-
24
- The NetworkPlotter class uses a NetworkGraph object and provides methods to plot the network with
25
- flexible node and edge properties. It also supports plotting labels, contours, drawing the network's
26
- perimeter, and adjusting background colors.
27
- """
28
-
29
- def __init__(
30
- self,
31
- graph: NetworkGraph,
32
- figsize: Tuple = (10, 10),
33
- background_color: Union[str, List, Tuple, np.ndarray] = "white",
34
- background_alpha: Union[float, None] = 1.0,
35
- pad: float = 0.3,
36
- ) -> None:
37
- """Initialize the NetworkPlotter with a NetworkGraph object and plotting parameters.
38
-
39
- Args:
40
- graph (NetworkGraph): The network data and attributes to be visualized.
41
- figsize (Tuple, optional): Size of the figure in inches (width, height). Defaults to (10, 10).
42
- background_color (str, List, Tuple, np.ndarray, optional): Background color of the plot. Defaults to "white".
43
- background_alpha (float, None, optional): Transparency level of the background color. If provided, it overrides
44
- any existing alpha values found in background_color. Defaults to 1.0.
45
- pad (float, optional): Padding value to adjust the axis limits. Defaults to 0.3.
46
- """
47
- self.graph = graph
48
- # Initialize the plot with the specified parameters
49
- self.ax = self._initialize_plot(
50
- graph=graph,
51
- figsize=figsize,
52
- background_color=background_color,
53
- background_alpha=background_alpha,
54
- pad=pad,
55
- )
56
- super().__init__(graph=graph, ax=self.ax)
57
-
58
- def _initialize_plot(
59
- self,
60
- graph: NetworkGraph,
61
- figsize: Tuple,
62
- background_color: Union[str, List, Tuple, np.ndarray],
63
- background_alpha: Union[float, None],
64
- pad: float,
65
- ) -> plt.Axes:
66
- """Set up the plot with figure size and background color.
67
-
68
- Args:
69
- graph (NetworkGraph): The network data and attributes to be visualized.
70
- figsize (Tuple): Size of the figure in inches (width, height).
71
- background_color (str, List, Tuple, or np.ndarray): Background color of the plot. Can be a single color or an array of colors.
72
- background_alpha (float, None, optional): Transparency level of the background color. If provided, it overrides any existing
73
- alpha values found in `background_color`.
74
- pad (float, optional): Padding value to adjust the axis limits.
75
-
76
- Returns:
77
- plt.Axes: The axis object for the plot.
78
- """
79
- # Log the plotter settings
80
- params.log_plotter(
81
- figsize=figsize,
82
- background_color=background_color,
83
- background_alpha=background_alpha,
84
- pad=pad,
85
- )
86
-
87
- # Extract node coordinates from the network graph
88
- node_coordinates = graph.node_coordinates
89
- # Calculate the center and radius of the bounding box around the network
90
- center, radius = calculate_bounding_box(node_coordinates)
91
-
92
- # Create a new figure and axis for plotting
93
- fig, ax = plt.subplots(figsize=figsize)
94
- fig.tight_layout() # Adjust subplot parameters to give specified padding
95
- # Set axis limits based on the calculated bounding box and radius
96
- ax.set_xlim([center[0] - radius - pad, center[0] + radius + pad])
97
- ax.set_ylim([center[1] - radius - pad, center[1] + radius + pad])
98
- ax.set_aspect("equal") # Ensure the aspect ratio is equal
99
-
100
- # Set the background color of the plot
101
- # Convert color to RGBA using the to_rgba helper function
102
- fig.patch.set_facecolor(
103
- to_rgba(color=background_color, alpha=background_alpha, num_repeats=1)
104
- ) # num_repeats=1 for single color
105
- ax.invert_yaxis() # Invert the y-axis to match typical image coordinates
106
- # Remove axis spines for a cleaner look
107
- for spine in ax.spines.values():
108
- spine.set_visible(False)
109
-
110
- # Hide axis ticks and labels
111
- ax.set_xticks([])
112
- ax.set_yticks([])
113
- ax.patch.set_visible(False) # Hide the axis background
114
-
115
- return ax
116
-
117
- @staticmethod
118
- def savefig(*args, pad_inches: float = 0.5, dpi: int = 100, **kwargs) -> None:
119
- """Save the current plot to a file with additional export options.
120
-
121
- Args:
122
- *args: Positional arguments passed to `plt.savefig`.
123
- pad_inches (float, optional): Padding around the figure when saving. Defaults to 0.5.
124
- dpi (int, optional): Dots per inch (DPI) for the exported image. Defaults to 300.
125
- **kwargs: Keyword arguments passed to `plt.savefig`, such as filename and format.
126
- """
127
- # Ensure user-provided kwargs take precedence
128
- kwargs.setdefault("dpi", dpi)
129
- kwargs.setdefault("pad_inches", pad_inches)
130
- # Ensure the plot is saved with tight bounding box if not specified
131
- kwargs.setdefault("bbox_inches", "tight")
132
- # Call plt.savefig with combined arguments
133
- plt.savefig(*args, **kwargs)
134
-
135
- @staticmethod
136
- def show(*args, **kwargs) -> None:
137
- """Display the current plot.
138
-
139
- Args:
140
- *args: Positional arguments passed to `plt.show`.
141
- **kwargs: Keyword arguments passed to `plt.show`.
142
- """
143
- plt.show(*args, **kwargs)