rectanglepy 0.0.39__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.
- rectanglepy/__init__.py +8 -0
- rectanglepy/data/hao1_annotations_small.csv +96 -0
- rectanglepy/data/hao1_counts_small.csv +6934 -0
- rectanglepy/data/small_fino_bulks.csv +3739 -0
- rectanglepy/pp/__init__.py +4 -0
- rectanglepy/pp/create_signature.py +456 -0
- rectanglepy/pp/rectangle_signature.py +80 -0
- rectanglepy/rectangle.py +117 -0
- rectanglepy/tl/__init__.py +3 -0
- rectanglepy/tl/deconvolution.py +333 -0
- rectanglepy-0.0.39.dist-info/METADATA +104 -0
- rectanglepy-0.0.39.dist-info/RECORD +14 -0
- rectanglepy-0.0.39.dist-info/WHEEL +4 -0
- rectanglepy-0.0.39.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import multiprocessing
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import quadprog
|
|
7
|
+
import statsmodels.api as sm
|
|
8
|
+
from joblib import Parallel, delayed, parallel_backend
|
|
9
|
+
from loguru import logger
|
|
10
|
+
|
|
11
|
+
from rectanglepy.pp.rectangle_signature import RectangleSignatureResult
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _scale_weights(weights: np.ndarray) -> np.ndarray:
|
|
15
|
+
min_weight = np.nextafter(min(weights), np.float64(1.0)) # prevent division by zero
|
|
16
|
+
return weights / min_weight
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def solve_qp(
|
|
20
|
+
signature: pd.DataFrame,
|
|
21
|
+
bulk: pd.Series,
|
|
22
|
+
prev_assignments: list[int or str] = None,
|
|
23
|
+
prev_solution: pd.Series = None,
|
|
24
|
+
gld: np.ndarray = None,
|
|
25
|
+
multiplier: int = None,
|
|
26
|
+
) -> np.ndarray:
|
|
27
|
+
"""Performs quadratic programming optimization to solve the deconvolution problem.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
signature : pd.DataFrame
|
|
32
|
+
The signature matrix for deconvolution. Each row represents a gene and each column represents a cell type.
|
|
33
|
+
bulk : pd.Series
|
|
34
|
+
The bulk data for deconvolution. Each entry represents the expression level of a gene.
|
|
35
|
+
prev_assignments : default is None
|
|
36
|
+
A list of previous assignments of cell types to genes. If provided, the function will use these assignments as additional QP constraints.
|
|
37
|
+
prev_solution : default is None
|
|
38
|
+
A series of previous solution for each cell type. If provided, the function will use the prev solution as additional QP constraints..
|
|
39
|
+
gld : default is None
|
|
40
|
+
An array of gene length data. If provided, the function will use this data to adjust the weights.
|
|
41
|
+
multiplier : default is None
|
|
42
|
+
A multiplier for the weights. If provided, the function will use this multiplier to adjust the weights.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
np.ndarray
|
|
47
|
+
An array of corrected cell fractions. Each entry represents the fraction of a cell type in the bulk data.
|
|
48
|
+
|
|
49
|
+
Notes
|
|
50
|
+
-----
|
|
51
|
+
This function uses quadratic programming to solve the deconvolution problem. The objective is to minimize the difference between the observed bulk data and the data predicted by the signature matrix and the cell fractions. The function also includes constraints to ensure that the cell fractions are non-negative and sum to 1, and to make the solution similar to the previous assignments and weights if they are provided.
|
|
52
|
+
"""
|
|
53
|
+
# ------------------ QP-based deconvolution
|
|
54
|
+
# Minimize 1/2 x^T G x - a^T x
|
|
55
|
+
# Subject to C.T x >= b
|
|
56
|
+
if multiplier is None:
|
|
57
|
+
a = np.dot(signature.T, bulk).astype("double")
|
|
58
|
+
G = np.dot(signature.T, signature).astype("double")
|
|
59
|
+
else:
|
|
60
|
+
weights = np.square(1 / (signature @ gld))
|
|
61
|
+
weights_dampened = np.clip(_scale_weights(weights), None, multiplier)
|
|
62
|
+
W = np.diag(weights_dampened)
|
|
63
|
+
G = np.dot(signature.T, np.dot(W, signature))
|
|
64
|
+
a = np.dot(signature.T, np.dot(W, bulk))
|
|
65
|
+
|
|
66
|
+
# Compute the constraints matrices
|
|
67
|
+
n_genes = G.shape[0]
|
|
68
|
+
# Constraint 1: sum of all fractions is below or equal to 1
|
|
69
|
+
C1 = -np.ones((n_genes, 1))
|
|
70
|
+
b1 = -np.ones(1)
|
|
71
|
+
# Constraint 2: every fraction is greater or equal to 0
|
|
72
|
+
C2 = np.eye(n_genes)
|
|
73
|
+
b2 = np.zeros(n_genes)
|
|
74
|
+
# Constraint 3: if a previous solution is provided, the new solution should be similar to the previous one
|
|
75
|
+
prev_constraints, prev_b = [], []
|
|
76
|
+
if prev_solution is not None:
|
|
77
|
+
for cluster in prev_solution.index:
|
|
78
|
+
C_upper = [-np.ones(1) if str(x) == str(cluster) else np.zeros(1) for x in prev_assignments]
|
|
79
|
+
C_lower = [np.ones(1) if str(x) == str(cluster) else np.zeros(1) for x in prev_assignments]
|
|
80
|
+
prev_constraints.extend([C_upper, C_lower])
|
|
81
|
+
prev_weight = prev_solution.loc[cluster]
|
|
82
|
+
# allow a 3% variation in the previous weights
|
|
83
|
+
prev_weight_upper = min(1, prev_weight + 0.03)
|
|
84
|
+
prev_weight_lower = max(0, prev_weight - 0.03)
|
|
85
|
+
prev_b.extend([prev_weight_upper * np.ones(1) * -1, prev_weight_lower * np.ones(1)])
|
|
86
|
+
|
|
87
|
+
C = np.concatenate((C1, C2, *prev_constraints), axis=1)
|
|
88
|
+
b = np.concatenate((b1, b2, *prev_b), axis=0)
|
|
89
|
+
|
|
90
|
+
scale = np.linalg.norm(G)
|
|
91
|
+
solution = quadprog.solve_qp(G / scale, a / scale, C, b, factorized=False)
|
|
92
|
+
return solution[0]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _find_dampening_constant(signature: pd.DataFrame, bulk: pd.Series, qp_gld: np.ndarray) -> int:
|
|
96
|
+
solutions_std = []
|
|
97
|
+
np.random.seed(1)
|
|
98
|
+
weights = np.square(1 / (np.dot(signature, qp_gld)))
|
|
99
|
+
weights_scaled = _scale_weights(weights)
|
|
100
|
+
weights_scaled_no_inf = weights_scaled[weights_scaled != np.inf]
|
|
101
|
+
qp_gld_sum = sum(qp_gld)
|
|
102
|
+
# try multiple values of the dampening constant (multiplier)
|
|
103
|
+
# for each, calculate the variance of the dampened weighted solution for a subset of genes
|
|
104
|
+
max_range = 40
|
|
105
|
+
multiplier_range = min(max_range, math.ceil(np.log2(max(weights_scaled_no_inf))))
|
|
106
|
+
for i in range(multiplier_range):
|
|
107
|
+
solutions = []
|
|
108
|
+
multiplier = 2**i
|
|
109
|
+
weights_dampened = np.array([multiplier if multiplier <= x else x for x in weights_scaled]).astype("double")
|
|
110
|
+
for _ in range(100):
|
|
111
|
+
subset = np.random.choice(len(signature), size=len(signature) // 2, replace=False)
|
|
112
|
+
bulk_subset = bulk.iloc[list(subset)]
|
|
113
|
+
signature_subset = signature.iloc[subset, :]
|
|
114
|
+
fit = sm.WLS(bulk_subset, -1 + signature_subset, weights=weights_dampened[subset]).fit()
|
|
115
|
+
solution = fit.params * qp_gld_sum / sum(fit.params)
|
|
116
|
+
solutions.append(solution)
|
|
117
|
+
solutions_df = pd.DataFrame(solutions)
|
|
118
|
+
|
|
119
|
+
solutions_std.append(solutions_df.std(axis=0))
|
|
120
|
+
solutions_std_df = pd.DataFrame(solutions_std)
|
|
121
|
+
means = solutions_std_df.apply(lambda x: np.mean(x**2), axis=1)
|
|
122
|
+
best_dampening_constant = means.idxmin()
|
|
123
|
+
return best_dampening_constant
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _calculate_dwls(
|
|
127
|
+
signature: pd.DataFrame,
|
|
128
|
+
bulk: pd.Series,
|
|
129
|
+
prev_assignments: list[int or str] = None,
|
|
130
|
+
prev_weights: pd.Series = None,
|
|
131
|
+
) -> pd.Series:
|
|
132
|
+
genes = list(set(signature.index) & set(bulk.index))
|
|
133
|
+
signature = signature.loc[genes].sort_index()
|
|
134
|
+
bulk = bulk.loc[genes].sort_index().astype("double")
|
|
135
|
+
|
|
136
|
+
approximate_solution = solve_qp(signature, bulk, prev_assignments, prev_weights)
|
|
137
|
+
dampening_constant = _find_dampening_constant(signature, bulk, approximate_solution)
|
|
138
|
+
multiplier = 2**dampening_constant
|
|
139
|
+
|
|
140
|
+
max_iterations = 1000
|
|
141
|
+
convergence_threshold = 0.002
|
|
142
|
+
change = 1
|
|
143
|
+
iterations = 2
|
|
144
|
+
solutions_sum = approximate_solution
|
|
145
|
+
while (change > convergence_threshold) and (iterations < max_iterations):
|
|
146
|
+
dampened_solution = solve_qp(signature, bulk, prev_assignments, prev_weights, approximate_solution, multiplier)
|
|
147
|
+
solutions_sum += dampened_solution
|
|
148
|
+
solution_averages = solutions_sum / iterations
|
|
149
|
+
change = np.linalg.norm(solution_averages - approximate_solution, 1)
|
|
150
|
+
approximate_solution = solution_averages
|
|
151
|
+
iterations += 1
|
|
152
|
+
|
|
153
|
+
if iterations == max_iterations:
|
|
154
|
+
logger.warning("Dampened weighted least squares did not converge, using last solution")
|
|
155
|
+
|
|
156
|
+
return pd.Series(approximate_solution, index=signature.columns)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def deconvolution(
|
|
160
|
+
signatures: RectangleSignatureResult,
|
|
161
|
+
bulks: pd.DataFrame,
|
|
162
|
+
correct_mrna_bias: bool = True,
|
|
163
|
+
n_cpus: int = None,
|
|
164
|
+
) -> pd.DataFrame:
|
|
165
|
+
"""Performs recursive deconvolution using rectangle signatures and bulk data.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
signatures : RectangleSignatureResult
|
|
170
|
+
The rectangle signature result containing the signature data and results.
|
|
171
|
+
bulks : pandas.DataFrame
|
|
172
|
+
The tpm normalized bulk data for deconvolution. Rows are samples and columns are genes.
|
|
173
|
+
correct_mrna_bias : bool
|
|
174
|
+
A flag indicating whether to correct for mRNA bias. Defaults to True.
|
|
175
|
+
n_cpus : int
|
|
176
|
+
The number of CPUs to use for parallel processing. If not provided, the function will use all available CPUs. Each CPU will process a bulk sample.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
A DataFrame containing the estimated cell fractions resulting from deconvolution. Each row represents a sample and each column represents a cell type.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
if n_cpus is not None:
|
|
184
|
+
num_processes = n_cpus
|
|
185
|
+
else:
|
|
186
|
+
num_processes = multiprocessing.cpu_count()
|
|
187
|
+
|
|
188
|
+
with parallel_backend("loky", inner_max_num_threads=1):
|
|
189
|
+
results = Parallel(
|
|
190
|
+
n_jobs=num_processes,
|
|
191
|
+
)(
|
|
192
|
+
delayed(_process_bulk)(signatures, i, bulk, bulks.columns, correct_mrna_bias)
|
|
193
|
+
for i, bulk in enumerate(bulks.values)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
result_df = pd.DataFrame(results, index=bulks.index)
|
|
197
|
+
|
|
198
|
+
# Return the result DataFrame
|
|
199
|
+
return result_df
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _process_bulk(
|
|
203
|
+
signatures: RectangleSignatureResult, i: int, bulk: pd.Series, var_names: pd.Index, correct_mrna_bias: bool
|
|
204
|
+
) -> pd.Series:
|
|
205
|
+
try:
|
|
206
|
+
logger.info(f"Deconvolute fractions for bulk: {i}")
|
|
207
|
+
bulk = pd.Series(bulk, index=var_names)
|
|
208
|
+
result = _deconvolute(signatures, bulk, correct_mrna_bias=correct_mrna_bias)
|
|
209
|
+
logger.info(f"Finished deconvolution for bulk: {i}")
|
|
210
|
+
return result
|
|
211
|
+
except Exception as e:
|
|
212
|
+
logger.warning(f"Deconvolution failed for bulk: {i} with error: {e}")
|
|
213
|
+
return pd.Series(index=signatures.pseudobulk_sig_cpm.columns)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _deconvolute(signatures: RectangleSignatureResult, bulk: pd.Series, correct_mrna_bias: bool = True) -> pd.Series:
|
|
217
|
+
bulk_direct_reduced = bulk[bulk.index.isin(signatures.signature_genes)]
|
|
218
|
+
signature_genes_direct_reduced = signatures.signature_genes[
|
|
219
|
+
signatures.signature_genes.isin(bulk_direct_reduced.index)
|
|
220
|
+
]
|
|
221
|
+
pseudobulk_sig_cpm = signatures.pseudobulk_sig_cpm
|
|
222
|
+
clustered_pseudobulk_sig_cpm = signatures.clustered_pseudobulk_sig_cpm
|
|
223
|
+
bias_factors = signatures.bias_factors
|
|
224
|
+
|
|
225
|
+
if not correct_mrna_bias:
|
|
226
|
+
bias_factors = bias_factors * 0 + 1
|
|
227
|
+
|
|
228
|
+
signature = pseudobulk_sig_cpm.loc[signature_genes_direct_reduced] * bias_factors
|
|
229
|
+
start_fractions = _calculate_dwls(signature, bulk)
|
|
230
|
+
|
|
231
|
+
if clustered_pseudobulk_sig_cpm is None:
|
|
232
|
+
start_fractions = correct_for_unknown_cell_content(bulk, pseudobulk_sig_cpm, start_fractions, bias_factors)
|
|
233
|
+
return start_fractions
|
|
234
|
+
|
|
235
|
+
cluster_bias_factors = signatures.clustered_bias_factors
|
|
236
|
+
if not correct_mrna_bias:
|
|
237
|
+
cluster_bias_factors = cluster_bias_factors * 0 + 1
|
|
238
|
+
|
|
239
|
+
bulk_rec_reduced = bulk[bulk.index.isin(clustered_pseudobulk_sig_cpm.index)]
|
|
240
|
+
clustered_signature_genes = signatures.clustered_signature_genes[
|
|
241
|
+
signatures.clustered_signature_genes.isin(bulk_rec_reduced.index)
|
|
242
|
+
]
|
|
243
|
+
clustered_signature = clustered_pseudobulk_sig_cpm.loc[clustered_signature_genes] * cluster_bias_factors
|
|
244
|
+
|
|
245
|
+
union_genes = list(set(signature_genes_direct_reduced) | set(clustered_signature_genes))
|
|
246
|
+
union_direct_signature = pseudobulk_sig_cpm.loc[union_genes] * bias_factors
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
clustered_fractions = _calculate_dwls(clustered_signature, bulk)
|
|
250
|
+
recursive_fractions = _calculate_dwls(signature, bulk, signatures.assignments, clustered_fractions)
|
|
251
|
+
except Exception as e:
|
|
252
|
+
logger.warning(f"Recursive deconvolution failed with error: {e}")
|
|
253
|
+
return start_fractions
|
|
254
|
+
|
|
255
|
+
union_direct_fraction = _calculate_dwls(union_direct_signature, bulk)
|
|
256
|
+
|
|
257
|
+
averaged_start_fractions = (start_fractions + union_direct_fraction) / 2
|
|
258
|
+
|
|
259
|
+
final_fractions = []
|
|
260
|
+
cell_types_with_low_number_of_marker_genes = signatures.cell_types_with_low_number_of_marker_genes()
|
|
261
|
+
for cell_type in list(averaged_start_fractions.index):
|
|
262
|
+
if cell_type in cell_types_with_low_number_of_marker_genes:
|
|
263
|
+
final_fractions.append(recursive_fractions[cell_type])
|
|
264
|
+
else:
|
|
265
|
+
final_fractions.append(averaged_start_fractions[cell_type])
|
|
266
|
+
|
|
267
|
+
final_fractions = pd.Series(final_fractions, index=averaged_start_fractions.index)
|
|
268
|
+
|
|
269
|
+
final_fractions = correct_for_unknown_cell_content(bulk, pseudobulk_sig_cpm, final_fractions, bias_factors)
|
|
270
|
+
return final_fractions
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def correct_for_unknown_cell_content(
|
|
274
|
+
bulk: pd.Series, pseudo_signature_cpm: pd.DataFrame, estimates: pd.Series, bias_factors: pd.Series
|
|
275
|
+
) -> pd.Series:
|
|
276
|
+
r"""Performs correction for unknown cell content using the pseudo signature and bulk data.
|
|
277
|
+
|
|
278
|
+
Reconstructs the bulk expression profiles through the estimated cell fractions (weighted by the mRNA bias factors) and cell-type-specific expression profiles (i.e. signature).
|
|
279
|
+
|
|
280
|
+
.. math::
|
|
281
|
+
\text{bulk_est} = \text{pseudo_signature} \times (\text{estimates}^T \times \text{bias_factors})
|
|
282
|
+
|
|
283
|
+
The unknown cellular content is then calculated as the difference of per-sample overall expression levels in the true vs. reconstructed bulk, divided by the overall expression in the true bulk.
|
|
284
|
+
|
|
285
|
+
.. math::
|
|
286
|
+
\text{ukn_cc} = \frac{\text{bulk} - \text{bulk_est}}{\sum_{i=1}^{n} x_i}
|
|
287
|
+
|
|
288
|
+
Finally, the methods corrects (i.e. scales) the cell fraction estimates so that their sum equals 1 - the unknown cellular content and returns this corrected value to the user.
|
|
289
|
+
|
|
290
|
+
.. math::
|
|
291
|
+
\text{estimates_fix} = \frac{\text{estimates}}{\sum_{i=1}^{n} x_i} \times (1 - \text{ukn_cc})
|
|
292
|
+
|
|
293
|
+
Parameters
|
|
294
|
+
----------
|
|
295
|
+
bulk
|
|
296
|
+
The bulk count data for deconvolution, indexed by gene. Normalized by TPM.
|
|
297
|
+
pseudo_signature_cpm
|
|
298
|
+
Averaged sc data, indexed by gene. Normalized by CPM. Contains all genes.
|
|
299
|
+
estimates
|
|
300
|
+
The estimated cell fractions resulting from the deconvolution. Indexed by cell type.
|
|
301
|
+
bias_factors
|
|
302
|
+
The mRNA bias factors of the sc data atlas.
|
|
303
|
+
|
|
304
|
+
Returns
|
|
305
|
+
-------
|
|
306
|
+
pd.Series: The corrected cell fractions, indexed by cell type. Adds an "Unknown" cell type.
|
|
307
|
+
"""
|
|
308
|
+
if estimates.sum() == 0:
|
|
309
|
+
estimates_fix = estimates
|
|
310
|
+
# analysis fails if all cell fractions are zero, so we set the unknown cell content to ß
|
|
311
|
+
estimates_fix.loc["Unknown"] = 0
|
|
312
|
+
return estimates_fix
|
|
313
|
+
|
|
314
|
+
signature = pseudo_signature_cpm.sort_index()
|
|
315
|
+
bulk = bulk.sort_index()
|
|
316
|
+
|
|
317
|
+
# Reconstruct the bulk expression profiles through matrix multiplication
|
|
318
|
+
# of the estimated cell fractions (weighted by the scaling factors) and
|
|
319
|
+
# cell-type-specific expression profiles (i.e. signature)
|
|
320
|
+
bulk_est = pd.Series(np.dot(signature, (estimates.T * bias_factors).T))
|
|
321
|
+
bulk_est.index = signature.index
|
|
322
|
+
|
|
323
|
+
# Calculate the unknown cellular content ad the difference of
|
|
324
|
+
# per-sample overall expression levels in the true vs. reconstructed
|
|
325
|
+
# bulk RNA-seq data, divided by the overall expression in the true bulk
|
|
326
|
+
ukn_cc = (bulk - bulk_est).sum() / (bulk.sum())
|
|
327
|
+
ukn_cc = max(0, ukn_cc)
|
|
328
|
+
# Correct (i.e. scale) the cell fraction estimates so that their sum
|
|
329
|
+
# equals 1 - the unknown cellular content estimated above
|
|
330
|
+
estimates_fix = estimates / estimates.sum() * (1 - ukn_cc)
|
|
331
|
+
estimates_fix.loc["Unknown"] = abs(ukn_cc)
|
|
332
|
+
|
|
333
|
+
return estimates_fix
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: rectanglepy
|
|
3
|
+
Version: 0.0.39
|
|
4
|
+
Summary: A very interesting piece of code
|
|
5
|
+
Project-URL: Documentation, https://rectanglepy.readthedocs.io/
|
|
6
|
+
Project-URL: Source, https://github.com/bernheder/Rectangle
|
|
7
|
+
Project-URL: Home-page, https://github.com/bernheder/Rectangle
|
|
8
|
+
Author: Bernhard Eder
|
|
9
|
+
Maintainer-email: Bernhard Eder <Bernhard.Eder@student.uibk.ac.at>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2023, Bernhard Eder
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Python: >=3.10
|
|
33
|
+
Requires-Dist: loguru
|
|
34
|
+
Requires-Dist: pydeseq2==0.4.1
|
|
35
|
+
Requires-Dist: quadprog==0.1.11
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: bump2version; extra == 'dev'
|
|
38
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
39
|
+
Requires-Dist: twine>=4.0.2; extra == 'dev'
|
|
40
|
+
Provides-Extra: doc
|
|
41
|
+
Requires-Dist: ipykernel; extra == 'doc'
|
|
42
|
+
Requires-Dist: ipython; extra == 'doc'
|
|
43
|
+
Requires-Dist: myst-nb; extra == 'doc'
|
|
44
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == 'doc'
|
|
45
|
+
Requires-Dist: sphinx-book-theme>=1.0.0; extra == 'doc'
|
|
46
|
+
Requires-Dist: sphinx-copybutton; extra == 'doc'
|
|
47
|
+
Requires-Dist: sphinx>=4; extra == 'doc'
|
|
48
|
+
Requires-Dist: sphinxcontrib-bibtex>=1.0.0; extra == 'doc'
|
|
49
|
+
Provides-Extra: test
|
|
50
|
+
Requires-Dist: pytest; extra == 'test'
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# Rectangle
|
|
54
|
+
|
|
55
|
+
[![Tests][badge-tests]][link-tests]
|
|
56
|
+
[![Documentation][badge-docs]][link-docs]
|
|
57
|
+
|
|
58
|
+
[badge-tests]: https://img.shields.io/github/actions/workflow/status/bernheder/Rectangle/test.yaml?branch=main
|
|
59
|
+
[link-tests]: https://github.com/bernheder/Rectangle/actions/workflows/test.yml
|
|
60
|
+
[badge-docs]: https://img.shields.io/readthedocs/Rectangle
|
|
61
|
+
|
|
62
|
+
Rectangle embodies a ”second-generation” deconvolution methodology, setting itself apart from other second-generation
|
|
63
|
+
methods through its efficiency in signature creation and its handling of challenges within the deconvolution process.
|
|
64
|
+
To establish a precise deconvolution method, we employ a hierarchical analysis approach, incorporate mRNA bias
|
|
65
|
+
correction, and provide an estimation of unknown cellular content.
|
|
66
|
+
|
|
67
|
+
## Getting started
|
|
68
|
+
|
|
69
|
+
Please refer to the [documentation][link-docs]. In particular, the
|
|
70
|
+
|
|
71
|
+
- [API documentation][link-api].
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
You need to have Python 3.10 or newer installed on your system. If you don't have
|
|
76
|
+
Python installed, we recommend installing [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge).
|
|
77
|
+
|
|
78
|
+
How to install Rectangle:
|
|
79
|
+
|
|
80
|
+
<!--
|
|
81
|
+
1) Install the latest release of `Rectangle` from `PyPI <https://pypi.org/project/rectanglepy/>`_:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install rectanglepy
|
|
85
|
+
```
|
|
86
|
+
-->
|
|
87
|
+
|
|
88
|
+
## Release notes
|
|
89
|
+
|
|
90
|
+
See the [changelog][changelog].
|
|
91
|
+
|
|
92
|
+
## Contact
|
|
93
|
+
|
|
94
|
+
If you found a bug, please use the [issue tracker][issue-tracker].
|
|
95
|
+
|
|
96
|
+
## Citation
|
|
97
|
+
|
|
98
|
+
> t.b.a
|
|
99
|
+
|
|
100
|
+
[scverse-discourse]: https://discourse.scverse.org/
|
|
101
|
+
[issue-tracker]: https://github.com/bernheder/Rectangle/issues
|
|
102
|
+
[changelog]: https://Rectanglepy.readthedocs.io/latest/changelog.html
|
|
103
|
+
[link-docs]: https://Rectanglepy.readthedocs.io
|
|
104
|
+
[link-api]: https://Rectanglepy.readthedocs.io/latest/api.html
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
rectanglepy/__init__.py,sha256=WntxT4hQzXFIGQOVxYG_kag47PO8VygUBQMQLem6xak,211
|
|
2
|
+
rectanglepy/rectangle.py,sha256=yTkdrM4KWLvPQMa2so-FfevpYhcj-McHZ3KGPXpbm7o,4732
|
|
3
|
+
rectanglepy/data/hao1_annotations_small.csv,sha256=uV1IB3xKS7SyUvxO2LxJ-zkG8DDLRb8cFPNfB8OcB4s,2896
|
|
4
|
+
rectanglepy/data/hao1_counts_small.csv,sha256=H-LAZQfRmMsXYgflOmpvooa-jIGKgJvBXeNzKdJStdU,2694169
|
|
5
|
+
rectanglepy/data/small_fino_bulks.csv,sha256=vBdUCVOww7vzQh-ECIt9HKpF1wkeFRYOVOPgI4mlYzk,91148
|
|
6
|
+
rectanglepy/pp/__init__.py,sha256=aEhro1Qq8ZAqMUaOxgLbuvSGRk5VhLxIkbnjV6vr1qk,185
|
|
7
|
+
rectanglepy/pp/create_signature.py,sha256=hrvSAom0wZaNc1HOD0U0GVXH2eNm7ZbF3RAKiEvTdB4,19253
|
|
8
|
+
rectanglepy/pp/rectangle_signature.py,sha256=8qxHLy_im9UX2miCVRHE9nn7IHwLExLlkQz9krDYc_Y,3468
|
|
9
|
+
rectanglepy/tl/__init__.py,sha256=0GCo2syQrjTZ4GJtj2qiFDiBIi3mUd-SBU6SSc7N7EA,80
|
|
10
|
+
rectanglepy/tl/deconvolution.py,sha256=hKZkhzZUcLk-GRdL2f7_jHvCz1CaDmfUvu0gkJVNH9k,14808
|
|
11
|
+
rectanglepy-0.0.39.dist-info/METADATA,sha256=oiib2qv_GEDnvKDMdIc3tkCUeygzFBMctQBPwjqHlUg,4113
|
|
12
|
+
rectanglepy-0.0.39.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
|
|
13
|
+
rectanglepy-0.0.39.dist-info/licenses/LICENSE,sha256=uMoqBtwv3v_iNXuN-0ShGN4XVvdx7K7-SvcCmLVg_I0,1071
|
|
14
|
+
rectanglepy-0.0.39.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023, Bernhard Eder
|
|
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.
|