Color Utilities

Importing dartwork_mpl registers the named color libraries that users reach for in plotting code: dartwork Color (dc.), OpenColor (oc.), Tailwind (tw.), Material Design (md.), Ant Design (ad.), Chakra UI (cu.), and Primer (pr.). Use those strings anywhere matplotlib accepts a color. In addition to the named palette, a Color class provides perceptually uniform color manipulation across OKLab, OKLCH, RGB, and hex color spaces.

Example

import matplotlib.pyplot as plt
import dartwork_mpl as dm

# Named colors
plt.plot(x, y, color="dc.teal2", label="Series A")
lighter = dm.mix_colors("dc.teal2", "white", alpha=0.35)
muted_line = dm.pseudo_alpha("dc.teal3", alpha=0.6)

# Color class — perceptual manipulation
color = dm.oklch(0.7, 0.15, 150)
color.oklch.C *= 1.2                  # boost chroma
print(color.to_hex())                 # '#...'

# Interpolation
palette = dm.cspace('#FF6B6B', '#4ECDC4', n=5, space='oklch')
for i, c in enumerate(palette):
    ax.bar(i, 1, color=c.to_hex())

cspace('#FF6B6B', '#4ECDC4', n=8, space='oklch') interpolates perceptually through OKLCH — hover a step for its hex:

Named colours, mix_colors, and pseudo_alpha compose the same way — see the snippet above.

API

Color Manipulation

Color management and conversion utilities for Matplotlib.

Provides facilities for loading, registering, and converting colors across OKLab, OKLCH, RGB, and Hex color spaces.

class dartwork_mpl._colors.Color(value: Color | str)[source]

Bases: object

Color in OKLab/OKLCH/RGB/Hex color spaces.

A wrapper over a single canonical store (OKLab coordinates) with per-space property views (color.oklab / color.oklch / color.rgb). The constructor takes a string (or pass-through Color) — bare numerics are rejected because three floats give no way to tell OKLab apart from OKLCH or RGB. For already-typed numeric input, use from_oklab() / from_oklch() / from_rgb() / from_hex() / from_name() (or the top-level wrappers oklab() / oklch() / rgb() / hex()).

Equality and hashing are by value — two colors with the same OKLab coordinates compare equal (__eq__()) and hash equal (__hash__()).

Note

Unlike Length, Color is currently mutable: the oklab / oklch / rgb views write back to the underlying store in place (hence copy()). Because it is both mutable and value-hashable, do not mutate a Color after using it as a dict / set key. A future release will make Color immutable (view setters returning a new instance); see issue #233.

Parameters:

value (Color or str) – Either another Color (returned as a fresh copy with the same OKLab coordinates) or a string parseable by Color.parse() — hex ("#ff0000"), functional ("rgb(1, 0, 0)" / "oklch(0.7, 0.15, 30)" / "oklab(...)"), or a palette/matplotlib color name ("oc.red5", "red").

Examples

>>> import dartwork_mpl as dm
>>> dm.Color("#ff0000")
>>> dm.Color("oklch(0.7, 0.15, 30)")
>>> dm.Color("oc.red5")
>>> dm.Color(dm.oklab(0.7, 0.1, 0.2))   # pass-through copy
copy() Color[source]

Create a copy of the Color object.

Returns:

A new Color instance with the same OKLab coordinates.

Return type:

Color

Examples

>>> import dartwork_mpl as dm
>>> color = dm.oklab(0.7, 0.1, 0.2)
>>> new_color = color.copy()
>>>
>>> # Modify the copy without affecting the original
>>> new_color.oklab.L += 0.1
>>> print(color.oklab.L)      # 0.7 (unchanged)
>>> print(new_color.oklab.L)  # 0.8 (modified)
classmethod from_hex(hex_str: str) Color[source]

Create a Color from hex color string.

Parameters:

hex_str (str) – Hex color string (#RGB or #RRGGBB).

Returns:

Color instance.

Return type:

Color

classmethod from_name(name: str) Color[source]

Create a Color from matplotlib color name.

Supports all matplotlib color names including: - Basic colors: ‘red’, ‘blue’, ‘green’, etc. - Named colors: ‘aliceblue’, ‘antiquewhite’, etc. - Custom dartwork-mpl colors: ‘oc.red5’, ‘tw.blue500’, etc.

Parameters:

name (str) – Matplotlib color name (e.g., ‘red’, ‘oc.blue5’, ‘tw.blue500’).

Returns:

Color instance.

Return type:

Color

Raises:

ValueError – If the color name is not recognized by matplotlib.

classmethod from_oklab(L: float, a: float, b: float) Color[source]

Create a Color from OKLab coordinates.

Parameters:
  • L (float) – OKLab coordinates (L typically in [0, 1]).

  • a (float) – OKLab coordinates (L typically in [0, 1]).

  • b (float) – OKLab coordinates (L typically in [0, 1]).

Returns:

Color instance.

Return type:

Color

classmethod from_oklch(L: float, C: float, h: float) Color[source]

Create a Color from OKLCH coordinates.

Parameters:
  • L (float) – Lightness and Chroma (L typically in [0, 1], C >= 0).

  • C (float) – Lightness and Chroma (L typically in [0, 1], C >= 0).

  • h (float) – Hue in degrees [0, 360).

Returns:

Color instance.

Return type:

Color

classmethod from_rgb(r: float, g: float, b: float) Color[source]

Create a Color from RGB values.

Automatically detects if values are in [0, 1] or [0, 255] range. If all values are <= 1.0, treats as [0, 1]. Otherwise, treats as [0, 255]. In 0-255 mode the exact values 0 and 1 are read as byte values (11/255, nearly black), since they are legitimate byte intensities — e.g. from_rgb(255, 0, 1); fractional values between 0 and 1 mixed into 0-255 mode are rejected as ambiguous instead.

Parameters:
  • r (float) – RGB values (auto-detected range).

  • g (float) – RGB values (auto-detected range).

  • b (float) – RGB values (auto-detected range).

Returns:

Color instance.

Return type:

Color

in_gamut(tol: float = 1e-06) bool[source]

Whether this color is representable inside the sRGB gamut.

Returns True when every linear-sRGB channel falls within [0, 1] (within tol), i.e. to_rgb() returns the color directly. Returns False for out-of-gamut colors, which to_rgb() gamut-maps by reducing chroma while holding lightness and hue (so the rendered color stays close in L/h).

Parameters:

tol (float, optional) – Numerical tolerance on the [0, 1] bounds, to absorb floating-point error at the gamut boundary. Default 1e-6.

Return type:

bool

Examples

>>> import dartwork_mpl as dm
>>> dm.Color.from_oklch(0.7, 0.05, 30).in_gamut()
True
>>> dm.Color.from_oklch(0.7, 0.40, 30).in_gamut()
False
property oklab: OklabView

Get OKLab view of the color.

Returns:

View object for OKLab color space access.

Return type:

OklabView

Examples

>>> import dartwork_mpl as dm
>>> color = dm.oklab(0.7, 0.1, 0.2)
>>>
>>> # Attribute access
>>> L = color.oklab.L
>>> a = color.oklab.a
>>>
>>> # Unpacking
>>> L, a, b = color.oklab
>>>
>>> # Writing
>>> color.oklab.L += 0.1
property oklch: OklchView

Get OKLCH view of the color.

Returns:

View object for OKLCH color space access.

Return type:

OklchView

Examples

>>> import dartwork_mpl as dm
>>> color = dm.oklch(0.7, 0.2, 120)
>>>
>>> # Attribute access
>>> L = color.oklch.L
>>> C = color.oklch.C
>>> h = color.oklch.h
>>>
>>> # Unpacking
>>> L, C, h = color.oklch
>>>
>>> # Writing
>>> color.oklch.C *= 1.2
classmethod parse(value: str) Color[source]

Parse a string in any supported form into a Color.

Routes by the leading character / token of value:

  • "#rgb" / "#rrggbb"from_hex().

  • "rgb(r, g, b)" (auto 0-1 / 0-255 detection), "oklch(L, C, h)" (h in degrees), "oklab(L, a, b)" → corresponding factory. Function name is case-insensitive; arguments are comma-separated and tolerant of internal whitespace.

  • Anything else falls through to from_name() (matplotlib named colors, oc., tw., md., ad., cu., pr., dc.).

Parameters:

value (str) – The color string to parse. Surrounding whitespace is stripped.

Return type:

Color

Raises:
  • TypeError – If value is not a str.

  • ValueError – If a functional form has the wrong number of arguments, non-numeric arguments, or the underlying factory rejects the value.

property rgb: RgbView

Get RGB view of the color.

Returns:

View object for RGB color space access.

Return type:

RgbView

Examples

>>> import dartwork_mpl as dm
>>> color = dm.rgb(0.8, 0.2, 0.3)
>>>
>>> # Attribute access
>>> r = color.rgb.r
>>> g = color.rgb.g
>>>
>>> # Unpacking
>>> r, g, b = color.rgb
>>>
>>> # Writing
>>> color.rgb.r = 0.9
to_hex() str[source]

Convert to hex color string.

Returns:

Hex color string (#RRGGBB).

Return type:

str

to_oklab() tuple[float, float, float][source]

Convert to OKLab coordinates.

Returns:

(L, a, b) OKLab coordinates.

Return type:

tuple[float, float, float]

to_oklch() tuple[float, float, float][source]

Convert to OKLCH coordinates.

Returns:

(L, C, h) OKLCH coordinates, where h is in degrees [0, 360).

Return type:

tuple[float, float, float]

to_rgb() tuple[float, float, float][source]

Convert to RGB values.

Returns:

(r, g, b) sRGB values in range [0, 1].

Return type:

tuple[float, float, float]

Notes

Colors inside the sRGB gamut convert exactly. Out-of-gamut colors are gamut-mapped by reducing chroma while holding lightness (L) and hue (h) fixed — a binary search to the sRGB gamut boundary along the requested OKLCH hue line (CSS Color 4 style) — so the rendered color keeps the requested L and h instead of the per-channel clamp’s L/h drift. A final per-channel clamp absorbs sub-tolerance boundary residual and clips an achromatic L outside [0, 1] (which chroma reduction alone cannot represent). Use in_gamut() to detect whether a color required mapping.

class dartwork_mpl._colors.OklabView(color: Color)[source]

Bases: _BaseColorView

View class for OKLab color space access.

Provides attribute-based access to OKLab coordinates (L, a, b) with support for reading, writing, unpacking, and indexing.

Parameters:

color (Color) – The Color instance to view.

Examples

>>> import dartwork_mpl as dm
>>> color = dm.oklab(0.7, 0.1, 0.2)
>>>
>>> # Attribute access
>>> L = color.oklab.L
>>> a = color.oklab.a
>>>
>>> # Unpacking
>>> L, a, b = color.oklab
>>>
>>> # Indexing
>>> a = color.oklab[1]
>>>
>>> # Writing
>>> color.oklab.L += 0.1
>>> color.oklab.a = 0.2
property L: float

Lightness component.

property a: float

Green-red component.

property b: float

Blue-yellow component.

dartwork_mpl._colors.OklabViewIterator

alias of _ColorViewIterator

class dartwork_mpl._colors.OklchView(color: Color)[source]

Bases: _BaseColorView

View class for OKLCH color space access.

Provides attribute-based access to OKLCH coordinates (L, C, h) with support for reading, writing, unpacking, and indexing.

Parameters:

color (Color) – The Color instance to view.

Examples

>>> import dartwork_mpl as dm
>>> color = dm.oklch(0.7, 0.2, 120)
>>>
>>> # Attribute access
>>> L = color.oklch.L
>>> C = color.oklch.C
>>> h = color.oklch.h
>>>
>>> # Unpacking
>>> L, C, h = color.oklch
>>>
>>> # Indexing
>>> C = color.oklch[1]
>>>
>>> # Writing
>>> color.oklch.C *= 1.2
>>> color.oklch.h = 180
property C: float

Chroma component.

property L: float

Lightness component.

property h: float

Hue component in degrees [0, 360).

dartwork_mpl._colors.OklchViewIterator

alias of _ColorViewIterator

class dartwork_mpl._colors.RgbView(color: Color)[source]

Bases: _BaseColorView

View class for RGB color space access.

Provides attribute-based access to RGB coordinates (r, g, b) with support for reading, writing, unpacking, and indexing.

Parameters:

color (Color) – The Color instance to view.

Examples

>>> import dartwork_mpl as dm
>>> color = dm.rgb(0.8, 0.2, 0.3)
>>>
>>> # Attribute access
>>> r = color.rgb.r
>>> g = color.rgb.g
>>>
>>> # Unpacking
>>> r, g, b = color.rgb
>>>
>>> # Indexing
>>> g = color.rgb[1]
>>>
>>> # Writing
>>> color.rgb.r = 0.9
>>> color.rgb.g += 0.1
property b: float

Blue component [0, 1].

property g: float

Green component [0, 1].

property r: float

Red component [0, 1].

dartwork_mpl._colors.RgbViewIterator

alias of _ColorViewIterator

dartwork_mpl._colors.color(value: Color | str) Color[source]

Parse a string (or pass through a Color) into a Color.

String-parser counterpart to hex(), rgb(), oklch(), oklab(), and palette-name lookup. Mirrors dartwork_mpl.length() for unit strings.

Examples

>>> import dartwork_mpl as dm
>>> dm.color("#ff0000")            # hex
>>> dm.color("rgb(1, 0, 0)")       # functional
>>> dm.color("oklch(0.7, 0.15, 30)")
>>> dm.color("oc.red5")            # palette name
Parameters:

value (Color or str) – A Color instance is returned as a fresh copy with the same OKLab coordinates. A string is dispatched through Color.parse().

Return type:

Color

dartwork_mpl._colors.colors(name: str, n: int | None = None, *, reverse: bool = False) Colormap | list[str][source]

Return a Model B colormap or designed discrete color form.

Bare family names ("aurora") and registered names ("dc.aurora") are equivalent. n=None returns the matplotlib colormap for that family; n=int returns the deterministic designed discrete form as hex strings.

dartwork_mpl._colors.cspace(start_color: Color | str, end_color: Color | str, n: int, space: str = 'oklch') list[Color][source]

Interpolate between two colors to produce a list of evenly spaced colors.

Similar to numpy’s linspace, but operating in color space.

Parameters:
  • start_color (Color | str) – Starting color (Color instance or hex string).

  • end_color (Color | str) – Ending color (Color instance or hex string).

  • n (int) – Total number of colors to generate (including start and end).

  • space (str, optional) – Color space for interpolation: ‘oklch’ (default), ‘oklab’, or ‘rgb’. ‘oklch’ produces the most perceptually uniform results.

Returns:

List of interpolated Color objects.

Return type:

list[Color]

Raises:
  • TypeError – If start_color or end_color is not a Color instance or hex string.

  • ValueError – If an unsupported color space is specified.

dartwork_mpl._colors.ensure_contrast(color: Any, background: Any, *, min_ratio: float = 4.5) str[source]

Adjust a color until it reaches a minimum contrast ratio.

color is returned unchanged when it already meets min_ratio. Otherwise the color’s HLS lightness is moved toward the pole, black or white, that gives the stronger WCAG contrast against background. Hue and saturation are held constant while a binary search finds the smallest deterministic lightness change that reaches the requested ratio, or the pole if the requested ratio is unreachable.

Parameters:
  • color (color-like) – Foreground color accepted by Matplotlib.

  • background (color-like) – Background color accepted by Matplotlib.

  • min_ratio (float, optional) – Minimum WCAG contrast ratio to satisfy. Default 4.5.

Returns:

color unchanged when it already passes and is a string; otherwise an adjusted "#rrggbb" color.

Return type:

str

Raises:

ValueError – If min_ratio is not a positive finite number.

Examples

>>> ensure_contrast("#ddddaa", "white")
'#7a7a31'
>>> ensure_contrast("black", "white")
'black'
dartwork_mpl._colors.hex(hex_str: str) Color[source]

Convenience wrapper to create a Color from a hex string.

Parameters:

hex_str (str) – Hex color code string (#RGB or #RRGGBB format).

Returns:

A new Color instance.

Return type:

Color

Notes

This is the public dm.hex constructor and intentionally shares the name of the builtin hex. The shadow is scoped to this module / the dartwork_mpl namespace; use builtins.hex if you need the integer-to-hex builtin alongside it.

dartwork_mpl._colors.list_colors(kind: Literal['sequential', 'multi-hue', 'diverging', 'cyclic', 'qualitative'] | str | None = None) list[dict[str, object]][source]

List Model B color families and their metadata.

dartwork_mpl._colors.oklab(L: float, a: float, b: float) Color[source]

Convenience wrapper to create a Color from OKLab coordinates.

Parameters:
  • L (float) – OKLab color coordinates.

  • a (float) – OKLab color coordinates.

  • b (float) – OKLab color coordinates.

Returns:

A new Color instance.

Return type:

Color

dartwork_mpl._colors.oklch(L: float, C: float, h: float) Color[source]

Convenience wrapper to create a Color from OKLCH coordinates.

Parameters:
  • L (float) – Lightness and chroma values.

  • C (float) – Lightness and chroma values.

  • h (float) – Hue angle in degrees [0, 360).

Returns:

A new Color instance.

Return type:

Color

dartwork_mpl._colors.readable_text_color(background: Any, *, light: str | None = None, dark: str | None = None, threshold: float | None = None) str[source]

Choose the more readable text color for a background.

Parameters:
  • background (color-like) – Background color accepted by Matplotlib.

  • light (str or None, optional) – Candidate light ink. None uses the library’s standard light ink, "white". Default None.

  • dark (str or None, optional) – Candidate dark ink. None uses the standard dark text color inherited by the light style presets, "black". Default None.

  • threshold (float or None, optional) – Accepted for compatibility with threshold-based callers. Selection is always based on the higher WCAG contrast ratio. Default None.

Returns:

The selected ink color string, either light or dark.

Return type:

str

Examples

>>> readable_text_color("#222222")
'white'
>>> readable_text_color("#f7f7f7")
'black'
dartwork_mpl._colors.rgb(r: float, g: float, b: float) Color[source]

Convenience wrapper to create a Color from RGB values.

Parameters:
  • r (float) – RGB color values (auto-detected as [0-1] or [0-255] range).

  • g (float) – RGB color values (auto-detected as [0-1] or [0-255] range).

  • b (float) – RGB color values (auto-detected as [0-1] or [0-255] range).

Returns:

A new Color instance.

Return type:

Color

dartwork_mpl._colors.set_colors(name_or_list: str | Iterable[str] | None = None, *, ax: Axes | None = None, n: int | None = None, styles: bool = False) None[source]

Set the matplotlib color cycle from a Model B family or explicit list.

dartwork_mpl._colors.show_colors(kind: Literal['sequential', 'multi-hue', 'diverging', 'cyclic', 'qualitative'] | str | None = None, names: Iterable[str] | None = None, n: int | None = None) Figure[source]

Return a compact preview figure for Model B color families.

Note

mix_colors and pseudo_alpha are defined in the util module but re-exported from the top-level dartwork_mpl namespace for convenience alongside other color helpers.

dartwork_mpl.mix_colors(color1: str | tuple[float, float, float], color2: str | tuple[float, float, float], alpha: float = 0.5) tuple[float, float, float][source]

Blend two colors in OKLab space (perceptually uniform blend).

Blends in OKLab rather than gamma-encoded sRGB, so midpoints avoid the “muddy” saturation dip that naive RGB mixing produces for saturated hues (e.g. red + blue → purple, not a dark desaturated grey).

Parameters:
  • color1 (str | tuple[float, float, float]) – First color to blend. Any format recognized by matplotlib.

  • color2 (str | tuple[float, float, float]) – Second color to blend. Any format recognized by matplotlib.

  • alpha (float, optional) – Weight of color1 (0 → color2, 1 → color1). Default is 0.5.

Returns:

sRGB tuple of the blended result, compatible with any matplotlib color= argument.

Return type:

tuple[float, float, float]

Raises:

ValueError – If alpha is not a finite number in [0, 1]. Values outside the closed interval extrapolate and gamut-clamp to a plausible-looking but wrong colour (e.g. alpha=2 yields salmon for a red/blue blend), so they are rejected rather than silently returned.

Notes

The result will differ subtly from previous versions for non-grayscale blends — gradients now look smoother and less desaturated through saturated midpoints. dm.pseudo_alpha (which delegates to this function) inherits the same improvement.

dartwork_mpl.pseudo_alpha(color: str | tuple[float, float, float], alpha: float = 1.0, background: str | tuple[float, float, float] = 'white') tuple[float, float, float][source]

Return an opaque RGB that simulates alpha transparency against a background.

True alpha can cause darkening artifacts when lines overlap or cover images. This function blends the color with the background to produce a flat (opaque) color that visually mimics transparency.

Parameters:
  • color (str | tuple[float, float, float]) – The target foreground color.

  • alpha (float, optional) – Simulated opacity (0 to 1). Default is 1.0 (fully opaque).

  • background (str | tuple[float, float, float], optional) – Background color to blend against. Default is “white”.

Returns:

RGB tuple of the composited color.

Return type:

tuple[float, float, float]

Color Interpolation

dartwork_mpl.cspace(start_color: Color | str, end_color: Color | str, n: int, space: str = 'oklch') list[Color][source]

Interpolate between two colors to produce a list of evenly spaced colors.

Similar to numpy’s linspace, but operating in color space.

Parameters:
  • start_color (Color | str) – Starting color (Color instance or hex string).

  • end_color (Color | str) – Ending color (Color instance or hex string).

  • n (int) – Total number of colors to generate (including start and end).

  • space (str, optional) – Color space for interpolation: ‘oklch’ (default), ‘oklab’, or ‘rgb’. ‘oklch’ produces the most perceptually uniform results.

Returns:

List of interpolated Color objects.

Return type:

list[Color]

Raises:
  • TypeError – If start_color or end_color is not a Color instance or hex string.

  • ValueError – If an unsupported color space is specified.

Model B Color API

dartwork_mpl.colors(name: str, n: None = None, *, reverse: bool = False) Colormap[source]
dartwork_mpl.colors(name: str, n: int, *, reverse: bool = False) list[str]

Return a Model B colormap or designed discrete color form.

Bare family names ("aurora") and registered names ("dc.aurora") are equivalent. n=None returns the matplotlib colormap for that family; n=int returns the deterministic designed discrete form as hex strings.

dartwork_mpl.set_colors(name_or_list: str | Iterable[str] | None = None, *, ax: Axes | None = None, n: int | None = None, styles: bool = False) None[source]

Set the matplotlib color cycle from a Model B family or explicit list.

dartwork_mpl.list_colors(kind: Literal['sequential', 'multi-hue', 'diverging', 'cyclic', 'qualitative'] | str | None = None) list[dict[str, object]][source]

List Model B color families and their metadata.

dartwork_mpl.show_colors(kind: Literal['sequential', 'multi-hue', 'diverging', 'cyclic', 'qualitative'] | str | None = None, names: Iterable[str] | None = None, n: int | None = None) Figure[source]

Return a compact preview figure for Model B color families.