plotille 6.0.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.

Potentially problematic release.


This version of plotille might be problematic. Click here for more details.

plotille/__init__.py ADDED
@@ -0,0 +1,41 @@
1
+ # The MIT License
2
+
3
+ # Copyright (c) 2017 - 2025 Tammo Ippen, tammo.ippen@posteo.de
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ from ._canvas import Canvas
24
+ from ._cmaps import Colormap, ListedColormap
25
+ from ._colors import color, hsl
26
+ from ._figure import Figure
27
+ from ._graphs import hist, hist_aggregated, histogram, plot, scatter
28
+
29
+ __all__ = [
30
+ "Canvas",
31
+ "Colormap",
32
+ "Figure",
33
+ "ListedColormap",
34
+ "color",
35
+ "hist",
36
+ "hist_aggregated",
37
+ "histogram",
38
+ "hsl",
39
+ "plot",
40
+ "scatter",
41
+ ]
plotille/_canvas.py ADDED
@@ -0,0 +1,443 @@
1
+ # The MIT License
2
+
3
+ # Copyright (c) 2017 - 2025 Tammo Ippen, tammo.ippen@posteo.de
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ import os
24
+ from collections.abc import Sequence
25
+ from typing import Any, Union
26
+
27
+ from ._colors import MAX_RGB, RGB_VALUES, ColorDefinition, RGB_t, rgb2byte
28
+ from ._dots import Dots
29
+ from ._util import roundeven
30
+
31
+ DotCoord = int
32
+ RefCoord = Union[float, int]
33
+
34
+
35
+ class Canvas:
36
+ """A canvas object for plotting braille dots
37
+
38
+ A Canvas object has a `width` x `height` characters large canvas, in which it
39
+ can plot indivitual braille point, lines out of braille points, rectangles,...
40
+ Since a full braille character has 2 x 4 dots (⣿), the canvas has `width` * 2,
41
+ `height` * 4 dots to plot into in total.
42
+
43
+ It maintains two coordinate systems: a reference system with the limits (xmin, ymin)
44
+ in the lower left corner to (xmax, ymax) in the upper right corner is transformed
45
+ into the canvas discrete, i.e. dots, coordinate system (0, 0) to (`width` * 2,
46
+ `height` * 4). It does so transparently to clients of the Canvas, i.e. all plotting
47
+ functions only accept coordinates in the reference system. If the coordinates are
48
+ outside the reference system, they are not plotted.
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ width: DotCoord,
54
+ height: DotCoord,
55
+ xmin: RefCoord = 0,
56
+ ymin: RefCoord = 0,
57
+ xmax: RefCoord = 1,
58
+ ymax: RefCoord = 1,
59
+ background: ColorDefinition = None,
60
+ **color_kwargs: Any,
61
+ ) -> None:
62
+ """Initiate a Canvas object
63
+
64
+ Parameters:
65
+ width: int The number of characters for the width (columns) of
66
+ the canvas.
67
+ height: int The number of characters for the hight (rows) of the
68
+ canvas.
69
+ xmin, ymin: float Lower left corner of reference system.
70
+ xmax, ymax: float Upper right corner of reference system.
71
+ background: multiple Background color of the canvas.
72
+ **color_kwargs: More arguments to the color-function.
73
+ See `plotille.color()`.
74
+
75
+ Returns:
76
+ Canvas object
77
+ """
78
+ assert isinstance(width, int), "`width` has to be of type `int`"
79
+ assert isinstance(height, int), "`height` has to be of type `int`"
80
+ assert width > 0, "`width` has to be greater than 0"
81
+ assert height > 0, "`height` has to be greater than 0"
82
+ assert isinstance(xmin, (int, float))
83
+ assert isinstance(xmax, (int, float))
84
+ assert isinstance(ymin, (int, float))
85
+ assert isinstance(ymax, (int, float))
86
+ assert xmin < xmax, f"xmin ({xmin}) has to be smaller than xmax ({xmax})"
87
+ assert ymin < ymax, f"ymin ({ymin}) has to be smaller than ymax ({ymax})"
88
+
89
+ # characters in X / Y direction
90
+ self._width = width
91
+ self._height = height
92
+ # the X / Y limits of the canvas, i.e. (0, 0) in canvas is (xmin,ymin) and
93
+ # (width-1, height-1) in canvas is (xmax, ymax)
94
+ self._xmin = xmin
95
+ self._xmax = xmax
96
+ self._ymin = ymin
97
+ self._ymax = ymax
98
+ # value of x/y between one point
99
+ self._x_delta_pt = abs((xmax - xmin) / (width * 2))
100
+ self._y_delta_pt = abs((ymax - ymin) / (height * 4))
101
+ # the canvas to print in
102
+ self._color_mode = color_kwargs.get("mode", "names")
103
+ self._canvas = [
104
+ [Dots(bg=background, **color_kwargs) for j_ in range(width)]
105
+ for i_ in range(height)
106
+ ]
107
+
108
+ def __str__(self) -> str:
109
+ return f"Canvas(width={self.width}, height={self.height}, xmin={self.xmin}, ymin={self.ymin}, xmax={self.xmax}, ymax={self.ymax})"
110
+
111
+ def __repr__(self) -> str:
112
+ return self.__str__()
113
+
114
+ @property
115
+ def width(self) -> int:
116
+ """Number of characters in X direction"""
117
+ return self._width
118
+
119
+ @property
120
+ def height(self) -> int:
121
+ """Number of characters in Y direction"""
122
+ return self._height
123
+
124
+ @property
125
+ def xmin(self) -> RefCoord:
126
+ """Get xmin coordinate of reference coordinate system [including]."""
127
+ return self._xmin
128
+
129
+ @property
130
+ def ymin(self) -> RefCoord:
131
+ """Get ymin coordinate of reference coordinate system [including]."""
132
+ return self._ymin
133
+
134
+ @property
135
+ def xmax(self) -> RefCoord:
136
+ """Get xmax coordinate of reference coordinate system [excluding]."""
137
+ return self._xmax
138
+
139
+ @property
140
+ def xmax_inside(self) -> float:
141
+ "Get max x-coordinate of reference coordinate system still inside the canvas."
142
+ return self.xmin + (self.width * 2 - 1) * self._x_delta_pt
143
+
144
+ @property
145
+ def ymax(self) -> RefCoord:
146
+ """Get ymax coordinate of reference coordinate system [excluding]."""
147
+ return self._ymax
148
+
149
+ @property
150
+ def ymax_inside(self) -> float:
151
+ "Get max y-coordinate of reference coordinate system still inside the canvas."
152
+ return self.ymin + (self.height * 4 - 1) * self._y_delta_pt
153
+
154
+ def _transform_x(self, x: RefCoord) -> DotCoord:
155
+ return int(roundeven((x - self.xmin) / self._x_delta_pt))
156
+
157
+ def _transform_y(self, y: RefCoord) -> DotCoord:
158
+ return int(roundeven((y - self.ymin) / self._y_delta_pt))
159
+
160
+ def _set(
161
+ self,
162
+ x_idx: int,
163
+ y_idx: int,
164
+ set_: bool = True,
165
+ color: ColorDefinition = None,
166
+ marker: str | None = None,
167
+ ) -> None:
168
+ """Put a dot into the canvas at (x_idx, y_idx) [canvas coordinate system]
169
+
170
+ Parameters:
171
+ x: int x-coordinate on canvas.
172
+ y: int y-coordinate on canvas.
173
+ set_: bool Whether to plot or remove the point.
174
+ color: multiple Color of the point.
175
+ marker: str Instead of braille dots set a marker char.
176
+ """
177
+ x_c, x_p = x_idx // 2, x_idx % 2
178
+ y_c, y_p = y_idx // 4, y_idx % 4
179
+
180
+ if 0 <= x_c < self.width and 0 <= y_c < self.height:
181
+ self._canvas[y_c][x_c].update(x_p, y_p, set_, marker)
182
+ if color:
183
+ if set_:
184
+ self._canvas[y_c][x_c].fg = color
185
+ elif color == self._canvas[y_c][x_c].fg:
186
+ self._canvas[y_c][x_c].fg = None
187
+
188
+ def dots_between(
189
+ self, x0: RefCoord, y0: RefCoord, x1: RefCoord, y1: RefCoord
190
+ ) -> tuple[DotCoord, DotCoord]:
191
+ """Number of dots between (x0, y0) and (x1, y1).
192
+
193
+ Parameters:
194
+ x0, y0: float Point 0
195
+ x1, y1: float Point 1
196
+
197
+ Returns:
198
+ (int, int): dots in (x, y) direction
199
+ """
200
+ x0_idx = self._transform_x(x0)
201
+ y0_idx = self._transform_y(y0)
202
+ x1_idx = self._transform_x(x1)
203
+ y1_idx = self._transform_y(y1)
204
+
205
+ return x1_idx - x0_idx, y1_idx - y0_idx
206
+
207
+ def text(
208
+ self,
209
+ x: RefCoord,
210
+ y: RefCoord,
211
+ text: str,
212
+ set_: bool = True,
213
+ color: ColorDefinition = None,
214
+ ) -> None:
215
+ """Put some text into the canvas at (x, y) [reference coordinate system]
216
+
217
+ Parameters:
218
+ x: float x-coordinate on reference system.
219
+ y: float y-coordinate on reference system.
220
+ set_: bool Whether to set the text or clear the characters.
221
+ text: str The text to add.
222
+ color: multiple Color of the point.
223
+ """
224
+ x_idx = self._transform_x(x) // 2
225
+ y_idx = self._transform_y(y) // 4
226
+
227
+ for idx in range(self.width - x_idx):
228
+ if text is None or len(text) <= idx:
229
+ break
230
+ val: str | None = text[idx]
231
+ if not set_:
232
+ val = None
233
+ self._canvas[y_idx][x_idx + idx].marker = val
234
+ if color:
235
+ if set_:
236
+ self._canvas[y_idx][x_idx + idx].fg = color
237
+ elif color == self._canvas[y_idx][x_idx + idx].fg:
238
+ self._canvas[y_idx][x_idx + idx].fg = None
239
+
240
+ def point(
241
+ self,
242
+ x: RefCoord,
243
+ y: RefCoord,
244
+ set_: bool = True,
245
+ color: ColorDefinition = None,
246
+ marker: str | None = None,
247
+ ) -> None:
248
+ """Put a point into the canvas at (x, y) [reference coordinate system]
249
+
250
+ Parameters:
251
+ x: float x-coordinate on reference system.
252
+ y: float y-coordinate on reference system.
253
+ set_: bool Whether to plot or remove the point.
254
+ color: multiple Color of the point.
255
+ marker: str Instead of braille dots set a marker char.
256
+ """
257
+ x_idx = self._transform_x(x)
258
+ y_idx = self._transform_y(y)
259
+ self._set(x_idx, y_idx, set_, color, marker)
260
+
261
+ def fill_char(self, x: RefCoord, y: RefCoord, set_: bool = True) -> None:
262
+ """Fill the complete character at the point (x, y) [reference coordinate system]
263
+
264
+ Parameters:
265
+ x: float x-coordinate on reference system.
266
+ y: float y-coordinate on reference system.
267
+ set_: bool Whether to plot or remove the point.
268
+ """
269
+ x_idx = self._transform_x(x)
270
+ y_idx = self._transform_y(y)
271
+
272
+ x_c = x_idx // 2
273
+ y_c = y_idx // 4
274
+
275
+ if set_:
276
+ self._canvas[y_c][x_c].fill()
277
+ else:
278
+ self._canvas[y_c][x_c].clear()
279
+
280
+ def line(
281
+ self,
282
+ x0: RefCoord,
283
+ y0: RefCoord,
284
+ x1: RefCoord,
285
+ y1: RefCoord,
286
+ set_: bool = True,
287
+ color: ColorDefinition = None,
288
+ ) -> None:
289
+ """Plot line between point (x0, y0) and (x1, y1) [reference coordinate system].
290
+
291
+ Parameters:
292
+ x0, y0: float Point 0
293
+ x1, y1: float Point 1
294
+ set_: bool Whether to plot or remove the line.
295
+ color: multiple Color of the line.
296
+ """
297
+ x0_idx = self._transform_x(x0)
298
+ y0_idx = self._transform_y(y0)
299
+ self._set(x0_idx, y0_idx, set_, color)
300
+
301
+ x1_idx = self._transform_x(x1)
302
+ y1_idx = self._transform_y(y1)
303
+ self._set(x1_idx, y1_idx, set_, color)
304
+
305
+ x_diff = x1_idx - x0_idx
306
+ y_diff = y1_idx - y0_idx
307
+ steps = max(abs(x_diff), abs(y_diff))
308
+ for i in range(1, steps):
309
+ xb = x0_idx + int(roundeven(x_diff / steps * i))
310
+ yb = y0_idx + int(roundeven(y_diff / steps * i))
311
+ self._set(xb, yb, set_, color)
312
+
313
+ def rect(
314
+ self,
315
+ xmin: RefCoord,
316
+ ymin: RefCoord,
317
+ xmax: RefCoord,
318
+ ymax: RefCoord,
319
+ set_: bool = True,
320
+ color: ColorDefinition = None,
321
+ ) -> None:
322
+ """Plot rectangle with bbox (xmin, ymin) and (xmax, ymax).
323
+
324
+ In the reference coordinate system.
325
+
326
+ Parameters:
327
+ xmin, ymin: float Lower left corner of rectangle.
328
+ xmax, ymax: float Upper right corner of rectangle.
329
+ set_: bool Whether to plot or remove the rect.
330
+ color: multiple Color of the rect.
331
+ """
332
+ assert xmin <= xmax
333
+ assert ymin <= ymax
334
+ self.line(xmin, ymin, xmin, ymax, set_, color)
335
+ self.line(xmin, ymax, xmax, ymax, set_, color)
336
+ self.line(xmax, ymax, xmax, ymin, set_, color)
337
+ self.line(xmax, ymin, xmin, ymin, set_, color)
338
+
339
+ def braille_image(
340
+ self,
341
+ pixels: Sequence[int],
342
+ threshold: int = 127,
343
+ inverse: bool = False,
344
+ color: ColorDefinition = None,
345
+ set_: bool = True,
346
+ ) -> None:
347
+ """Print an image using braille dots into the canvas.
348
+
349
+ The pixels and braille dots in the canvas are a 1-to-1 mapping, hence
350
+ a 80 x 80 pixel image will need a 40 x 20 canvas.
351
+
352
+ Example:
353
+ from PIL import Image
354
+ import plotille as plt
355
+
356
+ img = Image.open("/path/to/image")
357
+ img = img.convert('L')
358
+ img = img.resize((80, 80))
359
+ cvs = plt.Canvas(40, 20)
360
+ cvs.braille_image(img.getdata(), 125)
361
+ print(cvs.plot())
362
+
363
+ Parameters:
364
+ pixels: list[number] All pixels of the image in one list.
365
+ threshold: float All pixels above this threshold will be
366
+ drawn.
367
+ inverse: bool Whether to invert the image.
368
+ color: multiple Color of the point.
369
+ set_: bool Whether to plot or remove the dots.
370
+ """
371
+ assert len(pixels) == self.width * 2 * self.height * 4
372
+ row_size = self.width * 2
373
+
374
+ for idx, value in enumerate(pixels):
375
+ do_dot = value >= threshold
376
+ if inverse:
377
+ do_dot = not do_dot
378
+ if not do_dot:
379
+ continue
380
+ y = self.height * 4 - idx // row_size - 1
381
+ x = idx % row_size
382
+
383
+ self._set(x, y, color=color, set_=set_)
384
+
385
+ def image(self, pixels: Sequence[RGB_t | None], set_: bool = True) -> None:
386
+ """Print an image using background colors into the canvas.
387
+
388
+ The pixels of the image and the characters in the canvas are a
389
+ 1-to-1 mapping, hence a 80 x 80 image will need a 80 x 80 canvas.
390
+
391
+ Example:
392
+ from PIL import Image
393
+ import plotille as plt
394
+
395
+ img = Image.open("/path/to/image")
396
+ img = img.convert('RGB')
397
+ img = img.resize((40, 40))
398
+ cvs = plt.Canvas(40, 40, mode='rgb')
399
+ cvs.image(img.getdata())
400
+ print(cvs.plot())
401
+
402
+ Parameters:
403
+ pixels: list[(R,G,B)] All pixels of the image in one list.
404
+ set_: bool Whether to plot or remove the background
405
+ colors.
406
+ """
407
+ assert len(pixels) == self.width * self.height
408
+
409
+ for idx, values in enumerate(pixels):
410
+ if values is None:
411
+ continue
412
+ # RGB
413
+ assert len(values) == RGB_VALUES
414
+ assert all(0 <= v <= MAX_RGB for v in values)
415
+
416
+ y = self.height - idx // self.width - 1
417
+ x = idx % self.width
418
+
419
+ color_value: ColorDefinition
420
+ if set_ is False:
421
+ color_value = None
422
+ elif self._color_mode == "rgb":
423
+ color_value = values
424
+ elif self._color_mode == "byte":
425
+ color_value = rgb2byte(*values)
426
+ else:
427
+ raise NotImplementedError(
428
+ "Only color_modes rgb and byte are supported."
429
+ )
430
+
431
+ self._canvas[y][x].bg = color_value
432
+
433
+ def plot(self, linesep: str = os.linesep) -> str:
434
+ """Transform canvas into `print`-able string
435
+
436
+ Parameters:
437
+ linesep: str The requested line separator. default: os.linesep
438
+
439
+ Returns:
440
+ unicode: The canvas as a string.
441
+ """
442
+
443
+ return linesep.join("".join(map(str, row)) for row in reversed(self._canvas))
plotille/_cmaps.py ADDED
@@ -0,0 +1,124 @@
1
+ # The MIT License
2
+
3
+ # Copyright (c) 2017 - 2025 Tammo Ippen, tammo.ippen@posteo.de
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ import math
24
+ from collections.abc import Sequence
25
+
26
+ from . import _cmaps_data
27
+
28
+ Number = float | int
29
+
30
+
31
+ class Colormap:
32
+ """
33
+ Baseclass for all scalar to RGB mappings.
34
+
35
+ Typically, Colormap instances are used to convert data values (floats)
36
+ from the interval `[0, 1]` to the RGB color that the respective
37
+ Colormap represents. Scaling the data into the `[0, 1]` interval is
38
+ responsibility of the caller.
39
+ """
40
+
41
+ def __init__(self, name: str, lookup_table: Sequence[Sequence[float]]) -> None:
42
+ """
43
+ Parameters
44
+ ----------
45
+ name : str
46
+ The name of the colormap.
47
+ N : int
48
+ The number of rgb quantization levels.
49
+ """
50
+ self.name: str = name
51
+ self._lookup_table: Sequence[Sequence[float]] = lookup_table
52
+ self.bad: Sequence[Number] | None = None
53
+ self.over: Sequence[Number] | None = None
54
+ self.under: Sequence[Number] | None = None
55
+
56
+ def __call__(
57
+ self, X: Number | Sequence[Number]
58
+ ) -> Sequence[Number] | list[Sequence[Number] | None] | None:
59
+ """
60
+ Parameters
61
+ ----------
62
+ X : float or iterable of floats
63
+ The data value(s) to convert to RGB.
64
+ For floats, X should be in the interval `[0.0, 1.0]` to
65
+ return the RGB values `X*100` percent along the Colormap line.
66
+
67
+ Returns
68
+ -------
69
+ Tuple of RGB values if X is scalar, otherwise an array of
70
+ RGB values with a shape of `X.shape + (3, )`.
71
+ """
72
+ try:
73
+ return [self._process_value(x) for x in X] # type: ignore [union-attr]
74
+ except TypeError:
75
+ # not iterable
76
+ assert isinstance(X, (int, float))
77
+ return self._process_value(X)
78
+
79
+ def _process_value(self, x: Number) -> Sequence[Number] | None:
80
+ if not isinstance(x, (int, float)) or math.isnan(x) or math.isinf(x):
81
+ return self.bad
82
+ if x < 0:
83
+ return self.under
84
+ if x > 1:
85
+ return self.over
86
+ idx = round(x * (len(self._lookup_table) - 1))
87
+ return self._lookup_table[idx]
88
+
89
+
90
+ class ListedColormap(Colormap):
91
+ def __init__(self, name: str, colors: Sequence[Sequence[int]]) -> None:
92
+ super().__init__(name, lookup_table=colors)
93
+
94
+ @classmethod
95
+ def from_relative(
96
+ cls, name: str, colors: Sequence[Sequence[float]]
97
+ ) -> "ListedColormap":
98
+ return cls(
99
+ name,
100
+ [(round(255 * r), round(255 * g), round(255 * b)) for r, g, b in colors],
101
+ )
102
+
103
+
104
+ # Always generate a new cmap, such that you can override bad / over under values easily.
105
+ cmaps = {}
106
+ cmaps["magma"] = lambda: ListedColormap.from_relative("magma", _cmaps_data.magma_data)
107
+ cmaps["inferno"] = lambda: ListedColormap.from_relative(
108
+ "inferno", _cmaps_data.inferno_data
109
+ )
110
+ cmaps["plasma"] = lambda: ListedColormap.from_relative(
111
+ "plasma", _cmaps_data.plasma_data
112
+ )
113
+ cmaps["viridis"] = lambda: ListedColormap.from_relative(
114
+ "viridis", _cmaps_data.viridis_data
115
+ )
116
+ cmaps["jet"] = lambda: ListedColormap.from_relative("jet", _cmaps_data.jet_data)
117
+ cmaps["copper"] = lambda: ListedColormap.from_relative(
118
+ "copper", _cmaps_data.copper_data
119
+ )
120
+ cmaps["gray"] = lambda: ListedColormap(
121
+ name="gray", colors=[(idx, idx, idx) for idx in range(256)]
122
+ )
123
+
124
+ # for more, have a look at https://matplotlib.org/stable/tutorials/colors/colormaps.html