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.
- risk/__init__.py +1 -1
- risk/annotations/__init__.py +2 -2
- risk/annotations/annotations.py +9 -9
- risk/annotations/io.py +0 -2
- risk/log/__init__.py +2 -2
- risk/neighborhoods/__init__.py +3 -5
- risk/neighborhoods/api.py +446 -0
- risk/neighborhoods/community.py +4 -2
- risk/neighborhoods/domains.py +28 -1
- risk/network/__init__.py +1 -3
- risk/network/graph/__init__.py +1 -1
- risk/network/graph/api.py +194 -0
- risk/network/graph/summary.py +6 -2
- risk/network/io.py +0 -2
- risk/network/plotter/__init__.py +6 -0
- risk/network/plotter/api.py +54 -0
- risk/network/{plot → plotter}/canvas.py +3 -3
- risk/network/{plot → plotter}/contour.py +2 -2
- risk/network/{plot → plotter}/labels.py +3 -3
- risk/network/{plot → plotter}/network.py +136 -3
- risk/network/{plot → plotter}/utils/colors.py +15 -6
- risk/risk.py +10 -483
- risk/stats/__init__.py +8 -4
- risk/stats/binom.py +51 -0
- risk/stats/chi2.py +69 -0
- risk/stats/hypergeom.py +27 -17
- risk/stats/permutation/__init__.py +1 -1
- risk/stats/permutation/permutation.py +44 -55
- risk/stats/permutation/test_functions.py +25 -17
- risk/stats/poisson.py +15 -9
- risk/stats/zscore.py +68 -0
- {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/METADATA +1 -1
- risk_network-0.0.9b25.dist-info/RECORD +44 -0
- risk/network/plot/__init__.py +0 -6
- risk/network/plot/plotter.py +0 -143
- risk_network-0.0.9b23.dist-info/RECORD +0 -39
- /risk/network/{plot → plotter}/utils/layout.py +0 -0
- {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/LICENSE +0 -0
- {risk_network-0.0.9b23.dist-info → risk_network-0.0.9b25.dist-info}/WHEEL +0 -0
- {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:
|
14
|
+
neighborhoods: csr_matrix,
|
15
|
+
annotations: csr_matrix,
|
16
|
+
null_distribution: str = "network",
|
14
17
|
) -> Dict[str, Any]:
|
15
|
-
"""
|
18
|
+
"""
|
19
|
+
Compute hypergeometric test for enrichment and depletion in neighborhoods with selectable null distribution.
|
16
20
|
|
17
21
|
Args:
|
18
|
-
neighborhoods (
|
19
|
-
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
|
-
|
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
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
#
|
45
|
-
annotated_in_neighborhood = neighborhoods.T @ annotations
|
46
|
-
|
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,11 +3,12 @@ risk/stats/permutation/permutation
|
|
3
3
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
4
4
|
"""
|
5
5
|
|
6
|
-
from multiprocessing import get_context,
|
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:
|
19
|
-
annotations:
|
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 (
|
30
|
-
annotations (
|
31
|
-
score_metric (str, optional): Metric to use for scoring ('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:
|
70
|
-
annotations:
|
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
|
78
|
+
"""Run the permutation test to calculate depletion and enrichment counts.
|
78
79
|
|
79
80
|
Args:
|
80
|
-
neighborhoods (
|
81
|
-
annotations (
|
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
|
-
|
143
|
-
with
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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:
|
185
|
-
neighborhoods_matrix_obsv:
|
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 (
|
197
|
-
neighborhoods_matrix_obsv (
|
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:
|
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 (
|
20
|
-
annotation_matrix (
|
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:
|
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
|
-
|
27
|
-
|
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:
|
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 (
|
37
|
-
annotation_matrix (
|
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 =
|
44
|
-
# Calculate the number of elements in each neighborhood
|
45
|
-
N =
|
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
|
-
|
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
|
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:
|
14
|
+
neighborhoods: csr_matrix,
|
15
|
+
annotations: csr_matrix,
|
16
|
+
null_distribution: str = "network",
|
14
17
|
) -> Dict[str, Any]:
|
15
|
-
"""
|
18
|
+
"""
|
19
|
+
Compute Poisson test for enrichment and depletion in neighborhoods with selectable null distribution.
|
16
20
|
|
17
21
|
Args:
|
18
|
-
neighborhoods (
|
19
|
-
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(
|
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(
|
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(
|
42
|
-
depletion_pvals = poisson.cdf(
|
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}
|
@@ -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,,
|
risk/network/plot/__init__.py
DELETED
risk/network/plot/plotter.py
DELETED
@@ -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)
|