Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import math
from typing import List, Sequence
from .charts_stack_types import StackedValue, StackOffset
from .math_round_float import round_float ← from math.round-float ^1.0.0 · built alongside by fune
def stack(series: Sequence[Sequence[float]], offset: StackOffset) -> List[List[StackedValue]]:
"""Stack series position by position, as d3.stack does with the series in
the given order: stackOffsetNone (zero), stackOffsetExpand and
stackOffsetDiverging. Running totals stay unrounded; only the returned
edges are rounded."""
if offset not in ("zero", "expand", "diverging"):
raise ValueError("stack offset must be zero, expand or diverging, received %r" % (offset,))
n = len(series)
if n == 0:
return []
m = len(series[0])
for s in series:
if len(s) != m:
raise ValueError("every series must have the same number of values")
for v in s:
if isinstance(v, bool) or not isinstance(v, (int, float)) or not math.isfinite(v):
raise TypeError("stack values must be finite numbers, received %r" % (v,))
if offset == "expand" and v < 0:
raise ValueError("expand needs values of zero or more, received %r" % (v,))
lower = [[0.0] * m for _ in range(n)]
upper = [[0.0] * m for _ in range(n)]
for j in range(m):
if offset == "diverging":
up = 0.0
down = 0.0
for i in range(n):
v = float(series[i][j])
if v > 0:
lower[i][j] = up
up += v
upper[i][j] = up
elif v < 0:
upper[i][j] = down
down += v
lower[i][j] = down
else:
lower[i][j] = 0.0
upper[i][j] = 0.0
else:
total = 0.0
if offset == "expand":
for i in range(n):
total += float(series[i][j])
top = 0.0
for i in range(n):
v = float(series[i][j])
if offset == "expand":
v = v / total if total > 0 else 0.0
lower[i][j] = top
top += v
upper[i][j] = top
return [
[StackedValue(y0=round_float(lower[i][j], 6), y1=round_float(upper[i][j], 6)) for j in range(m)]
for i in range(n)
]