scMultiChat 0.1.0__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.
- MultiChat/Analysis/Intra_strength.py +1758 -0
- MultiChat/Analysis/Processing.py +152 -0
- MultiChat/Analysis/__init__.py +2 -0
- MultiChat/Heterogeneous_g_emb/__init__.py +13 -0
- MultiChat/Heterogeneous_g_emb/_settings.py +156 -0
- MultiChat/Heterogeneous_g_emb/_utils.py +143 -0
- MultiChat/Heterogeneous_g_emb/_version.py +3 -0
- MultiChat/Heterogeneous_g_emb/plotting/__init__.py +19 -0
- MultiChat/Heterogeneous_g_emb/plotting/_palettes.py +180 -0
- MultiChat/Heterogeneous_g_emb/plotting/_plot.py +1498 -0
- MultiChat/Heterogeneous_g_emb/plotting/_post_training.py +742 -0
- MultiChat/Heterogeneous_g_emb/plotting/_utils.py +103 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/__init__.py +26 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/_general.py +91 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/_pca.py +182 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/_qc.py +727 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/_utils.py +60 -0
- MultiChat/Heterogeneous_g_emb/preprocessing/_variable_genes.py +82 -0
- MultiChat/Heterogeneous_g_emb/readwrite.py +250 -0
- MultiChat/Heterogeneous_g_emb/tools/__init__.py +23 -0
- MultiChat/Heterogeneous_g_emb/tools/_gene_scores.py +346 -0
- MultiChat/Heterogeneous_g_emb/tools/_general.py +71 -0
- MultiChat/Heterogeneous_g_emb/tools/_integration.py +197 -0
- MultiChat/Heterogeneous_g_emb/tools/_pbg.py +1184 -0
- MultiChat/Heterogeneous_g_emb/tools/_post_training.py +919 -0
- MultiChat/Heterogeneous_g_emb/tools/_umap.py +58 -0
- MultiChat/Heterogeneous_g_emb/tools/_utils.py +253 -0
- MultiChat/Model/Layers.py +116 -0
- MultiChat/Model/__init__.py +3 -0
- MultiChat/Model/model_training.py +166 -0
- MultiChat/Model/modules.py +93 -0
- MultiChat/Model/utilities.py +234 -0
- MultiChat/Plot/Visualization.py +470 -0
- MultiChat/Plot/__init__.py +1 -0
- MultiChat/__init__.py +12 -0
- scmultichat-0.1.0.dist-info/METADATA +156 -0
- scmultichat-0.1.0.dist-info/RECORD +39 -0
- scmultichat-0.1.0.dist-info/WHEEL +5 -0
- scmultichat-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
"""Quality Control"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.sparse import (
|
|
5
|
+
issparse,
|
|
6
|
+
csr_matrix,
|
|
7
|
+
)
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def cal_qc(adata, expr_cutoff=1):
|
|
12
|
+
"""Calculate quality control metrics.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
adata: AnnData
|
|
17
|
+
Annotated data matrix.
|
|
18
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
19
|
+
Expression cutoff.
|
|
20
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
21
|
+
assay: `str`, optional (default: 'rna')
|
|
22
|
+
Choose from {'rna','atac'},case insensitive
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
updates `adata` with the following fields.
|
|
26
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
27
|
+
The number of read count each gene has.
|
|
28
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
29
|
+
The number of cells in which each gene is expressed.
|
|
30
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
31
|
+
The percentage of cells in which each gene is expressed.
|
|
32
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
33
|
+
The number of read count each cell has.
|
|
34
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
35
|
+
The number of genes expressed in each cell.
|
|
36
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
37
|
+
The percentage of genes expressed in each cell.
|
|
38
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
39
|
+
The number of peaks expressed in each cell.
|
|
40
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
41
|
+
The percentage of peaks expressed in each cell.
|
|
42
|
+
pct_mt: `pandas.Series` (`adata.obs['pct_mt']`,dtype `float`)
|
|
43
|
+
the percentage of counts in mitochondrial genes
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
if not issparse(adata.X):
|
|
47
|
+
adata.X = csr_matrix(adata.X)
|
|
48
|
+
|
|
49
|
+
n_counts = adata.X.sum(axis=0).A1
|
|
50
|
+
adata.var['n_counts'] = n_counts
|
|
51
|
+
n_samples = (adata.X >= expr_cutoff).sum(axis=0).A1
|
|
52
|
+
adata.var['n_samples'] = n_samples
|
|
53
|
+
adata.var['pct_samples'] = n_samples/adata.shape[0]
|
|
54
|
+
|
|
55
|
+
n_counts = adata.X.sum(axis=1).A1
|
|
56
|
+
adata.obs['n_counts'] = n_counts
|
|
57
|
+
n_features = (adata.X >= expr_cutoff).sum(axis=1).A1
|
|
58
|
+
adata.obs['n_features'] = n_features
|
|
59
|
+
adata.obs['pct_features'] = n_features/adata.shape[1]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cal_qc_rna(adata, expr_cutoff=1):
|
|
63
|
+
"""Calculate quality control metrics.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
adata: AnnData
|
|
68
|
+
Annotated data matrix.
|
|
69
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
70
|
+
Expression cutoff.
|
|
71
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
72
|
+
assay: `str`, optional (default: 'rna')
|
|
73
|
+
Choose from {'rna','atac'},case insensitive
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
updates `adata` with the following fields.
|
|
77
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
78
|
+
The number of read count each gene has.
|
|
79
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
80
|
+
The number of cells in which each gene is expressed.
|
|
81
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
82
|
+
The percentage of cells in which each gene is expressed.
|
|
83
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
84
|
+
The number of read count each cell has.
|
|
85
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
86
|
+
The number of genes expressed in each cell.
|
|
87
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
88
|
+
The percentage of genes expressed in each cell.
|
|
89
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
90
|
+
The number of peaks expressed in each cell.
|
|
91
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
92
|
+
The percentage of peaks expressed in each cell.
|
|
93
|
+
pct_mt: `pandas.Series` (`adata.obs['pct_mt']`,dtype `float`)
|
|
94
|
+
the percentage of counts in mitochondrial genes
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
if not issparse(adata.X):
|
|
98
|
+
adata.X = csr_matrix(adata.X)
|
|
99
|
+
|
|
100
|
+
n_counts = adata.X.sum(axis=0).A1
|
|
101
|
+
adata.var['n_counts'] = n_counts
|
|
102
|
+
n_cells = (adata.X >= expr_cutoff).sum(axis=0).A1
|
|
103
|
+
adata.var['n_cells'] = n_cells
|
|
104
|
+
adata.var['pct_cells'] = n_cells/adata.shape[0]
|
|
105
|
+
|
|
106
|
+
n_counts = adata.X.sum(axis=1).A1
|
|
107
|
+
adata.obs['n_counts'] = n_counts
|
|
108
|
+
n_features = (adata.X >= expr_cutoff).sum(axis=1).A1
|
|
109
|
+
adata.obs['n_genes'] = n_features
|
|
110
|
+
adata.obs['pct_genes'] = n_features/adata.shape[1]
|
|
111
|
+
r = re.compile("^MT-", flags=re.IGNORECASE)
|
|
112
|
+
mt_genes = list(filter(r.match, adata.var_names))
|
|
113
|
+
if len(mt_genes) > 0:
|
|
114
|
+
n_counts_mt = adata[:, mt_genes].X.sum(axis=1).A1
|
|
115
|
+
adata.obs['pct_mt'] = n_counts_mt/n_counts
|
|
116
|
+
else:
|
|
117
|
+
adata.obs['pct_mt'] = 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def cal_qc_atac(adata, expr_cutoff=1):
|
|
121
|
+
"""Calculate quality control metrics.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
adata: AnnData
|
|
126
|
+
Annotated data matrix.
|
|
127
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
128
|
+
Expression cutoff.
|
|
129
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
130
|
+
assay: `str`, optional (default: 'rna')
|
|
131
|
+
Choose from {'rna','atac'},case insensitive
|
|
132
|
+
Returns
|
|
133
|
+
-------
|
|
134
|
+
updates `adata` with the following fields.
|
|
135
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
136
|
+
The number of read count each gene has.
|
|
137
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
138
|
+
The number of cells in which each gene is expressed.
|
|
139
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
140
|
+
The percentage of cells in which each gene is expressed.
|
|
141
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
142
|
+
The number of read count each cell has.
|
|
143
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
144
|
+
The number of genes expressed in each cell.
|
|
145
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
146
|
+
The percentage of genes expressed in each cell.
|
|
147
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
148
|
+
The number of peaks expressed in each cell.
|
|
149
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
150
|
+
The percentage of peaks expressed in each cell.
|
|
151
|
+
pct_mt: `pandas.Series` (`adata.obs['pct_mt']`,dtype `float`)
|
|
152
|
+
the percentage of counts in mitochondrial genes
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
if not issparse(adata.X):
|
|
156
|
+
adata.X = csr_matrix(adata.X)
|
|
157
|
+
|
|
158
|
+
n_counts = adata.X.sum(axis=0).A1
|
|
159
|
+
adata.var['n_counts'] = n_counts
|
|
160
|
+
n_cells = (adata.X >= expr_cutoff).sum(axis=0).A1
|
|
161
|
+
adata.var['n_cells'] = n_cells
|
|
162
|
+
adata.var['pct_cells'] = n_cells/adata.shape[0]
|
|
163
|
+
|
|
164
|
+
n_counts = adata.X.sum(axis=1).A1
|
|
165
|
+
adata.obs['n_counts'] = n_counts
|
|
166
|
+
n_features = (adata.X >= expr_cutoff).sum(axis=1).A1
|
|
167
|
+
adata.obs['n_peaks'] = n_features
|
|
168
|
+
adata.obs['pct_peaks'] = n_features/adata.shape[1]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def filter_samples(adata,
|
|
172
|
+
min_n_features=1,
|
|
173
|
+
max_n_features=None,
|
|
174
|
+
min_pct_features=None,
|
|
175
|
+
max_pct_features=None,
|
|
176
|
+
min_n_counts=None,
|
|
177
|
+
max_n_counts=None,
|
|
178
|
+
expr_cutoff=1):
|
|
179
|
+
"""Filter out samples based on different metrics.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
adata: AnnData
|
|
184
|
+
Annotated data matrix.
|
|
185
|
+
min_n_features: `int`, optional (default: None)
|
|
186
|
+
Minimum number of features expressed
|
|
187
|
+
min_pct_features: `float`, optional (default: None)
|
|
188
|
+
Minimum percentage of features expressed
|
|
189
|
+
min_n_counts: `int`, optional (default: None)
|
|
190
|
+
Minimum number of read count for one cell
|
|
191
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
192
|
+
Expression cutoff.
|
|
193
|
+
If greater than expr_cutoff,the gene is considered 'expressed'
|
|
194
|
+
assay: `str`, optional (default: 'rna')
|
|
195
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
updates `adata` with a subset of cells that pass the filtering.
|
|
199
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
200
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
201
|
+
The number of read count each cell has.
|
|
202
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
203
|
+
The number of genes expressed in each cell.
|
|
204
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
205
|
+
The percentage of genes expressed in each cell.
|
|
206
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
207
|
+
The number of peaks expressed in each cell.
|
|
208
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
209
|
+
The percentage of peaks expressed in each cell.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
if not issparse(adata.X):
|
|
213
|
+
adata.X = csr_matrix(adata.X)
|
|
214
|
+
if 'n_counts' in adata.obs_keys():
|
|
215
|
+
n_counts = adata.obs['n_counts']
|
|
216
|
+
else:
|
|
217
|
+
n_counts = np.sum(adata.X, axis=1).A
|
|
218
|
+
adata.obs['n_counts'] = n_counts
|
|
219
|
+
if 'n_features' in adata.obs_keys():
|
|
220
|
+
n_features = adata.obs['n_features']
|
|
221
|
+
else:
|
|
222
|
+
n_features = np.sum(adata.X >= expr_cutoff, axis=1).A1
|
|
223
|
+
adata.obs['n_features'] = n_features
|
|
224
|
+
if 'pct_features' in adata.obs_keys():
|
|
225
|
+
pct_features = adata.obs['pct_features']
|
|
226
|
+
else:
|
|
227
|
+
pct_features = n_features/adata.shape[1]
|
|
228
|
+
adata.obs['pct_features'] = pct_features
|
|
229
|
+
|
|
230
|
+
print('before filtering: ')
|
|
231
|
+
print(f"{adata.shape[0]} samples, {adata.shape[1]} feature")
|
|
232
|
+
if sum(list(map(lambda x: x is None,
|
|
233
|
+
[min_n_features,
|
|
234
|
+
min_pct_features,
|
|
235
|
+
min_n_counts,
|
|
236
|
+
max_n_features,
|
|
237
|
+
max_pct_features,
|
|
238
|
+
max_n_counts]))) == 6:
|
|
239
|
+
print('No filtering')
|
|
240
|
+
else:
|
|
241
|
+
cell_subset = np.ones(len(adata.obs_names), dtype=bool)
|
|
242
|
+
if min_n_features is not None:
|
|
243
|
+
print('filter samples based on min_n_features')
|
|
244
|
+
cell_subset = (n_features >= min_n_features) & cell_subset
|
|
245
|
+
if max_n_features is not None:
|
|
246
|
+
print('filter samples based on max_n_features')
|
|
247
|
+
cell_subset = (n_features <= max_n_features) & cell_subset
|
|
248
|
+
if min_pct_features is not None:
|
|
249
|
+
print('filter samples based on min_pct_features')
|
|
250
|
+
cell_subset = (pct_features >= min_pct_features) & cell_subset
|
|
251
|
+
if max_pct_features is not None:
|
|
252
|
+
print('filter samples based on max_pct_features')
|
|
253
|
+
cell_subset = (pct_features <= max_pct_features) & cell_subset
|
|
254
|
+
if min_n_counts is not None:
|
|
255
|
+
print('filter samples based on min_n_counts')
|
|
256
|
+
cell_subset = (n_counts >= min_n_counts) & cell_subset
|
|
257
|
+
if max_n_counts is not None:
|
|
258
|
+
print('filter samples based on max_n_counts')
|
|
259
|
+
cell_subset = (n_counts <= max_n_counts) & cell_subset
|
|
260
|
+
adata._inplace_subset_obs(cell_subset)
|
|
261
|
+
print('after filtering out low-quality samples: ')
|
|
262
|
+
print(f"{adata.shape[0]} samples, {adata.shape[1]} feature")
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def filter_cells_rna(adata,
|
|
267
|
+
min_n_genes=None,
|
|
268
|
+
max_n_genes=None,
|
|
269
|
+
min_pct_genes=None,
|
|
270
|
+
max_pct_genes=None,
|
|
271
|
+
min_n_counts=None,
|
|
272
|
+
max_n_counts=None,
|
|
273
|
+
expr_cutoff=1):
|
|
274
|
+
"""Filter out cells for RNA-seq based on different metrics.
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
adata: AnnData
|
|
279
|
+
Annotated data matrix.
|
|
280
|
+
min_n_genes: `int`, optional (default: None)
|
|
281
|
+
Minimum number of genes expressed
|
|
282
|
+
min_pct_genes: `float`, optional (default: None)
|
|
283
|
+
Minimum percentage of genes expressed
|
|
284
|
+
min_n_counts: `int`, optional (default: None)
|
|
285
|
+
Minimum number of read count for one cell
|
|
286
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
287
|
+
Expression cutoff.
|
|
288
|
+
If greater than expr_cutoff,the gene is considered 'expressed'
|
|
289
|
+
assay: `str`, optional (default: 'rna')
|
|
290
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
291
|
+
Returns
|
|
292
|
+
-------
|
|
293
|
+
updates `adata` with a subset of cells that pass the filtering.
|
|
294
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
295
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
296
|
+
The number of read count each cell has.
|
|
297
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
298
|
+
The number of genes expressed in each cell.
|
|
299
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
300
|
+
The percentage of genes expressed in each cell.
|
|
301
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
302
|
+
The number of peaks expressed in each cell.
|
|
303
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
304
|
+
The percentage of peaks expressed in each cell.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
if not issparse(adata.X):
|
|
308
|
+
adata.X = csr_matrix(adata.X)
|
|
309
|
+
if 'n_counts' in adata.obs_keys():
|
|
310
|
+
n_counts = adata.obs['n_counts']
|
|
311
|
+
else:
|
|
312
|
+
n_counts = np.sum(adata.X, axis=1).A1
|
|
313
|
+
adata.obs['n_counts'] = n_counts
|
|
314
|
+
|
|
315
|
+
if 'n_genes' in adata.obs_keys():
|
|
316
|
+
n_genes = adata.obs['n_genes']
|
|
317
|
+
else:
|
|
318
|
+
n_genes = np.sum(adata.X >= expr_cutoff, axis=1).A1
|
|
319
|
+
adata.obs['n_genes'] = n_genes
|
|
320
|
+
if 'pct_genes' in adata.obs_keys():
|
|
321
|
+
pct_genes = adata.obs['pct_genes']
|
|
322
|
+
else:
|
|
323
|
+
pct_genes = n_genes/adata.shape[1]
|
|
324
|
+
adata.obs['pct_genes'] = pct_genes
|
|
325
|
+
|
|
326
|
+
print('before filtering: ')
|
|
327
|
+
print(f"{adata.shape[0]} cells, {adata.shape[1]} genes")
|
|
328
|
+
if sum(list(map(lambda x: x is None,
|
|
329
|
+
[min_n_genes,
|
|
330
|
+
min_pct_genes,
|
|
331
|
+
min_n_counts,
|
|
332
|
+
max_n_genes,
|
|
333
|
+
max_pct_genes,
|
|
334
|
+
max_n_counts]))) == 6:
|
|
335
|
+
print('No filtering')
|
|
336
|
+
else:
|
|
337
|
+
cell_subset = np.ones(len(adata.obs_names), dtype=bool)
|
|
338
|
+
if min_n_genes is not None:
|
|
339
|
+
print('filter cells based on min_n_genes')
|
|
340
|
+
cell_subset = (n_genes >= min_n_genes) & cell_subset
|
|
341
|
+
if max_n_genes is not None:
|
|
342
|
+
print('filter cells based on max_n_genes')
|
|
343
|
+
cell_subset = (n_genes <= max_n_genes) & cell_subset
|
|
344
|
+
if min_pct_genes is not None:
|
|
345
|
+
print('filter cells based on min_pct_genes')
|
|
346
|
+
cell_subset = (pct_genes >= min_pct_genes) & cell_subset
|
|
347
|
+
if max_pct_genes is not None:
|
|
348
|
+
print('filter cells based on max_pct_genes')
|
|
349
|
+
cell_subset = (pct_genes <= max_pct_genes) & cell_subset
|
|
350
|
+
if min_n_counts is not None:
|
|
351
|
+
print('filter cells based on min_n_counts')
|
|
352
|
+
cell_subset = (n_counts >= min_n_counts) & cell_subset
|
|
353
|
+
if max_n_counts is not None:
|
|
354
|
+
print('filter cells based on max_n_counts')
|
|
355
|
+
cell_subset = (n_counts <= max_n_counts) & cell_subset
|
|
356
|
+
adata._inplace_subset_obs(cell_subset)
|
|
357
|
+
print('after filtering out low-quality cells: ')
|
|
358
|
+
print(f"{adata.shape[0]} cells, {adata.shape[1]} genes")
|
|
359
|
+
return None
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def filter_cells_atac(adata,
|
|
363
|
+
min_n_peaks=None,
|
|
364
|
+
max_n_peaks=None,
|
|
365
|
+
min_pct_peaks=None,
|
|
366
|
+
max_pct_peaks=None,
|
|
367
|
+
min_n_counts=None,
|
|
368
|
+
max_n_counts=None,
|
|
369
|
+
expr_cutoff=1):
|
|
370
|
+
"""Filter out cells for ATAC-seq based on different metrics.
|
|
371
|
+
|
|
372
|
+
Parameters
|
|
373
|
+
----------
|
|
374
|
+
adata: AnnData
|
|
375
|
+
Annotated data matrix.
|
|
376
|
+
min_n_peaks: `int`, optional (default: None)
|
|
377
|
+
Minimum number of peaks expressed
|
|
378
|
+
min_pct_peaks: `float`, optional (default: None)
|
|
379
|
+
Minimum percentage of peaks expressed
|
|
380
|
+
min_n_counts: `int`, optional (default: None)
|
|
381
|
+
Minimum number of read count for one cell
|
|
382
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
383
|
+
Expression cutoff.
|
|
384
|
+
If greater than expr_cutoff,the gene is considered 'expressed'
|
|
385
|
+
assay: `str`, optional (default: 'rna')
|
|
386
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
387
|
+
Returns
|
|
388
|
+
-------
|
|
389
|
+
updates `adata` with a subset of cells that pass the filtering.
|
|
390
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
391
|
+
n_counts: `pandas.Series` (`adata.obs['n_counts']`,dtype `int`)
|
|
392
|
+
The number of read count each cell has.
|
|
393
|
+
n_genes: `pandas.Series` (`adata.obs['n_genes']`,dtype `int`)
|
|
394
|
+
The number of genes expressed in each cell.
|
|
395
|
+
pct_genes: `pandas.Series` (`adata.obs['pct_genes']`,dtype `float`)
|
|
396
|
+
The percentage of genes expressed in each cell.
|
|
397
|
+
n_peaks: `pandas.Series` (`adata.obs['n_peaks']`,dtype `int`)
|
|
398
|
+
The number of peaks expressed in each cell.
|
|
399
|
+
pct_peaks: `pandas.Series` (`adata.obs['pct_peaks']`,dtype `int`)
|
|
400
|
+
The percentage of peaks expressed in each cell.
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
if not issparse(adata.X):
|
|
404
|
+
adata.X = csr_matrix(adata.X)
|
|
405
|
+
if 'n_counts' in adata.obs_keys():
|
|
406
|
+
n_counts = adata.obs['n_counts']
|
|
407
|
+
else:
|
|
408
|
+
n_counts = np.sum(adata.X, axis=1).A1
|
|
409
|
+
adata.obs['n_counts'] = n_counts
|
|
410
|
+
|
|
411
|
+
if 'n_peaks' in adata.obs_keys():
|
|
412
|
+
n_peaks = adata.obs['n_peaks']
|
|
413
|
+
else:
|
|
414
|
+
n_peaks = np.sum(adata.X >= expr_cutoff, axis=1).A1
|
|
415
|
+
adata.obs['n_peaks'] = n_peaks
|
|
416
|
+
if 'pct_peaks' in adata.obs_keys():
|
|
417
|
+
pct_peaks = adata.obs['pct_peaks']
|
|
418
|
+
else:
|
|
419
|
+
pct_peaks = n_peaks/adata.shape[1]
|
|
420
|
+
adata.obs['pct_peaks'] = pct_peaks
|
|
421
|
+
|
|
422
|
+
print('before filtering: ')
|
|
423
|
+
print(f"{adata.shape[0]} cells, {adata.shape[1]} peaks")
|
|
424
|
+
if sum(list(map(lambda x: x is None,
|
|
425
|
+
[min_n_peaks,
|
|
426
|
+
min_pct_peaks,
|
|
427
|
+
min_n_counts,
|
|
428
|
+
max_n_peaks,
|
|
429
|
+
max_pct_peaks,
|
|
430
|
+
max_n_counts]))) == 6:
|
|
431
|
+
print('No filtering')
|
|
432
|
+
else:
|
|
433
|
+
cell_subset = np.ones(len(adata.obs_names), dtype=bool)
|
|
434
|
+
if min_n_peaks is not None:
|
|
435
|
+
print('filter cells based on min_n_peaks')
|
|
436
|
+
cell_subset = (n_peaks >= min_n_peaks) & cell_subset
|
|
437
|
+
if max_n_peaks is not None:
|
|
438
|
+
print('filter cells based on max_n_peaks')
|
|
439
|
+
cell_subset = (n_peaks <= max_n_peaks) & cell_subset
|
|
440
|
+
if min_pct_peaks is not None:
|
|
441
|
+
print('filter cells based on min_pct_peaks')
|
|
442
|
+
cell_subset = (pct_peaks >= min_pct_peaks) & cell_subset
|
|
443
|
+
if max_pct_peaks is not None:
|
|
444
|
+
print('filter cells based on max_pct_peaks')
|
|
445
|
+
cell_subset = (pct_peaks <= max_pct_peaks) & cell_subset
|
|
446
|
+
if min_n_counts is not None:
|
|
447
|
+
print('filter cells based on min_n_counts')
|
|
448
|
+
cell_subset = (n_counts >= min_n_counts) & cell_subset
|
|
449
|
+
if max_n_counts is not None:
|
|
450
|
+
print('filter cells based on max_n_counts')
|
|
451
|
+
cell_subset = (n_counts <= max_n_counts) & cell_subset
|
|
452
|
+
adata._inplace_subset_obs(cell_subset)
|
|
453
|
+
print('after filtering out low-quality cells: ')
|
|
454
|
+
print(f"{adata.shape[0]} cells, {adata.shape[1]} peaks")
|
|
455
|
+
return None
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def filter_genes(adata,
|
|
459
|
+
min_n_cells=3,
|
|
460
|
+
max_n_cells=None,
|
|
461
|
+
min_pct_cells=None,
|
|
462
|
+
max_pct_cells=None,
|
|
463
|
+
min_n_counts=None,
|
|
464
|
+
max_n_counts=None,
|
|
465
|
+
expr_cutoff=1):
|
|
466
|
+
"""Filter out features based on different metrics.
|
|
467
|
+
|
|
468
|
+
Parameters
|
|
469
|
+
----------
|
|
470
|
+
adata: AnnData
|
|
471
|
+
Annotated data matrix.
|
|
472
|
+
min_n_cells: `int`, optional (default: 5)
|
|
473
|
+
Minimum number of cells expressing one feature
|
|
474
|
+
min_pct_cells: `float`, optional (default: None)
|
|
475
|
+
Minimum percentage of cells expressing one feature
|
|
476
|
+
min_n_counts: `int`, optional (default: None)
|
|
477
|
+
Minimum number of read count for one feature
|
|
478
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
479
|
+
Expression cutoff.
|
|
480
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
481
|
+
assay: `str`, optional (default: 'rna')
|
|
482
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
483
|
+
|
|
484
|
+
Returns
|
|
485
|
+
-------
|
|
486
|
+
updates `adata` with a subset of features that pass the filtering.
|
|
487
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
488
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
489
|
+
The number of read count each gene has.
|
|
490
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
491
|
+
The number of cells in which each gene is expressed.
|
|
492
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
493
|
+
The percentage of cells in which each gene is expressed.
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
feature = 'genes'
|
|
497
|
+
if not issparse(adata.X):
|
|
498
|
+
adata.X = csr_matrix(adata.X)
|
|
499
|
+
|
|
500
|
+
if 'n_counts' in adata.var_keys():
|
|
501
|
+
n_counts = adata.var['n_counts']
|
|
502
|
+
else:
|
|
503
|
+
n_counts = np.sum(adata.X, axis=0).A1
|
|
504
|
+
adata.var['n_counts'] = n_counts
|
|
505
|
+
if 'n_cells' in adata.var_keys():
|
|
506
|
+
n_cells = adata.var['n_cells']
|
|
507
|
+
else:
|
|
508
|
+
n_cells = np.sum(adata.X >= expr_cutoff, axis=0).A1
|
|
509
|
+
adata.var['n_cells'] = n_cells
|
|
510
|
+
if 'pct_cells' in adata.var_keys():
|
|
511
|
+
pct_cells = adata.var['pct_cells']
|
|
512
|
+
else:
|
|
513
|
+
pct_cells = n_cells/adata.shape[0]
|
|
514
|
+
adata.var['pct_cells'] = pct_cells
|
|
515
|
+
|
|
516
|
+
print('Before filtering: ')
|
|
517
|
+
print(str(adata.shape[0])+' cells, ' + str(adata.shape[1])+' '+feature)
|
|
518
|
+
if sum(list(map(lambda x: x is None,
|
|
519
|
+
[min_n_cells, min_pct_cells, min_n_counts,
|
|
520
|
+
max_n_cells, max_pct_cells, max_n_counts,
|
|
521
|
+
]))) == 6:
|
|
522
|
+
print('No filtering')
|
|
523
|
+
else:
|
|
524
|
+
feature_subset = np.ones(len(adata.var_names), dtype=bool)
|
|
525
|
+
if min_n_cells is not None:
|
|
526
|
+
print('Filter '+feature+' based on min_n_cells')
|
|
527
|
+
feature_subset = (n_cells >= min_n_cells) & feature_subset
|
|
528
|
+
if max_n_cells is not None:
|
|
529
|
+
print('Filter '+feature+' based on max_n_cells')
|
|
530
|
+
feature_subset = (n_cells <= max_n_cells) & feature_subset
|
|
531
|
+
if min_pct_cells is not None:
|
|
532
|
+
print('Filter '+feature+' based on min_pct_cells')
|
|
533
|
+
feature_subset = (pct_cells >= min_pct_cells) & feature_subset
|
|
534
|
+
if max_pct_cells is not None:
|
|
535
|
+
print('Filter '+feature+' based on max_pct_cells')
|
|
536
|
+
feature_subset = (pct_cells <= max_pct_cells) & feature_subset
|
|
537
|
+
if min_n_counts is not None:
|
|
538
|
+
print('Filter '+feature+' based on min_n_counts')
|
|
539
|
+
feature_subset = (n_counts >= min_n_counts) & feature_subset
|
|
540
|
+
if max_n_counts is not None:
|
|
541
|
+
print('Filter '+feature+' based on max_n_counts')
|
|
542
|
+
feature_subset = (n_counts <= max_n_counts) & feature_subset
|
|
543
|
+
adata._inplace_subset_var(feature_subset)
|
|
544
|
+
print('After filtering out low-expressed '+feature+': ')
|
|
545
|
+
print(str(adata.shape[0])+' cells, ' + str(adata.shape[1])+' '+feature)
|
|
546
|
+
return None
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def filter_peaks(adata,
|
|
550
|
+
min_n_cells=5,
|
|
551
|
+
max_n_cells=None,
|
|
552
|
+
min_pct_cells=None,
|
|
553
|
+
max_pct_cells=None,
|
|
554
|
+
min_n_counts=None,
|
|
555
|
+
max_n_counts=None,
|
|
556
|
+
expr_cutoff=1):
|
|
557
|
+
"""Filter out features based on different metrics.
|
|
558
|
+
|
|
559
|
+
Parameters
|
|
560
|
+
----------
|
|
561
|
+
adata: AnnData
|
|
562
|
+
Annotated data matrix.
|
|
563
|
+
min_n_cells: `int`, optional (default: 5)
|
|
564
|
+
Minimum number of cells expressing one feature
|
|
565
|
+
min_pct_cells: `float`, optional (default: None)
|
|
566
|
+
Minimum percentage of cells expressing one feature
|
|
567
|
+
min_n_counts: `int`, optional (default: None)
|
|
568
|
+
Minimum number of read count for one feature
|
|
569
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
570
|
+
Expression cutoff.
|
|
571
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
572
|
+
assay: `str`, optional (default: 'rna')
|
|
573
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
574
|
+
|
|
575
|
+
Returns
|
|
576
|
+
-------
|
|
577
|
+
updates `adata` with a subset of features that pass the filtering.
|
|
578
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
579
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
580
|
+
The number of read count each gene has.
|
|
581
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
582
|
+
The number of cells in which each gene is expressed.
|
|
583
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
584
|
+
The percentage of cells in which each gene is expressed.
|
|
585
|
+
"""
|
|
586
|
+
|
|
587
|
+
feature = 'peaks'
|
|
588
|
+
if not issparse(adata.X):
|
|
589
|
+
adata.X = csr_matrix(adata.X)
|
|
590
|
+
|
|
591
|
+
if 'n_counts' in adata.var_keys():
|
|
592
|
+
n_counts = adata.var['n_counts']
|
|
593
|
+
else:
|
|
594
|
+
n_counts = np.sum(adata.X, axis=0).A1
|
|
595
|
+
adata.var['n_counts'] = n_counts
|
|
596
|
+
if 'n_cells' in adata.var_keys():
|
|
597
|
+
n_cells = adata.var['n_cells']
|
|
598
|
+
else:
|
|
599
|
+
n_cells = np.sum(adata.X >= expr_cutoff, axis=0).A1
|
|
600
|
+
adata.var['n_cells'] = n_cells
|
|
601
|
+
if 'pct_cells' in adata.var_keys():
|
|
602
|
+
pct_cells = adata.var['pct_cells']
|
|
603
|
+
else:
|
|
604
|
+
pct_cells = n_cells/adata.shape[0]
|
|
605
|
+
adata.var['pct_cells'] = pct_cells
|
|
606
|
+
|
|
607
|
+
print('Before filtering: ')
|
|
608
|
+
print(str(adata.shape[0])+' cells, ' + str(adata.shape[1])+' '+feature)
|
|
609
|
+
if sum(list(map(lambda x: x is None,
|
|
610
|
+
[min_n_cells, min_pct_cells, min_n_counts,
|
|
611
|
+
max_n_cells, max_pct_cells, max_n_counts,
|
|
612
|
+
]))) == 6:
|
|
613
|
+
print('No filtering')
|
|
614
|
+
else:
|
|
615
|
+
feature_subset = np.ones(len(adata.var_names), dtype=bool)
|
|
616
|
+
if min_n_cells is not None:
|
|
617
|
+
print('Filter '+feature+' based on min_n_cells')
|
|
618
|
+
feature_subset = (n_cells >= min_n_cells) & feature_subset
|
|
619
|
+
if max_n_cells is not None:
|
|
620
|
+
print('Filter '+feature+' based on max_n_cells')
|
|
621
|
+
feature_subset = (n_cells <= max_n_cells) & feature_subset
|
|
622
|
+
if min_pct_cells is not None:
|
|
623
|
+
print('Filter '+feature+' based on min_pct_cells')
|
|
624
|
+
feature_subset = (pct_cells >= min_pct_cells) & feature_subset
|
|
625
|
+
if max_pct_cells is not None:
|
|
626
|
+
print('Filter '+feature+' based on max_pct_cells')
|
|
627
|
+
feature_subset = (pct_cells <= max_pct_cells) & feature_subset
|
|
628
|
+
if min_n_counts is not None:
|
|
629
|
+
print('Filter '+feature+' based on min_n_counts')
|
|
630
|
+
feature_subset = (n_counts >= min_n_counts) & feature_subset
|
|
631
|
+
if max_n_counts is not None:
|
|
632
|
+
print('Filter '+feature+' based on max_n_counts')
|
|
633
|
+
feature_subset = (n_counts <= max_n_counts) & feature_subset
|
|
634
|
+
adata._inplace_subset_var(feature_subset)
|
|
635
|
+
print('After filtering out low-expressed '+feature+': ')
|
|
636
|
+
print(str(adata.shape[0])+' cells, ' + str(adata.shape[1])+' '+feature)
|
|
637
|
+
return None
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
def filter_features(adata,
|
|
641
|
+
min_n_samples=5,
|
|
642
|
+
max_n_samples=None,
|
|
643
|
+
min_pct_samples=None,
|
|
644
|
+
max_pct_samples=None,
|
|
645
|
+
min_n_counts=None,
|
|
646
|
+
max_n_counts=None,
|
|
647
|
+
expr_cutoff=1):
|
|
648
|
+
"""Filter out features based on different metrics.
|
|
649
|
+
|
|
650
|
+
Parameters
|
|
651
|
+
----------
|
|
652
|
+
adata: AnnData
|
|
653
|
+
Annotated data matrix.
|
|
654
|
+
min_n_cells: `int`, optional (default: 5)
|
|
655
|
+
Minimum number of cells expressing one feature
|
|
656
|
+
min_pct_cells: `float`, optional (default: None)
|
|
657
|
+
Minimum percentage of cells expressing one feature
|
|
658
|
+
min_n_counts: `int`, optional (default: None)
|
|
659
|
+
Minimum number of read count for one feature
|
|
660
|
+
expr_cutoff: `float`, optional (default: 1)
|
|
661
|
+
Expression cutoff.
|
|
662
|
+
If greater than expr_cutoff,the feature is considered 'expressed'
|
|
663
|
+
assay: `str`, optional (default: 'rna')
|
|
664
|
+
Choose from {{'rna','atac'}},case insensitive
|
|
665
|
+
|
|
666
|
+
Returns
|
|
667
|
+
-------
|
|
668
|
+
updates `adata` with a subset of features that pass the filtering.
|
|
669
|
+
updates `adata` with the following fields if cal_qc() was not performed.
|
|
670
|
+
n_counts: `pandas.Series` (`adata.var['n_counts']`,dtype `int`)
|
|
671
|
+
The number of read count each gene has.
|
|
672
|
+
n_cells: `pandas.Series` (`adata.var['n_cells']`,dtype `int`)
|
|
673
|
+
The number of cells in which each gene is expressed.
|
|
674
|
+
pct_cells: `pandas.Series` (`adata.var['pct_cells']`,dtype `float`)
|
|
675
|
+
The percentage of cells in which each gene is expressed.
|
|
676
|
+
"""
|
|
677
|
+
|
|
678
|
+
if not issparse(adata.X):
|
|
679
|
+
adata.X = csr_matrix(adata.X)
|
|
680
|
+
if 'n_counts' in adata.var_keys():
|
|
681
|
+
n_counts = adata.var['n_counts']
|
|
682
|
+
else:
|
|
683
|
+
n_counts = np.sum(adata.X, axis=0).A1
|
|
684
|
+
adata.var['n_counts'] = n_counts
|
|
685
|
+
if 'n_samples' in adata.var_keys():
|
|
686
|
+
n_samples = adata.var['n_samples']
|
|
687
|
+
else:
|
|
688
|
+
n_samples = np.sum(adata.X >= expr_cutoff, axis=0).A1
|
|
689
|
+
adata.var['n_samples'] = n_samples
|
|
690
|
+
if 'pct_samples' in adata.var_keys():
|
|
691
|
+
pct_samples = adata.var['pct_samples']
|
|
692
|
+
else:
|
|
693
|
+
pct_samples = n_samples/adata.shape[0]
|
|
694
|
+
adata.var['pct_samples'] = pct_samples
|
|
695
|
+
|
|
696
|
+
print('Before filtering: ')
|
|
697
|
+
print(f"{adata.shape[0]} samples, {adata.shape[1]} features")
|
|
698
|
+
|
|
699
|
+
if sum(list(map(lambda x: x is None,
|
|
700
|
+
[min_n_samples, min_pct_samples, min_n_counts,
|
|
701
|
+
max_n_samples, max_pct_samples, max_n_counts,
|
|
702
|
+
]))) == 6:
|
|
703
|
+
print('No filtering')
|
|
704
|
+
else:
|
|
705
|
+
feature_subset = np.ones(len(adata.var_names), dtype=bool)
|
|
706
|
+
if min_n_samples is not None:
|
|
707
|
+
print('Filter features based on min_n_samples')
|
|
708
|
+
feature_subset = (n_samples >= min_n_samples) & feature_subset
|
|
709
|
+
if max_n_samples is not None:
|
|
710
|
+
print('Filter features based on max_n_samples')
|
|
711
|
+
feature_subset = (n_samples <= max_n_samples) & feature_subset
|
|
712
|
+
if min_pct_samples is not None:
|
|
713
|
+
print('Filter features based on min_pct_samples')
|
|
714
|
+
feature_subset = (pct_samples >= min_pct_samples) & feature_subset
|
|
715
|
+
if max_pct_samples is not None:
|
|
716
|
+
print('Filter features based on max_pct_samples')
|
|
717
|
+
feature_subset = (pct_samples <= max_pct_samples) & feature_subset
|
|
718
|
+
if min_n_counts is not None:
|
|
719
|
+
print('Filter features based on min_n_counts')
|
|
720
|
+
feature_subset = (n_counts >= min_n_counts) & feature_subset
|
|
721
|
+
if max_n_counts is not None:
|
|
722
|
+
print('Filter features based on max_n_counts')
|
|
723
|
+
feature_subset = (n_counts <= max_n_counts) & feature_subset
|
|
724
|
+
adata._inplace_subset_var(feature_subset)
|
|
725
|
+
print('After filtering out low-expressed features: ')
|
|
726
|
+
print(f"{adata.shape[0]} samples, {adata.shape[1]} features")
|
|
727
|
+
return None
|