Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import Sequence
from .charts_axis_types import Axis, AxisOrient, AxisTick, Line
from .math_round_float import round_float ← from math.round-float ^1.0.0 · built alongside by fune
# d3-axis's default gap between the end of a tick mark and its label.
_LABEL_PADDING = 3
def axis_pixel(value: float) -> float:
"""A pixel coordinate rounded to 2 places, the precision every axis output uses."""
return round_float(value, 2)
def axis_line(x1: float, y1: float, x2: float, y2: float) -> Line:
return Line(x1=axis_pixel(x1), y1=axis_pixel(y1), x2=axis_pixel(x2), y2=axis_pixel(y2))
def check_orient(orient: str) -> None:
if orient not in ("bottom", "top", "left", "right"):
raise ValueError('orient must be bottom, top, left or right, received "%s"' % (orient,))
def axis_from_ticks(
positions: Sequence[float],
labels: Sequence[str],
range: Sequence[float], # noqa: A002 - the manifest names it range
orient: AxisOrient,
position: float,
tick_size: float,
) -> Axis:
"""Axis geometry from tick positions and labels, for any scale (d3-axis layout)."""
check_orient(orient)
if len(positions) != len(labels):
raise ValueError(
"positions and labels must be the same length, received %d and %d" % (len(positions), len(labels))
)
if len(range) != 2:
raise ValueError("range must have exactly 2 values, [from, to]; got %d" % len(range))
horizontal = orient in ("bottom", "top")
sign = 1 if orient in ("bottom", "right") else -1
mark_end = position + sign * tick_size
label_at = position + sign * (tick_size + _LABEL_PADDING)
ticks = []
for p, label in zip(positions, labels):
if horizontal:
ticks.append(
AxisTick(
position=axis_pixel(p),
label=label,
tick=axis_line(p, position, p, mark_end),
label_x=axis_pixel(p),
label_y=axis_pixel(label_at),
anchor="middle",
baseline="hanging" if orient == "bottom" else "alphabetic",
)
)
else:
ticks.append(
AxisTick(
position=axis_pixel(p),
label=label,
tick=axis_line(position, p, mark_end, p),
label_x=axis_pixel(label_at),
label_y=axis_pixel(p),
anchor="end" if orient == "left" else "start",
baseline="middle",
)
)
if horizontal:
line = axis_line(range[0], position, range[1], position)
else:
line = axis_line(position, range[0], position, range[1])
return Axis(orient=orient, position=axis_pixel(position), line=line, ticks=ticks)