Scales

Scales map data values into visual values such as positions, widths, radii, or colors.

Scale classes are exported from top-level pydreamplet.

import pydreamplet as dp

Visual Example

import pydreamplet as dp

values = [12, 35, 24, 50]
labels = ["A", "B", "C", "D"]

x = dp.BandScale(labels, (30, 310), padding=0.2)
y = dp.LinearScale((0, 50), (150, 30))
color = dp.ColorScale((0, 50), ("#14b8a6", "#f83898"))
radius = dp.CircleScale((0, 50), (8, 24))

svg = dp.SVG(340, 180)
svg.append(dp.Line(24, 150, 320, 150, stroke="currentColor", stroke_width=2, opacity=0.35))

for label, value in zip(labels, values):
    cx = x.map(label) + x.bandwidth / 2
    cy = y.map(value)
    svg.append(
        dp.Circle(cx=cx, cy=cy, r=radius.map(value), fill=color.map(value), opacity=0.9),
        dp.Text(label, x=cx, y=168, font_size=14, text_anchor="middle", fill="currentColor"),
    )

LinearScale

LinearScale(domain: NumericPair, output_range: NumericPair)

Maps a numeric value linearly from domain to output_range.

MemberTypeNotes
map(value)float -> floatMaps from domain to output range.
invert(value)float -> floatMaps from output range back to domain.
domainNumericPairReassigning recalculates the slope.
output_rangeNumericPairReassigning recalculates the slope.
scale = dp.LinearScale((0, 10), (0, 100))

assert scale.map(5) == 50
assert scale.invert(50) == 5

BandScale

BandScale(
    domain: list[Any] | tuple[Any, ...] | Iterable[Any],
    output_range: NumericPair,
    padding: float = 0.1,
    outer_padding: float | None = None,
)

Maps distinct categorical values to band start positions.

MemberTypeNotes
map(value)Any -> floatRaises ValueError for unknown values.
bandwidthfloatComputed width of one band.
stepfloatDistance between band starts.
domainlist[Any]Values must be distinct on construction.
output_rangeNumericPairOutput interval.
paddingfloatInner padding multiplier.
outer_paddingfloatDefaults to padding.
scale = dp.BandScale(["a", "b", "c"], (0, 300), padding=0.1)

x = scale.map("b")
width = scale.bandwidth

PointScale

PointScale(
    domain: list[Any] | tuple[Any, ...] | Iterable[Any],
    output_range: NumericPair,
    padding: float = 0.5,
)

Maps distinct categorical values to discrete points.

MemberTypeNotes
map(value)Any -> float | NoneReturns None for unknown values.
domainlist[Any]Must contain at least one distinct value.
output_rangeNumericPairOutput interval.
paddingfloatPadding at both range ends.

OrdinalScale

OrdinalScale(
    domain: list[Any] | tuple[Any, ...] | Iterable[Any],
    output_range: list[Any] | tuple[Any, ...] | Sequence[Any],
)

Maps categories to output values in order. If the domain is longer than the output range, output values repeat cyclically.

scale = dp.OrdinalScale(["a", "b", "c"], ["red", "blue"])

assert scale.map("a") == "red"
assert scale.map("c") == "red"

ColorScale

ColorScale(domain: NumericPair, output_range: tuple[str, str] | list[str])

Interpolates between two hex colors and clamps values outside the domain.

scale = dp.ColorScale((0, 100), ("#000000", "#ffffff"))

assert scale.map(50) == "#7f7f7f"
assert scale.map(150) == "#ffffff"

output_range must contain exactly two colors. Domain endpoints must be distinct.

SquareScale

SquareScale(domain: NumericPair, output_range: NumericPair)

Maps through a square-root transform. It is useful when a square side length should represent area.

scale = dp.SquareScale((0, 100), (0, 10))

assert scale.map(25) == 5

Domain values must be non-negative and distinct after square-root conversion.

CircleScale

CircleScale(domain: NumericPair, output_range: NumericPair)

Maps values to circle radii so the circle area changes linearly with the input.

scale = dp.CircleScale((0, 100), (5, 10))

radius = scale.map(50)

Domain endpoints must be distinct.