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.
Files changed (39) hide show
  1. MultiChat/Analysis/Intra_strength.py +1758 -0
  2. MultiChat/Analysis/Processing.py +152 -0
  3. MultiChat/Analysis/__init__.py +2 -0
  4. MultiChat/Heterogeneous_g_emb/__init__.py +13 -0
  5. MultiChat/Heterogeneous_g_emb/_settings.py +156 -0
  6. MultiChat/Heterogeneous_g_emb/_utils.py +143 -0
  7. MultiChat/Heterogeneous_g_emb/_version.py +3 -0
  8. MultiChat/Heterogeneous_g_emb/plotting/__init__.py +19 -0
  9. MultiChat/Heterogeneous_g_emb/plotting/_palettes.py +180 -0
  10. MultiChat/Heterogeneous_g_emb/plotting/_plot.py +1498 -0
  11. MultiChat/Heterogeneous_g_emb/plotting/_post_training.py +742 -0
  12. MultiChat/Heterogeneous_g_emb/plotting/_utils.py +103 -0
  13. MultiChat/Heterogeneous_g_emb/preprocessing/__init__.py +26 -0
  14. MultiChat/Heterogeneous_g_emb/preprocessing/_general.py +91 -0
  15. MultiChat/Heterogeneous_g_emb/preprocessing/_pca.py +182 -0
  16. MultiChat/Heterogeneous_g_emb/preprocessing/_qc.py +727 -0
  17. MultiChat/Heterogeneous_g_emb/preprocessing/_utils.py +60 -0
  18. MultiChat/Heterogeneous_g_emb/preprocessing/_variable_genes.py +82 -0
  19. MultiChat/Heterogeneous_g_emb/readwrite.py +250 -0
  20. MultiChat/Heterogeneous_g_emb/tools/__init__.py +23 -0
  21. MultiChat/Heterogeneous_g_emb/tools/_gene_scores.py +346 -0
  22. MultiChat/Heterogeneous_g_emb/tools/_general.py +71 -0
  23. MultiChat/Heterogeneous_g_emb/tools/_integration.py +197 -0
  24. MultiChat/Heterogeneous_g_emb/tools/_pbg.py +1184 -0
  25. MultiChat/Heterogeneous_g_emb/tools/_post_training.py +919 -0
  26. MultiChat/Heterogeneous_g_emb/tools/_umap.py +58 -0
  27. MultiChat/Heterogeneous_g_emb/tools/_utils.py +253 -0
  28. MultiChat/Model/Layers.py +116 -0
  29. MultiChat/Model/__init__.py +3 -0
  30. MultiChat/Model/model_training.py +166 -0
  31. MultiChat/Model/modules.py +93 -0
  32. MultiChat/Model/utilities.py +234 -0
  33. MultiChat/Plot/Visualization.py +470 -0
  34. MultiChat/Plot/__init__.py +1 -0
  35. MultiChat/__init__.py +12 -0
  36. scmultichat-0.1.0.dist-info/METADATA +156 -0
  37. scmultichat-0.1.0.dist-info/RECORD +39 -0
  38. scmultichat-0.1.0.dist-info/WHEEL +5 -0
  39. 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