Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_round_float::round_float; ← from math.round-float ^1.0.0 · built alongside by fune
/// 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.
///
/// # Panics
/// Panics on an unknown offset, series of different lengths, a non-finite
/// value, or a negative value with expand.
pub fn stack(series: &[Vec<f64>], offset: &str) -> Vec<Vec<StackedValue>> {
if offset != "zero" && offset != "expand" && offset != "diverging" {
panic!("stack offset must be zero, expand or diverging, received {}", offset);
}
let n = series.len();
if n == 0 {
return Vec::new();
}
let m = series[0].len();
for s in series {
if s.len() != m {
panic!("every series must have the same number of values");
}
for v in s {
if !v.is_finite() {
panic!("stack values must be finite numbers, received {}", v);
}
if offset == "expand" && *v < 0.0 {
panic!("expand needs values of zero or more, received {}", v);
}
}
}
let mut lower = vec![vec![0.0; m]; n];
let mut upper = vec![vec![0.0; m]; n];
for j in 0..m {
if offset == "diverging" {
let mut up = 0.0;
let mut down = 0.0;
for i in 0..n {
let v = series[i][j];
if v > 0.0 {
lower[i][j] = up;
up += v;
upper[i][j] = up;
} else if v < 0.0 {
upper[i][j] = down;
down += v;
lower[i][j] = down;
} else {
lower[i][j] = 0.0;
upper[i][j] = 0.0;
}
}
} else {
let mut total = 0.0;
if offset == "expand" {
for i in 0..n {
total += series[i][j];
}
}
let mut top = 0.0;
for i in 0..n {
let mut v = series[i][j];
if offset == "expand" {
v = if total > 0.0 { v / total } else { 0.0 };
}
lower[i][j] = top;
top += v;
upper[i][j] = top;
}
}
}
(0..n)
.map(|i| {
(0..m)
.map(|j| StackedValue { y0: round_float(lower[i][j], 6), y1: round_float(upper[i][j], 6) })
.collect()
})
.collect()
}
pub fn stacked_value_to_value(s: &StackedValue) -> Value {
Value::obj(vec![("y0", Value::Float(s.y0)), ("y1", Value::Float(s.y1))])
}
pub fn fune_vector(args: &[Value]) -> Value {
let series: Vec<Vec<f64>> = args[0]
.as_arr()
.iter()
.map(|s| s.as_arr().iter().map(|v| v.as_f64()).collect())
.collect();
Value::Arr(
stack(&series, args[1].as_str())
.iter()
.map(|row| Value::Arr(row.iter().map(stacked_value_to_value).collect()))
.collect(),
)
}