Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

okpalette-0.2.0.tar.gz (102.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

okpalette-0.2.0-cp312-abi3-win_amd64.whl (309.0 kB view details)

Uploaded CPython 3.12+Windows x86-64

okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (478.6 kB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ x86-64

okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (466.8 kB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ ARM64

okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl (413.6 kB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

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

Hashes for okpalette-0.2.0.tar.gz
Algorithm Hash digest
SHA256 45311c6c70f83948a245ab15a61c90cb573513c7b221c88f71ec5e0b7cdd8523
MD5 99a4b444786c566cd5f05f415d1f9e2c
BLAKE2b-256 64283fc72b569e300572fc156ae22bdde2998b935bcaa0d7e71ca214daafdf67

See more details on using hashes here.

Provenance

The following attestation bundles were made for okpalette-0.2.0.tar.gz:

Publisher: release.yml on pmbaumgartner/okpalette

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for okpalette-0.2.0-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 e3a6ff1df67b05e154d10145d89faa8c6496537a73c6dd360f7cf74eb21d8f6c
MD5 8adaec27f21735b1c70b66185a007691
BLAKE2b-256 f9c9b5a15f2b85439190c6fd4d64769675dd0f99adf909da74b344dfd3122b6b

See more details on using hashes here.

Provenance

The following attestation bundles were made for okpalette-0.2.0-cp312-abi3-win_amd64.whl:

Publisher: release.yml on pmbaumgartner/okpalette

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for okpalette-0.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 25d712fe2bab65c32e06a0681deae36e460ea533467ef13887b229e1d7a4e667
MD5 6737538edb75b04d0d8212c42e6a9143
BLAKE2b-256 2d0f04cbab87688d41e4121f9ac340d4c082a14007969cca049122ffc7b4c947

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for okpalette-0.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 d0bb2e6dc8b8ead5dffe011db142dc78bc7fcbafb713d7040f8588644fcd3c99
MD5 2e62baa00364aae120800816ccc54179
BLAKE2b-256 91476aa37a1083db8de4474598b4c6d2cc43dc0e0c822bd09aadc50c66ea3668

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for okpalette-0.2.0-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 11cd33207a3bc70245f6611839687b8f25cbf2d288f6c0f75b2a327aa3935c9d
MD5 3f0a5692fcc711e12aed3665095cc6c8
BLAKE2b-256 54dd4890576f7eec9b33cee0af59d16b476b38b44056dae99c87453c56ebe936

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page