///|
fn invalid_step(message : String) -> @core.DataError {
@core.DataError::InvalidReference(message~)
}
///|
fn step_points(
xs : Array[Double],
ys : Array[Double],
mode : String,
) -> Array[@core.Point] raise @core.DataError {
if mode != "pre" && mode != "post" && mode != "mid" {
raise invalid_step("step where must be pre, post, or mid")
}
let values = @core.series(xs, ys)
let count = values.length()
let points = Array(capacity=count * 2)
if count == 0 {
return points
}
if mode == "pre" {
points.push(@core.point(xs[0], ys[0]))
for index in 1.. Array[Double] {
if edges.length() != 0 {
edges.copy()
} else {
let result = Array(capacity=values.length() + 1)
for index in 0..<=values.length() {
result.push(Double::from_int(index))
}
result
}
}
///|
fn validate_stairs(
values : Array[Double],
edges : Array[Double],
orientation : String,
) -> Unit raise @core.DataError {
if orientation != "vertical" && orientation != "horizontal" {
raise invalid_step("stairs orientation must be vertical or horizontal")
}
if edges.length() != 0 && edges.length() != values.length() + 1 {
raise invalid_step("stairs edges must have one more value than values")
}
}
///|
fn stairs_points(
values : Array[Double],
edges : Array[Double],
orientation : String,
baseline : Double,
close : Bool,
) -> Array[@core.Point] {
let result = Array(capacity=values.length() * 2 + 2)
if values.length() == 0 {
return result
}
if close {
if orientation == "vertical" {
result.push(@core.point(edges[0], baseline))
result.push(@core.point(edges[0], values[0]))
} else {
result.push(@core.point(baseline, edges[0]))
result.push(@core.point(values[0], edges[0]))
}
} else if orientation == "vertical" {
result.push(@core.point(edges[0], values[0]))
} else {
result.push(@core.point(values[0], edges[0]))
}
for index in 0.. 0 {
if orientation == "vertical" {
result.push(@core.point(edges[index], values[index]))
} else {
result.push(@core.point(values[index], edges[index]))
}
}
if orientation == "vertical" {
result.push(@core.point(edges[index + 1], values[index]))
} else {
result.push(@core.point(values[index], edges[index + 1]))
}
}
if close {
let last = values.length() - 1
if orientation == "vertical" {
result.push(@core.point(edges[last + 1], baseline))
} else {
result.push(@core.point(baseline, edges[last + 1]))
}
}
result
}
///|
/// Add a step plot with `pre`, `post`, or `mid` transition semantics.
pub fn Figure::step(
self : Figure,
xs : Array[Double],
ys : Array[Double],
where_~ : String = "pre",
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.axes().step(xs, ys, where_~, color~, label~)
}
///|
/// Add a step plot through the axes view.
pub fn Axes::step(
self : Axes,
xs : Array[Double],
ys : Array[Double],
where_~ : String = "pre",
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.line(step_points(xs, ys, where_), color~, label~)
}
///|
/// Draw a stepwise constant function from values and bin edges.
pub fn Figure::stairs(
self : Figure,
values : Array[Double],
edges~ : Array[Double] = [],
orientation~ : String = "vertical",
baseline~ : Double = 0.0,
fill~ : Bool = false,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self
.axes()
.stairs(values, edges~, orientation~, baseline~, fill~, color~, label~)
}
///|
/// Draw a stepwise constant function through the axes view.
pub fn Axes::stairs(
self : Axes,
values : Array[Double],
edges~ : Array[Double] = [],
orientation~ : String = "vertical",
baseline~ : Double = 0.0,
fill~ : Bool = false,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
validate_stairs(values, edges, orientation)
let actual_edges = stairs_edges(values, edges)
let points = stairs_points(values, actual_edges, orientation, baseline, fill)
if fill {
let resolved_color = self.resolve_color(color)
self.push_artist(
Artist::Polygon(
points,
@core.style(resolved_color, width=0.0, fill=resolved_color),
),
)
self.add_auto_legend(label, resolved_color, LegendKind::Patch)
} else {
self.line(
stairs_points(values, actual_edges, orientation, baseline, false),
color~,
label~,
)
}
}