pyCoReGraph 0.0.1a1__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.
- coregraph/__init__.py +57 -0
- coregraph/analysis/__init__.py +45 -0
- coregraph/analysis/bins.py +23 -0
- coregraph/analysis/correlations.py +110 -0
- coregraph/analysis/fdr.py +100 -0
- coregraph/analysis/queries.py +118 -0
- coregraph/analysis/subset.py +64 -0
- coregraph/graphics/__init__.py +33 -0
- coregraph/graphics/animations.py +56 -0
- coregraph/graphics/colors.py +9 -0
- coregraph/graphics/network.py +214 -0
- coregraph/graphics/plots.py +85 -0
- coregraph/models/__init__.py +11 -0
- coregraph/models/coregraph.py +221 -0
- coregraph/models/cors.py +63 -0
- coregraph/models/graphics.py +38 -0
- coregraph/models/stargraph.py +41 -0
- coregraph/utils/__init__.py +23 -0
- coregraph/utils/decorators.py +39 -0
- coregraph/utils/formatting.py +16 -0
- coregraph/utils/validation.py +25 -0
- pycoregraph-0.0.1a1.dist-info/METADATA +65 -0
- pycoregraph-0.0.1a1.dist-info/RECORD +26 -0
- pycoregraph-0.0.1a1.dist-info/WHEEL +5 -0
- pycoregraph-0.0.1a1.dist-info/licenses/LICENSE +21 -0
- pycoregraph-0.0.1a1.dist-info/top_level.txt +1 -0
coregraph/__init__.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
__version__ = "0.0.1a1"
|
|
2
|
+
|
|
3
|
+
# Models
|
|
4
|
+
from coregraph.models import (
|
|
5
|
+
CoReGraph_Cors,
|
|
6
|
+
CoReGraph_Graphics,
|
|
7
|
+
CoReGraph,
|
|
8
|
+
StarGraph,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# Analysis
|
|
12
|
+
from coregraph.analysis.queries import (
|
|
13
|
+
get_correlation,
|
|
14
|
+
get_all_correlations,
|
|
15
|
+
get_mac,
|
|
16
|
+
get_mac_results,
|
|
17
|
+
get_regulated_genes,
|
|
18
|
+
get_regulator_genes,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Graphics
|
|
22
|
+
from coregraph.graphics.plots import (
|
|
23
|
+
plot_expression,
|
|
24
|
+
plot_correlations,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from coregraph.graphics.animations import (
|
|
28
|
+
animate_correlations,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from coregraph.graphics.network import (
|
|
32
|
+
animate_network,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
from coregraph.analysis.subset import (
|
|
36
|
+
starry,
|
|
37
|
+
subset_coregraph,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"CoReGraph",
|
|
42
|
+
"CoReGraph_Cors",
|
|
43
|
+
"CoReGraph_Graphics",
|
|
44
|
+
"StarGraph",
|
|
45
|
+
"get_correlation",
|
|
46
|
+
"get_all_correlations",
|
|
47
|
+
"get_mac",
|
|
48
|
+
"get_mac_results",
|
|
49
|
+
"get_regulated_genes",
|
|
50
|
+
"get_regulator_genes",
|
|
51
|
+
"plot_expression",
|
|
52
|
+
"plot_correlations",
|
|
53
|
+
"animate_correlations",
|
|
54
|
+
"animate_network",
|
|
55
|
+
"starry",
|
|
56
|
+
"subset_coregraph"
|
|
57
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from .correlations import (
|
|
2
|
+
_calculate_all_cors,
|
|
3
|
+
_calculate_LEAP_cors,
|
|
4
|
+
_calculate_star_cors,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
from .bins import (
|
|
8
|
+
_calculate_bins,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from .fdr import (
|
|
12
|
+
_calculate_FDR,
|
|
13
|
+
_calculate_star_FDR
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .queries import (
|
|
17
|
+
get_correlation,
|
|
18
|
+
get_all_correlations,
|
|
19
|
+
get_mac,
|
|
20
|
+
get_mac_results,
|
|
21
|
+
get_regulated_genes,
|
|
22
|
+
get_regulator_genes,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Correlations
|
|
27
|
+
"_calculate_all_cors",
|
|
28
|
+
"_calculate_LEAP_cors",
|
|
29
|
+
"_calculate_star_cors",
|
|
30
|
+
|
|
31
|
+
# FDR
|
|
32
|
+
"_calculate_FDR",
|
|
33
|
+
"_calculate_star_FDR",
|
|
34
|
+
|
|
35
|
+
# Bins
|
|
36
|
+
"_calculate_bins",
|
|
37
|
+
|
|
38
|
+
# Queries
|
|
39
|
+
"get_correlation",
|
|
40
|
+
"get_all_correlations",
|
|
41
|
+
"get_mac",
|
|
42
|
+
"get_mac_results",
|
|
43
|
+
"get_regulated_genes",
|
|
44
|
+
"get_regulator_genes",
|
|
45
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## BINS ##
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _calculate_bins(data, pseudotime, n_bins):
|
|
7
|
+
'''Discretize pseudotime expression in bins'''
|
|
8
|
+
|
|
9
|
+
bin_range = (pseudotime.max() - pseudotime.min())/n_bins
|
|
10
|
+
bin_seq = pseudotime.min() + np.arange(1,n_bins)*bin_range
|
|
11
|
+
bins = (np.digitize(pseudotime, bin_seq)*bin_range)+(bin_range/2)
|
|
12
|
+
|
|
13
|
+
mean_res = np.empty((data.shape[0], n_bins), dtype=np.float64)
|
|
14
|
+
std_res = np.empty((data.shape[0], n_bins), dtype=np.float64)
|
|
15
|
+
for i, b in enumerate(np.unique(bins)):
|
|
16
|
+
mean_res[:,i] = np.mean(data[:,bins==b], axis=1)
|
|
17
|
+
std_res[:,i] = np.mean(data[:,bins==b], axis=1)
|
|
18
|
+
|
|
19
|
+
mean = mean_res
|
|
20
|
+
std = std_res
|
|
21
|
+
scaled = mean/np.max(mean, axis=1)[:, None]
|
|
22
|
+
|
|
23
|
+
return bins, mean, std, scaled
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
## CORRELATIONS ##
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _calculate_all_cors(data, window, i, tensor, reflag, MAC, LAG_id, LAG, LAG_means, dim3_start, step=1, num_format=np.array([1,15]), dtype=np.float64):
|
|
7
|
+
'''Calculate all lagged correlations for a unique given reference i'''
|
|
8
|
+
dim3 = dim3_start
|
|
9
|
+
n_genes, n_cells = data.shape
|
|
10
|
+
|
|
11
|
+
data_ref = data[:,i:window+i]
|
|
12
|
+
mean_ref = np.mean(data_ref, axis=1)
|
|
13
|
+
cent_ref = data_ref.T - mean_ref
|
|
14
|
+
rowsumx_ref = np.sum(cent_ref, axis=0).reshape(1, -1)
|
|
15
|
+
rowsumx2_ref = np.sum(np.square(cent_ref), axis=0).reshape(1, -1)
|
|
16
|
+
|
|
17
|
+
for j in range(i, n_cells-window+1, step):
|
|
18
|
+
data_lag = data[:,j:window+j]
|
|
19
|
+
mean_lag = np.mean(data_lag, axis=1)
|
|
20
|
+
cent_lag = data_lag.T - mean_lag
|
|
21
|
+
rowsumx_lag = np.sum(cent_lag, axis=0).reshape(1, -1)
|
|
22
|
+
rowsumx2_lag = np.sum(np.square(cent_lag), axis=0).reshape(1, -1)
|
|
23
|
+
|
|
24
|
+
Cor = (np.dot(cent_ref.T, cent_lag) - (1 / window) * np.dot(rowsumx_ref.T, rowsumx_lag)) / \
|
|
25
|
+
np.dot(np.sqrt(rowsumx2_ref - rowsumx_ref**2 / window).T, np.sqrt(rowsumx2_lag - rowsumx_lag**2 / window))
|
|
26
|
+
|
|
27
|
+
np.fill_diagonal(Cor, 1)
|
|
28
|
+
Cor = np.round(np.nan_to_num(Cor, nan=0)*num_format[0], num_format[1])
|
|
29
|
+
Cor = Cor.astype(dtype)
|
|
30
|
+
tensor[:,:,dim3] = Cor
|
|
31
|
+
LAG_means[dim3] = mean_lag
|
|
32
|
+
reflag[dim3,0] = i
|
|
33
|
+
reflag[dim3,1] = j
|
|
34
|
+
|
|
35
|
+
# Update MAC
|
|
36
|
+
ind = np.abs(MAC) < np.abs(Cor)
|
|
37
|
+
MAC[ind] = Cor[ind]
|
|
38
|
+
LAG[ind] = j-i
|
|
39
|
+
LAG_id[0][ind] = i
|
|
40
|
+
LAG_id[1][ind] = j
|
|
41
|
+
#
|
|
42
|
+
dim3 += 1
|
|
43
|
+
|
|
44
|
+
return dim3, MAC, LAG_id, LAG, LAG_means
|
|
45
|
+
|
|
46
|
+
def _calculate_LEAP_cors(data, window, i=0, step=1, num_format=np.array([1,15]), dtype=np.float64):
|
|
47
|
+
'''Calculate all lagged correlations for a unique given reference i using LEAP traditional algorithm'''
|
|
48
|
+
n_genes, n_cells = data.shape
|
|
49
|
+
MAC = np.zeros((n_genes, n_genes))
|
|
50
|
+
LAG = np.zeros((n_genes, n_genes))
|
|
51
|
+
|
|
52
|
+
data_ref = data[:,i:window+i]
|
|
53
|
+
mean_ref = np.mean(data_ref, axis=1)
|
|
54
|
+
cent_ref = data_ref.T - mean_ref
|
|
55
|
+
rowsumx_ref = np.sum(cent_ref, axis=0).reshape(1, -1)
|
|
56
|
+
rowsumx2_ref = np.sum(np.square(cent_ref), axis=0).reshape(1, -1)
|
|
57
|
+
|
|
58
|
+
for j in range(i, n_cells - window, step):
|
|
59
|
+
data_lag = data[:,j:window+j]
|
|
60
|
+
mean_lag = np.mean(data_lag, axis=1)
|
|
61
|
+
cent_lag = data_lag.T - mean_lag
|
|
62
|
+
rowsumx_lag = np.sum(cent_lag, axis=0).reshape(1, -1)
|
|
63
|
+
rowsumx2_lag = np.sum(np.square(cent_lag), axis=0).reshape(1, -1)
|
|
64
|
+
|
|
65
|
+
Cor = np.dot(cent_ref.T, cent_lag) - (1 / window) * np.dot(rowsumx_ref.T, rowsumx_lag) / \
|
|
66
|
+
np.dot(np.sqrt(rowsumx2_ref - rowsumx_ref**2 / window).T, np.sqrt(rowsumx2_lag - rowsumx_lag**2 / window))
|
|
67
|
+
|
|
68
|
+
np.fill_diagonal(Cor, 1)
|
|
69
|
+
Cor = np.round(np.nan_to_num(Cor, nan=0)*num_format[0], num_format[1])
|
|
70
|
+
Cor = Cor.astype(dtype)
|
|
71
|
+
# Update MAC
|
|
72
|
+
ind = np.where(np.abs(MAC) > np.abs(Cor))
|
|
73
|
+
LAG[ind] = j - i
|
|
74
|
+
MAC[ind] = Cor[ind]
|
|
75
|
+
|
|
76
|
+
return MAC, LAG
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _calculate_star_cors(data, target_row, MAC, window, i, step=1, num_format=np.array([1,15]), dtype=np.float64):
|
|
80
|
+
'''Calculate all lagged correlations for a unique given reference i using a single reference row against all rows.'''
|
|
81
|
+
|
|
82
|
+
n_genes, n_cells = data.shape
|
|
83
|
+
|
|
84
|
+
# Take reference row only
|
|
85
|
+
data_ref = data[target_row, i:window+i]
|
|
86
|
+
mean_ref = np.mean(data_ref)
|
|
87
|
+
cent_ref = data_ref - mean_ref
|
|
88
|
+
|
|
89
|
+
sum_ref = np.sum(cent_ref)
|
|
90
|
+
sum_ref2 = np.sum(np.square(cent_ref), axis=0)
|
|
91
|
+
|
|
92
|
+
for j in range(i, n_cells - window, step):
|
|
93
|
+
data_lag = data[:, j:window+j]
|
|
94
|
+
mean_lag = np.mean(data_lag, axis=1)
|
|
95
|
+
cent_lag = data_lag - mean_lag[:, None]
|
|
96
|
+
|
|
97
|
+
rowsumx_lag = np.sum(cent_lag, axis=1)
|
|
98
|
+
rowsumx2_lag = np.sum(cent_lag * cent_lag, axis=1)
|
|
99
|
+
cross = np.dot(cent_lag, cent_ref)
|
|
100
|
+
|
|
101
|
+
Cor = (cross - (rowsumx_lag * sum_ref) / window) / \
|
|
102
|
+
(np.sqrt(rowsumx2_lag - (rowsumx_lag * rowsumx_lag) / window) * np.sqrt(sum_ref2 - (sum_ref * sum_ref) / window))
|
|
103
|
+
|
|
104
|
+
Cor = np.round(np.nan_to_num(Cor, nan=0)*num_format[0], num_format[1])
|
|
105
|
+
Cor = Cor.astype(dtype)
|
|
106
|
+
|
|
107
|
+
ind = np.where(np.abs(MAC) < np.abs(Cor))
|
|
108
|
+
MAC[ind] = Cor[ind]
|
|
109
|
+
|
|
110
|
+
return MAC
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
## FDR ##
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from coregraph.analysis.correlations import (_calculate_LEAP_cors, _calculate_star_cors)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _calculate_FDR(data, MAC, window, n_perms = 100, FDR_cutoffs = 101, step=1, num_format=np.array([1,15]), dtype=np.float64):
|
|
9
|
+
'''Calculate False Discovery Rate by permutations'''
|
|
10
|
+
|
|
11
|
+
MAC_true = np.absolute(MAC.copy())
|
|
12
|
+
samp_size = np.minimum(100, data.shape[0])
|
|
13
|
+
MACs_perm = np.zeros((n_perms, samp_size, samp_size))
|
|
14
|
+
np.fill_diagonal(MAC_true, -1)
|
|
15
|
+
|
|
16
|
+
# simplified MAC_counter function
|
|
17
|
+
for n in range(0, n_perms):
|
|
18
|
+
np.random.seed(n)
|
|
19
|
+
data_perm = data[0:samp_size,:].copy()
|
|
20
|
+
inds = np.random.choice(data.shape[0], size=samp_size, replace=False)
|
|
21
|
+
|
|
22
|
+
for z in range(0, samp_size):
|
|
23
|
+
data_perm[z,:] = np.random.permutation(data[inds[z],:])
|
|
24
|
+
|
|
25
|
+
MAC_p, _ = _calculate_LEAP_cors(data_perm, window, 0, step, num_format, dtype)
|
|
26
|
+
MAC_p = np.absolute(MAC_p)
|
|
27
|
+
np.fill_diagonal(MAC_p, -1)
|
|
28
|
+
MACs_perm[n] = MAC_p
|
|
29
|
+
|
|
30
|
+
# Calculate FDR
|
|
31
|
+
cors = np.linspace(0, 1, FDR_cutoffs)
|
|
32
|
+
num_cors_perm = np.full(FDR_cutoffs, 0)
|
|
33
|
+
MACs_observed = np.full(FDR_cutoffs, 0)
|
|
34
|
+
|
|
35
|
+
for r in range(0, FDR_cutoffs):
|
|
36
|
+
num_cors_perm[r] += np.sum(MACs_perm >= cors[r])
|
|
37
|
+
MACs_observed[r] += np.sum(MAC_true >= cors[r])
|
|
38
|
+
|
|
39
|
+
perm_size = samp_size*samp_size-samp_size
|
|
40
|
+
obs_size = MAC_true.shape[0]*MAC_true.shape[1]-MAC_true.shape[0]
|
|
41
|
+
MACs_ave_perm = num_cors_perm/n_perms*(obs_size/perm_size)
|
|
42
|
+
fdr = np.full(FDR_cutoffs, np.nan)
|
|
43
|
+
|
|
44
|
+
for s in range(0,FDR_cutoffs):
|
|
45
|
+
if MACs_observed[s] == 0:
|
|
46
|
+
fdr[s] = 0
|
|
47
|
+
else:
|
|
48
|
+
fdr[s] = MACs_ave_perm[s]/MACs_observed[s]
|
|
49
|
+
|
|
50
|
+
results = np.column_stack((cors, MACs_observed, MACs_ave_perm, fdr))
|
|
51
|
+
|
|
52
|
+
return results[::-1]
|
|
53
|
+
|
|
54
|
+
def _calculate_star_FDR(data, target_row, MAC, window, n_perms = 100, FDR_cutoffs = 101, step=1, num_format=np.array([1,15]), dtype=np.float64):
|
|
55
|
+
'''Calculate False Discovery Rate by permutations for a single reference row against all rows.'''
|
|
56
|
+
|
|
57
|
+
MAC_true = np.absolute(MAC.copy())
|
|
58
|
+
samp_size = np.minimum(100, data.shape[0])
|
|
59
|
+
MACs_perm = np.zeros((n_perms, samp_size))
|
|
60
|
+
MAC_true[target_row] = -1
|
|
61
|
+
|
|
62
|
+
# simplified MAC_counter function
|
|
63
|
+
for n in range(0, n_perms):
|
|
64
|
+
np.random.seed(n)
|
|
65
|
+
ref_perm = data[target_row,:].copy()
|
|
66
|
+
data_perm = data[0:samp_size-1,:].copy()
|
|
67
|
+
data_perm = np.concatenate((ref_perm.reshape((1,-1)), data_perm))
|
|
68
|
+
inds = np.random.choice(data.shape[0], size=samp_size, replace=False)
|
|
69
|
+
|
|
70
|
+
for z in range(0, samp_size):
|
|
71
|
+
data_perm[z,:] = np.random.permutation(data[inds[z],:])
|
|
72
|
+
|
|
73
|
+
MAC_p = _calculate_star_cors(data_perm, 0, np.zeros((samp_size), dtype=dtype), window, i=0, step=step, num_format=num_format, dtype=dtype)
|
|
74
|
+
MAC_p = np.absolute(MAC_p)
|
|
75
|
+
MAC_p[0] = -1
|
|
76
|
+
MACs_perm[n] = MAC_p
|
|
77
|
+
|
|
78
|
+
### Calculate FDR ###
|
|
79
|
+
cors = np.linspace(0, 1, FDR_cutoffs)
|
|
80
|
+
num_cors_perm = np.full(FDR_cutoffs, 0)
|
|
81
|
+
MACs_observed = np.full(FDR_cutoffs, 0)
|
|
82
|
+
|
|
83
|
+
for r in range(0, FDR_cutoffs):
|
|
84
|
+
num_cors_perm[r] += np.sum(MACs_perm >= cors[r])
|
|
85
|
+
MACs_observed[r] += np.sum(MAC_true >= cors[r])
|
|
86
|
+
|
|
87
|
+
perm_size = samp_size-1
|
|
88
|
+
obs_size = MAC_true.shape[0]-1
|
|
89
|
+
MACs_ave_perm = num_cors_perm/n_perms*(obs_size/perm_size)
|
|
90
|
+
fdr = np.full(FDR_cutoffs, np.nan)
|
|
91
|
+
|
|
92
|
+
for s in range(0,FDR_cutoffs):
|
|
93
|
+
if MACs_observed[s] == 0:
|
|
94
|
+
fdr[s] = 0
|
|
95
|
+
else:
|
|
96
|
+
fdr[s] = MACs_ave_perm[s]/MACs_observed[s]
|
|
97
|
+
|
|
98
|
+
results = np.column_stack((cors, MACs_observed, MACs_ave_perm, fdr))
|
|
99
|
+
|
|
100
|
+
return results[::-1]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
## QUERIES ##
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from coregraph.utils.decorators import (requires_cors, requires_FDR)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@requires_cors
|
|
12
|
+
def get_correlation(C: CoReGraph, regulator: str, target: str, ref_lag: tuple[int, int]) -> float:
|
|
13
|
+
'''Get correlation value between two genes at a specific (reference, lag) window pair.'''
|
|
14
|
+
ref, lag = ref_lag
|
|
15
|
+
|
|
16
|
+
if (ref % C.cors.step != 0) or (lag % C.cors.step != 0):
|
|
17
|
+
raise ValueError(f"ref_lag must be multiples of step={C.cors.step}")
|
|
18
|
+
|
|
19
|
+
reg_idx = C.gene_to_idx[regulator]
|
|
20
|
+
tar_idx = C.gene_to_idx[target]
|
|
21
|
+
|
|
22
|
+
if ref <= lag:
|
|
23
|
+
tensor_i = reg_idx
|
|
24
|
+
tensor_j = tar_idx
|
|
25
|
+
search_ref = ref
|
|
26
|
+
search_lag = lag
|
|
27
|
+
else:
|
|
28
|
+
tensor_i = tar_idx
|
|
29
|
+
tensor_j = reg_idx
|
|
30
|
+
search_ref = lag
|
|
31
|
+
search_lag = ref
|
|
32
|
+
|
|
33
|
+
dim3 = np.argwhere((C.cors.reflag[:, 0] == search_ref) & (C.cors.reflag[:, 1] == search_lag))[0][0]
|
|
34
|
+
|
|
35
|
+
value = (C.cors.tensor[tensor_i, tensor_j, dim3] / C.cors.num_format[0])
|
|
36
|
+
|
|
37
|
+
return float(value)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@requires_cors
|
|
41
|
+
def get_all_correlations(C: CoReGraph, regulator: str, target: str, ref: int) -> np.ndarray:
|
|
42
|
+
'''Get all lagged correlations between two genes for a fixed reference window.'''
|
|
43
|
+
if (ref % C.cors.step != 0) :
|
|
44
|
+
raise ValueError(f"ref must be a multiple of step={C.cors.step}")
|
|
45
|
+
|
|
46
|
+
correlations = np.empty(C.cors.n_steps, dtype=C.cors.dtype)
|
|
47
|
+
|
|
48
|
+
for i in range(C.cors.n_steps):
|
|
49
|
+
lag = i * C.cors.step
|
|
50
|
+
correlations[i] = get_correlation(C,regulator,target,(ref, lag))
|
|
51
|
+
|
|
52
|
+
return correlations
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@requires_cors
|
|
56
|
+
def get_mac(C: CoReGraph, regulator: str, target: str) -> dict:
|
|
57
|
+
'''Get maximal absolute correlation (MAC) and corresponding reference/lag pair for two genes.'''
|
|
58
|
+
reg_idx = C.gene_to_idx[regulator]
|
|
59
|
+
tar_idx = C.gene_to_idx[target]
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
"ref": int(C.cors.LAG_id[0, reg_idx, tar_idx]),
|
|
63
|
+
"lag": int(C.cors.LAG_id[1, reg_idx, tar_idx]),
|
|
64
|
+
"cor": float(C.cors.MAC[reg_idx, tar_idx] / C.cors.num_format[0])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@requires_cors
|
|
69
|
+
def get_mac_results(C: CoReGraph) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
70
|
+
'''Get MAC and LAG matrices.'''
|
|
71
|
+
mac_df = pd.DataFrame(C.cors.MAC / C.cors.num_format[0], index=C.gene_id, columns=C.gene_id)
|
|
72
|
+
lag_df = pd.DataFrame(C.cors.LAG, index=C.gene_id, columns=C.gene_id)
|
|
73
|
+
|
|
74
|
+
return mac_df, lag_df
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@requires_cors
|
|
78
|
+
@requires_FDR
|
|
79
|
+
def get_regulated_genes(C: CoReGraph, regulator: str, cor_threshold: float=0.0) -> pd.DataFrame:
|
|
80
|
+
'''Get genes regulated by a regulator gene.'''
|
|
81
|
+
reg_idx = C.gene_to_idx[regulator]
|
|
82
|
+
|
|
83
|
+
values = (C.cors.MAC[reg_idx, :] / C.cors.num_format[0])
|
|
84
|
+
|
|
85
|
+
df = pd.DataFrame({
|
|
86
|
+
"gene": C.gene_id,
|
|
87
|
+
"correlation": values,
|
|
88
|
+
"lag": C.cors.LAG[reg_idx, :]
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
df = df[np.abs(df["correlation"]) > cor_threshold]
|
|
92
|
+
|
|
93
|
+
df = df.sort_values(by="correlation", key=np.abs, ascending=False)
|
|
94
|
+
|
|
95
|
+
return df.set_index("gene")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@requires_cors
|
|
99
|
+
@requires_FDR
|
|
100
|
+
def get_regulator_genes(C: CoReGraph, target: str, cor_threshold: float=0.0) -> pd.DataFrame:
|
|
101
|
+
'''Get genes regulated by a regulator gene.'''
|
|
102
|
+
tar_idx = C.gene_to_idx[target]
|
|
103
|
+
|
|
104
|
+
values = (C.cors.MAC[:, tar_idx] / C.cors.num_format[0])
|
|
105
|
+
|
|
106
|
+
df = pd.DataFrame({
|
|
107
|
+
"gene": C.gene_id,
|
|
108
|
+
"correlation": values,
|
|
109
|
+
"lag": C.cors.LAG[:, tar_idx]
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
df = df[np.abs(df["correlation"]) > cor_threshold]
|
|
113
|
+
|
|
114
|
+
df = df.sort_values(by="correlation", key=np.abs, ascending=False)
|
|
115
|
+
|
|
116
|
+
return df.set_index("gene")
|
|
117
|
+
|
|
118
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
## REDUCTIONS ##
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
from coregraph.models.coregraph import CoReGraph
|
|
9
|
+
from coregraph.models.stargraph import StarGraph
|
|
10
|
+
|
|
11
|
+
from coregraph.analysis.correlations import _calculate_star_cors
|
|
12
|
+
from coregraph.analysis.fdr import _calculate_star_FDR
|
|
13
|
+
from coregraph.utils.validation import _solve_step
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def starry(x, central_gene, window, FDR_thr=0.05, n_perms=100, FDR_cutoffs=501, step=None, n_steps=None, verbose=False):
|
|
17
|
+
'''Wrapped function to estimate starry gene regulatory network centered on a given gene'''
|
|
18
|
+
n_genes, n_cells = x.data.shape
|
|
19
|
+
target_row = x.gene_id.index(central_gene)
|
|
20
|
+
step, n_steps = _solve_step(step, n_steps, window, n_cells)
|
|
21
|
+
|
|
22
|
+
## Calculate MAC ##
|
|
23
|
+
MAC = np.zeros((n_genes), dtype=np.float64)
|
|
24
|
+
|
|
25
|
+
np.seterr(divide='ignore', invalid='ignore')
|
|
26
|
+
iterator = tqdm(range(0, n_cells-window+1, step), desc="Calculating Correlations", disable=not verbose)
|
|
27
|
+
for i in iterator:
|
|
28
|
+
MAC = _calculate_star_cors(x.data, target_row, MAC, window, i, step)
|
|
29
|
+
|
|
30
|
+
## Calculate FDR ##
|
|
31
|
+
FDR = _calculate_star_FDR(x.data, target_row, MAC, window, n_perms, FDR_cutoffs, step)
|
|
32
|
+
FDR = pd.DataFrame(FDR)
|
|
33
|
+
FDR.columns = ["cors", "MACs_observed", "MACs_ave_perm", "FDR"]
|
|
34
|
+
FDR[["MACs_observed"]] = FDR[["MACs_observed"]].astype(int)
|
|
35
|
+
|
|
36
|
+
cor_thr = min(FDR['cors'][FDR['FDR'] < FDR_thr])
|
|
37
|
+
MAC = pd.DataFrame(MAC, index=x.gene_id, columns=['MAC'])
|
|
38
|
+
MAC = MAC.sort_values(by='MAC', key=abs, ascending=False)
|
|
39
|
+
|
|
40
|
+
## Create a new object and fill in it ##
|
|
41
|
+
star = StarGraph()
|
|
42
|
+
star.central_gene = central_gene
|
|
43
|
+
star.window = window
|
|
44
|
+
star.step = step
|
|
45
|
+
star.n_steps = n_steps
|
|
46
|
+
star.MAC = MAC
|
|
47
|
+
star.FDR = FDR
|
|
48
|
+
star.set_FDR_threshold(FDR_thr)
|
|
49
|
+
|
|
50
|
+
return star
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def subset_coregraph(C: CoReGraph, gene_list: list[str]) -> CoReGraph:
|
|
54
|
+
id_dict = {}
|
|
55
|
+
for i, b in enumerate(C.gene_id):
|
|
56
|
+
id_dict[b] = i
|
|
57
|
+
|
|
58
|
+
shared_id = [id_dict[g] for g in gene_list]
|
|
59
|
+
shared_id.sort()
|
|
60
|
+
subdata = C.data[shared_id,:]
|
|
61
|
+
subid = [C.gene_id[g] for g in shared_id]
|
|
62
|
+
|
|
63
|
+
subobject = CoReGraph(subdata, C.pseudotime, subid, C.cell_id)
|
|
64
|
+
return subobject
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .colors import (
|
|
2
|
+
ColorBlind,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
from .plots import (
|
|
6
|
+
plot_expression,
|
|
7
|
+
plot_correlations,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from .animations import (
|
|
11
|
+
animate_correlations,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .network import (
|
|
15
|
+
animate_network,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
# Colors
|
|
20
|
+
"ColorBlind",
|
|
21
|
+
|
|
22
|
+
# Plots
|
|
23
|
+
"plot_expression",
|
|
24
|
+
"plot_correlations",
|
|
25
|
+
|
|
26
|
+
# Animations
|
|
27
|
+
"animate_correlations",
|
|
28
|
+
|
|
29
|
+
# Network
|
|
30
|
+
"animate_network",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
## ANIMATIONS ##
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import matplotlib.patches as patches
|
|
8
|
+
|
|
9
|
+
from matplotlib.animation import FuncAnimation
|
|
10
|
+
|
|
11
|
+
from coregraph.graphics.colors import ColorBlind
|
|
12
|
+
from coregraph.analysis.queries import (get_all_correlations)
|
|
13
|
+
from coregraph.utils.decorators import (requires_cors, requires_bins)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@requires_bins
|
|
17
|
+
@requires_cors
|
|
18
|
+
def animate_correlations(C: CoReGraph, regulator: str, target: str, ref: int, scaled: bool=False, decimals: int=15, color: list=(ColorBlind[0], ColorBlind[3]), linewidth: float=1, figsize: tuple=(8,4)):
|
|
19
|
+
'''Animate lagged correlations.'''
|
|
20
|
+
if C.graphics.n_bins is None:
|
|
21
|
+
raise ValueError("Bins have not been calculated.")
|
|
22
|
+
|
|
23
|
+
values = (C.graphics.scaled if scaled else C.graphics.mean)
|
|
24
|
+
reg_idx = C.gene_to_idx[regulator]
|
|
25
|
+
tar_idx = C.gene_to_idx[target]
|
|
26
|
+
y_max = np.max([values[reg_idx, :], values[tar_idx, :]]) * 1.1
|
|
27
|
+
all_cors = get_all_correlations(C, regulator, target, ref)
|
|
28
|
+
all_cors_norm = (all_cors / np.max(np.abs(all_cors)))
|
|
29
|
+
|
|
30
|
+
fig, ax = plt.subplots(1, 2, figsize=figsize, width_ratios=[25, 1],)
|
|
31
|
+
x = np.unique(C.graphics.bin_id)
|
|
32
|
+
|
|
33
|
+
# Regulator and target lines
|
|
34
|
+
ax[0].plot(x, values[reg_idx, :], color=color[0])
|
|
35
|
+
ax[0].plot(x, values[tar_idx, :], color=color[1],)
|
|
36
|
+
|
|
37
|
+
fixed_rect = ax[0].add_patch(patches.Rectangle((ref, 0), C.cors.window, y_max, facecolor=color[0], alpha=0.1,))
|
|
38
|
+
moving_rect = ax[0].add_patch(patches.Rectangle((0, 0), C.cors.window, y_max, facecolor=color[1], alpha=0.1,))
|
|
39
|
+
|
|
40
|
+
cor_text = ax[0].annotate("", (C.n_cells * 0.01, y_max * 0.8))
|
|
41
|
+
lag_text = ax[0].annotate("", (C.n_cells * 0.01, y_max * 0.9))
|
|
42
|
+
|
|
43
|
+
def update(frame):
|
|
44
|
+
lag = frame * C.cors.step
|
|
45
|
+
moving_rect.set_x(lag)
|
|
46
|
+
cor = all_cors[frame]
|
|
47
|
+
cor_text.set_text(f"cor = {np.round(cor, decimals)}")
|
|
48
|
+
lag_text.set_text(f"lag = {lag}")
|
|
49
|
+
|
|
50
|
+
return (moving_rect, cor_text, lag_text)
|
|
51
|
+
|
|
52
|
+
ani = FuncAnimation(fig, update, frames=C.cors.n_steps, blit=True)
|
|
53
|
+
#HTML(ani.to_jshtml())
|
|
54
|
+
return ani
|
|
55
|
+
|
|
56
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## COLORS ##
|
|
2
|
+
|
|
3
|
+
# Colorblind friendly set of colors
|
|
4
|
+
Blues = ['#016BA0','#5F9ED1','#A1C8EB','#3399FF', '#006ddb','#330066']
|
|
5
|
+
YReds = ['#FF0000','#FF9933','#F0E442','#ffff6d','#FF7070']
|
|
6
|
+
Greys = ['#131313','#555555','#809099','#CFCFCF','#F2F4F4']
|
|
7
|
+
Others = ['#FFBBAB']
|
|
8
|
+
|
|
9
|
+
ColorBlind = [Blues[0], YReds[0], Blues[1], YReds[1], Blues[2], YReds[2], Blues[3], YReds[3], Blues[4], YReds[4], Blues[5], Others[0], Greys[0], Greys[1], Greys[2], Greys[3], Greys[4]]
|