///|
fn validate_error_values(values : Array[Double]) -> Unit raise @core.DataError {
for value in values {
if value.is_nan() || value.is_inf() || value < 0.0 {
raise @core.DataError::InvalidErrorBar(
message="error values must be finite and non-negative",
)
}
}
}
///|
/// Add a line with optional symmetric x/y error bars.
///
/// An empty error array disables that direction; otherwise its length must
/// match the x/y sample count.
pub fn Figure::errorbar(
self : Figure,
xs : Array[Double],
ys : Array[Double],
yerr~ : Array[Double] = [],
xerr~ : Array[Double] = [],
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.axes().errorbar(xs, ys, yerr~, xerr~, color~, label~)
}
///|
/// Add error bars through the axes view.
pub fn Axes::errorbar(
self : Axes,
xs : Array[Double],
ys : Array[Double],
yerr~ : Array[Double] = [],
xerr~ : Array[Double] = [],
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
let values = @core.series(xs, ys)
let points = values.points()
if yerr.length() != 0 && yerr.length() != points.length() {
raise @core.DataError::LengthMismatch(
expected=points.length(),
actual=yerr.length(),
)
}
if xerr.length() != 0 && xerr.length() != points.length() {
raise @core.DataError::LengthMismatch(
expected=points.length(),
actual=xerr.length(),
)
}
validate_error_values(yerr)
validate_error_values(xerr)
let resolved_color = self.resolve_color(color)
let start = self.state.val.artists.length()
self.push_artist(
Artist::ErrorBar(
points,
yerr.copy(),
xerr.copy(),
@core.style(resolved_color),
),
)
self.add_auto_legend(label, resolved_color, LegendKind::Line)
self.add_container(ContainerKind::ErrorBar, start, label)
}