scales-python 1.4.0.9000__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.
- scales/__init__.py +295 -0
- scales/_colors.py +272 -0
- scales/_palettes_data.py +595 -0
- scales/_utils.py +579 -0
- scales/bounds.py +512 -0
- scales/breaks.py +627 -0
- scales/breaks_log.py +268 -0
- scales/colour_manip.py +681 -0
- scales/colour_mapping.py +593 -0
- scales/colour_ramp.py +126 -0
- scales/labels.py +2144 -0
- scales/minor_breaks.py +197 -0
- scales/palettes.py +1328 -0
- scales/py.typed +0 -0
- scales/range.py +223 -0
- scales/scale_continuous.py +146 -0
- scales/scale_discrete.py +196 -0
- scales/transforms.py +1338 -0
- scales_python-1.4.0.9000.dist-info/METADATA +73 -0
- scales_python-1.4.0.9000.dist-info/RECORD +22 -0
- scales_python-1.4.0.9000.dist-info/WHEEL +4 -0
- scales_python-1.4.0.9000.dist-info/licenses/LICENSE +3 -0
scales/colour_ramp.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Colour ramp interpolation for the scales package.
|
|
3
|
+
|
|
4
|
+
Python port of R/colour-ramp.R from the R scales package
|
|
5
|
+
(https://github.com/r-lib/scales). Creates callable colour ramps that
|
|
6
|
+
map values in [0, 1] to hex colour strings by interpolation in CIELAB
|
|
7
|
+
colour space, matching R's ``farver``-based implementation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Callable, List, Optional, Sequence, Union
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from ._colors import to_hex, to_rgba
|
|
16
|
+
from numpy.typing import ArrayLike
|
|
17
|
+
|
|
18
|
+
from .colour_manip import _lab_to_rgb, _rgb_to_lab
|
|
19
|
+
from .palettes import ContinuousPalette
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"colour_ramp",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def colour_ramp(
|
|
27
|
+
colors: Sequence[str],
|
|
28
|
+
na_color: Optional[str] = None,
|
|
29
|
+
alpha: bool = True,
|
|
30
|
+
) -> ContinuousPalette:
|
|
31
|
+
"""
|
|
32
|
+
Create a colour ramp that maps [0, 1] values to colours.
|
|
33
|
+
|
|
34
|
+
Interpolation is performed in CIELAB colour space by linearly
|
|
35
|
+
interpolating L, a, b channels independently (matching R's
|
|
36
|
+
``farver``-based ``colour_ramp``).
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
colors : sequence of str
|
|
41
|
+
One or more colours (any format accepted by matplotlib) that
|
|
42
|
+
define the endpoints and optional interior knots of the ramp.
|
|
43
|
+
na_color : str, optional
|
|
44
|
+
Colour to use for ``NaN`` / missing values. If *None*, ``NaN``
|
|
45
|
+
inputs produce ``None`` entries in the output list.
|
|
46
|
+
alpha : bool, default True
|
|
47
|
+
If *True*, the alpha channel is preserved in the output hex strings
|
|
48
|
+
(``#RRGGBBAA``). If *False*, the alpha channel is stripped.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
ContinuousPalette
|
|
53
|
+
A palette ``f(x)`` where *x* is an array-like of floats in
|
|
54
|
+
[0, 1]. Returns a list of hex colour strings of the same length.
|
|
55
|
+
|
|
56
|
+
Examples
|
|
57
|
+
--------
|
|
58
|
+
>>> ramp = colour_ramp(["red", "blue"])
|
|
59
|
+
>>> ramp([0.0, 0.5, 1.0]) # doctest: +SKIP
|
|
60
|
+
['#ff0000ff', '#ca2883ff', '#0000ffff']
|
|
61
|
+
"""
|
|
62
|
+
if len(colors) == 0:
|
|
63
|
+
raise ValueError("colour_ramp requires at least one colour.")
|
|
64
|
+
|
|
65
|
+
# Single colour: return constant function (matches R behaviour)
|
|
66
|
+
if len(colors) == 1:
|
|
67
|
+
single = to_hex(to_rgba(colors[0]), keep_alpha=True)
|
|
68
|
+
single_no_alpha = to_hex(to_rgba(colors[0])[:3], keep_alpha=False)
|
|
69
|
+
|
|
70
|
+
def _const_ramp(x: ArrayLike) -> List[Optional[str]]:
|
|
71
|
+
x = np.asarray(x, dtype=float)
|
|
72
|
+
result: List[Optional[str]] = []
|
|
73
|
+
for val in x.flat:
|
|
74
|
+
if np.isnan(val):
|
|
75
|
+
result.append(na_color)
|
|
76
|
+
else:
|
|
77
|
+
result.append(single if alpha else single_no_alpha)
|
|
78
|
+
return result
|
|
79
|
+
|
|
80
|
+
# R: new_continuous_palette(fun, type="colour", na_safe=!is.na(na.color))
|
|
81
|
+
return ContinuousPalette(
|
|
82
|
+
_const_ramp, type="colour", na_safe=na_color is not None
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Convert all colours to CIELAB + alpha
|
|
86
|
+
rgba_list = [to_rgba(c) for c in colors]
|
|
87
|
+
lab_array = np.array(
|
|
88
|
+
[_rgb_to_lab(r, g, b) for r, g, b, _a in rgba_list]
|
|
89
|
+
) # shape (n, 3): L, a, b
|
|
90
|
+
alpha_array = np.array([a for _r, _g, _b, a in rgba_list])
|
|
91
|
+
|
|
92
|
+
x_in = np.linspace(0.0, 1.0, len(colors))
|
|
93
|
+
|
|
94
|
+
# R: if (!alpha || all(lab_in[, 4] == 1)) alpha_interp returns NULL
|
|
95
|
+
# When alpha is disabled or all inputs are fully opaque, skip alpha
|
|
96
|
+
# interpolation and return #RRGGBB (not #RRGGBBAA).
|
|
97
|
+
_has_alpha = alpha and not np.all(alpha_array == 1.0)
|
|
98
|
+
|
|
99
|
+
def _ramp(x: ArrayLike) -> List[Optional[str]]:
|
|
100
|
+
x = np.asarray(x, dtype=float)
|
|
101
|
+
result: List[Optional[str]] = []
|
|
102
|
+
for val in x.flat:
|
|
103
|
+
if np.isnan(val) or val < 0.0 or val > 1.0:
|
|
104
|
+
# R: approxfun(rule=1) returns NA for out-of-[0,1],
|
|
105
|
+
# then encode_colour returns NA, mapped to na_color.
|
|
106
|
+
result.append(na_color)
|
|
107
|
+
else:
|
|
108
|
+
L = float(np.interp(val, x_in, lab_array[:, 0]))
|
|
109
|
+
a = float(np.interp(val, x_in, lab_array[:, 1]))
|
|
110
|
+
b = float(np.interp(val, x_in, lab_array[:, 2]))
|
|
111
|
+
r, g, bl = _lab_to_rgb(L, a, b)
|
|
112
|
+
if _has_alpha:
|
|
113
|
+
a_val = float(np.interp(val, x_in, alpha_array))
|
|
114
|
+
result.append(
|
|
115
|
+
to_hex((r, g, bl, a_val), keep_alpha=True)
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
result.append(
|
|
119
|
+
to_hex((r, g, bl), keep_alpha=False)
|
|
120
|
+
)
|
|
121
|
+
return result
|
|
122
|
+
|
|
123
|
+
# R: new_continuous_palette(fun, type="colour", na_safe=!is.na(na.color))
|
|
124
|
+
return ContinuousPalette(
|
|
125
|
+
_ramp, type="colour", na_safe=na_color is not None
|
|
126
|
+
)
|