Fast, dependency-free OKLab categorical color palettes powered by Rust
Project description
okpalette
Categorical color palettes for Python.
Use okpalette when you need distinct, stable colors for labels, plots, dashboards, or reports.
pip install okpalette
With uv:
uv add okpalette
from okpalette import create_palette
colors = create_palette(8)
Create A Palette
create_palette() returns lowercase hex colors by default.
from okpalette import create_palette
colors = create_palette(10)
# ["#080050", "#e00800", "#1078ff", ...]
The same inputs produce the same colors, so category mappings stay stable across runs.
Use RGB tuples when that fits your plotting library better:
rgb = create_palette(5, format="rgb")
# [(8, 0, 80), (224, 8, 0), ...]
rgb01 = create_palette(5, format="rgb01")
# [(0.03137254901960784, 0.0, 0.3137254901960784), ...]
Extend Colors
Use extend_palette() when you already have brand colors or a small palette.
from okpalette import extend_palette
brand = ["#0057b8", "#ffd700"]
colors = extend_palette(brand, 12)
assert colors[:2] == ["#0057b8", "#ffd700"]
assert len(colors) == 12
Use existing colors as anchors without returning them:
new_colors = extend_palette(brand, 10, include_existing=False)
Map Labels To Colors
Use create_label_palette() when positions should influence which label gets
which color. Nearby or overlapping labels are assigned more distinct colors.
from okpalette import create_label_palette
positions = [(0.0, 0.0), (0.2, 0.0), (5.0, 0.0), (5.2, 0.0)]
labels = ["control", "treated", "control", "outlier"]
colors = create_label_palette(positions, labels)
# {"control": "#080050", "treated": "#e00800", "outlier": ...}
Labels may be strings, integers, tuples, or other hashable Python objects. The returned dict preserves first-seen label order.
Keep specific label colors fixed:
colors = create_label_palette(
positions,
labels,
fixed_colors={"control": "#0057b8"},
)
For dataframe-like objects, read position and label columns by duck typing:
colors = create_label_palette_from_columns(
data,
positions=["x", "y"],
label="cluster",
)
Tune Appearance
By default, white is treated as a background color. Use
background_contrast="high" when plotting against pale panes or figure
backgrounds.
colors = create_palette(
32,
background="#ffffff",
background_contrast="normal",
lightness=(0.20, 0.75),
chroma=(0.05, None),
)
Allow white when you need it:
colors = create_palette(8, background=None, lightness=None, chroma=None)
Avoid other colors:
colors = create_palette(
16,
avoid_colors=["#000000"],
background=["#ffffff", "#f2f2f2"],
background_contrast="high",
)
background accepts one color or a sequence of colors and filters candidates
too close to those backgrounds. avoid_colors keeps exact colors out of the
palette and uses them as distance anchors.
Limit hue ranges:
warm = create_palette(10, hue=(330, 100))
cool = create_palette(10, hue=(150, 280))
Common constraints:
muted = create_palette(12, chroma=(0.02, 0.12))
bright = create_palette(12, chroma=(0.10, None))
mid_lightness = create_palette(12, lightness=(0.30, 0.80))
lightness is OKLab L in 0..1. hue is OKLCH degrees in 0..360; ranges can wrap around zero.
Preview And Save
from okpalette import create_palette, save_palette, view_palette
colors = create_palette(12)
view_palette(colors)
save_palette(colors, "palette.svg")
save_palette(colors, "palette.png")
view_palette() works in notebooks through _repr_svg_() and _repr_png_().
For raw preview bytes:
from okpalette import palette_png, palette_svg
svg = palette_svg(colors)
png = palette_png(colors)
Color Inputs
Accepted color inputs:
"#0fA"
"00ffaa"
(255, 128, 0)
(1.0, 0.5, 0.0)
Integer RGB tuples use 0..255. Normalized RGB tuples use floats in 0.0..1.0.
Ambiguous integer tuples such as (1, 0, 0) are rejected; write (1.0, 0.0, 0.0)
for normalized RGB.
Grid Size
grid_size controls how many candidate colors are searched.
quick = create_palette(24, grid_size="coarse") # step 16
default = create_palette(24, grid_size="medium") # step 8
fine = create_palette(24, grid_size="fine") # step 4
custom = create_palette(24, grid_size=12)
If constraints leave too few candidates, okpalette raises ValueError with a hint
to relax lightness, chroma, hue, or grid_size.
API
create_palette(
palette_size,
*,
seed_colors=(),
avoid_colors=None,
background="#ffffff",
background_contrast="normal",
lightness=(0.20, 0.90),
chroma=(0.04, None),
hue=None,
grid_size="medium",
lightness_weight=1.0,
chroma_weight=1.0,
format="hex",
)
extend_palette(
colors,
target_size,
*,
include_existing=True,
**create_palette_options,
)
create_label_palette(
positions,
labels,
*,
fixed_colors=None,
seed_colors=(),
avoid_colors=None,
background="#ffffff",
background_contrast="normal",
lightness=(0.20, 0.90),
chroma=(0.04, None),
hue=None,
grid_size="medium",
lightness_weight=1.0,
chroma_weight=1.0,
neighbors=8,
max_points=50_000,
format="hex",
)
create_label_palette_from_columns(data, *, positions, label, **create_label_palette_options)
view_palette(palette, *, width=1246, height=154)
palette_svg(palette, *, width=1246, height=154)
palette_png(palette, *, width=1246, height=154)
save_palette(palette, path, *, width=1246, height=154)
How It Works
okpalette uses a greedy Glasbey-style algorithm. It starts with anchor colors
such as seeds, avoid colors, and the background, then repeatedly chooses the
candidate color that is farthest from the nearest anchor or selected color.
Distances are measured in OKLab. Lightness, chroma, and hue constraints are applied through OKLab and OKLCH before colors are selected.
For label palettes, okpalette builds a weighted label-neighborhood graph from
the input positions, then uses that graph while choosing and assigning colors.
The default max_points=50_000 bounds graph construction for large datasets;
use max_points=None to opt into all-points preprocessing.
The result is deterministic, fast, and stable when extending a palette. It is not a global optimizer.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file okpalette-0.2.0.tar.gz.
File metadata
- Download URL: okpalette-0.2.0.tar.gz
- Upload date:
- Size: 102.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45311c6c70f83948a245ab15a61c90cb573513c7b221c88f71ec5e0b7cdd8523
|
|
| MD5 |
99a4b444786c566cd5f05f415d1f9e2c
|
|
| BLAKE2b-256 |
64283fc72b569e300572fc156ae22bdde2998b935bcaa0d7e71ca214daafdf67
|
Provenance
The following attestation bundles were made for okpalette-0.2.0.tar.gz:
Publisher:
release.yml on pmbaumgartner/okpalette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
okpalette-0.2.0.tar.gz -
Subject digest:
45311c6c70f83948a245ab15a61c90cb573513c7b221c88f71ec5e0b7cdd8523 - Sigstore transparency entry: 1586757465
- Sigstore integration time:
-
Permalink:
pmbaumgartner/okpalette@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/pmbaumgartner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file okpalette-0.2.0-cp312-abi3-win_amd64.whl.
File metadata
- Download URL: okpalette-0.2.0-cp312-abi3-win_amd64.whl
- Upload date:
- Size: 309.0 kB
- Tags: CPython 3.12+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3a6ff1df67b05e154d10145d89faa8c6496537a73c6dd360f7cf74eb21d8f6c
|
|
| MD5 |
8adaec27f21735b1c70b66185a007691
|
|
| BLAKE2b-256 |
f9c9b5a15f2b85439190c6fd4d64769675dd0f99adf909da74b344dfd3122b6b
|
Provenance
The following attestation bundles were made for okpalette-0.2.0-cp312-abi3-win_amd64.whl:
Publisher:
release.yml on pmbaumgartner/okpalette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
okpalette-0.2.0-cp312-abi3-win_amd64.whl -
Subject digest:
e3a6ff1df67b05e154d10145d89faa8c6496537a73c6dd360f7cf74eb21d8f6c - Sigstore transparency entry: 1586757685
- Sigstore integration time:
-
Permalink:
pmbaumgartner/okpalette@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/pmbaumgartner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 478.6 kB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25d712fe2bab65c32e06a0681deae36e460ea533467ef13887b229e1d7a4e667
|
|
| MD5 |
6737538edb75b04d0d8212c42e6a9143
|
|
| BLAKE2b-256 |
2d0f04cbab87688d41e4121f9ac340d4c082a14007969cca049122ffc7b4c947
|
Provenance
The following attestation bundles were made for okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on pmbaumgartner/okpalette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
25d712fe2bab65c32e06a0681deae36e460ea533467ef13887b229e1d7a4e667 - Sigstore transparency entry: 1586757640
- Sigstore integration time:
-
Permalink:
pmbaumgartner/okpalette@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/pmbaumgartner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 466.8 kB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0bb2e6dc8b8ead5dffe011db142dc78bc7fcbafb713d7040f8588644fcd3c99
|
|
| MD5 |
2e62baa00364aae120800816ccc54179
|
|
| BLAKE2b-256 |
91476aa37a1083db8de4474598b4c6d2cc43dc0e0c822bd09aadc50c66ea3668
|
Provenance
The following attestation bundles were made for okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on pmbaumgartner/okpalette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
d0bb2e6dc8b8ead5dffe011db142dc78bc7fcbafb713d7040f8588644fcd3c99 - Sigstore transparency entry: 1586757521
- Sigstore integration time:
-
Permalink:
pmbaumgartner/okpalette@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/pmbaumgartner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 413.6 kB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11cd33207a3bc70245f6611839687b8f25cbf2d288f6c0f75b2a327aa3935c9d
|
|
| MD5 |
3f0a5692fcc711e12aed3665095cc6c8
|
|
| BLAKE2b-256 |
54dd4890576f7eec9b33cee0af59d16b476b38b44056dae99c87453c56ebe936
|
Provenance
The following attestation bundles were made for okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on pmbaumgartner/okpalette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl -
Subject digest:
11cd33207a3bc70245f6611839687b8f25cbf2d288f6c0f75b2a327aa3935c9d - Sigstore transparency entry: 1586757583
- Sigstore integration time:
-
Permalink:
pmbaumgartner/okpalette@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/pmbaumgartner
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0104f05c61f110a9170b4ae3c8fb2a5e4c39b1b5 -
Trigger Event:
push
-
Statement type: