c3-colors 2.0.1__tar.gz

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.
@@ -0,0 +1,12 @@
1
+ /node_modules
2
+ node_modules
3
+ /docs
4
+ lib
5
+ dist
6
+ packages/c3/README.md
7
+
8
+ # Python
9
+ .venv
10
+ __pycache__
11
+ *.egg-info
12
+ .pytest_cache
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.5
2
+ Name: c3-colors
3
+ Version: 2.0.1
4
+ Summary: Consistent Categorical Colors - Deterministic colors for maps
5
+ Project-URL: Homepage, https://github.com/mapequation/c3
6
+ Project-URL: Repository, https://github.com/mapequation/c3
7
+ Project-URL: Issues, https://github.com/mapequation/c3/issues
8
+ Author: @mapequation
9
+ License-Expression: Apache-2.0
10
+ Keywords: categorical,colors,oklab,oklch,palette
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Visualization
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+
17
+ # C3 for Python - Consistent Categorical Colors
18
+
19
+ A pure Python port of [`@mapequation/c3`](https://www.npmjs.com/package/@mapequation/c3): deterministic, distinct colors for categories and nested modules, spread over hue, lightness and chroma in OKLCH. No dependencies.
20
+
21
+ It gives the same colors as the npm package, checked against shared fixtures (within rounding), and the version numbers match, so `c3-colors` 2.0.0 gives the colors of `@mapequation/c3` 2.0.0.
22
+
23
+ ### Install
24
+
25
+ ```sh
26
+ pip install c3-colors
27
+ ```
28
+
29
+ or `uv add c3-colors`, and import it as `c3`. Requires Python 3.11 or later.
30
+
31
+ ### Usage
32
+
33
+ The API mirrors the JavaScript one, with options as keyword arguments in snake_case.
34
+ The [tutorial notebook](examples/tutorial.ipynb) walks through it with matplotlib, and colors a map with geopandas and network modules with networkx and Infomap.
35
+
36
+ ```python
37
+ import c3
38
+
39
+ c3.palette(5)
40
+ # ['#2b9bea', '#cf9f71', '#3b8559', '#b46ba5', '#00b3bb']
41
+
42
+ c3.palette(10, tone="pastel", offset=90)
43
+ c3.palette([3, 1, 1, 2]) # weights: heavier colors get more hue space
44
+ c3.palette(8, seeds=["#ff0000"], method="farthest")
45
+ c3.palette(40, end="darker") # later colors in a darker end zone
46
+ c3.palette(12, tone={"chroma": (0.1, 0.2), "warm_hue": 60, "tilt": 0.3})
47
+ c3.palette(10, tone=c3.swatches["mural"]) # infer the tone from colors
48
+
49
+ colors = c3.hierarchy([
50
+ {"path": [1, 1], "flow": 0.3},
51
+ {"path": [1, 2], "flow": 0.2},
52
+ {"path": [2, 1], "flow": 0.5},
53
+ ])
54
+ colors([1, 2]) # color of module 1:2
55
+ colors.modules # all modules with path, flow, color and radius, depth first
56
+
57
+ c3.tones["vivid"] # {'lightness': (0.55, 0.7), 'chroma': (0.15, 0.21), 'warm_hue': 285, 'tilt': 0}
58
+ c3.infer_tone(["#e41a1c", "#377eb8", "#4daf4a"])
59
+ c3.oklab("steelblue"), c3.oklch("#2b9bea")
60
+ c3.distance("#2b9bea", "#2b9beb") # about 0.02 is just noticeable
61
+ ```
62
+
63
+ Tone and end zone fields are snake_case too: `warm_hue` for `warmHue`, `min_gap` for `minGap`.
64
+
65
+ ### Hue sources
66
+
67
+ `hue` is `"Oklch"` (the OKLCH hue circle, the default), one of the d3 color schemes `"Turbo"`, `"Sinebow"` or `"Rainbow"`, or any callable from `t` in [0, 1] to a color. The callable can return a CSS color string like `"#rrggbb"` or `"rgb(r, g, b)"`, or a sequence of floats in [0, 1] (alpha is ignored), the convention of matplotlib colormaps:
68
+
69
+ ```python
70
+ import matplotlib
71
+
72
+ c3.palette(10, hue=matplotlib.colormaps["viridis"])
73
+ ```
74
+
75
+ matplotlib is not a dependency. The other d3 scheme names the npm package accepts raise a `ValueError`; pass the scheme as a callable instead.
76
+
77
+ ### Development
78
+
79
+ ```sh
80
+ cd python
81
+ uv run pytest
82
+ uv run --group notebook python examples/execute.py # re-execute the tutorial in place
83
+ ```
84
+
85
+ The tests check every case in `fixtures/c3.json` at the repository root, which the TypeScript library generates with `pnpm --filter @mapequation/c3 fixtures`.
86
+ They also check that the committed tutorial notebook has been executed without errors, so re-execute it after changing colors or the notebook.
87
+ The `notebook` dependency group has what the tutorial needs, and the notebook downloads the Census state boundaries when it runs.
@@ -0,0 +1,71 @@
1
+ # C3 for Python - Consistent Categorical Colors
2
+
3
+ A pure Python port of [`@mapequation/c3`](https://www.npmjs.com/package/@mapequation/c3): deterministic, distinct colors for categories and nested modules, spread over hue, lightness and chroma in OKLCH. No dependencies.
4
+
5
+ It gives the same colors as the npm package, checked against shared fixtures (within rounding), and the version numbers match, so `c3-colors` 2.0.0 gives the colors of `@mapequation/c3` 2.0.0.
6
+
7
+ ### Install
8
+
9
+ ```sh
10
+ pip install c3-colors
11
+ ```
12
+
13
+ or `uv add c3-colors`, and import it as `c3`. Requires Python 3.11 or later.
14
+
15
+ ### Usage
16
+
17
+ The API mirrors the JavaScript one, with options as keyword arguments in snake_case.
18
+ The [tutorial notebook](examples/tutorial.ipynb) walks through it with matplotlib, and colors a map with geopandas and network modules with networkx and Infomap.
19
+
20
+ ```python
21
+ import c3
22
+
23
+ c3.palette(5)
24
+ # ['#2b9bea', '#cf9f71', '#3b8559', '#b46ba5', '#00b3bb']
25
+
26
+ c3.palette(10, tone="pastel", offset=90)
27
+ c3.palette([3, 1, 1, 2]) # weights: heavier colors get more hue space
28
+ c3.palette(8, seeds=["#ff0000"], method="farthest")
29
+ c3.palette(40, end="darker") # later colors in a darker end zone
30
+ c3.palette(12, tone={"chroma": (0.1, 0.2), "warm_hue": 60, "tilt": 0.3})
31
+ c3.palette(10, tone=c3.swatches["mural"]) # infer the tone from colors
32
+
33
+ colors = c3.hierarchy([
34
+ {"path": [1, 1], "flow": 0.3},
35
+ {"path": [1, 2], "flow": 0.2},
36
+ {"path": [2, 1], "flow": 0.5},
37
+ ])
38
+ colors([1, 2]) # color of module 1:2
39
+ colors.modules # all modules with path, flow, color and radius, depth first
40
+
41
+ c3.tones["vivid"] # {'lightness': (0.55, 0.7), 'chroma': (0.15, 0.21), 'warm_hue': 285, 'tilt': 0}
42
+ c3.infer_tone(["#e41a1c", "#377eb8", "#4daf4a"])
43
+ c3.oklab("steelblue"), c3.oklch("#2b9bea")
44
+ c3.distance("#2b9bea", "#2b9beb") # about 0.02 is just noticeable
45
+ ```
46
+
47
+ Tone and end zone fields are snake_case too: `warm_hue` for `warmHue`, `min_gap` for `minGap`.
48
+
49
+ ### Hue sources
50
+
51
+ `hue` is `"Oklch"` (the OKLCH hue circle, the default), one of the d3 color schemes `"Turbo"`, `"Sinebow"` or `"Rainbow"`, or any callable from `t` in [0, 1] to a color. The callable can return a CSS color string like `"#rrggbb"` or `"rgb(r, g, b)"`, or a sequence of floats in [0, 1] (alpha is ignored), the convention of matplotlib colormaps:
52
+
53
+ ```python
54
+ import matplotlib
55
+
56
+ c3.palette(10, hue=matplotlib.colormaps["viridis"])
57
+ ```
58
+
59
+ matplotlib is not a dependency. The other d3 scheme names the npm package accepts raise a `ValueError`; pass the scheme as a callable instead.
60
+
61
+ ### Development
62
+
63
+ ```sh
64
+ cd python
65
+ uv run pytest
66
+ uv run --group notebook python examples/execute.py # re-execute the tutorial in place
67
+ ```
68
+
69
+ The tests check every case in `fixtures/c3.json` at the repository root, which the TypeScript library generates with `pnpm --filter @mapequation/c3 fixtures`.
70
+ They also check that the committed tutorial notebook has been executed without errors, so re-execute it after changing colors or the notebook.
71
+ The `notebook` dependency group has what the tutorial needs, and the notebook downloads the Census state boundaries when it runs.
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "c3-colors"
3
+ version = "2.0.1"
4
+ description = "Consistent Categorical Colors - Deterministic colors for maps"
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ authors = [{ name = "@mapequation" }]
8
+ requires-python = ">=3.11"
9
+ dependencies = []
10
+ keywords = ["colors", "palette", "categorical", "oklab", "oklch"]
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "Topic :: Scientific/Engineering :: Visualization",
14
+ "Typing :: Typed",
15
+ ]
16
+
17
+ [project.urls]
18
+ Homepage = "https://github.com/mapequation/c3"
19
+ Repository = "https://github.com/mapequation/c3"
20
+ Issues = "https://github.com/mapequation/c3/issues"
21
+
22
+ [build-system]
23
+ requires = ["hatchling"]
24
+ build-backend = "hatchling.build"
25
+
26
+ [tool.hatch.build.targets.wheel]
27
+ packages = ["src/c3"]
28
+
29
+ # The tests and the tutorial need the rest of the repo
30
+ [tool.hatch.build.targets.sdist]
31
+ include = ["src", "README.md"]
32
+
33
+ [dependency-groups]
34
+ dev = ["pytest>=8"]
35
+ notebook = [
36
+ "geopandas>=1.0",
37
+ "infomap>=2.8",
38
+ "ipykernel>=6.29",
39
+ "matplotlib>=3.9",
40
+ "nbclient>=0.10",
41
+ "networkx>=3.4",
42
+ ]
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
@@ -0,0 +1,48 @@
1
+ """C3 - Consistent Categorical Colors. Deterministic colors for maps.
2
+
3
+ A Python port of the npm package @mapequation/c3, tested against the same fixtures.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from importlib.metadata import PackageNotFoundError, version
9
+
10
+ from ._hierarchy import Hierarchy, Module, ModuleColor, hierarchy
11
+ from ._oklab import Lab, Lch, distance
12
+ from ._oklab import parse_oklab as oklab
13
+ from ._oklab import parse_oklch as oklch
14
+ from ._palette import EndZone, HueSource, Method, palette
15
+ from ._schemes import Scheme, SchemeName
16
+ from ._swatches import swatches
17
+ from ._tone import PartialTone, Range, Tone, ToneName, ToneOption, infer_tone, tones
18
+
19
+ try:
20
+ __version__ = version("c3-colors")
21
+ except PackageNotFoundError: # pragma: no cover
22
+ __version__ = "0.0.0"
23
+
24
+ __all__ = [
25
+ "palette",
26
+ "hierarchy",
27
+ "tones",
28
+ "infer_tone",
29
+ "swatches",
30
+ "oklab",
31
+ "oklch",
32
+ "distance",
33
+ "EndZone",
34
+ "Hierarchy",
35
+ "HueSource",
36
+ "Lab",
37
+ "Lch",
38
+ "Method",
39
+ "Module",
40
+ "ModuleColor",
41
+ "PartialTone",
42
+ "Range",
43
+ "Scheme",
44
+ "SchemeName",
45
+ "Tone",
46
+ "ToneName",
47
+ "ToneOption",
48
+ ]
@@ -0,0 +1,284 @@
1
+ """CSS color parsing: hex, rgb(), rgba(), hsl(), hsla() and named colors.
2
+
3
+ Follows d3-color's ``rgb()``, which the TypeScript library parses colors with, and its
4
+ ``formatRgb()``, which the d3 color schemes return.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ import re
11
+
12
+ RGB = tuple[float, float, float]
13
+
14
+ _NUM = r"([+-]?(?:[0-9]*\.)?[0-9]+(?:[eE][+-]?[0-9]+)?)"
15
+ _RE_I = r"\s*([+-]?[0-9]+)\s*"
16
+ _RE_N = rf"\s*{_NUM}\s*"
17
+ _RE_P = rf"\s*{_NUM}%\s*"
18
+
19
+ _HEX = re.compile(r"#([0-9a-f]{3,8})")
20
+ _RGB_INTEGER = re.compile(rf"rgb\({_RE_I},{_RE_I},{_RE_I}\)")
21
+ _RGB_PERCENT = re.compile(rf"rgb\({_RE_P},{_RE_P},{_RE_P}\)")
22
+ _RGBA_INTEGER = re.compile(rf"rgba\({_RE_I},{_RE_I},{_RE_I},{_RE_N}\)")
23
+ _RGBA_PERCENT = re.compile(rf"rgba\({_RE_P},{_RE_P},{_RE_P},{_RE_N}\)")
24
+ _HSL_PERCENT = re.compile(rf"hsl\({_RE_N},{_RE_P},{_RE_P}\)")
25
+ _HSLA_PERCENT = re.compile(rf"hsla\({_RE_N},{_RE_P},{_RE_P},{_RE_N}\)")
26
+
27
+
28
+ def parse_rgb(color: object) -> RGB | None:
29
+ """A CSS color as (r, g, b) in 0 to 255, unclamped, or None if it can't be parsed or is transparent."""
30
+ fmt = str(color).strip().lower()
31
+ if m := _HEX.fullmatch(fmt):
32
+ digits = m.group(1)
33
+ n = int(digits, 16)
34
+ if len(digits) == 6:
35
+ return _rgbn(n)
36
+ if len(digits) == 3:
37
+ return (
38
+ float((n >> 8 & 0xF) | (n >> 4 & 0xF0)),
39
+ float((n >> 4 & 0xF) | (n & 0xF0)),
40
+ float(((n & 0xF) << 4) | (n & 0xF)),
41
+ )
42
+ if len(digits) == 8:
43
+ return _rgba(n >> 24 & 0xFF, n >> 16 & 0xFF, n >> 8 & 0xFF, (n & 0xFF) / 0xFF)
44
+ if len(digits) == 4:
45
+ return _rgba(
46
+ (n >> 12 & 0xF) | (n >> 8 & 0xF0),
47
+ (n >> 8 & 0xF) | (n >> 4 & 0xF0),
48
+ (n >> 4 & 0xF) | (n & 0xF0),
49
+ (((n & 0xF) << 4) | (n & 0xF)) / 0xFF,
50
+ )
51
+ return None
52
+ if m := _RGB_INTEGER.fullmatch(fmt):
53
+ return (float(m[1]), float(m[2]), float(m[3]))
54
+ if m := _RGB_PERCENT.fullmatch(fmt):
55
+ return (float(m[1]) * 255 / 100, float(m[2]) * 255 / 100, float(m[3]) * 255 / 100)
56
+ if m := _RGBA_INTEGER.fullmatch(fmt):
57
+ return _rgba(float(m[1]), float(m[2]), float(m[3]), float(m[4]))
58
+ if m := _RGBA_PERCENT.fullmatch(fmt):
59
+ return _rgba(float(m[1]) * 255 / 100, float(m[2]) * 255 / 100, float(m[3]) * 255 / 100, float(m[4]))
60
+ if m := _HSL_PERCENT.fullmatch(fmt):
61
+ return _hsla(float(m[1]), float(m[2]) / 100, float(m[3]) / 100, 1.0)
62
+ if m := _HSLA_PERCENT.fullmatch(fmt):
63
+ return _hsla(float(m[1]), float(m[2]) / 100, float(m[3]) / 100, float(m[4]))
64
+ if fmt in NAMED:
65
+ return _rgbn(NAMED[fmt])
66
+ return None # also "transparent"
67
+
68
+
69
+ def _rgbn(n: int) -> RGB:
70
+ return (float(n >> 16 & 0xFF), float(n >> 8 & 0xFF), float(n & 0xFF))
71
+
72
+
73
+ def _rgba(r: float, g: float, b: float, a: float) -> RGB | None:
74
+ return None if a <= 0 else (float(r), float(g), float(b))
75
+
76
+
77
+ def _hsla(h: float, s: float, l: float, a: float) -> RGB | None:
78
+ if a <= 0:
79
+ return None
80
+ if s <= 0 or l <= 0 or l >= 1: # grey, black or white
81
+ return (l * 255, l * 255, l * 255)
82
+ h %= 360
83
+ m2 = l + (l if l < 0.5 else 1 - l) * s
84
+ m1 = 2 * l - m2
85
+ return (
86
+ _hsl2rgb(h - 240 if h >= 240 else h + 120, m1, m2),
87
+ _hsl2rgb(h, m1, m2),
88
+ _hsl2rgb(h + 240 if h < 120 else h - 120, m1, m2),
89
+ )
90
+
91
+
92
+ def _hsl2rgb(h: float, m1: float, m2: float) -> float:
93
+ if h < 60:
94
+ v = m1 + (m2 - m1) * h / 60
95
+ elif h < 180:
96
+ v = m2
97
+ elif h < 240:
98
+ v = m1 + (m2 - m1) * (240 - h) / 60
99
+ else:
100
+ v = m1
101
+ return v * 255
102
+
103
+
104
+ def round_byte(value: float) -> int:
105
+ """A color channel rounded to an integer in 0 to 255, with halves rounded up."""
106
+ return max(0, min(255, math.floor(value + 0.5)))
107
+
108
+
109
+ def format_rgb(r: float, g: float, b: float) -> str:
110
+ """An opaque color as "rgb(r, g, b)" with rounded, clamped channels, like d3's rgb.formatRgb()."""
111
+ return f"rgb({round_byte(r)}, {round_byte(g)}, {round_byte(b)})"
112
+
113
+
114
+ # d3-color cubehelix
115
+ _A = -0.14861
116
+ _B = +1.78277
117
+ _C = -0.29227
118
+ _D = -0.90649
119
+ _E = +1.97294
120
+
121
+
122
+ def cubehelix_rgb(h: float, s: float, l: float) -> RGB:
123
+ """d3.cubehelix(h, s, l).rgb()"""
124
+ hr = math.radians(h + 120)
125
+ a = s * l * (1 - l)
126
+ cosh = math.cos(hr)
127
+ sinh = math.sin(hr)
128
+ return (
129
+ 255 * (l + a * (_A * cosh + _B * sinh)),
130
+ 255 * (l + a * (_C * cosh + _D * sinh)),
131
+ 255 * (l + a * (_E * cosh)),
132
+ )
133
+
134
+
135
+ NAMED: dict[str, int] = {
136
+ "aliceblue": 0xf0f8ff,
137
+ "antiquewhite": 0xfaebd7,
138
+ "aqua": 0x00ffff,
139
+ "aquamarine": 0x7fffd4,
140
+ "azure": 0xf0ffff,
141
+ "beige": 0xf5f5dc,
142
+ "bisque": 0xffe4c4,
143
+ "black": 0x000000,
144
+ "blanchedalmond": 0xffebcd,
145
+ "blue": 0x0000ff,
146
+ "blueviolet": 0x8a2be2,
147
+ "brown": 0xa52a2a,
148
+ "burlywood": 0xdeb887,
149
+ "cadetblue": 0x5f9ea0,
150
+ "chartreuse": 0x7fff00,
151
+ "chocolate": 0xd2691e,
152
+ "coral": 0xff7f50,
153
+ "cornflowerblue": 0x6495ed,
154
+ "cornsilk": 0xfff8dc,
155
+ "crimson": 0xdc143c,
156
+ "cyan": 0x00ffff,
157
+ "darkblue": 0x00008b,
158
+ "darkcyan": 0x008b8b,
159
+ "darkgoldenrod": 0xb8860b,
160
+ "darkgray": 0xa9a9a9,
161
+ "darkgreen": 0x006400,
162
+ "darkgrey": 0xa9a9a9,
163
+ "darkkhaki": 0xbdb76b,
164
+ "darkmagenta": 0x8b008b,
165
+ "darkolivegreen": 0x556b2f,
166
+ "darkorange": 0xff8c00,
167
+ "darkorchid": 0x9932cc,
168
+ "darkred": 0x8b0000,
169
+ "darksalmon": 0xe9967a,
170
+ "darkseagreen": 0x8fbc8f,
171
+ "darkslateblue": 0x483d8b,
172
+ "darkslategray": 0x2f4f4f,
173
+ "darkslategrey": 0x2f4f4f,
174
+ "darkturquoise": 0x00ced1,
175
+ "darkviolet": 0x9400d3,
176
+ "deeppink": 0xff1493,
177
+ "deepskyblue": 0x00bfff,
178
+ "dimgray": 0x696969,
179
+ "dimgrey": 0x696969,
180
+ "dodgerblue": 0x1e90ff,
181
+ "firebrick": 0xb22222,
182
+ "floralwhite": 0xfffaf0,
183
+ "forestgreen": 0x228b22,
184
+ "fuchsia": 0xff00ff,
185
+ "gainsboro": 0xdcdcdc,
186
+ "ghostwhite": 0xf8f8ff,
187
+ "gold": 0xffd700,
188
+ "goldenrod": 0xdaa520,
189
+ "gray": 0x808080,
190
+ "green": 0x008000,
191
+ "greenyellow": 0xadff2f,
192
+ "grey": 0x808080,
193
+ "honeydew": 0xf0fff0,
194
+ "hotpink": 0xff69b4,
195
+ "indianred": 0xcd5c5c,
196
+ "indigo": 0x4b0082,
197
+ "ivory": 0xfffff0,
198
+ "khaki": 0xf0e68c,
199
+ "lavender": 0xe6e6fa,
200
+ "lavenderblush": 0xfff0f5,
201
+ "lawngreen": 0x7cfc00,
202
+ "lemonchiffon": 0xfffacd,
203
+ "lightblue": 0xadd8e6,
204
+ "lightcoral": 0xf08080,
205
+ "lightcyan": 0xe0ffff,
206
+ "lightgoldenrodyellow": 0xfafad2,
207
+ "lightgray": 0xd3d3d3,
208
+ "lightgreen": 0x90ee90,
209
+ "lightgrey": 0xd3d3d3,
210
+ "lightpink": 0xffb6c1,
211
+ "lightsalmon": 0xffa07a,
212
+ "lightseagreen": 0x20b2aa,
213
+ "lightskyblue": 0x87cefa,
214
+ "lightslategray": 0x778899,
215
+ "lightslategrey": 0x778899,
216
+ "lightsteelblue": 0xb0c4de,
217
+ "lightyellow": 0xffffe0,
218
+ "lime": 0x00ff00,
219
+ "limegreen": 0x32cd32,
220
+ "linen": 0xfaf0e6,
221
+ "magenta": 0xff00ff,
222
+ "maroon": 0x800000,
223
+ "mediumaquamarine": 0x66cdaa,
224
+ "mediumblue": 0x0000cd,
225
+ "mediumorchid": 0xba55d3,
226
+ "mediumpurple": 0x9370db,
227
+ "mediumseagreen": 0x3cb371,
228
+ "mediumslateblue": 0x7b68ee,
229
+ "mediumspringgreen": 0x00fa9a,
230
+ "mediumturquoise": 0x48d1cc,
231
+ "mediumvioletred": 0xc71585,
232
+ "midnightblue": 0x191970,
233
+ "mintcream": 0xf5fffa,
234
+ "mistyrose": 0xffe4e1,
235
+ "moccasin": 0xffe4b5,
236
+ "navajowhite": 0xffdead,
237
+ "navy": 0x000080,
238
+ "oldlace": 0xfdf5e6,
239
+ "olive": 0x808000,
240
+ "olivedrab": 0x6b8e23,
241
+ "orange": 0xffa500,
242
+ "orangered": 0xff4500,
243
+ "orchid": 0xda70d6,
244
+ "palegoldenrod": 0xeee8aa,
245
+ "palegreen": 0x98fb98,
246
+ "paleturquoise": 0xafeeee,
247
+ "palevioletred": 0xdb7093,
248
+ "papayawhip": 0xffefd5,
249
+ "peachpuff": 0xffdab9,
250
+ "peru": 0xcd853f,
251
+ "pink": 0xffc0cb,
252
+ "plum": 0xdda0dd,
253
+ "powderblue": 0xb0e0e6,
254
+ "purple": 0x800080,
255
+ "rebeccapurple": 0x663399,
256
+ "red": 0xff0000,
257
+ "rosybrown": 0xbc8f8f,
258
+ "royalblue": 0x4169e1,
259
+ "saddlebrown": 0x8b4513,
260
+ "salmon": 0xfa8072,
261
+ "sandybrown": 0xf4a460,
262
+ "seagreen": 0x2e8b57,
263
+ "seashell": 0xfff5ee,
264
+ "sienna": 0xa0522d,
265
+ "silver": 0xc0c0c0,
266
+ "skyblue": 0x87ceeb,
267
+ "slateblue": 0x6a5acd,
268
+ "slategray": 0x708090,
269
+ "slategrey": 0x708090,
270
+ "snow": 0xfffafa,
271
+ "springgreen": 0x00ff7f,
272
+ "steelblue": 0x4682b4,
273
+ "tan": 0xd2b48c,
274
+ "teal": 0x008080,
275
+ "thistle": 0xd8bfd8,
276
+ "tomato": 0xff6347,
277
+ "turquoise": 0x40e0d0,
278
+ "violet": 0xee82ee,
279
+ "wheat": 0xf5deb3,
280
+ "white": 0xffffff,
281
+ "whitesmoke": 0xf5f5f5,
282
+ "yellow": 0xffff00,
283
+ "yellowgreen": 0x9acd32,
284
+ }