sclab 0.1.7__py3-none-any.whl → 0.2.2__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.
Potentially problematic release.
This version of sclab might be problematic. Click here for more details.
- sclab/__init__.py +3 -1
- sclab/_io.py +89 -12
- sclab/_methods_registry.py +65 -0
- sclab/_sclab.py +229 -21
- sclab/dataset/_dataset.py +3 -5
- sclab/dataset/processor/_processor.py +22 -15
- sclab/dataset/processor/_results_panel.py +80 -0
- sclab/dataset/processor/step/_processor_step_base.py +12 -6
- sclab/examples/processor_steps/__init__.py +2 -0
- sclab/examples/processor_steps/_cluster.py +2 -2
- sclab/examples/processor_steps/_differential_expression.py +328 -0
- sclab/examples/processor_steps/_neighbors.py +2 -2
- sclab/examples/processor_steps/_pca.py +2 -2
- sclab/examples/processor_steps/_preprocess.py +2 -2
- sclab/examples/processor_steps/_qc.py +2 -2
- sclab/examples/processor_steps/_umap.py +2 -2
- sclab/methods/__init__.py +28 -0
- sclab/scanpy/_compat.py +92 -0
- sclab/scanpy/_settings.py +526 -0
- sclab/scanpy/logging.py +290 -0
- sclab/scanpy/plotting/__init__.py +0 -0
- sclab/scanpy/plotting/_rcmod.py +73 -0
- sclab/scanpy/plotting/palettes.py +221 -0
- sclab/scanpy/readwrite.py +1108 -0
- {sclab-0.1.7.dist-info → sclab-0.2.2.dist-info}/METADATA +22 -11
- sclab-0.2.2.dist-info/RECORD +42 -0
- {sclab-0.1.7.dist-info → sclab-0.2.2.dist-info}/WHEEL +1 -1
- sclab-0.2.2.dist-info/licenses/LICENSE +29 -0
- sclab-0.1.7.dist-info/RECORD +0 -30
sclab/scanpy/logging.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"""Logging and Profiling"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import sys
|
|
7
|
+
import warnings
|
|
8
|
+
from datetime import datetime, timedelta, timezone
|
|
9
|
+
from functools import partial, update_wrapper
|
|
10
|
+
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
|
|
13
|
+
import anndata.logging
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from typing import IO
|
|
17
|
+
|
|
18
|
+
from ._settings import ScanpyConfig
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# This is currently the only documented API
|
|
22
|
+
__all__ = ["print_versions"]
|
|
23
|
+
|
|
24
|
+
HINT = (INFO + DEBUG) // 2
|
|
25
|
+
logging.addLevelName(HINT, "HINT")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _RootLogger(logging.RootLogger):
|
|
29
|
+
def __init__(self, level):
|
|
30
|
+
super().__init__(level)
|
|
31
|
+
self.propagate = False
|
|
32
|
+
_RootLogger.manager = logging.Manager(self)
|
|
33
|
+
|
|
34
|
+
def log(
|
|
35
|
+
self,
|
|
36
|
+
level: int,
|
|
37
|
+
msg: str,
|
|
38
|
+
*,
|
|
39
|
+
extra: dict | None = None,
|
|
40
|
+
time: datetime | None = None,
|
|
41
|
+
deep: str | None = None,
|
|
42
|
+
) -> datetime:
|
|
43
|
+
from ._settings import settings
|
|
44
|
+
|
|
45
|
+
now = datetime.now(timezone.utc)
|
|
46
|
+
time_passed: timedelta = None if time is None else now - time
|
|
47
|
+
extra = {
|
|
48
|
+
**(extra or {}),
|
|
49
|
+
"deep": deep if settings.verbosity.level < level else None,
|
|
50
|
+
"time_passed": time_passed,
|
|
51
|
+
}
|
|
52
|
+
super().log(level, msg, extra=extra)
|
|
53
|
+
return now
|
|
54
|
+
|
|
55
|
+
def critical(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
56
|
+
return self.log(CRITICAL, msg, time=time, deep=deep, extra=extra)
|
|
57
|
+
|
|
58
|
+
def error(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
59
|
+
return self.log(ERROR, msg, time=time, deep=deep, extra=extra)
|
|
60
|
+
|
|
61
|
+
def warning(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
62
|
+
return self.log(WARNING, msg, time=time, deep=deep, extra=extra)
|
|
63
|
+
|
|
64
|
+
def info(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
65
|
+
return self.log(INFO, msg, time=time, deep=deep, extra=extra)
|
|
66
|
+
|
|
67
|
+
def hint(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
68
|
+
return self.log(HINT, msg, time=time, deep=deep, extra=extra)
|
|
69
|
+
|
|
70
|
+
def debug(self, msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
71
|
+
return self.log(DEBUG, msg, time=time, deep=deep, extra=extra)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _set_log_file(settings: ScanpyConfig):
|
|
75
|
+
file = settings.logfile
|
|
76
|
+
name = settings.logpath
|
|
77
|
+
root = settings._root_logger
|
|
78
|
+
h = logging.StreamHandler(file) if name is None else logging.FileHandler(name)
|
|
79
|
+
h.setFormatter(_LogFormatter())
|
|
80
|
+
h.setLevel(root.level)
|
|
81
|
+
for handler in list(root.handlers):
|
|
82
|
+
root.removeHandler(handler)
|
|
83
|
+
root.addHandler(h)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _set_log_level(settings: ScanpyConfig, level: int):
|
|
87
|
+
root = settings._root_logger
|
|
88
|
+
root.setLevel(level)
|
|
89
|
+
for h in list(root.handlers):
|
|
90
|
+
h.setLevel(level)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class _LogFormatter(logging.Formatter):
|
|
94
|
+
def __init__(
|
|
95
|
+
self, fmt="{levelname}: {message}", datefmt="%Y-%m-%d %H:%M", style="{"
|
|
96
|
+
):
|
|
97
|
+
super().__init__(fmt, datefmt, style)
|
|
98
|
+
|
|
99
|
+
def format(self, record: logging.LogRecord):
|
|
100
|
+
format_orig = self._style._fmt
|
|
101
|
+
if record.levelno == INFO:
|
|
102
|
+
self._style._fmt = "{message}"
|
|
103
|
+
elif record.levelno == HINT:
|
|
104
|
+
self._style._fmt = "--> {message}"
|
|
105
|
+
elif record.levelno == DEBUG:
|
|
106
|
+
self._style._fmt = " {message}"
|
|
107
|
+
if record.time_passed:
|
|
108
|
+
# strip microseconds
|
|
109
|
+
if record.time_passed.microseconds:
|
|
110
|
+
record.time_passed = timedelta(
|
|
111
|
+
seconds=int(record.time_passed.total_seconds())
|
|
112
|
+
)
|
|
113
|
+
if "{time_passed}" in record.msg:
|
|
114
|
+
record.msg = record.msg.replace(
|
|
115
|
+
"{time_passed}", str(record.time_passed)
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
self._style._fmt += " ({time_passed})"
|
|
119
|
+
if record.deep:
|
|
120
|
+
record.msg = f"{record.msg}: {record.deep}"
|
|
121
|
+
result = logging.Formatter.format(self, record)
|
|
122
|
+
self._style._fmt = format_orig
|
|
123
|
+
return result
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
print_memory_usage = anndata.logging.print_memory_usage
|
|
127
|
+
get_memory_usage = anndata.logging.get_memory_usage
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
_DEPENDENCIES_NUMERICS = [
|
|
131
|
+
"anndata", # anndata actually shouldn't, but as long as it's in development
|
|
132
|
+
"umap",
|
|
133
|
+
"numpy",
|
|
134
|
+
"scipy",
|
|
135
|
+
"pandas",
|
|
136
|
+
("sklearn", "scikit-learn"),
|
|
137
|
+
"statsmodels",
|
|
138
|
+
"igraph",
|
|
139
|
+
"louvain",
|
|
140
|
+
"leidenalg",
|
|
141
|
+
"pynndescent",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _versions_dependencies(dependencies):
|
|
146
|
+
# this is not the same as the requirements!
|
|
147
|
+
for mod in dependencies:
|
|
148
|
+
mod_name, dist_name = mod if isinstance(mod, tuple) else (mod, mod)
|
|
149
|
+
try:
|
|
150
|
+
imp = __import__(mod_name)
|
|
151
|
+
yield dist_name, imp.__version__
|
|
152
|
+
except (ImportError, AttributeError):
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def print_header(*, file=None):
|
|
157
|
+
"""\
|
|
158
|
+
Versions that might influence the numerical results.
|
|
159
|
+
Matplotlib and Seaborn are excluded from this.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
file
|
|
164
|
+
Optional path for dependency output.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
modules = ["scanpy"] + _DEPENDENCIES_NUMERICS
|
|
168
|
+
print(
|
|
169
|
+
" ".join(f"{mod}=={ver}" for mod, ver in _versions_dependencies(modules)),
|
|
170
|
+
file=file or sys.stdout,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def print_versions(*, file: IO[str] | None = None):
|
|
175
|
+
"""\
|
|
176
|
+
Print versions of imported packages, OS, and jupyter environment.
|
|
177
|
+
|
|
178
|
+
For more options (including rich output) use `session_info.show` directly.
|
|
179
|
+
|
|
180
|
+
Parameters
|
|
181
|
+
----------
|
|
182
|
+
file
|
|
183
|
+
Optional path for output.
|
|
184
|
+
"""
|
|
185
|
+
import session_info
|
|
186
|
+
|
|
187
|
+
if file is not None:
|
|
188
|
+
from contextlib import redirect_stdout
|
|
189
|
+
|
|
190
|
+
warnings.warn(
|
|
191
|
+
"Passing argument 'file' to print_versions is deprecated, and will be "
|
|
192
|
+
"removed in a future version.",
|
|
193
|
+
FutureWarning,
|
|
194
|
+
)
|
|
195
|
+
with redirect_stdout(file):
|
|
196
|
+
print_versions()
|
|
197
|
+
else:
|
|
198
|
+
session_info.show(
|
|
199
|
+
dependencies=True,
|
|
200
|
+
html=False,
|
|
201
|
+
excludes=[
|
|
202
|
+
"builtins",
|
|
203
|
+
"stdlib_list",
|
|
204
|
+
"importlib_metadata",
|
|
205
|
+
# Special module present if test coverage being calculated
|
|
206
|
+
# https://gitlab.com/joelostblom/session_info/-/issues/10
|
|
207
|
+
"$coverage",
|
|
208
|
+
],
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def print_version_and_date(*, file=None):
|
|
213
|
+
"""\
|
|
214
|
+
Useful for starting a notebook so you see when you started working.
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
file
|
|
219
|
+
Optional path for output.
|
|
220
|
+
"""
|
|
221
|
+
from . import __version__
|
|
222
|
+
|
|
223
|
+
if file is None:
|
|
224
|
+
file = sys.stdout
|
|
225
|
+
print(
|
|
226
|
+
f"Running Scanpy {__version__}, on {datetime.now():%Y-%m-%d %H:%M}.",
|
|
227
|
+
file=file,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _copy_docs_and_signature(fn):
|
|
232
|
+
return partial(update_wrapper, wrapped=fn, assigned=["__doc__", "__annotations__"])
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def error(
|
|
236
|
+
msg: str,
|
|
237
|
+
*,
|
|
238
|
+
time: datetime = None,
|
|
239
|
+
deep: str | None = None,
|
|
240
|
+
extra: dict | None = None,
|
|
241
|
+
) -> datetime:
|
|
242
|
+
"""\
|
|
243
|
+
Log message with specific level and return current time.
|
|
244
|
+
|
|
245
|
+
Parameters
|
|
246
|
+
----------
|
|
247
|
+
msg
|
|
248
|
+
Message to display.
|
|
249
|
+
time
|
|
250
|
+
A time in the past. If this is passed, the time difference from then
|
|
251
|
+
to now is appended to `msg` as ` (HH:MM:SS)`.
|
|
252
|
+
If `msg` contains `{time_passed}`, the time difference is instead
|
|
253
|
+
inserted at that position.
|
|
254
|
+
deep
|
|
255
|
+
If the current verbosity is higher than the log function’s level,
|
|
256
|
+
this gets displayed as well
|
|
257
|
+
extra
|
|
258
|
+
Additional values you can specify in `msg` like `{time_passed}`.
|
|
259
|
+
"""
|
|
260
|
+
from ._settings import settings
|
|
261
|
+
|
|
262
|
+
return settings._root_logger.error(msg, time=time, deep=deep, extra=extra)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@_copy_docs_and_signature(error)
|
|
266
|
+
def warning(msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
267
|
+
from ._settings import settings
|
|
268
|
+
|
|
269
|
+
return settings._root_logger.warning(msg, time=time, deep=deep, extra=extra)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@_copy_docs_and_signature(error)
|
|
273
|
+
def info(msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
274
|
+
from ._settings import settings
|
|
275
|
+
|
|
276
|
+
return settings._root_logger.info(msg, time=time, deep=deep, extra=extra)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
@_copy_docs_and_signature(error)
|
|
280
|
+
def hint(msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
281
|
+
from ._settings import settings
|
|
282
|
+
|
|
283
|
+
return settings._root_logger.hint(msg, time=time, deep=deep, extra=extra)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@_copy_docs_and_signature(error)
|
|
287
|
+
def debug(msg, *, time=None, deep=None, extra=None) -> datetime:
|
|
288
|
+
from ._settings import settings
|
|
289
|
+
|
|
290
|
+
return settings._root_logger.debug(msg, time=time, deep=deep, extra=extra)
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Set the default matplotlib.rcParams."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import matplotlib as mpl
|
|
6
|
+
from cycler import cycler
|
|
7
|
+
from matplotlib import rcParams
|
|
8
|
+
|
|
9
|
+
from . import palettes
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def set_rcParams_scanpy(fontsize=14, color_map=None):
|
|
13
|
+
"""Set matplotlib.rcParams to Scanpy defaults.
|
|
14
|
+
|
|
15
|
+
Call this through `settings.set_figure_params`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# figure
|
|
19
|
+
rcParams["figure.figsize"] = (4, 4)
|
|
20
|
+
rcParams["figure.subplot.left"] = 0.18
|
|
21
|
+
rcParams["figure.subplot.right"] = 0.96
|
|
22
|
+
rcParams["figure.subplot.bottom"] = 0.15
|
|
23
|
+
rcParams["figure.subplot.top"] = 0.91
|
|
24
|
+
|
|
25
|
+
rcParams["lines.linewidth"] = 1.5 # the line width of the frame
|
|
26
|
+
rcParams["lines.markersize"] = 6
|
|
27
|
+
rcParams["lines.markeredgewidth"] = 1
|
|
28
|
+
|
|
29
|
+
# font
|
|
30
|
+
rcParams["font.sans-serif"] = [
|
|
31
|
+
"Arial",
|
|
32
|
+
"Helvetica",
|
|
33
|
+
"DejaVu Sans",
|
|
34
|
+
"Bitstream Vera Sans",
|
|
35
|
+
"sans-serif",
|
|
36
|
+
]
|
|
37
|
+
fontsize = fontsize
|
|
38
|
+
rcParams["font.size"] = fontsize
|
|
39
|
+
rcParams["legend.fontsize"] = 0.92 * fontsize
|
|
40
|
+
rcParams["axes.titlesize"] = fontsize
|
|
41
|
+
rcParams["axes.labelsize"] = fontsize
|
|
42
|
+
|
|
43
|
+
# legend
|
|
44
|
+
rcParams["legend.numpoints"] = 1
|
|
45
|
+
rcParams["legend.scatterpoints"] = 1
|
|
46
|
+
rcParams["legend.handlelength"] = 0.5
|
|
47
|
+
rcParams["legend.handletextpad"] = 0.4
|
|
48
|
+
|
|
49
|
+
# color cycle
|
|
50
|
+
rcParams["axes.prop_cycle"] = cycler(color=palettes.default_20)
|
|
51
|
+
|
|
52
|
+
# lines
|
|
53
|
+
rcParams["axes.linewidth"] = 0.8
|
|
54
|
+
rcParams["axes.edgecolor"] = "black"
|
|
55
|
+
rcParams["axes.facecolor"] = "white"
|
|
56
|
+
|
|
57
|
+
# ticks
|
|
58
|
+
rcParams["xtick.color"] = "k"
|
|
59
|
+
rcParams["ytick.color"] = "k"
|
|
60
|
+
rcParams["xtick.labelsize"] = fontsize
|
|
61
|
+
rcParams["ytick.labelsize"] = fontsize
|
|
62
|
+
|
|
63
|
+
# axes grid
|
|
64
|
+
rcParams["axes.grid"] = True
|
|
65
|
+
rcParams["grid.color"] = ".8"
|
|
66
|
+
|
|
67
|
+
# color map
|
|
68
|
+
rcParams["image.cmap"] = rcParams["image.cmap"] if color_map is None else color_map
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def set_rcParams_defaults():
|
|
72
|
+
"""Reset `matplotlib.rcParams` to defaults."""
|
|
73
|
+
rcParams.update(mpl.rcParamsDefault)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Color palettes in addition to matplotlib's palettes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from matplotlib import cm, colors
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
11
|
+
|
|
12
|
+
# Colorblindness adjusted vega_10
|
|
13
|
+
# See https://github.com/scverse/scanpy/issues/387
|
|
14
|
+
vega_10 = list(map(colors.to_hex, cm.tab10.colors))
|
|
15
|
+
vega_10_scanpy = vega_10.copy()
|
|
16
|
+
vega_10_scanpy[2] = "#279e68" # green
|
|
17
|
+
vega_10_scanpy[4] = "#aa40fc" # purple
|
|
18
|
+
vega_10_scanpy[8] = "#b5bd61" # kakhi
|
|
19
|
+
|
|
20
|
+
# default matplotlib 2.0 palette
|
|
21
|
+
# see 'category20' on https://github.com/vega/vega/wiki/Scales#scale-range-literals
|
|
22
|
+
vega_20 = list(map(colors.to_hex, cm.tab20.colors))
|
|
23
|
+
|
|
24
|
+
# reorderd, some removed, some added
|
|
25
|
+
vega_20_scanpy = [
|
|
26
|
+
# dark without grey:
|
|
27
|
+
*vega_20[0:14:2],
|
|
28
|
+
*vega_20[16::2],
|
|
29
|
+
# light without grey:
|
|
30
|
+
*vega_20[1:15:2],
|
|
31
|
+
*vega_20[17::2],
|
|
32
|
+
# manual additions:
|
|
33
|
+
"#ad494a",
|
|
34
|
+
"#8c6d31",
|
|
35
|
+
]
|
|
36
|
+
vega_20_scanpy[2] = vega_10_scanpy[2]
|
|
37
|
+
vega_20_scanpy[4] = vega_10_scanpy[4]
|
|
38
|
+
vega_20_scanpy[7] = vega_10_scanpy[8] # kakhi shifted by missing grey
|
|
39
|
+
# TODO: also replace pale colors if necessary
|
|
40
|
+
|
|
41
|
+
default_20 = vega_20_scanpy
|
|
42
|
+
|
|
43
|
+
# https://graphicdesign.stackexchange.com/questions/3682/where-can-i-find-a-large-palette-set-of-contrasting-colors-for-coloring-many-d
|
|
44
|
+
# update 1
|
|
45
|
+
# orig reference https://research.wu.ac.at/en/publications/escaping-rgbland-selecting-colors-for-statistical-graphics-26
|
|
46
|
+
zeileis_28 = [
|
|
47
|
+
"#023fa5",
|
|
48
|
+
"#7d87b9",
|
|
49
|
+
"#bec1d4",
|
|
50
|
+
"#d6bcc0",
|
|
51
|
+
"#bb7784",
|
|
52
|
+
"#8e063b",
|
|
53
|
+
"#4a6fe3",
|
|
54
|
+
"#8595e1",
|
|
55
|
+
"#b5bbe3",
|
|
56
|
+
"#e6afb9",
|
|
57
|
+
"#e07b91",
|
|
58
|
+
"#d33f6a",
|
|
59
|
+
"#11c638",
|
|
60
|
+
"#8dd593",
|
|
61
|
+
"#c6dec7",
|
|
62
|
+
"#ead3c6",
|
|
63
|
+
"#f0b98d",
|
|
64
|
+
"#ef9708",
|
|
65
|
+
"#0fcfc0",
|
|
66
|
+
"#9cded6",
|
|
67
|
+
"#d5eae7",
|
|
68
|
+
"#f3e1eb",
|
|
69
|
+
"#f6c4e1",
|
|
70
|
+
"#f79cd4",
|
|
71
|
+
# these last ones were added:
|
|
72
|
+
"#7f7f7f",
|
|
73
|
+
"#c7c7c7",
|
|
74
|
+
"#1CE6FF",
|
|
75
|
+
"#336600",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
default_28 = zeileis_28
|
|
79
|
+
|
|
80
|
+
# from https://godsnotwheregodsnot.blogspot.com/2012/09/color-distribution-methodology.html
|
|
81
|
+
godsnot_102 = [
|
|
82
|
+
# "#000000", # remove the black, as often, we have black colored annotation
|
|
83
|
+
"#FFFF00",
|
|
84
|
+
"#1CE6FF",
|
|
85
|
+
"#FF34FF",
|
|
86
|
+
"#FF4A46",
|
|
87
|
+
"#008941",
|
|
88
|
+
"#006FA6",
|
|
89
|
+
"#A30059",
|
|
90
|
+
"#FFDBE5",
|
|
91
|
+
"#7A4900",
|
|
92
|
+
"#0000A6",
|
|
93
|
+
"#63FFAC",
|
|
94
|
+
"#B79762",
|
|
95
|
+
"#004D43",
|
|
96
|
+
"#8FB0FF",
|
|
97
|
+
"#997D87",
|
|
98
|
+
"#5A0007",
|
|
99
|
+
"#809693",
|
|
100
|
+
"#6A3A4C",
|
|
101
|
+
"#1B4400",
|
|
102
|
+
"#4FC601",
|
|
103
|
+
"#3B5DFF",
|
|
104
|
+
"#4A3B53",
|
|
105
|
+
"#FF2F80",
|
|
106
|
+
"#61615A",
|
|
107
|
+
"#BA0900",
|
|
108
|
+
"#6B7900",
|
|
109
|
+
"#00C2A0",
|
|
110
|
+
"#FFAA92",
|
|
111
|
+
"#FF90C9",
|
|
112
|
+
"#B903AA",
|
|
113
|
+
"#D16100",
|
|
114
|
+
"#DDEFFF",
|
|
115
|
+
"#000035",
|
|
116
|
+
"#7B4F4B",
|
|
117
|
+
"#A1C299",
|
|
118
|
+
"#300018",
|
|
119
|
+
"#0AA6D8",
|
|
120
|
+
"#013349",
|
|
121
|
+
"#00846F",
|
|
122
|
+
"#372101",
|
|
123
|
+
"#FFB500",
|
|
124
|
+
"#C2FFED",
|
|
125
|
+
"#A079BF",
|
|
126
|
+
"#CC0744",
|
|
127
|
+
"#C0B9B2",
|
|
128
|
+
"#C2FF99",
|
|
129
|
+
"#001E09",
|
|
130
|
+
"#00489C",
|
|
131
|
+
"#6F0062",
|
|
132
|
+
"#0CBD66",
|
|
133
|
+
"#EEC3FF",
|
|
134
|
+
"#456D75",
|
|
135
|
+
"#B77B68",
|
|
136
|
+
"#7A87A1",
|
|
137
|
+
"#788D66",
|
|
138
|
+
"#885578",
|
|
139
|
+
"#FAD09F",
|
|
140
|
+
"#FF8A9A",
|
|
141
|
+
"#D157A0",
|
|
142
|
+
"#BEC459",
|
|
143
|
+
"#456648",
|
|
144
|
+
"#0086ED",
|
|
145
|
+
"#886F4C",
|
|
146
|
+
"#34362D",
|
|
147
|
+
"#B4A8BD",
|
|
148
|
+
"#00A6AA",
|
|
149
|
+
"#452C2C",
|
|
150
|
+
"#636375",
|
|
151
|
+
"#A3C8C9",
|
|
152
|
+
"#FF913F",
|
|
153
|
+
"#938A81",
|
|
154
|
+
"#575329",
|
|
155
|
+
"#00FECF",
|
|
156
|
+
"#B05B6F",
|
|
157
|
+
"#8CD0FF",
|
|
158
|
+
"#3B9700",
|
|
159
|
+
"#04F757",
|
|
160
|
+
"#C8A1A1",
|
|
161
|
+
"#1E6E00",
|
|
162
|
+
"#7900D7",
|
|
163
|
+
"#A77500",
|
|
164
|
+
"#6367A9",
|
|
165
|
+
"#A05837",
|
|
166
|
+
"#6B002C",
|
|
167
|
+
"#772600",
|
|
168
|
+
"#D790FF",
|
|
169
|
+
"#9B9700",
|
|
170
|
+
"#549E79",
|
|
171
|
+
"#FFF69F",
|
|
172
|
+
"#201625",
|
|
173
|
+
"#72418F",
|
|
174
|
+
"#BC23FF",
|
|
175
|
+
"#99ADC0",
|
|
176
|
+
"#3A2465",
|
|
177
|
+
"#922329",
|
|
178
|
+
"#5B4534",
|
|
179
|
+
"#FDE8DC",
|
|
180
|
+
"#404E55",
|
|
181
|
+
"#0089A3",
|
|
182
|
+
"#CB7E98",
|
|
183
|
+
"#A4E804",
|
|
184
|
+
"#324E72",
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
default_102 = godsnot_102
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _plot_color_cycle(clists: Mapping[str, Sequence[str]]):
|
|
191
|
+
import matplotlib.pyplot as plt
|
|
192
|
+
import numpy as np
|
|
193
|
+
from matplotlib.colors import BoundaryNorm, ListedColormap
|
|
194
|
+
|
|
195
|
+
fig, axes = plt.subplots(nrows=len(clists)) # type: plt.Figure, plt.Axes
|
|
196
|
+
fig.subplots_adjust(top=0.95, bottom=0.01, left=0.3, right=0.99)
|
|
197
|
+
axes[0].set_title("Color Maps/Cycles", fontsize=14)
|
|
198
|
+
|
|
199
|
+
for ax, (name, clist) in zip(axes, clists.items()):
|
|
200
|
+
n = len(clist)
|
|
201
|
+
ax.imshow(
|
|
202
|
+
np.arange(n)[None, :].repeat(2, 0),
|
|
203
|
+
aspect="auto",
|
|
204
|
+
cmap=ListedColormap(clist),
|
|
205
|
+
norm=BoundaryNorm(np.arange(n + 1) - 0.5, n),
|
|
206
|
+
)
|
|
207
|
+
pos = list(ax.get_position().bounds)
|
|
208
|
+
x_text = pos[0] - 0.01
|
|
209
|
+
y_text = pos[1] + pos[3] / 2.0
|
|
210
|
+
fig.text(x_text, y_text, name, va="center", ha="right", fontsize=10)
|
|
211
|
+
|
|
212
|
+
# Turn off all ticks & spines
|
|
213
|
+
for ax in axes:
|
|
214
|
+
ax.set_axis_off()
|
|
215
|
+
fig.show()
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if __name__ == "__main__":
|
|
219
|
+
_plot_color_cycle(
|
|
220
|
+
{name: colors for name, colors in globals().items() if isinstance(colors, list)}
|
|
221
|
+
)
|