///|
fn discrete_error(message : String) -> @core.DataError {
@core.DataError::InvalidReference(message~)
}
///|
fn finite_discrete(value : Double) -> Bool {
!value.is_nan() && !value.is_inf()
}
///|
fn stem_locations(
heads : Array[Double],
locs : Array[Double],
) -> Array[Double] raise @core.DataError {
if locs.length() == 0 {
let result = Array(capacity=heads.length())
for index in 0.. Unit raise @core.DataError {
self.axes().stem(heads, locs~, bottom~, orientation~, color~, label~)
}
///|
/// Draw stems through the axes view.
pub fn Axes::stem(
self : Axes,
heads : Array[Double],
locs~ : Array[Double] = [],
bottom~ : Double = 0.0,
orientation~ : String = "vertical",
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
if orientation != "vertical" && orientation != "horizontal" {
raise discrete_error("stem orientation must be vertical or horizontal")
}
if !finite_discrete(bottom) {
raise @core.DataError::NonFiniteLimit(
axis=if orientation == "vertical" { "y" } else { "x" },
)
}
let locations = stem_locations(heads, locs)
let resolved_color = self.resolve_color(color)
let start = self.state.val.artists.length()
let markers = Array(capacity=heads.length())
for index in 0.. Double {
if values.length() == 0 {
fallback
} else if values.length() == 1 {
values[0]
} else {
values[index]
}
}
///|
/// Draw parallel event markers for one or more sequences of positions.
pub fn Figure::eventplot(
self : Figure,
positions : Array[Array[Double]],
orientation~ : String = "horizontal",
lineoffsets~ : Array[Double] = [],
linelengths~ : Array[Double] = [],
linewidth~ : Double = 1.0,
color~ : String = "",
) -> Unit raise @core.DataError {
self
.axes()
.eventplot(
positions,
orientation~,
lineoffsets~,
linelengths~,
linewidth~,
color~,
)
}
///|
/// Draw parallel event markers through the axes view.
pub fn Axes::eventplot(
self : Axes,
positions : Array[Array[Double]],
orientation~ : String = "horizontal",
lineoffsets~ : Array[Double] = [],
linelengths~ : Array[Double] = [],
linewidth~ : Double = 1.0,
color~ : String = "",
) -> Unit raise @core.DataError {
if orientation != "horizontal" && orientation != "vertical" {
raise discrete_error("eventplot orientation must be horizontal or vertical")
}
if !finite_discrete(linewidth) || linewidth < 0.0 {
raise discrete_error("eventplot linewidth must be finite and non-negative")
}
if lineoffsets.length() != 0 &&
lineoffsets.length() != 1 &&
lineoffsets.length() != positions.length() {
raise @core.DataError::LengthMismatch(
expected=positions.length(),
actual=lineoffsets.length(),
)
}
if linelengths.length() != 0 &&
linelengths.length() != 1 &&
linelengths.length() != positions.length() {
raise @core.DataError::LengthMismatch(
expected=positions.length(),
actual=linelengths.length(),
)
}
let resolved_color = self.resolve_color(color)
for group_index, group in positions {
let offset = if lineoffsets.length() == 0 {
if positions.length() == 1 {
1.0
} else {
Double::from_int(group_index)
}
} else if lineoffsets.length() == 1 && positions.length() > 1 {
Double::from_int(group_index) * lineoffsets[0]
} else {
lineoffsets[group_index]
}
let length = event_value(linelengths, group_index, 1.0)
if !finite_discrete(offset) || !finite_discrete(length) || length < 0.0 {
raise discrete_error("eventplot offsets and lengths must be finite")
}
for position in group {
if !finite_discrete(position) {
continue
}
if orientation == "horizontal" {
self.push_artist(
Artist::Line(
[
@core.point(position, offset - length / 2.0),
@core.point(position, offset + length / 2.0),
],
@core.style(resolved_color, width=linewidth),
),
)
} else {
self.push_artist(
Artist::Line(
[
@core.point(offset - length / 2.0, position),
@core.point(offset + length / 2.0, position),
],
@core.style(resolved_color, width=linewidth),
),
)
}
}
}
}