// Error-bar rendering shared by the bar, line and scatter charts.
///|
/// A vertical error bar centered on `x` (pixel coordinates): a stem from
/// `y_lo` to `y_hi` with horizontal caps at both ends.
fn error_bar(
x : Double,
y_lo : Double,
y_hi : Double,
cap_w : Double,
color : String,
) -> String {
let sb = StringBuilder::new()
sb.write_string(
elem("line", [
("x1", num(x)),
("y1", num(y_lo)),
("x2", num(x)),
("y2", num(y_hi)),
("stroke", color),
("stroke-width", "1.5"),
]),
)
for y in [y_lo, y_hi] {
sb.write_string(
elem("line", [
("x1", num(x - cap_w / 2.0)),
("y1", num(y)),
("x2", num(x + cap_w / 2.0)),
("y2", num(y)),
("stroke", color),
("stroke-width", "1.5"),
]),
)
}
sb.to_string()
}
///|
/// Symmetric error magnitude for point `i`, or 0 when no error was supplied.
fn error_at(errors : Array[Double], i : Int) -> Double {
if i < errors.length() {
let e = errors[i]
if e < 0.0 {
-e
} else {
e
}
} else {
0.0
}
}
///|
/// Extent of `values` widened so that every `value ± error` stays inside.
fn extent_with_errors(
values : Array[Double],
errors : Array[Double],
) -> (Double, Double) {
let (lo0, hi0) = extent(values)
let mut lo = lo0
let mut hi = hi0
for i in 0.. hi {
hi = values[i] + e
}
}
(lo, hi)
}