exprmat 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. {exprmat-0.1.4 → exprmat-0.1.6}/PKG-INFO +3 -2
  2. exprmat-0.1.6/exprmat/clustering/rogue.py +333 -0
  3. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/finders.py +31 -0
  4. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/plotting/expression.py +31 -2
  5. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/plotting/palettes.py +1 -1
  6. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/__init__.py +1 -1
  7. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/plot.py +21 -1
  8. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/qc.py +10 -9
  9. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reader/experiment.py +145 -25
  10. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reader/matcher.py +46 -5
  11. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/plot.py +137 -34
  12. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/utils.py +2 -2
  13. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/PKG-INFO +3 -2
  14. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/SOURCES.txt +1 -1
  15. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/requires.txt +1 -0
  16. {exprmat-0.1.4 → exprmat-0.1.6}/setup.py +3 -2
  17. exprmat-0.1.4/exprmat/data/mmu/gencode.tsv.gz +0 -0
  18. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/__init__.py +0 -0
  19. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/ansi.py +0 -0
  20. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/clustering/__init__.py +0 -0
  21. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/clustering/leiden.py +0 -0
  22. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/clustering/spectral.py +0 -0
  23. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/clustering/utils.py +0 -0
  24. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/cnv/__init__.py +0 -0
  25. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/cnv/cnvscore.py +0 -0
  26. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/cnv/infercnv.py +0 -0
  27. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/configuration.py +0 -0
  28. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/__init__.py +0 -0
  29. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/delim.py +0 -0
  30. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/gff.py +0 -0
  31. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/hsa/genome.tsv.gz +0 -0
  32. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/mmu/genome.tsv.gz +0 -0
  33. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/private.py +0 -0
  34. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/data/ranges.py +0 -0
  35. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/descriptive/__init__.py +0 -0
  36. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/descriptive/de.py +0 -0
  37. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/descriptive/kde.py +0 -0
  38. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/plotting/__init__.py +0 -0
  39. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/plotting/cnv.py +0 -0
  40. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/plotting/de.py +0 -0
  41. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/doublets/__init__.py +0 -0
  42. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/doublets/composite.py +0 -0
  43. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/doublets/scrublet.py +0 -0
  44. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/filter.py +0 -0
  45. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/integrate.py +0 -0
  46. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/linear.py +0 -0
  47. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/normal.py +0 -0
  48. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sctransform/__init__.py +0 -0
  49. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sctransform/estimate.py +0 -0
  50. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sctransform/ksmooth.py +0 -0
  51. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sctransform/residual.py +0 -0
  52. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sctransform/transform.py +0 -0
  53. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/sparse.py +0 -0
  54. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/preprocessing/uniform.py +0 -0
  55. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reader/__init__.py +0 -0
  56. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reader/metadata.py +0 -0
  57. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/__init__.py +0 -0
  58. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/forceatlas.py +0 -0
  59. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/mde.py +0 -0
  60. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/nn.py +0 -0
  61. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/pca.py +0 -0
  62. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/pumap.py +0 -0
  63. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/tsne.py +0 -0
  64. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat/reduction/umap.py +0 -0
  65. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/dependency_links.txt +0 -0
  66. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/not-zip-safe +0 -0
  67. {exprmat-0.1.4 → exprmat-0.1.6}/exprmat.egg-info/top_level.txt +0 -0
  68. {exprmat-0.1.4 → exprmat-0.1.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: exprmat
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: routines to process expression matrices
5
5
  Home-page: https://github.com/yang-z-03/exprmat
6
6
  Author: Zheng Yang
@@ -28,6 +28,7 @@ Requires-Dist: datashader
28
28
  Requires-Dist: fa2_modified
29
29
  Requires-Dist: pynndescent
30
30
  Requires-Dist: gseapy
31
+ Requires-Dist: sh
31
32
  Dynamic: author
32
33
  Dynamic: author-email
33
34
  Dynamic: home-page
@@ -0,0 +1,333 @@
1
+
2
+ import numpy as np
3
+ import pandas as pd
4
+ import statsmodels.api as sm
5
+ from skmisc import loess
6
+ from scipy.stats import norm
7
+ from statsmodels.stats.multitest import multipletests
8
+ from exprmat.ansi import error, warning, info
9
+
10
+
11
+ # the entropy of the genes across cell j is defined to be:
12
+ #
13
+ # s1 = ln(mean(expr_j))
14
+ #
15
+ # this assumes that all cells in the cluster is homogenous. while the alternative
16
+ # assumption is that cells are totally heterogenous, and each cell represent its
17
+ # distinct state. the entropy for a totally heterogenous dataset is:
18
+ #
19
+ # s2 = mean(log(expr_ij))
20
+ #
21
+ # for calculation, this is simply a conversion of mean and log transform.
22
+ # r is a small positive value to avoid nan's been introduced due to invalid log.
23
+ # we require that the expression matrix have gene names as row names.
24
+
25
+ def rogue_entropy(C, varname, r = 1):
26
+ '''
27
+ Calculate entropy for genes. A completely homogenous gene will yield entropy
28
+ as mean logrithmized counts (mean.expr). Expect raw count matrix.
29
+ '''
30
+
31
+ entropy = np.log(C + 1).mean(axis = 0) # per gene.
32
+ mean_expr = np.log(C.mean(axis = 0) + r)
33
+ return pd.DataFrame({
34
+ 'gene': varname,
35
+ 'entropy': entropy.tolist()[0],
36
+ 'mean.expr': mean_expr.tolist()[0]
37
+ })
38
+
39
+
40
+ # fit the relationship between expression entropy and mean gene expression:
41
+ #
42
+ # in real-world dataset, there must be to some extent, heterogenous components
43
+ # in the dataset clusters. s1 > s2. and for different techniques for rna sequencing
44
+ # there is a systematic bias on the data distribution. we need a fitting step
45
+ # to make sure that the highly-variable genes in the clusters are picked.
46
+ #
47
+ #' @param span is a parameter for loess for controls of fit smoothness.
48
+ #' @param mt.method multiple testing method used in p.adjust.
49
+ #
50
+ # the returning dataframe consists of [1] gene names, [2] log mean expression (s1),
51
+ # [3] fit, the fitted curve of real world log mean expression trajectory (s1'),
52
+ # [4] ds, delta of entropy, the difference between s2 and s1',
53
+ # [5] p.value, assume that ds is normal, and the p value of normal distribution.
54
+ # [6] p.adj, the multi-test adjusted p value for normal approximation. and
55
+ # [7] entropy, the expression entropy per se.
56
+ #
57
+ # the returning values are sorted according to decreasing delta of entropy, so
58
+ # that the most highly-variable genes ranked on the top.
59
+
60
+ # available correction methods:
61
+ # * bonferroni : one-step correction
62
+ # * sidak : one-step correction
63
+ # * holm-sidak : step down method using Sidak adjustments
64
+ # * holm : step-down method using Bonferroni adjustments
65
+ # * simes-hochberg : step-up method (independent)
66
+ # * hommel : closed method based on Simes tests (non-negative)
67
+ # * fdr_bh : Benjamini/Hochberg (non-negative)
68
+ # * fdr_by : Benjamini/Yekutieli (negative)
69
+ # * fdr_tsbh : two stage fdr correction (non-negative)
70
+ # * fdr_tsbky : two stage fdr correction (non-negative)
71
+
72
+ def smoothen_entropy_lowess(df, span = 0.5, correction = "fdr_bh"):
73
+
74
+ df = df.loc[
75
+ np.isfinite(df['mean.expr']) &
76
+ df['entropy'] > 0, :
77
+ ].copy()
78
+
79
+ fit = sm.nonparametric.lowess(
80
+ exog = df['mean.expr'],
81
+ endog = df['entropy'], frac = span,
82
+ xvals = df['mean.expr']
83
+ )
84
+
85
+ df['fit'] = fit
86
+ df['ds'] = df['fit'] - df['entropy']
87
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
88
+ training = df.loc[df['pval'] > 0.1, :].copy()
89
+
90
+ fit2 = sm.nonparametric.lowess(
91
+ exog = training['mean.expr'],
92
+ endog = training['entropy'], frac = span,
93
+ xvals = df['mean.expr']
94
+ )
95
+
96
+ df['fit'] = fit2
97
+ df['ds'] = df['fit'] - df['entropy']
98
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
99
+ training = df.loc[df['pval'] > 0.1, :].copy()
100
+
101
+ fit3 = sm.nonparametric.lowess(
102
+ exog = training['mean.expr'],
103
+ endog = training['entropy'], frac = span,
104
+ xvals = df['mean.expr']
105
+ )
106
+
107
+ df['fit'] = fit3
108
+ df['ds'] = df['fit'] - df['entropy']
109
+ df = df.loc[np.isfinite(df['ds']), :]
110
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
111
+ df['qval'] = multipletests(df['pval'], method = correction)[1]
112
+
113
+ return df.sort_values(['ds'], ascending = False)
114
+
115
+
116
+ def smoothen_entropy_loess(df, span = 0.5, correction = "fdr_bh"):
117
+
118
+ df = df.loc[
119
+ np.isfinite(df['mean.expr']) &
120
+ df['entropy'] > 0, :
121
+ ].copy()
122
+
123
+ model = loess.loess(df['mean.expr'], df['entropy'], span = span)
124
+ model.fit()
125
+ fit = model.predict(df['mean.expr'])
126
+
127
+ df['fit'] = fit.values
128
+ df['ds'] = df['fit'] - df['entropy']
129
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
130
+ training = df.loc[df['pval'] > 0.1, :].copy()
131
+
132
+ df = df.loc[df['mean.expr'] <= np.max(training['mean.expr']), :].copy()
133
+ model = loess.loess(training['mean.expr'], training['entropy'], span = span)
134
+ model.fit()
135
+ fit2 = model.predict(df['mean.expr'])
136
+
137
+ df['fit'] = fit2.values
138
+ df['ds'] = df['fit'] - df['entropy']
139
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
140
+ training = df.loc[df['pval'] > 0.1, :].copy()
141
+
142
+ df = df.loc[df['mean.expr'] <= np.max(training['mean.expr']), :].copy()
143
+ model = loess.loess(training['mean.expr'], training['entropy'], span = span)
144
+ model.fit()
145
+ fit3 = model.predict(df['mean.expr'])
146
+
147
+ df['fit'] = fit3.values
148
+ df['ds'] = df['fit'] - df['entropy']
149
+ df = df.loc[np.isfinite(df['ds']), :]
150
+ df['pval'] = 1 - norm.cdf(df['ds'], np.mean(df['ds']), np.std(df['ds']))
151
+ df['qval'] = multipletests(df['pval'], method = correction)[1]
152
+
153
+ return df.sort_values(['ds'], ascending = False)
154
+
155
+
156
+ smoothen_entropy = smoothen_entropy_loess
157
+
158
+ # identify highly informative genes using rogue's s-e model
159
+ #
160
+ # returns a tibble object with seven columns:
161
+ # [1] gene, the gene name.
162
+ # [2] mean.expr, the mean expression levels of genes.
163
+ # [3] entropy, the expected expression entropy from a given mean gene expression.
164
+ # [4] fit, the mean expression levels of genes.
165
+ # [5] ds, the entropy reduction against the null expectation.
166
+ # [6] p.value, the significance of ds against normal distribution.
167
+ # [7] p.adj, adjusted p value, or a copy of p.value if specifying not to adjust it.
168
+
169
+ def rogue_hvg(C, varname, span = 0.5, r = 1, correction = "fdr_bh", adjust_p = True):
170
+
171
+ entropy = rogue_entropy(C, varname, r = r)
172
+ entropy = smoothen_entropy(entropy, span = span, correction = correction)
173
+ if not adjust_p: entropy['qval'] = entropy["pval"]
174
+ return entropy
175
+
176
+
177
+ # assess the purity of single cell population by rogue index.
178
+ #
179
+ # we may either specify the platform to access the default k value, or specify
180
+ # a k value manually. the rogue test is meaned to be run with highly variable
181
+ # genes. you can either specify them manually in `features`, or it is recommended
182
+ # to use the s-e model to pick the hvgs for you.
183
+
184
+ def rogue_index(df, platform = "umi", cutoff = 0.05, k = None, features = None):
185
+
186
+ if k is None:
187
+ if platform is None:
188
+ warning("you should supply a constant k yourself, or specify the platform for ")
189
+ warning("us to automatically pick the k constant for you. possible platforms ")
190
+ warning("are `umi` or `full-length`, the default k value for each case is 45 ")
191
+ warning("and 500 respectively.")
192
+ error('routine exit.')
193
+
194
+ elif platform == 'umi': k = 45
195
+ elif platform == 'full-length': k = 500
196
+ else: error('platform should be one of `umi` or `full-length`.')
197
+
198
+ if features is not None:
199
+ df = df.loc[[x in features for x in df['gene'].tolist()], :]
200
+ sig = np.abs(df['ds'].to_numpy()).sum()
201
+ rogue = 1 - sig / (sig + k)
202
+
203
+ else:
204
+
205
+ df = df.loc[
206
+ (df['pval'] < cutoff) &
207
+ (df['qval'] < cutoff), :
208
+ ]
209
+
210
+ sig = np.abs(df['ds'].to_numpy()).sum()
211
+ rogue = 1 - sig / (sig + k)
212
+
213
+ return rogue
214
+
215
+
216
+ # remove outlier cells when calculating ROGUE
217
+ #' @param n remove this many outlier cells.
218
+
219
+ def remove_outliers(df, C, varname, n = 2, span = 0.5, r = 1, correction = 'fdr_bh'):
220
+
221
+ from exprmat.utils import choose_layer
222
+ signif_genes = df.loc[df['qval'] < 0.05, :]['gene'].tolist()
223
+ ngenes = len(signif_genes)
224
+ bool_mask_gene = [x in signif_genes for x in varname]
225
+ expr_cutoff = df['mean.expr'].to_numpy().min()
226
+
227
+ expr = C[:, bool_mask_gene]
228
+ signif_genes = []
229
+ for imask in range(len(bool_mask_gene)):
230
+ if bool_mask_gene[imask]: signif_genes.append(varname[imask])
231
+
232
+ for i in range(ngenes):
233
+ gene_expr = np.flip(np.array(np.sort(expr[:, i].T))[0])
234
+ gene_expr = gene_expr[n:]
235
+ mean = np.log(gene_expr.mean() + r)
236
+ entropy = np.mean(np.log(gene_expr + 1))
237
+ df.loc[df['gene'] == signif_genes[i], 'mean.expr'] = mean
238
+ df.loc[df['gene'] == signif_genes[i], 'entropy'] = entropy
239
+
240
+ df = df.loc[df['mean.expr'] > expr_cutoff, :]
241
+ del df['qval']
242
+ df = smoothen_entropy(df, span = span, correction = correction)
243
+ return df
244
+
245
+
246
+ def rogue(
247
+ adata, counts = 'X', platform = "umi", k = None,
248
+ min_cells = 10, min_genes = 10, outlier_n = 2,
249
+ span = 0.5, r = 1, correction = 'fdr_bh'
250
+ ):
251
+ '''
252
+ Calculate ROGUE heterogeneity index for the whole annotated data.
253
+ Users are recommended to filter the minimally expressing genes and cells,
254
+ and pick out the subset of interest before feeding into this method. Or
255
+ more conveniently, run the analysis on given categorical properties via
256
+ the wrapper function ``experiment.run_rna_rogue``.
257
+
258
+ Parameters
259
+ -----------
260
+
261
+ adata : anndata.AnnData
262
+ The set of data you would like to test for heterogeneity
263
+
264
+ counts : str = 'X'
265
+ ROGUE index is calculated on raw counts. Specify a layer of raw counts.
266
+
267
+ platform : Literal['umi', 'full-length']
268
+ Choose k value with preset technology
269
+
270
+ k : int = None
271
+ Manually picks a k value. It can be estimated from dataset using
272
+ ``estimate_k`` function, or use the recommended value via ``platform``.
273
+
274
+ outlier_n : int = 2
275
+ Remove n top-expressing cells during analysis
276
+
277
+ span : float = 0.5
278
+ Controls the smoothness of LOESS regression
279
+
280
+ correction : str = 'fdr_bh'
281
+ Multitest correction of p-value. Available correction methods:
282
+ * bonferroni : one-step correction
283
+ * sidak : one-step correction
284
+ * holm-sidak : step down method using Sidak adjustments
285
+ * holm : step-down method using Bonferroni adjustments
286
+ * simes-hochberg : step-up method (independent)
287
+ * hommel : closed method based on Simes tests (non-negative)
288
+ * fdr_bh : Benjamini/Hochberg (non-negative)
289
+ * fdr_by : Benjamini/Yekutieli (negative)
290
+ * fdr_tsbh : two stage fdr correction (non-negative)
291
+ * fdr_tsbky : two stage fdr correction (non-negative)
292
+
293
+ Returns
294
+ -----------
295
+ A floating point value, rogue index
296
+ '''
297
+
298
+ from exprmat.utils import choose_layer
299
+ C = choose_layer(adata, layer = counts).todense()
300
+ hvg = rogue_hvg(
301
+ C, adata.var_names.tolist(),
302
+ span = span, r = r, correction = correction
303
+ )
304
+
305
+ hvg = remove_outliers(
306
+ hvg, C, adata.var_names.tolist(),
307
+ n = outlier_n, span = span, r = r, correction = correction
308
+ )
309
+
310
+ return rogue_index(hvg, platform = platform, k = k)
311
+
312
+
313
+ # calculate the value of the reference factor k
314
+
315
+ def estimate_k(C, varname, span = 0.5, r = 1, correction = "fdr_bh", adjust_p = True):
316
+
317
+ entropy = rogue_entropy(C, varname, r = r)
318
+ entropy = smoothen_entropy(entropy, span = span, correction = correction)
319
+ if not adjust_p: entropy['qval'] = entropy["pval"]
320
+ entropy = entropy.loc[entropy['qval'] < 0.05, :]
321
+ k = entropy['ds'].to_numpy().sum()
322
+ return k // 2
323
+
324
+
325
+ def se_plot(df):
326
+
327
+ import seaborn as sns
328
+ return sns.scatterplot(
329
+ data = df,
330
+ x = 'mean.expr',
331
+ y = 'entropy',
332
+ hue = df['pval'].to_numpy() < 0.05
333
+ )
@@ -1,6 +1,7 @@
1
1
 
2
2
  import os
3
3
  import pandas
4
+ from exprmat.ansi import warning, info
4
5
  from exprmat.configuration import default as cfg
5
6
 
6
7
  basepath = os.path.dirname(__file__)
@@ -124,6 +125,36 @@ def get_mapper_ensembl(taxa):
124
125
  return ensembl_finder
125
126
 
126
127
 
128
+ def update_mapper(taxa, name, ens):
129
+ '''
130
+ Update the name ENSEMBL ID pair.
131
+ '''
132
+
133
+ if taxa not in genome.keys():
134
+ get_mapper_name(taxa)
135
+
136
+ if 'mapper.name' not in genome[taxa].keys():
137
+ get_mapper_name(taxa)
138
+
139
+ if 'mapper.ensembl' not in genome[taxa].keys():
140
+ get_mapper_ensembl(taxa)
141
+
142
+ if (name not in genome[taxa]['mapper.name'].keys()):
143
+ if (ens in genome[taxa]['mapper.ensembl'].keys()):
144
+ genome[taxa]['mapper.name'][name] = genome[taxa]['mapper.ensembl'][ens]
145
+ else: info(f'{ens} -> {name} pair could not be established.')
146
+
147
+ else:
148
+ if (ens not in genome[taxa]['mapper.ensembl'].keys()):
149
+ genome[taxa]['mapper.ensembl'][ens] = genome[taxa]['mapper.name'][name]
150
+ else: # both name and ens present in the dictionary, check for inconsistancy
151
+ if genome[taxa]['mapper.ensembl'][ens] != genome[taxa]['mapper.name'][name]:
152
+ warning(f'{ens} -> {name} is conflicted. ({ens} registered to {genome[taxa]["mapper.ensembl"][ens]}, while {name} to {genome[taxa]["mapper.name"][name]})')
153
+
154
+
155
+ return
156
+
157
+
127
158
  def update_mapper_name(taxa, name, ugene):
128
159
  '''
129
160
  Update the gene name to unique gene id mapping.
@@ -16,7 +16,7 @@ def barplot(
16
16
  colnames = ['logc' + x for x in [gene]]
17
17
  cellnames = ['c' + str(i) for i in range(len(adata.obs_names.tolist()))]
18
18
  lognorm = find_variable(adata, gene, layer = slot)
19
- data = pd.DataFrame(lognorm.toarray())
19
+ data = pd.DataFrame(lognorm)
20
20
 
21
21
  data.columns = colnames
22
22
  if split == None: data['split'] = 'default.split'
@@ -61,7 +61,36 @@ def barplot(
61
61
  axes.set_ylabel(gene)
62
62
  axes.set_xticks(selected_groups)
63
63
  axes.set_yticks([0.0, 2.5])
64
- axes.set_xticklabels(selected_groups, rotation = 45)
64
+
65
+ # axes.set_xticklabels(selected_groups, rotation = 45)
66
+
67
+ from scipy import stats
68
+ # here, we will run the wilcox test
69
+ gene_data = dropzeros.loc[dropzeros['name'] == gene,:]
70
+ if group != None:
71
+ xtl = []
72
+ for ct in selected_groups:
73
+ cell_data = gene_data.loc[gene_data['row'] == ct,:]
74
+ groups = [x for _, x in cell_data.groupby(cell_data['split'])]
75
+ values = [x['logc'].tolist() for x in groups]
76
+ if len(values) == 2:
77
+ w = stats.mannwhitneyu(values[0], values[1])
78
+ xtl += [ct + '\n{:.3f}'.format(w.pvalue)]
79
+ else: xtl += [ct]
80
+
81
+ axes.set_xticks(selected_groups)
82
+ axes.set_xticklabels(xtl, rotation = 45)
83
+
84
+ else:
85
+ groups = [x for _, x in gene_data.groupby(gene_data['split'])]
86
+ values = [x['logc'].tolist() for x in groups]
87
+ xtl = 'whole'
88
+ if len(values) == 2:
89
+ w = stats.mannwhitneyu(values[0], values[1])
90
+ xtl = 'whole\n{:.3f}'.format(w.pvalue)
91
+ axes.set_xticklabels([xtl], rotation = 45)
92
+ pass
93
+
65
94
  axes.spines[['left', 'top']].set_visible(False)
66
95
  axes.yaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.1f}"))
67
96
  fig.tight_layout()
@@ -29,7 +29,7 @@ module attribute, and the 'small' palettes (i.e. excluding the ones with 256
29
29
  colors) are collected and in a ``small_palettes`` attribute.
30
30
 
31
31
  This module includes some palettes that are useful for addressing color deficiencies,
32
- which contains `Paul Tol's color schemes`_, and ``Colorblind`` from
32
+ which contains Paul Tol's color schemes, and ``Colorblind`` from
33
33
  https://jfly.uni-koeln.de/color/#pallet.
34
34
 
35
35
  The following palettes are also introduced in `Paul Tol's color schemes` but with
@@ -84,7 +84,7 @@ def highly_variable(
84
84
  elif method == 'vst':
85
85
  df = highly_variable_genes_seurat(
86
86
  m_count, obs = adata.obs, var = adata.var, subset = False,
87
- **kwargs
87
+ n_top_genes = n_top_genes, **kwargs
88
88
  )
89
89
  adata.var[dest + '.means'] = df['means']
90
90
  adata.var[dest + '.vars'] = df['variances']
@@ -57,4 +57,24 @@ def rna_plot_qc_metrics(adata, sample_name, figsize = (10, 2.2)):
57
57
  fig.set_dpi(100)
58
58
  fig.tight_layout(pad = 0.1)
59
59
 
60
- return fig
60
+ return fig
61
+
62
+
63
+ def rna_plot_gene_histogram(adata, sample_name, ax):
64
+
65
+ h = ax.hist(adata.obs['n.genes'].tolist(), bins = 100)
66
+ ax.set_xlabel('Gene detection')
67
+ ax.set_ylabel('Frequency')
68
+ ax.set_title(sample_name if len(sample_name) < 20 else sample_name[:17] + ' ..')
69
+
70
+ ax.vlines(
71
+ x = [0, 150], ymin = 0, ymax = 10,
72
+ colors = 'red', linestyles = 'dotted'
73
+ )
74
+
75
+ ax.vlines(
76
+ x = [300, 600], ymin = 0, ymax = 10,
77
+ colors = 'black', linestyles = 'dotted'
78
+ )
79
+
80
+ ax.set_yscale('log')
@@ -153,15 +153,16 @@ def rna_qc(
153
153
  adata.obs['score.doublet.se'] = 0.0
154
154
  adata.obs['is.doublet'] = False
155
155
 
156
- adata.obs.loc[subset.obs['score.doublet'].index, 'score.doublet'] = \
157
- subset.obs['score.doublet']
158
- adata.obs.loc[subset.obs['score.doublet.se'].index, 'score.doublet.se'] = \
159
- subset.obs['score.doublet.se']
160
- if 'is.doublet' in subset.obs.columns.tolist():
161
- adata.obs.loc[subset.obs['score.doublet'].index, 'is.doublet'] = \
162
- subset.obs['is.doublet']
163
-
164
- adata.uns['scrublet'] = subset.uns['scrublet']
156
+ if doublet_method == 'scrublet':
157
+ adata.obs.loc[subset.obs['score.doublet'].index, 'score.doublet'] = \
158
+ subset.obs['score.doublet']
159
+ adata.obs.loc[subset.obs['score.doublet.se'].index, 'score.doublet.se'] = \
160
+ subset.obs['score.doublet.se']
161
+ if 'is.doublet' in subset.obs.columns.tolist():
162
+ adata.obs.loc[subset.obs['score.doublet'].index, 'is.doublet'] = \
163
+ subset.obs['is.doublet']
164
+ adata.uns['scrublet'] = subset.uns['scrublet']
165
+
165
166
  adata.obs['qc'] = adata.obs['filter']
166
167
  adata.var['qc'] = f_var
167
168