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,60 @@
1
+ """Utility functions and classes"""
2
+
3
+ import numpy as np
4
+ from kneed import KneeLocator
5
+ from scipy.sparse import csr_matrix, diags
6
+
7
+
8
+ def locate_elbow(x, y, S=10, min_elbow=0,
9
+ curve='convex', direction='decreasing', online=False,
10
+ **kwargs):
11
+ """Detect knee points
12
+
13
+ Parameters
14
+ ----------
15
+ x : `array_like`
16
+ x values
17
+ y : `array_like`
18
+ y values
19
+ S : `float`, optional (default: 10)
20
+ Sensitivity
21
+ min_elbow: `int`, optional (default: 0)
22
+ The minimum elbow location
23
+ curve: `str`, optional (default: 'convex')
24
+ Choose from {'convex','concave'}
25
+ If 'concave', algorithm will detect knees,
26
+ If 'convex', algorithm will detect elbows.
27
+ direction: `str`, optional (default: 'decreasing')
28
+ Choose from {'decreasing','increasing'}
29
+ online: `bool`, optional (default: False)
30
+ kneed will correct old knee points if True,
31
+ kneed will return first knee if False.
32
+ **kwargs: `dict`, optional
33
+ Extra arguments to KneeLocator.
34
+
35
+ Returns
36
+ -------
37
+ elbow: `int`
38
+ elbow point
39
+ """
40
+ kneedle = KneeLocator(x[int(min_elbow):], y[int(min_elbow):],
41
+ S=S, curve=curve,
42
+ direction=direction,
43
+ online=online,
44
+ **kwargs,
45
+ )
46
+ if kneedle.elbow is None:
47
+ elbow = len(y)
48
+ else:
49
+ elbow = int(kneedle.elbow)
50
+ return elbow
51
+
52
+
53
+ def cal_tf_idf(mat):
54
+ """Transform a count matrix to a tf-idf representation
55
+ """
56
+ mat = csr_matrix(mat)
57
+ tf = csr_matrix(mat/(mat.sum(axis=0)))
58
+ idf = np.array(np.log(1 + mat.shape[1] / mat.sum(axis=1))).flatten()
59
+ tf_idf = csr_matrix(np.dot(diags(idf), tf))
60
+ return tf_idf
@@ -0,0 +1,82 @@
1
+ """Preprocess"""
2
+
3
+ import numpy as np
4
+ from scipy.sparse import (
5
+ csr_matrix,
6
+ )
7
+ from sklearn.utils import sparsefuncs
8
+ from skmisc.loess import loess
9
+
10
+
11
+ def select_variable_genes(adata,
12
+ layer='raw',
13
+ span=0.3,
14
+ n_top_genes=2000,
15
+ ):
16
+ """Select highly variable genes.
17
+
18
+ This function implenments the method 'vst' in Seurat v3.
19
+ Inspired by Scanpy.
20
+
21
+ Parameters
22
+ ----------
23
+ adata: AnnData
24
+ Annotated data matrix.
25
+ layer: `str`, optional (default: 'raw')
26
+ The layer to use for calculating variable genes.
27
+ span: `float`, optional (default: 0.3)
28
+ Loess smoothing factor
29
+ n_top_genes: `int`, optional (default: 2000)
30
+ The number of genes to keep
31
+
32
+ Returns
33
+ -------
34
+ updates `adata` with the following fields.
35
+
36
+ variances_norm: `float`, (`adata.var['variances_norm']`)
37
+ Normalized variance per gene
38
+ variances: `float`, (`adata.var['variances']`)
39
+ Variance per gene.
40
+ means: `float`, (`adata.var['means']`)
41
+ Means per gene
42
+ highly_variable: `bool` (`adata.var['highly_variable']`)
43
+ Indicator of variable genes
44
+ """
45
+ if layer is None:
46
+ X = adata.X
47
+ else:
48
+ X = adata.layers[layer].astype(np.float64).copy()
49
+ mean, variance = sparsefuncs.mean_variance_axis(X, axis=0)
50
+ variance_expected = np.zeros(adata.shape[1], dtype=np.float64)
51
+ not_const = variance > 0
52
+
53
+ model = loess(np.log10(mean[not_const]),
54
+ np.log10(variance[not_const]),
55
+ span=span,
56
+ degree=2)
57
+ model.fit()
58
+ variance_expected[not_const] = 10**model.outputs.fitted_values
59
+ N = adata.shape[0]
60
+ clip_max = np.sqrt(N)
61
+ clip_val = np.sqrt(variance_expected) * clip_max + mean
62
+
63
+ X = csr_matrix(X)
64
+ mask = X.data > clip_val[X.indices]
65
+ X.data[mask] = clip_val[X.indices[mask]]
66
+
67
+ squared_X_sum = np.array(X.power(2).sum(axis=0))
68
+ X_sum = np.array(X.sum(axis=0))
69
+
70
+ norm_gene_var = (1 / ((N - 1) * variance_expected)) \
71
+ * ((N * np.square(mean))
72
+ + squared_X_sum
73
+ - 2 * X_sum * mean
74
+ )
75
+ norm_gene_var = norm_gene_var.flatten()
76
+
77
+ adata.var['variances_norm'] = norm_gene_var
78
+ adata.var['variances'] = variance
79
+ adata.var['means'] = mean
80
+ ids_top = norm_gene_var.argsort()[-n_top_genes:][::-1]
81
+ adata.var['highly_variable'] = np.isin(range(adata.shape[1]), ids_top)
82
+ print(f'{n_top_genes} variable genes are selected.')
@@ -0,0 +1,250 @@
1
+ """reading and writing"""
2
+
3
+ import os
4
+ import pandas as pd
5
+ import json
6
+ from anndata import (
7
+ AnnData,
8
+ read_h5ad,
9
+ read_csv,
10
+ read_excel,
11
+ read_hdf,
12
+ read_loom,
13
+ read_mtx,
14
+ read_text,
15
+ read_umi_tools,
16
+ read_zarr,
17
+ )
18
+ from pathlib import Path
19
+ import tables
20
+
21
+ from ._settings import settings
22
+ from ._utils import _read_legacy_10x_h5, _read_v3_10x_h5
23
+
24
+
25
+ def read_embedding(path_emb=None,
26
+ path_entity=None,
27
+ convert_alias=True,
28
+ path_entity_alias=None,
29
+ prefix=None,
30
+ num_epochs=None,
31
+ get_marker_significance=False,
32
+ path_entity_alias_marker=None):
33
+ """Read in entity embeddings from pbg training
34
+
35
+ Parameters
36
+ ----------
37
+ path_emb: `str`, optional (default: None)
38
+ Path to directory for pbg embedding model
39
+ If None, .settings.pbg_params['checkpoint_path'] will be used.
40
+ path_entity: `str`, optional (default: None)
41
+ Path to entity name file
42
+ prefix: `list`, optional (default: None)
43
+ A list of entity type prefixes to include.
44
+ By default, it reads in the embeddings of all entities.
45
+ convert_alias: `bool`, optional (default: True)
46
+ If True, it will convert entity aliases to the original indices
47
+ path_entity_alias: `str`, optional (default: None)
48
+ Path to entity alias file
49
+ num_epochs: `int`, optional (default: None)
50
+ The embedding result associated with num_epochs to read in
51
+
52
+ Returns
53
+ -------
54
+ dict_adata: `dict`
55
+ A dictionary of anndata objects of shape
56
+ (#entities x #dimensions)
57
+ """
58
+ pbg_params = settings.pbg_params
59
+ if path_emb is None:
60
+ path_emb = pbg_params['checkpoint_path']
61
+ if path_entity is None:
62
+ path_entity = pbg_params['entity_path']
63
+ if num_epochs is None:
64
+ num_epochs = pbg_params["num_epochs"]
65
+ if prefix is None:
66
+ prefix = []
67
+ assert isinstance(prefix, list), \
68
+ "`prefix` must be list"
69
+ if convert_alias:
70
+ if path_entity_alias is None:
71
+ path_entity_alias = Path(path_emb).parent.as_posix()
72
+ df_entity_alias = pd.read_csv(
73
+ os.path.join(path_entity_alias, 'entity_alias.txt'),
74
+ header=0,
75
+ index_col=0,
76
+ sep='\t')
77
+ df_entity_alias['id'] = df_entity_alias.index
78
+ df_entity_alias.index = df_entity_alias['alias'].values
79
+
80
+ if get_marker_significance:
81
+ path_emb_marker = os.path.join(Path(path_emb).parent.as_posix() + "_with_sig", os.path.basename(path_emb))
82
+ path_entity_marker = os.path.join(Path(path_entity).parent.parent.as_posix() + "_with_sig", 'input/entity')
83
+ if path_entity_alias_marker is None:
84
+ path_entity_alias = Path(path_emb).parent.as_posix() + "_with_sig"
85
+ dict_adata_with_sig = read_embedding(
86
+ path_emb=path_emb_marker,
87
+ path_entity=path_entity_marker,
88
+ convert_alias=True,
89
+ path_entity_alias=path_entity_alias_marker,
90
+ prefix=prefix,
91
+ num_epochs=num_epochs,
92
+ get_marker_significance=False
93
+ )
94
+
95
+ dict_adata = dict()
96
+ for x in os.listdir(path_emb):
97
+ if x.startswith('embeddings'):
98
+ entity_type = x.split('_')[1]
99
+ if (len(prefix) == 0) or (entity_type in prefix):
100
+ adata = \
101
+ read_hdf(os.path.join(path_emb,
102
+ f'embeddings_{entity_type}_0.'
103
+ f'v{num_epochs}.h5'),
104
+ key="embeddings")
105
+ with open(
106
+ os.path.join(path_entity,
107
+ f'entity_names_{entity_type}_0.json'), "rt")\
108
+ as tf:
109
+ names_entity = json.load(tf)
110
+ if convert_alias:
111
+ names_entity = \
112
+ df_entity_alias.loc[names_entity, 'id'].tolist()
113
+ adata.obs.index = names_entity
114
+ dict_adata[entity_type] = adata
115
+ if get_marker_significance:
116
+ try:
117
+ dict_adata[f"n{entity_type}"] = dict_adata_with_sig[f"n{entity_type}"]
118
+ except KeyError:
119
+ print(f"Null feature nodes for entity {entity_type} not embedded.")
120
+
121
+ return dict_adata
122
+
123
+
124
+ # modifed from
125
+ # scanpy https://github.com/theislab/scanpy/blob/master/scanpy/readwrite.py
126
+ def read_10x_h5(filename,
127
+ genome=None,
128
+ gex_only=True):
129
+ """Read 10x-Genomics-formatted hdf5 file.
130
+
131
+ Parameters
132
+ ----------
133
+ filename
134
+ Path to a 10x hdf5 file.
135
+ genome
136
+ Filter expression to genes within this genome. For legacy 10x h5
137
+ files, this must be provided if the data contains more than one genome.
138
+ gex_only
139
+ Only keep 'Gene Expression' data and ignore other feature types,
140
+ e.g. 'Antibody Capture', 'CRISPR Guide Capture', or 'Custom'
141
+
142
+ Returns
143
+ -------
144
+ adata: AnnData
145
+ Annotated data matrix, where observations/cells are named by their
146
+ barcode and variables/genes by gene name
147
+ """
148
+ with tables.open_file(str(filename), 'r') as f:
149
+ v3 = '/matrix' in f
150
+ if v3:
151
+ adata = _read_v3_10x_h5(filename)
152
+ if genome:
153
+ if genome not in adata.var['genome'].values:
154
+ raise ValueError(
155
+ f"Could not find data corresponding to "
156
+ f"genome '{genome}' in '{filename}'. "
157
+ f'Available genomes are:'
158
+ f' {list(adata.var["genome"].unique())}.'
159
+ )
160
+ adata = adata[:, adata.var['genome'] == genome]
161
+ if gex_only:
162
+ adata = adata[:, adata.var['feature_types'] == 'Gene Expression']
163
+ if adata.is_view:
164
+ adata = adata.copy()
165
+ else:
166
+ adata = _read_legacy_10x_h5(filename, genome=genome)
167
+ return adata
168
+
169
+
170
+ def load_pbg_config(path=None):
171
+ """Load PBG configuration into global setting
172
+
173
+ Parameters
174
+ ----------
175
+ path: `str`, optional (default: None)
176
+ Path to the directory for pbg configuration file
177
+ If None, `.settings.pbg_params['checkpoint_path']` will be used
178
+
179
+ Returns
180
+ -------
181
+ Updates `.settings.pbg_params`
182
+
183
+ """
184
+ if path is None:
185
+ path = settings.pbg_params['checkpoint_path']
186
+ path = os.path.normpath(path)
187
+ with open(os.path.join(path, 'config.json'), "rt") as tf:
188
+ pbg_params = json.load(tf)
189
+ settings.set_pbg_params(config=pbg_params)
190
+
191
+
192
+ def load_graph_stats(path=None):
193
+ """Load graph statistics into global setting
194
+
195
+ Parameters
196
+ ----------
197
+ path: `str`, optional (default: None)
198
+ Path to the directory for graph statistics file
199
+ If None, `.settings.pbg_params['checkpoint_path']` will be used
200
+
201
+ Returns
202
+ -------
203
+ Updates `.settings.graph_stats`
204
+ """
205
+ if path is None:
206
+ path = \
207
+ Path(settings.pbg_params['entity_path']).parent.parent.as_posix()
208
+ path = os.path.normpath(path)
209
+ with open(os.path.join(path, 'graph_stats.json'), "rt") as tf:
210
+ dict_graph_stats = json.load(tf)
211
+ dirname = os.path.basename(path)
212
+ settings.graph_stats[dirname] = dict_graph_stats.copy()
213
+
214
+
215
+ def write_bed(adata,
216
+ use_top_pcs=True,
217
+ filename=None
218
+ ):
219
+ """Write peaks into .bed file
220
+
221
+ Parameters
222
+ ----------
223
+ adata: AnnData
224
+ Annotated data matrix with peaks as variables.
225
+ use_top_pcs: `bool`, optional (default: True)
226
+ Use top-PCs-associated features
227
+ filename: `str`, optional (default: None)
228
+ Filename name for peaks.
229
+ By default, a file named 'peaks.bed' will be written to
230
+ `.settings.workdir`
231
+ """
232
+ if filename is None:
233
+ filename = os.path.join(settings.workdir, 'peaks.bed')
234
+ for x in ['chr', 'start', 'end']:
235
+ if x not in adata.var_keys():
236
+ raise ValueError(f"could not find {x} in `adata.var_keys()`")
237
+ if use_top_pcs:
238
+ assert 'top_pcs' in adata.var_keys(), \
239
+ "please run `si.pp.select_pcs_features()` first"
240
+ peaks_selected = adata.var[
241
+ adata.var['top_pcs']][['chr', 'start', 'end']]
242
+ else:
243
+ peaks_selected = adata.var[
244
+ ['chr', 'start', 'end']]
245
+ peaks_selected.to_csv(filename,
246
+ sep='\t',
247
+ header=False,
248
+ index=False)
249
+ fp, fn = os.path.split(filename)
250
+ print(f'"{fn}" was written to "{fp}".')
@@ -0,0 +1,23 @@
1
+ """The core functionality"""
2
+
3
+ from ._general import (
4
+ discretize,
5
+ )
6
+ from ._umap import umap
7
+ from ._gene_scores import gene_scores
8
+ from ._integration import (
9
+ infer_edges,
10
+ trim_edges
11
+ )
12
+ from ._pbg import (
13
+ gen_graph,
14
+ pbg_train
15
+ )
16
+ from ._post_training import (
17
+ softmax,
18
+ embed,
19
+ compare_entities,
20
+ query,
21
+ find_master_regulators,
22
+ find_target_genes,
23
+ )