rectanglepy 0.1.6__tar.gz → 0.1.8__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.
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.bumpversion.cfg +1 -1
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/CHANGELOG.md +16 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/PKG-INFO +3 -1
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/pyproject.toml +3 -1
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/pp/create_signature.py +17 -6
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/pp/rectangle_signature.py +4 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/rectangle.py +18 -5
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/test_rectangle.py +18 -3
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.cruft.json +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.editorconfig +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/workflows/build.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/workflows/release.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/workflows/release_testpypi.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.github/workflows/test.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.gitignore +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.pre-commit-config.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/.readthedocs.yaml +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/LICENSE +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/README.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/Makefile +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/_static/.gitkeep +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/_templates/.gitkeep +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/_templates/autosummary/class.rst +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/api.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/changelog.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/conf.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/contributing.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/extensions/typed_returns.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/index.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/make.bat +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/notebooks/example.ipynb +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/references.bib +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/docs/references.md +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/__init__.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/data/hao1_annotations_small.zip +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/data/hao1_counts_small.zip +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/data/small_fino_bulks.zip +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/pp/__init__.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/tl/__init__.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/src/rectanglepy/tl/deconvolution.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/TIL10_signature.txt +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/bulk_small.csv +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/cell_annotations_small.txt +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/quanTIseq_SimRNAseq_mixture_smaller.csv +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/quanTIseq_SimRNAseq_read_fractions_small.txt +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/sc_object_small.csv +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/signature_hao1.csv +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/test_pp.py +0 -0
- {rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/test_tl.py +0 -0
|
@@ -10,6 +10,22 @@ and this project adheres to [Semantic Versioning][].
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [0.1.8] - 2024-09-06
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- RectangleSignatureResult now returns correlation of bulk genes with the calculated Unknown cell type fraction
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- The consensus method now returns the estimations normalized to 1
|
|
22
|
+
|
|
23
|
+
## [0.1.7] - 2024-07-25
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Fixed bug in the consensus method.
|
|
28
|
+
|
|
13
29
|
## [0.1.6] - 2024-05-07
|
|
14
30
|
|
|
15
31
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rectanglepy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: Hierarchical deconvolution of bulk transcriptomics
|
|
5
5
|
Project-URL: Documentation, https://rectanglepy.readthedocs.io/
|
|
6
6
|
Project-URL: Source, https://github.com/ComputationalBiomedicineGroup/Rectangle
|
|
@@ -30,7 +30,9 @@ License: MIT License
|
|
|
30
30
|
SOFTWARE.
|
|
31
31
|
License-File: LICENSE
|
|
32
32
|
Requires-Python: >=3.10
|
|
33
|
+
Requires-Dist: anndata<0.10.9,>=0.8.0
|
|
33
34
|
Requires-Dist: loguru
|
|
35
|
+
Requires-Dist: numpy<2.0.0,>=1.0.0
|
|
34
36
|
Requires-Dist: pydeseq2==0.4.1
|
|
35
37
|
Requires-Dist: quadprog==0.1.11
|
|
36
38
|
Provides-Extra: dev
|
|
@@ -4,7 +4,7 @@ requires = ["hatchling"]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rectanglepy"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.8"
|
|
8
8
|
description = "Hierarchical deconvolution of bulk transcriptomics"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -22,6 +22,8 @@ dependencies = [
|
|
|
22
22
|
"pydeseq2==0.4.1",
|
|
23
23
|
"quadprog==0.1.11",
|
|
24
24
|
"loguru",
|
|
25
|
+
"numpy>=1.0.0,<2.0.0",
|
|
26
|
+
"anndata>=0.8.0,<0.10.9",
|
|
25
27
|
]
|
|
26
28
|
|
|
27
29
|
[project.optional-dependencies]
|
|
@@ -34,7 +34,9 @@ def _create_condition_number_matrices(de_adjusted, pseudo_signature):
|
|
|
34
34
|
loop_range = min(longest_de_analysis, 200)
|
|
35
35
|
range_minimum = 30
|
|
36
36
|
|
|
37
|
-
if loop_range <
|
|
37
|
+
if loop_range < 8:
|
|
38
|
+
range_minimum = 2
|
|
39
|
+
elif loop_range < range_minimum:
|
|
38
40
|
range_minimum = 8
|
|
39
41
|
|
|
40
42
|
for i in range(range_minimum, loop_range):
|
|
@@ -245,6 +247,7 @@ def build_rectangle_signatures(
|
|
|
245
247
|
subsample: bool = False,
|
|
246
248
|
sample_size: int = 1500,
|
|
247
249
|
n_cpus: int = None,
|
|
250
|
+
run: int = 0,
|
|
248
251
|
) -> RectangleSignatureResult:
|
|
249
252
|
r"""Builds rectangle signatures based on single-cell count data and annotations.
|
|
250
253
|
|
|
@@ -272,6 +275,8 @@ def build_rectangle_signatures(
|
|
|
272
275
|
The log fold change threshold for the DE analysis (only used if optimize_cutoffs is False).
|
|
273
276
|
n_cpus
|
|
274
277
|
The number of cpus to use for the DE analysis. Defaults to the number of cpus available.
|
|
278
|
+
run
|
|
279
|
+
The consensus run number for the analysis. Defaults to 0.
|
|
275
280
|
|
|
276
281
|
Returns
|
|
277
282
|
-------
|
|
@@ -286,7 +291,7 @@ def build_rectangle_signatures(
|
|
|
286
291
|
|
|
287
292
|
annotations = adata.obs[cell_type_col]
|
|
288
293
|
if subsample:
|
|
289
|
-
annotations = _even(annotations, sample_size)
|
|
294
|
+
annotations = _even(annotations, sample_size, run)
|
|
290
295
|
adata = adata[annotations.index]
|
|
291
296
|
|
|
292
297
|
if layer is not None:
|
|
@@ -365,9 +370,14 @@ def _optimize_parameters(
|
|
|
365
370
|
bulks, real_fractions = _generate_pseudo_bulks(sc_data, annotations, genes)
|
|
366
371
|
for p in ps:
|
|
367
372
|
for lfc in lfcs:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
try:
|
|
374
|
+
rmse, pearson_r = _assess_parameter_fit(
|
|
375
|
+
lfc, p, bulks, real_fractions, pseudo_signature_counts, de_results
|
|
376
|
+
)
|
|
377
|
+
logger.info(f"RMSE:{rmse}, Pearson R:{pearson_r} for p={p}, lfc={lfc}")
|
|
378
|
+
results.append({"p": p, "lfc": lfc, "rmse": rmse, "pearson_r": pearson_r})
|
|
379
|
+
except Exception as e:
|
|
380
|
+
logger.error(f"Error in assessing parameter fit for p={p}, lfc={lfc}: {e}")
|
|
371
381
|
|
|
372
382
|
results_df = pd.DataFrame(results)
|
|
373
383
|
results_df = results_df.sort_values(by=["pearson_r", "rmse"], ascending=[False, True])
|
|
@@ -448,7 +458,8 @@ def _reduce_to_common_genes(bulks: pd.DataFrame, sc_data: pd.DataFrame):
|
|
|
448
458
|
return bulks, sc_data
|
|
449
459
|
|
|
450
460
|
|
|
451
|
-
def _even(annotations: pd.Series, number: int) -> pd.Series:
|
|
461
|
+
def _even(annotations: pd.Series, number: int, run=0) -> pd.Series:
|
|
462
|
+
np.random.seed(run)
|
|
452
463
|
assert number > 0, "Number of cells must be greater than 0"
|
|
453
464
|
annotation_counts = annotations.value_counts()
|
|
454
465
|
selected_cells = []
|
|
@@ -22,6 +22,8 @@ class RectangleSignatureResult:
|
|
|
22
22
|
The number of marker genes per cell type, as a dictionary. Keys are cell type names, values are the number of marker genes.
|
|
23
23
|
optimization_result
|
|
24
24
|
The result of the p lfc cut off optimization, as a pd.DataFrame. Contains the following columns: p, lfc, pearson_r, rsme
|
|
25
|
+
unkn_gene_corr
|
|
26
|
+
The correlation between the unknown cell type and the genes linked to the unknown cell type.
|
|
25
27
|
"""
|
|
26
28
|
|
|
27
29
|
def __init__(
|
|
@@ -36,6 +38,7 @@ class RectangleSignatureResult:
|
|
|
36
38
|
marker_genes_per_cluster: dict[str, [str]] = None,
|
|
37
39
|
clustered_signature_genes: pd.Series = None,
|
|
38
40
|
cluster_assignments: list[int or str] = None,
|
|
41
|
+
unkn_gene_corr: pd.Series = None,
|
|
39
42
|
):
|
|
40
43
|
self.signature_genes = signature_genes
|
|
41
44
|
self.bias_factors = bias_factors
|
|
@@ -47,6 +50,7 @@ class RectangleSignatureResult:
|
|
|
47
50
|
self.clustered_bias_factors = clustered_bias_factors
|
|
48
51
|
self.clustered_signature_genes = clustered_signature_genes
|
|
49
52
|
self.assignments = cluster_assignments
|
|
53
|
+
self.unkn_gene_corr = unkn_gene_corr
|
|
50
54
|
|
|
51
55
|
def get_signature_matrix(self, include_mrna_bias=True) -> pd.DataFrame:
|
|
52
56
|
"""Calculates the signature matrix by multiplying the pseudobulk_sig_cpm DataFrame subset by signature_genes and the bias_factors Series.
|
|
@@ -94,8 +94,8 @@ def rectangle_consens(
|
|
|
94
94
|
rectangle_signature_results = []
|
|
95
95
|
most_recent_signatures = None
|
|
96
96
|
|
|
97
|
-
for
|
|
98
|
-
logger.info(f"Running consensus run {
|
|
97
|
+
for i in range(consensus_runs):
|
|
98
|
+
logger.info(f"Running consensus run {i + 1} of {consensus_runs}")
|
|
99
99
|
signatures = build_rectangle_signatures(
|
|
100
100
|
adata,
|
|
101
101
|
cell_type_col,
|
|
@@ -108,14 +108,19 @@ def rectangle_consens(
|
|
|
108
108
|
n_cpus=n_cpus,
|
|
109
109
|
subsample=subsample,
|
|
110
110
|
sample_size=sample_size,
|
|
111
|
+
run=i,
|
|
111
112
|
)
|
|
112
|
-
rectangle_signature_results.append(signatures)
|
|
113
113
|
most_recent_signatures = signatures
|
|
114
114
|
cell_fractions = deconvolution(signatures, bulks, correct_mrna_bias, n_cpus)
|
|
115
115
|
estimations.append(cell_fractions)
|
|
116
|
-
|
|
116
|
+
unkn_gene_corr = _genes_linked_to_unkn(bulks, cell_fractions["Unknown"])
|
|
117
|
+
signatures.unkn_gene_corr = unkn_gene_corr
|
|
118
|
+
rectangle_signature_results.append(signatures)
|
|
119
|
+
consensus_estimations = pd.concat(estimations).groupby(level=0).median()
|
|
120
|
+
# normalize the estimations to 1
|
|
121
|
+
consensus_estimations = consensus_estimations.div(consensus_estimations.sum(axis=1), axis=0)
|
|
117
122
|
consensus_results = ConsensusResult(estimations, rectangle_signature_results)
|
|
118
|
-
return
|
|
123
|
+
return consensus_estimations, most_recent_signatures, consensus_results
|
|
119
124
|
|
|
120
125
|
|
|
121
126
|
def rectangle(
|
|
@@ -196,3 +201,11 @@ def load_tutorial_data() -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
|
|
|
196
201
|
bulks = pd.read_csv(bulks_file, index_col=0, compression="zip")
|
|
197
202
|
|
|
198
203
|
return sc_counts.T, annotations, bulks.T
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _genes_linked_to_unkn(bulks: DataFrame, unkn_fractions: pd.Series):
|
|
207
|
+
genes = bulks.columns
|
|
208
|
+
corr = []
|
|
209
|
+
for gene in genes:
|
|
210
|
+
corr.append(unkn_fractions.corr(bulks.loc[:, gene]))
|
|
211
|
+
return pd.Series(corr, index=genes).sort_values(ascending=False)
|
|
@@ -15,22 +15,37 @@ def test_load_tutorial_data():
|
|
|
15
15
|
|
|
16
16
|
def test_rectangle():
|
|
17
17
|
sc_data, annotations, bulks = rectanglepy.load_tutorial_data()
|
|
18
|
+
sc_data = sc_data.iloc[:, :500]
|
|
18
19
|
sc_data_adata = AnnData(sc_data, obs=annotations.to_frame(name="cell_type"))
|
|
19
20
|
|
|
20
21
|
result = rectanglepy.rectangle(sc_data_adata, bulks)
|
|
22
|
+
estimations, signatures = result
|
|
21
23
|
|
|
22
|
-
assert isinstance(
|
|
23
|
-
assert isinstance(
|
|
24
|
+
assert isinstance(estimations, pd.DataFrame)
|
|
25
|
+
assert isinstance(signatures, RectangleSignatureResult)
|
|
26
|
+
assert isinstance(signatures.unkn_gene_corr, pd.Series)
|
|
24
27
|
|
|
25
28
|
|
|
26
29
|
def test_rectangle_consensus():
|
|
27
30
|
sc_data, annotations, bulks = rectanglepy.load_tutorial_data()
|
|
31
|
+
sc_data = sc_data.iloc[:, :500]
|
|
28
32
|
sc_data_adata = AnnData(sc_data, obs=annotations.to_frame(name="cell_type"))
|
|
29
33
|
|
|
30
34
|
result = rectanglepy.rectangle_consens(
|
|
31
|
-
sc_data_adata, bulks, optimize_cutoffs=False, p=0.5, lfc=0.0, consensus_runs=
|
|
35
|
+
sc_data_adata, bulks, optimize_cutoffs=False, p=0.5, lfc=0.0, consensus_runs=3, sample_size=50
|
|
32
36
|
)
|
|
33
37
|
|
|
34
38
|
assert isinstance(result[0], pd.DataFrame)
|
|
35
39
|
assert isinstance(result[1], RectangleSignatureResult)
|
|
36
40
|
assert isinstance(result[2], ConsensusResult)
|
|
41
|
+
|
|
42
|
+
estimations = result[0]
|
|
43
|
+
consensus_results = result[2]
|
|
44
|
+
signature_results = consensus_results.rectangle_signature_results
|
|
45
|
+
bias_factors = [result.bias_factors for result in signature_results]
|
|
46
|
+
# there was a problem with the random sampling, the bias factors should differ
|
|
47
|
+
assert bias_factors[0]["Monocytes"] != bias_factors[1]["Monocytes"]
|
|
48
|
+
assert bias_factors[0]["Monocytes"] != bias_factors[2]["Monocytes"]
|
|
49
|
+
assert bias_factors[1]["Monocytes"] != bias_factors[2]["Monocytes"]
|
|
50
|
+
# in the consensus we have to make sure that the estimations are again normalized to 1
|
|
51
|
+
assert estimations.sum(axis=1).all() == 1.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rectanglepy-0.1.6 → rectanglepy-0.1.8}/tests/data/quanTIseq_SimRNAseq_read_fractions_small.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|