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.
Files changed (33) hide show
  1. pycoregraph-0.0.1a1/LICENSE +21 -0
  2. pycoregraph-0.0.1a1/PKG-INFO +65 -0
  3. pycoregraph-0.0.1a1/README.md +15 -0
  4. pycoregraph-0.0.1a1/pyproject.toml +102 -0
  5. pycoregraph-0.0.1a1/setup.cfg +4 -0
  6. pycoregraph-0.0.1a1/src/coregraph/__init__.py +57 -0
  7. pycoregraph-0.0.1a1/src/coregraph/analysis/__init__.py +45 -0
  8. pycoregraph-0.0.1a1/src/coregraph/analysis/bins.py +23 -0
  9. pycoregraph-0.0.1a1/src/coregraph/analysis/correlations.py +110 -0
  10. pycoregraph-0.0.1a1/src/coregraph/analysis/fdr.py +100 -0
  11. pycoregraph-0.0.1a1/src/coregraph/analysis/queries.py +118 -0
  12. pycoregraph-0.0.1a1/src/coregraph/analysis/subset.py +64 -0
  13. pycoregraph-0.0.1a1/src/coregraph/graphics/__init__.py +33 -0
  14. pycoregraph-0.0.1a1/src/coregraph/graphics/animations.py +56 -0
  15. pycoregraph-0.0.1a1/src/coregraph/graphics/colors.py +9 -0
  16. pycoregraph-0.0.1a1/src/coregraph/graphics/network.py +214 -0
  17. pycoregraph-0.0.1a1/src/coregraph/graphics/plots.py +85 -0
  18. pycoregraph-0.0.1a1/src/coregraph/models/__init__.py +11 -0
  19. pycoregraph-0.0.1a1/src/coregraph/models/coregraph.py +221 -0
  20. pycoregraph-0.0.1a1/src/coregraph/models/cors.py +63 -0
  21. pycoregraph-0.0.1a1/src/coregraph/models/graphics.py +38 -0
  22. pycoregraph-0.0.1a1/src/coregraph/models/stargraph.py +41 -0
  23. pycoregraph-0.0.1a1/src/coregraph/utils/__init__.py +23 -0
  24. pycoregraph-0.0.1a1/src/coregraph/utils/decorators.py +39 -0
  25. pycoregraph-0.0.1a1/src/coregraph/utils/formatting.py +16 -0
  26. pycoregraph-0.0.1a1/src/coregraph/utils/validation.py +25 -0
  27. pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/PKG-INFO +65 -0
  28. pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/SOURCES.txt +31 -0
  29. pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/dependency_links.txt +1 -0
  30. pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/requires.txt +28 -0
  31. pycoregraph-0.0.1a1/src/pyCoReGraph.egg-info/top_level.txt +1 -0
  32. pycoregraph-0.0.1a1/tests/test_coregraph.py +13 -0
  33. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+