pyCoReGraph 0.0.1a1__tar.gz
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.
- pycoregraph-0.0.1a1/LICENSE +21 -0
- pycoregraph-0.0.1a1/PKG-INFO +65 -0
- pycoregraph-0.0.1a1/README.md +15 -0
- pycoregraph-0.0.1a1/pyproject.toml +102 -0
- pycoregraph-0.0.1a1/setup.cfg +4 -0
- pycoregraph-0.0.1a1/src/coregraph/__init__.py +57 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/__init__.py +45 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/bins.py +23 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/correlations.py +110 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/fdr.py +100 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/queries.py +118 -0
- pycoregraph-0.0.1a1/src/coregraph/analysis/subset.py +64 -0
- pycoregraph-0.0.1a1/src/coregraph/graphics/__init__.py +33 -0
- pycoregraph-0.0.1a1/src/coregraph/graphics/animations.py +56 -0
- pycoregraph-0.0.1a1/src/coregraph/graphics/colors.py +9 -0
- pycoregraph-0.0.1a1/src/coregraph/graphics/network.py +214 -0
- pycoregraph-0.0.1a1/src/coregraph/graphics/plots.py +85 -0
- pycoregraph-0.0.1a1/src/coregraph/models/__init__.py +11 -0
- pycoregraph-0.0.1a1/src/coregraph/models/coregraph.py +221 -0
- pycoregraph-0.0.1a1/src/coregraph/models/cors.py +63 -0
- pycoregraph-0.0.1a1/src/coregraph/models/graphics.py +38 -0
- pycoregraph-0.0.1a1/src/coregraph/models/stargraph.py +41 -0
- pycoregraph-0.0.1a1/src/coregraph/utils/__init__.py +23 -0
- pycoregraph-0.0.1a1/src/coregraph/utils/decorators.py +39 -0
- pycoregraph-0.0.1a1/src/coregraph/utils/formatting.py +16 -0
- pycoregraph-0.0.1a1/src/coregraph/utils/validation.py +25 -0
- pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/PKG-INFO +65 -0
- pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/SOURCES.txt +31 -0
- pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/dependency_links.txt +1 -0
- pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/requires.txt +28 -0
- pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/top_level.txt +1 -0
- pycoregraph-0.0.1a1/tests/test_coregraph.py +13 -0
- pycoregraph-0.0.1a1/tests/test_imports.py +10 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 JosephLeger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyCoReGraph
|
|
3
|
+
Version: 0.0.1a1
|
|
4
|
+
Summary: CoReGraph : Correlation-based dynamic gene Regulatory Graphs
|
|
5
|
+
Author-email: Joseph Léger <josephleger@outlook.fr>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/JosephLeger/CoReGraph
|
|
8
|
+
Project-URL: Repository, https://github.com/JosephLeger/CoReGraph
|
|
9
|
+
Project-URL: Issues, https://github.com/JosephLeger/CoReGraph/issues
|
|
10
|
+
Keywords: bioinformatics,single-cell,gene-regulatory-network,pseudotime,correlation,network-analysis,visualization
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: pandas>=2.0
|
|
26
|
+
Requires-Dist: matplotlib>=3.7
|
|
27
|
+
Requires-Dist: networkx>=3.0
|
|
28
|
+
Requires-Dist: scipy>=1.10
|
|
29
|
+
Requires-Dist: tqdm>=4.65
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
33
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
35
|
+
Requires-Dist: black>=24.0; extra == "dev"
|
|
36
|
+
Requires-Dist: ipykernel>=6.0; extra == "dev"
|
|
37
|
+
Provides-Extra: notebook
|
|
38
|
+
Requires-Dist: jupyter>=1.0; extra == "notebook"
|
|
39
|
+
Requires-Dist: ipython>=8.0; extra == "notebook"
|
|
40
|
+
Provides-Extra: all
|
|
41
|
+
Requires-Dist: pytest>=8.0; extra == "all"
|
|
42
|
+
Requires-Dist: build>=1.0; extra == "all"
|
|
43
|
+
Requires-Dist: twine>=5.0; extra == "all"
|
|
44
|
+
Requires-Dist: ruff>=0.4; extra == "all"
|
|
45
|
+
Requires-Dist: black>=24.0; extra == "all"
|
|
46
|
+
Requires-Dist: ipykernel>=6.0; extra == "all"
|
|
47
|
+
Requires-Dist: jupyter>=1.0; extra == "all"
|
|
48
|
+
Requires-Dist: ipython>=8.0; extra == "all"
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
|
|
51
|
+
# CoReGraph : **Co**rrelation-based dynamic gene **Re**gulatory **Graph**s
|
|
52
|
+
|
|
53
|
+
A Python package for dynamic lagged gene correlation analysis along pseudotime trajectories.
|
|
54
|
+
|
|
55
|
+
## Requirments
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python >= 3.10
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install coregraph
|
|
65
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# CoReGraph : **Co**rrelation-based dynamic gene **Re**gulatory **Graph**s
|
|
2
|
+
|
|
3
|
+
A Python package for dynamic lagged gene correlation analysis along pseudotime trajectories.
|
|
4
|
+
|
|
5
|
+
## Requirments
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python >= 3.10
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install coregraph
|
|
15
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyCoReGraph"
|
|
7
|
+
version = "0.0.1a1"
|
|
8
|
+
description = "CoReGraph : Correlation-based dynamic gene Regulatory Graphs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Joseph Léger", email = "josephleger@outlook.fr" }
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
keywords = [
|
|
18
|
+
"bioinformatics",
|
|
19
|
+
"single-cell",
|
|
20
|
+
"gene-regulatory-network",
|
|
21
|
+
"pseudotime",
|
|
22
|
+
"correlation",
|
|
23
|
+
"network-analysis",
|
|
24
|
+
"visualization"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Development Status :: 3 - Alpha",
|
|
29
|
+
|
|
30
|
+
"Intended Audience :: Science/Research",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
32
|
+
|
|
33
|
+
"License :: OSI Approved :: MIT License",
|
|
34
|
+
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.9",
|
|
37
|
+
"Programming Language :: Python :: 3.10",
|
|
38
|
+
"Programming Language :: Python :: 3.11",
|
|
39
|
+
"Programming Language :: Python :: 3.12",
|
|
40
|
+
|
|
41
|
+
"Operating System :: OS Independent"
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
dependencies = [
|
|
45
|
+
"numpy>=1.24",
|
|
46
|
+
"pandas>=2.0",
|
|
47
|
+
"matplotlib>=3.7",
|
|
48
|
+
"networkx>=3.0",
|
|
49
|
+
"scipy>=1.10",
|
|
50
|
+
"tqdm>=4.65"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[project.optional-dependencies]
|
|
54
|
+
|
|
55
|
+
dev = [
|
|
56
|
+
"pytest>=8.0",
|
|
57
|
+
"build>=1.0",
|
|
58
|
+
"twine>=5.0",
|
|
59
|
+
"ruff>=0.4",
|
|
60
|
+
"black>=24.0",
|
|
61
|
+
"ipykernel>=6.0"
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
notebook = [
|
|
65
|
+
"jupyter>=1.0",
|
|
66
|
+
"ipython>=8.0"
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
all = [
|
|
70
|
+
"pytest>=8.0",
|
|
71
|
+
"build>=1.0",
|
|
72
|
+
"twine>=5.0",
|
|
73
|
+
"ruff>=0.4",
|
|
74
|
+
"black>=24.0",
|
|
75
|
+
"ipykernel>=6.0",
|
|
76
|
+
"jupyter>=1.0",
|
|
77
|
+
"ipython>=8.0"
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
[project.urls]
|
|
81
|
+
Homepage = "https://github.com/JosephLeger/CoReGraph"
|
|
82
|
+
Repository = "https://github.com/JosephLeger/CoReGraph"
|
|
83
|
+
Issues = "https://github.com/JosephLeger/CoReGraph/issues"
|
|
84
|
+
|
|
85
|
+
[tool.setuptools]
|
|
86
|
+
include-package-data = true
|
|
87
|
+
package-dir = {"" = "src"}
|
|
88
|
+
|
|
89
|
+
[tool.setuptools.packages.find]
|
|
90
|
+
where = ["src"]
|
|
91
|
+
include = ["coregraph*"]
|
|
92
|
+
|
|
93
|
+
[tool.black]
|
|
94
|
+
line-length = 88
|
|
95
|
+
target-version = ["py310"]
|
|
96
|
+
|
|
97
|
+
[tool.ruff]
|
|
98
|
+
line-length = 88
|
|
99
|
+
target-version = "py310"
|
|
100
|
+
|
|
101
|
+
[tool.pytest.ini_options]
|
|
102
|
+
testpaths = ["tests"]
|
|
@@ -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
|
+
|