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,103 @@
1
+ """Utility functions and classes"""
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from pandas.api.types import (
6
+ is_numeric_dtype,
7
+ is_string_dtype,
8
+ is_categorical_dtype,
9
+ )
10
+ import matplotlib as mpl
11
+
12
+ from ._palettes import (
13
+ default_20,
14
+ default_28,
15
+ default_102
16
+ )
17
+
18
+
19
+ def get_colors(arr,
20
+ vmin=None,
21
+ vmax=None,
22
+ clip=False):
23
+ """Generate a list of colors for a given array
24
+ """
25
+
26
+ if not isinstance(arr, (pd.Series, np.ndarray)):
27
+ raise TypeError("`arr` must be pd.Series or np.ndarray")
28
+ colors = []
29
+ if is_numeric_dtype(arr):
30
+ image_cmap = mpl.rcParams['image.cmap']
31
+ cm = mpl.cm.get_cmap(image_cmap, 512)
32
+ if vmin is None:
33
+ vmin = min(arr)
34
+ if vmax is None:
35
+ vmax = max(arr)
36
+ norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax, clip=clip)
37
+ colors = [mpl.colors.to_hex(cm(norm(x))) for x in arr]
38
+ elif is_string_dtype(arr) or is_categorical_dtype(arr):
39
+ categories = np.unique(arr)
40
+ length = len(categories)
41
+ # check if default matplotlib palette has enough colors
42
+ # mpl.style.use('default')
43
+ if len(mpl.rcParams['axes.prop_cycle'].by_key()['color']) >= length:
44
+ cc = mpl.rcParams['axes.prop_cycle']()
45
+ palette = [mpl.colors.rgb2hex(next(cc)['color'])
46
+ for _ in range(length)]
47
+ else:
48
+ if length <= 20:
49
+ palette = default_20
50
+ elif length <= 28:
51
+ palette = default_28
52
+ elif length <= len(default_102): # 103 colors
53
+ palette = default_102
54
+ else:
55
+ rgb_rainbow = mpl.cm.rainbow(np.linspace(0, 1, length))
56
+ palette = [mpl.colors.rgb2hex(rgb_rainbow[i, :-1])
57
+ for i in range(length)]
58
+ colors = pd.Series(['']*len(arr))
59
+ for i, x in enumerate(categories):
60
+ ids = np.where(arr == x)[0]
61
+ colors[ids] = palette[i]
62
+ colors = list(colors)
63
+ else:
64
+ raise TypeError("unsupported data type for `arr`")
65
+ return colors
66
+
67
+
68
+ def generate_palette(arr):
69
+ """Generate a color palette for a given array
70
+ """
71
+
72
+ if not isinstance(arr, (pd.Series, np.ndarray)):
73
+ raise TypeError("`arr` must be pd.Series or np.ndarray")
74
+ colors = []
75
+ if is_string_dtype(arr) or is_categorical_dtype(arr):
76
+ categories = np.unique(arr)
77
+ length = len(categories)
78
+ # check if default matplotlib palette has enough colors
79
+ # mpl.style.use('default')
80
+ if len(mpl.rcParams['axes.prop_cycle'].by_key()['color']) >= length:
81
+ cc = mpl.rcParams['axes.prop_cycle']()
82
+ palette = [mpl.colors.rgb2hex(next(cc)['color'])
83
+ for _ in range(length)]
84
+ else:
85
+ if length <= 20:
86
+ palette = default_20
87
+ elif length <= 28:
88
+ palette = default_28
89
+ elif length <= len(default_102): # 103 colors
90
+ palette = default_102
91
+ else:
92
+ rgb_rainbow = mpl.cm.rainbow(np.linspace(0, 1, length))
93
+ palette = [mpl.colors.rgb2hex(rgb_rainbow[i, :-1])
94
+ for i in range(length)]
95
+ colors = pd.Series(['']*len(arr))
96
+ for i, x in enumerate(categories):
97
+ ids = np.where(arr == x)[0]
98
+ colors[ids] = palette[i]
99
+ colors = list(colors)
100
+ else:
101
+ raise TypeError("unsupported data type for `arr`")
102
+ dict_palette = dict(zip(arr, colors))
103
+ return dict_palette
@@ -0,0 +1,26 @@
1
+ """Preprocessing"""
2
+
3
+ from ._general import (
4
+ log_transform,
5
+ normalize,
6
+ binarize
7
+ )
8
+ from ._qc import (
9
+ cal_qc,
10
+ cal_qc_rna,
11
+ cal_qc_atac,
12
+ filter_samples,
13
+ filter_cells_rna,
14
+ filter_cells_atac,
15
+ filter_features,
16
+ filter_genes,
17
+ filter_peaks,
18
+ )
19
+ from ._pca import (
20
+ pca,
21
+ select_pcs,
22
+ select_pcs_features,
23
+ )
24
+ from ._variable_genes import (
25
+ select_variable_genes
26
+ )
@@ -0,0 +1,91 @@
1
+ """General preprocessing functions"""
2
+
3
+ import numpy as np
4
+ from sklearn.utils import sparsefuncs
5
+ from sklearn import preprocessing
6
+ from ._utils import (
7
+ cal_tf_idf
8
+ )
9
+ from scipy.sparse import (
10
+ issparse,
11
+ csr_matrix,
12
+ )
13
+
14
+
15
+ def log_transform(adata):
16
+ """Return the natural logarithm of one plus the input array, element-wise.
17
+
18
+ Parameters
19
+ ----------
20
+ adata: AnnData
21
+ Annotated data matrix.
22
+
23
+ Returns
24
+ -------
25
+ updates `adata` with the following fields.
26
+ X: `numpy.ndarray` (`adata.X`)
27
+ Store #observations × #var_genes logarithmized data matrix.
28
+ """
29
+ if not issparse(adata.X):
30
+ adata.X = csr_matrix(adata.X)
31
+ adata.X = np.log1p(adata.X)
32
+ return None
33
+
34
+
35
+ def binarize(adata,
36
+ threshold=1e-5):
37
+ """Binarize an array.
38
+ Parameters
39
+ ----------
40
+ adata: AnnData
41
+ Annotated data matrix.
42
+ threshold: `float`, optional (default: 1e-5)
43
+ Values below or equal to this are replaced by 0, above it by 1.
44
+
45
+ Returns
46
+ -------
47
+ updates `adata` with the following fields.
48
+ X: `numpy.ndarray` (`adata.X`)
49
+ Store #observations × #var_genes binarized data matrix.
50
+ """
51
+ if not issparse(adata.X):
52
+ adata.X = csr_matrix(adata.X)
53
+ adata.X = preprocessing.binarize(adata.X,
54
+ threshold=threshold,
55
+ copy=True)
56
+
57
+
58
+ def normalize(adata,
59
+ method='lib_size',
60
+ scale_factor=1e4,
61
+ save_raw=True):
62
+ """Normalize count matrix.
63
+
64
+ Parameters
65
+ ----------
66
+ adata: AnnData
67
+ Annotated data matrix.
68
+ method: `str`, optional (default: 'lib_size')
69
+ Choose from {{'lib_size','tf_idf'}}
70
+ Method used for dimension reduction.
71
+ 'lib_size': Total-count normalize (library-size correct)
72
+ 'tf_idf': TF-IDF (term frequency–inverse document frequency)
73
+ transformation
74
+
75
+ Returns
76
+ -------
77
+ updates `adata` with the following fields.
78
+ X: `numpy.ndarray` (`adata.X`)
79
+ Store #observations × #var_genes normalized data matrix.
80
+ """
81
+ if method not in ['lib_size', 'tf_idf']:
82
+ raise ValueError("unrecognized method '%s'" % method)
83
+ if not issparse(adata.X):
84
+ adata.X = csr_matrix(adata.X)
85
+ if save_raw:
86
+ adata.layers['raw'] = adata.X.copy()
87
+ if method == 'lib_size':
88
+ sparsefuncs.inplace_row_scale(adata.X, 1/adata.X.sum(axis=1).A)
89
+ adata.X = adata.X*scale_factor
90
+ if method == 'tf_idf':
91
+ adata.X = cal_tf_idf(adata.X)
@@ -0,0 +1,182 @@
1
+ """Principal component analysis"""
2
+
3
+ import numpy as np
4
+ from sklearn.decomposition import TruncatedSVD
5
+ from ._utils import (
6
+ locate_elbow,
7
+ )
8
+
9
+
10
+ def pca(adata,
11
+ n_components=50,
12
+ algorithm='randomized',
13
+ n_iter=5,
14
+ random_state=2021,
15
+ tol=0.0,
16
+ feature=None,
17
+ **kwargs,
18
+ ):
19
+ """perform Principal Component Analysis (PCA)
20
+
21
+ Parameters
22
+ ----------
23
+ adata: AnnData
24
+ Annotated data matrix.
25
+ n_components: `int`, optional (default: 50)
26
+ Desired dimensionality of output data
27
+ algorithm: `str`, optional (default: 'randomized')
28
+ SVD solver to use. Choose from {'arpack', 'randomized'}.
29
+ n_iter: `int`, optional (default: '5')
30
+ Number of iterations for randomized SVD solver.
31
+ Not used by ARPACK.
32
+ tol: `float`, optional (default: 0)
33
+ Tolerance for ARPACK. 0 means machine precision.
34
+ Ignored by randomized SVD solver.
35
+ feature: `str`, optional (default: None)
36
+ Feature used to perform PCA.
37
+ The data type of `.var[feature]` needs to be `bool`
38
+ If None, adata.X will be used.
39
+ kwargs:
40
+ Other keyword arguments are passed down to `TruncatedSVD()`
41
+
42
+ Returns
43
+ -------
44
+ updates `adata` with the following fields:
45
+ `.obsm['X_pca']` : `array`
46
+ PCA transformed X.
47
+ `.uns['pca']['PCs']` : `array`
48
+ Principal components in feature space,
49
+ representing the directions of maximum variance in the data.
50
+ `.uns['pca']['variance']` : `array`
51
+ The variance of the training samples transformed by a
52
+ projection to each component.
53
+ `.uns['pca']['variance_ratio']` : `array`
54
+ Percentage of variance explained by each of the selected components.
55
+ """
56
+ if feature is None:
57
+ X = adata.X.copy()
58
+ else:
59
+ mask = adata.var[feature]
60
+ X = adata[:, mask].X.copy()
61
+ svd = TruncatedSVD(n_components=n_components,
62
+ algorithm=algorithm,
63
+ n_iter=n_iter,
64
+ random_state=random_state,
65
+ tol=tol,
66
+ **kwargs)
67
+ svd.fit(X)
68
+ adata.obsm['X_pca'] = svd.transform(X)
69
+ adata.uns['pca'] = dict()
70
+ adata.uns['pca']['n_pcs'] = n_components
71
+ adata.uns['pca']['PCs'] = svd.components_.T
72
+ adata.uns['pca']['variance'] = svd.explained_variance_
73
+ adata.uns['pca']['variance_ratio'] = svd.explained_variance_ratio_
74
+
75
+
76
+ def select_pcs(adata,
77
+ n_pcs=None,
78
+ S=1,
79
+ curve='convex',
80
+ direction='decreasing',
81
+ online=False,
82
+ min_elbow=None,
83
+ **kwargs):
84
+ """select top PCs based on variance_ratio
85
+
86
+ Parameters
87
+ ----------
88
+ n_pcs: `int`, optional (default: None)
89
+ If n_pcs is None,
90
+ the number of PCs will be automatically selected with "`kneed
91
+ <https://kneed.readthedocs.io/>`__"
92
+ S : `float`, optional (default: 1)
93
+ Sensitivity
94
+ min_elbow: `int`, optional (default: None)
95
+ The minimum elbow location
96
+ By default, it is n_components/10
97
+ curve: `str`, optional (default: 'convex')
98
+ Choose from {'convex','concave'}
99
+ If 'concave', algorithm will detect knees,
100
+ If 'convex', algorithm will detect elbows.
101
+ direction: `str`, optional (default: 'decreasing')
102
+ Choose from {'decreasing','increasing'}
103
+ online: `bool`, optional (default: False)
104
+ kneed will correct old knee points if True,
105
+ kneed will return first knee if False.
106
+ **kwargs: `dict`, optional
107
+ Extra arguments to KneeLocator.
108
+ Returns
109
+
110
+ """
111
+ if n_pcs is None:
112
+ n_components = adata.obsm['X_pca'].shape[1]
113
+ if min_elbow is None:
114
+ min_elbow = n_components/10
115
+ n_pcs = locate_elbow(range(n_components),
116
+ adata.uns['pca']['variance_ratio'],
117
+ S=S,
118
+ curve=curve,
119
+ min_elbow=min_elbow,
120
+ direction=direction,
121
+ online=online,
122
+ **kwargs)
123
+ adata.uns['pca']['n_pcs'] = n_pcs
124
+ else:
125
+ adata.uns['pca']['n_pcs'] = n_pcs
126
+
127
+
128
+ def select_pcs_features(adata,
129
+ S=1,
130
+ curve='convex',
131
+ direction='decreasing',
132
+ online=False,
133
+ min_elbow=None,
134
+ **kwargs):
135
+ """select features that contribute to the top PCs
136
+
137
+ Parameters
138
+ ----------
139
+ S : `float`, optional (default: 10)
140
+ Sensitivity
141
+ min_elbow: `int`, optional (default: None)
142
+ The minimum elbow location.
143
+ By default, it is #features/6
144
+ curve: `str`, optional (default: 'convex')
145
+ Choose from {'convex','concave'}
146
+ If 'concave', algorithm will detect knees,
147
+ If 'convex', algorithm will detect elbows.
148
+ direction: `str`, optional (default: 'decreasing')
149
+ Choose from {'decreasing','increasing'}
150
+ online: `bool`, optional (default: False)
151
+ kneed will correct old knee points if True,
152
+ kneed will return first knee if False.
153
+ **kwargs: `dict`, optional
154
+ Extra arguments to KneeLocator.
155
+ Returns
156
+ -------
157
+ """
158
+ n_pcs = adata.uns['pca']['n_pcs']
159
+ n_features = adata.uns['pca']['PCs'].shape[0]
160
+ if min_elbow is None:
161
+ min_elbow = n_features/6
162
+ adata.uns['pca']['features'] = dict()
163
+ ids_features = list()
164
+ for i in range(n_pcs):
165
+ elbow = locate_elbow(range(n_features),
166
+ np.sort(
167
+ np.abs(adata.uns['pca']['PCs'][:, i],))[::-1],
168
+ S=S,
169
+ min_elbow=min_elbow,
170
+ curve=curve,
171
+ direction=direction,
172
+ online=online,
173
+ **kwargs)
174
+ ids_features_i = \
175
+ list(np.argsort(np.abs(
176
+ adata.uns['pca']['PCs'][:, i],))[::-1][:elbow])
177
+ adata.uns['pca']['features'][f'pc_{i}'] = ids_features_i
178
+ ids_features = ids_features + ids_features_i
179
+ print(f'#features selected from PC {i}: {len(ids_features_i)}')
180
+ adata.var['top_pcs'] = False
181
+ adata.var.loc[adata.var_names[np.unique(ids_features)], 'top_pcs'] = True
182
+ print(f'#features in total: {adata.var["top_pcs"].sum()}')