Scale Operations
Concatenation
concatenate_scales joins two or more scales at specified stitch positions into a single scale.
The stitch positions are relative to the final [0, 1] domain and there must be exactly
N−1 positions for N scales.
from polychromos.palette import Palette, HSLColorScale
# scale_1 occupies [0.0, 0.25]
# scale_2 occupies (0.25, 0.5]
# scale_3 occupies (0.5, 1.0]
combined: HSLColorScale = Palette.concatenate_scales(
[scale_1, scale_2, scale_3],
[0.25, 0.5],
)
Rescaling
rescale_color_scale remaps a scale's stops to a new domain, then pads or clips the result so
it always spans exactly [0, 1].
The new_domain parameter specifies where the original [0, 1] endpoints should land:
- If an endpoint moves inside
[0, 1], a solid-color stop is added at the corresponding boundary. - If an endpoint moves outside
[0, 1], an interpolated stop is added at the boundary and out-of-range stops are discarded.
# Contract: scale fills [0.2, 0.8]; solid pads at both ends
contracted = Palette.rescale_color_scale(scale, (0.2, 0.8))
# Expand: zoom into center half; boundaries are interpolated from the original scale
zoomed = Palette.rescale_color_scale(scale, (-0.5, 1.5))
Raises ValueError if new_domain min ≥ max, or if the entire domain falls outside [0, 1].
Stacking
stack_color_scales overlays multiple scales at given global positions. Each entry is a
(scale, domain_min, domain_max) tuple. Scales may be given in any order.
When two domains overlap, the later scale takes precedence. Interpolated stops are inserted at
each boundary to keep the gradient continuous. Gaps between scales produce natural interpolation.
After all layers are applied, the result is clipped and padded to [0, 1] using the same rules
as rescale_color_scale.
# Two non-overlapping scales with a gap in between
combined = Palette.stack_color_scales([
(scale_a, 0.0, 0.4),
(scale_b, 0.6, 1.0),
])
# Replace the center portion of a base scale
layered = Palette.stack_color_scales([
(base_scale, 0.0, 1.0),
(highlight_scale, 0.3, 0.7),
])
Raises ValueError if the list is empty or any entry has domain_min >= domain_max.