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,152 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ from sklearn.neighbors import NearestNeighbors
4
+ import scanpy as sc
5
+ import os
6
+ from tqdm import tqdm
7
+
8
+ def knn_smoothing(mat, k, latent_matrix):
9
+ '''
10
+ KNN smoothing function: Smooth the input matrix using k-nearest neighbors.
11
+ '''
12
+ nbrs = NearestNeighbors(n_neighbors=k, algorithm='auto').fit(latent_matrix)
13
+ distances, indices = nbrs.kneighbors(latent_matrix)
14
+ smoothed_mat = np.zeros_like(mat)
15
+ for i in range(mat.shape[1]):
16
+ smoothed_mat[:, i] = mat[:, indices[i, :]].sum(axis=1)
17
+
18
+ return smoothed_mat
19
+
20
+
21
+ def Preprocess_CCC_model(base_path, lr_database, cell_rep, expmatrix):
22
+ '''
23
+ smooth the expression matrix using KNN smoothing and normalize the expression of ligands and receptors.
24
+ '''
25
+ latent_fea = cell_rep
26
+ mat = expmatrix.to_numpy()
27
+ mat_smooth = knn_smoothing(mat, k=3, latent_matrix=latent_fea)
28
+ expmatrix_smooth = pd.DataFrame(mat_smooth, index=expmatrix.index, columns=expmatrix.columns)
29
+ expmatrix_smooth.to_csv(os.path.join(base_path, "CCC/expression_smooth.txt"), sep="\t", index=True, header=True)
30
+
31
+ # adata = sc.AnnData(mat_smooth)
32
+ # sc.pp.scale(adata, zero_center=True, max_value=10)
33
+ # data = adata.X
34
+ # mat_it = np.sum(data > 0, axis=1)
35
+
36
+ LR_ls = lr_database.apply(lambda row: f"{row['Ligand_Symbol']}->{row['Receptor_Symbol']}", axis=1).tolist()
37
+ ligand_exps = []
38
+ for ligand in lr_database['Ligand_Symbol']:
39
+ if '_' in ligand:
40
+ genes = ligand.split('_')
41
+ mean_expression = expmatrix_smooth.loc[genes, :].mean(axis=0)
42
+ ligand_exps.append(mean_expression)
43
+ else:
44
+ ligand_exps.append(expmatrix_smooth.loc[ligand, :])
45
+ ligand_exps = pd.DataFrame(ligand_exps, index=LR_ls, columns=expmatrix_smooth.columns)
46
+ receptor_exps = []
47
+ for receptor in lr_database['Receptor_Symbol']:
48
+ if '_' in receptor:
49
+ genes = receptor.split('_')
50
+ mean_expression = expmatrix_smooth.loc[genes, :].mean(axis=0)
51
+ receptor_exps.append(mean_expression)
52
+ else:
53
+ receptor_exps.append(expmatrix_smooth.loc[receptor, :])
54
+ receptor_exps = pd.DataFrame(receptor_exps, index=LR_ls, columns=expmatrix_smooth.columns)
55
+
56
+ ligand_exps_n = (ligand_exps - ligand_exps.min(axis=1).values[:, None]) / (ligand_exps.max(axis=1).values[:, None] - ligand_exps.min(axis=1).values[:, None])
57
+ receptor_exps_n = (receptor_exps - receptor_exps.min(axis=1).values[:, None]) / (receptor_exps.max(axis=1).values[:, None] - receptor_exps.min(axis=1).values[:, None])
58
+
59
+ pd.DataFrame(ligand_exps_n.T).to_csv(os.path.join(base_path, "CCC/ligands_expression.txt"), sep="\t", index=True, header=True)
60
+ pd.DataFrame(receptor_exps_n.T).to_csv(os.path.join(base_path, "CCC/receptors_expression.txt"), sep="\t", index=True, header=True)
61
+
62
+ return ligand_exps_n.T, receptor_exps_n.T
63
+
64
+
65
+ def select_peaks_by_genes_location(gene_info, hvg_genes, peaks_to_filter, scope = 250000):
66
+ filtered_gene_info = preprocess_gene_info(gene_info, scope)
67
+ gene_peaks = gene_peaks_pairs_by_location(filtered_gene_info, hvg_genes, peaks_to_filter)
68
+ filtered_peaks = select_peaks_from_pairs(gene_peaks)
69
+
70
+ return filtered_peaks, gene_peaks
71
+
72
+
73
+ def preprocess_gene_info(gene_info, scope = 250000):
74
+ filtered_gene_info = []
75
+ columns = ['id', 'chr', 'starts', 'ends', 'forward', 'backward', 'gene']
76
+ print("Preprocessing gene_info:")
77
+ for info in tqdm(gene_info.itertuples()):
78
+ chr = info.chr
79
+ starts = info.starts
80
+ ends = int(info.ends)
81
+ genes = info.genes
82
+ gene_info_id = chr + '-' + str(starts) + '-' + str(ends) + '-' + genes
83
+ forward = max(0, starts - scope)
84
+ backward = starts + scope
85
+ filtered_gene_info.append([gene_info_id, chr, starts, ends, forward, backward, genes])
86
+ filtered_gene_info = pd.DataFrame(filtered_gene_info, columns=columns)
87
+ filtered_gene_info = filtered_gene_info.drop_duplicates(subset=['id'])
88
+ return filtered_gene_info
89
+
90
+
91
+ def gene_peaks_pairs_by_location(filtered_gene_info, hvg_genes, peaks_to_filter):
92
+ gene_peaks = {}
93
+ print("Search the genes-peaks correspondence based on gene_info and scope:")
94
+ for info in tqdm(filtered_gene_info.itertuples()):
95
+ if not info.gene in hvg_genes:
96
+ continue
97
+ id = info.id
98
+ chr = info.chr
99
+ starts = info.starts
100
+ ends = info.ends
101
+ forward = info.forward
102
+ backward = info.backward
103
+ gene = info.gene
104
+ if not gene in gene_peaks:
105
+ gene_peaks[gene] = set()
106
+ for peak in peaks_to_filter:
107
+ peak_chr, coordinates = peak.split(':')
108
+ peak_start, peak_end = coordinates.split('-')
109
+ if peak_chr == chr and int(peak_start) >= forward and int(peak_end) <= backward:
110
+ gene_peaks[gene].add(peak)
111
+ gene_peaks = {gene: peaks for gene, peaks in gene_peaks.items() if len(peaks) > 0}
112
+ return gene_peaks
113
+
114
+ def select_peaks_from_pairs(gene_peaks):
115
+ filtered_peaks = set()
116
+ print("Search the filtered peaks:")
117
+ for key in tqdm(gene_peaks.keys()):
118
+ filtered_peaks.update(gene_peaks[key])
119
+ filtered_peaks = list(filtered_peaks)
120
+ print("After filtering peaks:", len(filtered_peaks))
121
+ return filtered_peaks
122
+
123
+ def cicero_peaks_peaks(cicero_conn, peakitems, cicero_cotoff):
124
+ filtered_conn = cicero_conn[abs(cicero_conn['coaccess']) >= cicero_cotoff]
125
+
126
+ result_dict = {}
127
+ for peakitem in tqdm(peakitems, desc="Processing peakitems"):
128
+ peak2_values = filtered_conn.loc[filtered_conn['Peak1'] == peakitem, 'Peak2'].tolist()
129
+ if peak2_values:
130
+ result_dict[peakitem] = peak2_values
131
+
132
+ return result_dict
133
+
134
+ def cicero_peaks_peaks_score(cicero_conn, peakitems, cicero_cotoff):
135
+ filtered_conn = cicero_conn[abs(cicero_conn['coaccess']) >= cicero_cotoff]
136
+
137
+ relevant_peaks = filtered_conn[filtered_conn['Peak1'].isin(peakitems)]
138
+
139
+ grouped = relevant_peaks.groupby('Peak1')
140
+
141
+ peaks_lst = []
142
+ scores_lst = []
143
+
144
+ for peakitem in tqdm(peakitems, desc="Processing peakitems"):
145
+ try:
146
+ group = grouped.get_group(peakitem)
147
+ peaks_lst.extend(group['Peak2'].tolist())
148
+ scores_lst.extend(group['coaccess'].tolist())
149
+ except KeyError:
150
+ continue # No matches for this peakitem
151
+
152
+ return peaks_lst, scores_lst
@@ -0,0 +1,2 @@
1
+ from . import Processing
2
+ from . import Intra_strength
@@ -0,0 +1,13 @@
1
+ """Heterogeneous Graph Embedding Module of MultiChat"""
2
+
3
+ from ._settings import settings
4
+ from . import preprocessing as pp
5
+ from . import tools as tl
6
+ from . import plotting as pl
7
+ from .readwrite import *
8
+ from ._version import __version__
9
+
10
+
11
+ import sys
12
+ sys.modules.update(
13
+ {f'{__name__}.{m}': globals()[m] for m in ['tl', 'pp', 'pl']})
@@ -0,0 +1,156 @@
1
+ """Configuration for HGE"""
2
+
3
+ import os
4
+ import seaborn as sns
5
+ import matplotlib as mpl
6
+
7
+
8
+ class HgeConfig:
9
+ """configuration class for HGE"""
10
+
11
+ def __init__(self,
12
+ workdir='./result_hge',
13
+ save_fig=False,
14
+ n_jobs=1):
15
+ self.workdir = workdir
16
+ self.save_fig = save_fig
17
+ self.n_jobs = n_jobs
18
+ self.set_pbg_params()
19
+ self.graph_stats = dict()
20
+
21
+ def set_figure_params(self,
22
+ context='notebook',
23
+ style='white',
24
+ palette='deep',
25
+ font='sans-serif',
26
+ font_scale=1.1,
27
+ color_codes=True,
28
+ dpi=80,
29
+ dpi_save=150,
30
+ fig_size=[5.4, 4.8],
31
+ rc=None):
32
+ """ Set global parameters for figures. Modified from sns.set()
33
+
34
+ Parameters
35
+ ----------
36
+ context : string or dict
37
+ Plotting context parameters, see `seaborn.plotting_context`
38
+ style: `string`,optional (default: 'white')
39
+ Axes style parameters, see `seaborn.axes_style`
40
+ palette : string or sequence
41
+ Color palette, see `seaborn.color_palette`
42
+ font_scale: `float`, optional (default: 1.3)
43
+ Separate scaling factor to independently
44
+ scale the size of the font elements.
45
+ color_codes : `bool`, optional (default: True)
46
+ If ``True`` and ``palette`` is a seaborn palette,
47
+ remap the shorthand color codes (e.g. "b", "g", "r", etc.)
48
+ to the colors from this palette.
49
+ dpi: `int`,optional (default: 80)
50
+ Resolution of rendered figures.
51
+ dpi_save: `int`,optional (default: 150)
52
+ Resolution of saved figures.
53
+ rc: `dict`,optional (default: None)
54
+ rc settings properties.
55
+ Parameter mappings to override the values in the preset style.
56
+ Please see "`matplotlibrc file
57
+ <https://matplotlib.org/tutorials/introductory/customizing.html#a-sample-matplotlibrc-file>`__"
58
+ """
59
+ sns.set(context=context,
60
+ style=style,
61
+ palette=palette,
62
+ font=font,
63
+ font_scale=font_scale,
64
+ color_codes=color_codes,
65
+ rc={'figure.dpi': dpi,
66
+ 'savefig.dpi': dpi_save,
67
+ 'figure.figsize': fig_size,
68
+ 'image.cmap': 'viridis',
69
+ 'lines.markersize': 6,
70
+ 'legend.columnspacing': 0.1,
71
+ 'legend.borderaxespad': 0.1,
72
+ 'legend.handletextpad': 0.1,
73
+ 'pdf.fonttype': 42,
74
+ })
75
+ if rc is not None:
76
+ assert isinstance(rc, dict), "rc must be dict"
77
+ for key, value in rc.items():
78
+ if key in mpl.rcParams.keys():
79
+ mpl.rcParams[key] = value
80
+ else:
81
+ raise Exception("unrecognized property '%s'" % key)
82
+
83
+ def set_workdir(self, workdir=None):
84
+ """Set working directory.
85
+
86
+ Parameters
87
+ ----------
88
+ workdir: `str`, optional (default: None)
89
+ Working directory.
90
+
91
+ Returns
92
+ -------
93
+ """
94
+ if workdir is None:
95
+ workdir = self.workdir
96
+ print("Using default working directory.")
97
+ if not os.path.exists(workdir):
98
+ os.makedirs(workdir)
99
+ self.workdir = workdir
100
+ self.set_pbg_params()
101
+ print('Saving results in: %s' % workdir)
102
+
103
+ def set_pbg_params(self, config=None):
104
+ """Set PBG parameters
105
+
106
+ Parameters
107
+ ----------
108
+ config : `dict`, optional (default: None)
109
+ PBG training configuration parameters.
110
+ By default it resets parameters to the default setting.
111
+
112
+ Returns
113
+ -------
114
+ """
115
+ if config is None:
116
+ config = dict(
117
+ # I/O data
118
+ entity_path="",
119
+ edge_paths=["", ],
120
+ checkpoint_path="",
121
+
122
+ # Graph structure
123
+ entities={},
124
+ relations=[],
125
+ dynamic_relations=False,
126
+
127
+ # Scoring model
128
+ dimension=50,
129
+ global_emb=False,
130
+ comparator='dot',
131
+
132
+ # Training
133
+ num_epochs=10,
134
+ workers=4,
135
+ num_batch_negs=50,
136
+ num_uniform_negs=50,
137
+ loss_fn='softmax',
138
+ lr=0.1,
139
+
140
+ early_stopping=False,
141
+ regularization_coef=0.0,
142
+ wd=0.0,
143
+ wd_interval=50,
144
+
145
+ # Evaluation during training
146
+ eval_fraction=0.05,
147
+ eval_num_batch_negs=50,
148
+ eval_num_uniform_negs=50,
149
+
150
+ checkpoint_preservation_interval=None,
151
+ )
152
+ assert isinstance(config, dict), "`config` must be dict"
153
+ self.pbg_params = config
154
+
155
+
156
+ settings = HgeConfig()
@@ -0,0 +1,143 @@
1
+ """Utility functions and classes"""
2
+
3
+ import numpy as np
4
+ from kneed import KneeLocator
5
+ import tables
6
+ from anndata import AnnData
7
+
8
+
9
+ def locate_elbow(x, y, S=10, min_elbow=0,
10
+ curve='convex', direction='decreasing', online=False,
11
+ **kwargs):
12
+ """Detect knee points
13
+
14
+ Parameters
15
+ ----------
16
+ x : `array-like`
17
+ x values
18
+ y : `array-like`
19
+ y values
20
+ S : `float`, optional (default: 10)
21
+ Sensitivity
22
+ min_elbow: `int`, optional (default: 0)
23
+ The minimum elbow location
24
+ curve: `str`, optional (default: 'convex')
25
+ Choose from {'convex','concave'}
26
+ If 'concave', algorithm will detect knees,
27
+ If 'convex', algorithm will detect elbows.
28
+ direction: `str`, optional (default: 'decreasing')
29
+ Choose from {'decreasing','increasing'}
30
+ online: `bool`, optional (default: False)
31
+ kneed will correct old knee points if True,
32
+ kneed will return first knee if False.
33
+ **kwargs: `dict`, optional
34
+ Extra arguments to KneeLocator.
35
+
36
+ Returns
37
+ -------
38
+ elbow: `int`
39
+ elbow point
40
+ """
41
+ kneedle = KneeLocator(x[int(min_elbow):], y[int(min_elbow):],
42
+ S=S, curve=curve,
43
+ direction=direction,
44
+ online=online,
45
+ **kwargs,
46
+ )
47
+ if kneedle.elbow is None:
48
+ elbow = len(y)
49
+ else:
50
+ elbow = int(kneedle.elbow)
51
+ return elbow
52
+
53
+
54
+ # modifed from
55
+ # scanpy https://github.com/theislab/scanpy/blob/master/scanpy/readwrite.py
56
+ def _read_legacy_10x_h5(filename, genome=None):
57
+ """
58
+ Read hdf5 file from Cell Ranger v2 or earlier versions.
59
+ """
60
+ with tables.open_file(str(filename), 'r') as f:
61
+ try:
62
+ children = [x._v_name for x in f.list_nodes(f.root)]
63
+ if not genome:
64
+ if len(children) > 1:
65
+ raise ValueError(
66
+ f"'{filename}' contains more than one genome. "
67
+ "For legacy 10x h5 "
68
+ "files you must specify the genome "
69
+ "if more than one is present. "
70
+ f"Available genomes are: {children}"
71
+ )
72
+ genome = children[0]
73
+ elif genome not in children:
74
+ raise ValueError(
75
+ f"Could not find genome '{genome}' in '{filename}'. "
76
+ f'Available genomes are: {children}'
77
+ )
78
+ dsets = {}
79
+ for node in f.walk_nodes('/' + genome, 'Array'):
80
+ dsets[node.name] = node.read()
81
+ # AnnData works with csr matrices
82
+ # 10x stores the transposed data, so we do the transposition
83
+ from scipy.sparse import csr_matrix
84
+
85
+ M, N = dsets['shape']
86
+ data = dsets['data']
87
+ if dsets['data'].dtype == np.dtype('int32'):
88
+ data = dsets['data'].view('float32')
89
+ data[:] = dsets['data']
90
+ matrix = csr_matrix(
91
+ (data, dsets['indices'], dsets['indptr']),
92
+ shape=(N, M),
93
+ )
94
+ # the csc matrix is automatically the transposed csr matrix
95
+ # as scanpy expects it, so, no need for a further transpostion
96
+ adata = AnnData(
97
+ matrix,
98
+ obs=dict(obs_names=dsets['barcodes'].astype(str)),
99
+ var=dict(
100
+ var_names=dsets['gene_names'].astype(str),
101
+ gene_ids=dsets['genes'].astype(str),
102
+ ),
103
+ )
104
+ return adata
105
+ except KeyError:
106
+ raise Exception('File is missing one or more required datasets.')
107
+
108
+
109
+ # modifed from
110
+ # scanpy https://github.com/theislab/scanpy/blob/master/scanpy/readwrite.py
111
+ def _read_v3_10x_h5(filename):
112
+ """
113
+ Read hdf5 file from Cell Ranger v3 or later versions.
114
+ """
115
+ with tables.open_file(str(filename), 'r') as f:
116
+ try:
117
+ dsets = {}
118
+ for node in f.walk_nodes('/matrix', 'Array'):
119
+ dsets[node.name] = node.read()
120
+ from scipy.sparse import csr_matrix
121
+
122
+ M, N = dsets['shape']
123
+ data = dsets['data']
124
+ if dsets['data'].dtype == np.dtype('int32'):
125
+ data = dsets['data'].view('float32')
126
+ data[:] = dsets['data']
127
+ matrix = csr_matrix(
128
+ (data, dsets['indices'], dsets['indptr']),
129
+ shape=(N, M),
130
+ )
131
+ adata = AnnData(
132
+ matrix,
133
+ obs=dict(obs_names=dsets['barcodes'].astype(str)),
134
+ var=dict(
135
+ var_names=dsets['name'].astype(str),
136
+ gene_ids=dsets['id'].astype(str),
137
+ feature_types=dsets['feature_type'].astype(str),
138
+ genome=dsets['genome'].astype(str),
139
+ ),
140
+ )
141
+ return adata
142
+ except KeyError:
143
+ raise Exception('File is missing one or more required datasets.')
@@ -0,0 +1,3 @@
1
+ """Version information"""
2
+
3
+ __version__ = "1.0"
@@ -0,0 +1,19 @@
1
+ """Plotting"""
2
+
3
+ from ._plot import (
4
+ pca_variance_ratio,
5
+ pcs_features,
6
+ variable_genes,
7
+ violin,
8
+ hist,
9
+ umap,
10
+ discretize,
11
+ node_similarity,
12
+ svd_nodes,
13
+ )
14
+ from ._post_training import (
15
+ pbg_metrics,
16
+ entity_metrics,
17
+ entity_barcode,
18
+ query
19
+ )
@@ -0,0 +1,180 @@
1
+ """Color palettes in addition to matplotlib's palettes.
2
+ This is modifed from
3
+ scanpy palettes https://github.com/theislab/scanpy/blob/master/scanpy/plotting/palettes.py # noqa
4
+ """
5
+
6
+ from matplotlib import cm, colors
7
+
8
+ # Colorblindness adjusted vega_10
9
+ # See https://github.com/theislab/scanpy/issues/387
10
+ vega_10 = list(map(colors.to_hex, cm.tab10.colors))
11
+ vega_10_scanpy = vega_10.copy()
12
+ vega_10_scanpy[2] = "#279e68" # green
13
+ vega_10_scanpy[4] = "#aa40fc" # purple
14
+ vega_10_scanpy[8] = "#b5bd61" # kakhi
15
+
16
+ # default matplotlib 2.0 palette
17
+ # see 'category20' on https://github.com/vega/vega/wiki/Scales#scale-range-literals # noqa
18
+ vega_20 = list(map(colors.to_hex, cm.tab20.colors))
19
+
20
+ # reorderd, some removed, some added
21
+ vega_20_scanpy = [
22
+ *vega_20[0:14:2],
23
+ *vega_20[16::2], # dark without grey
24
+ *vega_20[1:15:2],
25
+ *vega_20[17::2], # light without grey
26
+ "#ad494a",
27
+ "#8c6d31", # manual additions
28
+ ]
29
+ vega_20_scanpy[2] = vega_10_scanpy[2]
30
+ vega_20_scanpy[4] = vega_10_scanpy[4]
31
+ vega_20_scanpy[7] = vega_10_scanpy[8] # kakhi shifted by missing grey
32
+ # TODO: also replace pale colors if necessary
33
+
34
+ default_20 = vega_20_scanpy
35
+
36
+ # https://graphicdesign.stackexchange.com/questions/3682/where-can-i-find-a-large-palette-set-of-contrasting-colors-for-coloring-many-d
37
+ # update 1
38
+ # orig reference http://epub.wu.ac.at/1692/1/document.pdf
39
+ zeileis_28 = [
40
+ "#023fa5",
41
+ "#7d87b9",
42
+ "#bec1d4",
43
+ "#d6bcc0",
44
+ "#bb7784",
45
+ "#8e063b",
46
+ "#4a6fe3",
47
+ "#8595e1",
48
+ "#b5bbe3",
49
+ "#e6afb9",
50
+ "#e07b91",
51
+ "#d33f6a",
52
+ "#11c638",
53
+ "#8dd593",
54
+ "#c6dec7",
55
+ "#ead3c6",
56
+ "#f0b98d",
57
+ "#ef9708",
58
+ "#0fcfc0",
59
+ "#9cded6",
60
+ "#d5eae7",
61
+ "#f3e1eb",
62
+ "#f6c4e1",
63
+ "#f79cd4",
64
+ "#7f7f7f",
65
+ "#c7c7c7",
66
+ "#1CE6FF",
67
+ "#336600", # these last ones were added,
68
+ ]
69
+
70
+ default_28 = zeileis_28
71
+
72
+ # from http://godsnotwheregodsnot.blogspot.de/2012/09/color-distribution-methodology.html # noqa
73
+ godsnot_102 = [
74
+ # "#000000",
75
+ # remove the black, as often, we have black colored annotation
76
+ "#FFFF00",
77
+ "#1CE6FF",
78
+ "#FF34FF",
79
+ "#FF4A46",
80
+ "#008941",
81
+ "#006FA6",
82
+ "#A30059",
83
+ "#FFDBE5",
84
+ "#7A4900",
85
+ "#0000A6",
86
+ "#63FFAC",
87
+ "#B79762",
88
+ "#004D43",
89
+ "#8FB0FF",
90
+ "#997D87",
91
+ "#5A0007",
92
+ "#809693",
93
+ "#6A3A4C",
94
+ "#1B4400",
95
+ "#4FC601",
96
+ "#3B5DFF",
97
+ "#4A3B53",
98
+ "#FF2F80",
99
+ "#61615A",
100
+ "#BA0900",
101
+ "#6B7900",
102
+ "#00C2A0",
103
+ "#FFAA92",
104
+ "#FF90C9",
105
+ "#B903AA",
106
+ "#D16100",
107
+ "#DDEFFF",
108
+ "#000035",
109
+ "#7B4F4B",
110
+ "#A1C299",
111
+ "#300018",
112
+ "#0AA6D8",
113
+ "#013349",
114
+ "#00846F",
115
+ "#372101",
116
+ "#FFB500",
117
+ "#C2FFED",
118
+ "#A079BF",
119
+ "#CC0744",
120
+ "#C0B9B2",
121
+ "#C2FF99",
122
+ "#001E09",
123
+ "#00489C",
124
+ "#6F0062",
125
+ "#0CBD66",
126
+ "#EEC3FF",
127
+ "#456D75",
128
+ "#B77B68",
129
+ "#7A87A1",
130
+ "#788D66",
131
+ "#885578",
132
+ "#FAD09F",
133
+ "#FF8A9A",
134
+ "#D157A0",
135
+ "#BEC459",
136
+ "#456648",
137
+ "#0086ED",
138
+ "#886F4C",
139
+ "#34362D",
140
+ "#B4A8BD",
141
+ "#00A6AA",
142
+ "#452C2C",
143
+ "#636375",
144
+ "#A3C8C9",
145
+ "#FF913F",
146
+ "#938A81",
147
+ "#575329",
148
+ "#00FECF",
149
+ "#B05B6F",
150
+ "#8CD0FF",
151
+ "#3B9700",
152
+ "#04F757",
153
+ "#C8A1A1",
154
+ "#1E6E00",
155
+ "#7900D7",
156
+ "#A77500",
157
+ "#6367A9",
158
+ "#A05837",
159
+ "#6B002C",
160
+ "#772600",
161
+ "#D790FF",
162
+ "#9B9700",
163
+ "#549E79",
164
+ "#FFF69F",
165
+ "#201625",
166
+ "#72418F",
167
+ "#BC23FF",
168
+ "#99ADC0",
169
+ "#3A2465",
170
+ "#922329",
171
+ "#5B4534",
172
+ "#FDE8DC",
173
+ "#404E55",
174
+ "#0089A3",
175
+ "#CB7E98",
176
+ "#A4E804",
177
+ "#324E72",
178
+ ]
179
+
180
+ default_102 = godsnot_102