///|
/// Add a horizontal bar plot from y positions and widths.
fn horizontal_bar_points(values : Array[@core.Point]) -> Array[@core.Point] {
let points = Array(capacity=values.length())
for value in values {
points.push(@core.point(value.y(), value.x()))
}
points
}
///|
pub fn Figure::barh(
self : Figure,
ys : Array[Double],
widths : Array[Double],
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.axes().barh(ys, widths, color~, label~)
}
///|
/// Draw a horizontal reference line in data coordinates.
pub fn Figure::axhline(
self : Figure,
value : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.axes().axhline(value, color~, label~)
}
///|
/// Draw a vertical reference line in data coordinates.
pub fn Figure::axvline(
self : Figure,
value : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
self.axes().axvline(value, color~, label~)
}
///|
fn validate_axline_point(point : @core.Point) -> Unit raise @core.DataError {
if point.x().is_nan() ||
point.x().is_inf() ||
point.y().is_nan() ||
point.y().is_inf() {
raise @core.DataError::InvalidReference(
message="axline points must be finite",
)
}
}
///|
/// Draw an infinitely long line through one or two data points.
pub fn Figure::axline(
self : Figure,
xy1 : @core.Point,
xy2? : @core.Point,
slope? : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
match (xy2, slope) {
(Some(xy2), Some(slope)) =>
self.axes().axline(xy1, xy2~, slope~, color~, label~)
(Some(xy2), None) => self.axes().axline(xy1, xy2~, color~, label~)
(None, Some(slope)) => self.axes().axline(xy1, slope~, color~, label~)
(None, None) => self.axes().axline(xy1, color~, label~)
}
}
///|
/// Add text at a data coordinate.
pub fn Figure::text(
self : Figure,
x : Double,
y : Double,
value : String,
color~ : String = "#111827",
) -> Unit raise @core.DataError {
self.axes().text(x, y, value, color~)
}
///|
/// Add horizontal bars through the axes view.
pub fn Axes::barh(
self : Axes,
ys : Array[Double],
widths : Array[Double],
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
let values = @core.series(ys, widths)
let resolved_color = self.resolve_color(color)
let start = self.state.val.artists.length()
self.push_artist(
Artist::BarH(
horizontal_bar_points(values.points()),
@core.style(resolved_color, width=0.0, fill=resolved_color),
),
)
self.add_auto_legend(label, resolved_color, LegendKind::Patch)
self.add_container(ContainerKind::Bar, start, label)
}
///|
/// Add a horizontal reference line through the axes view.
pub fn Axes::axhline(
self : Axes,
value : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
if value.is_nan() || value.is_inf() {
raise @core.DataError::NonFiniteLimit(axis="y")
}
let resolved_color = self.resolve_color(color)
self.push_artist(Artist::HLine(value, @core.style(resolved_color)))
self.add_auto_legend(label, resolved_color, LegendKind::Line)
}
///|
/// Add a vertical reference line through the axes view.
pub fn Axes::axvline(
self : Axes,
value : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
if value.is_nan() || value.is_inf() {
raise @core.DataError::NonFiniteLimit(axis="x")
}
let resolved_color = self.resolve_color(color)
self.push_artist(Artist::VLine(value, @core.style(resolved_color)))
self.add_auto_legend(label, resolved_color, LegendKind::Line)
}
///|
/// Draw an infinitely long line through one or two data points.
pub fn Axes::axline(
self : Axes,
xy1 : @core.Point,
xy2? : @core.Point,
slope? : Double,
color~ : String = "",
label~ : String = "",
) -> Unit raise @core.DataError {
validate_axline_point(xy1)
let direction = match (xy2, slope) {
(Some(xy2), None) => {
validate_axline_point(xy2)
let value = @core.point(xy2.x() - xy1.x(), xy2.y() - xy1.y())
if value.x() == 0.0 && value.y() == 0.0 {
raise @core.DataError::InvalidReference(
message="axline points must be distinct",
)
}
value
}
(None, Some(slope)) => {
if slope.is_nan() || slope.is_inf() {
raise @core.DataError::InvalidReference(
message="axline slope must be finite",
)
}
if self.x_scale().is_nonlinear() || self.y_scale().is_nonlinear() {
raise @core.DataError::InvalidReference(
message="axline slope is not supported on non-linear axes",
)
}
@core.point(1.0, slope)
}
(Some(_), Some(_)) =>
raise @core.DataError::InvalidReference(
message="provide either xy2 or slope, not both",
)
(None, None) =>
raise @core.DataError::InvalidReference(
message="axline requires xy2 or slope",
)
}
let resolved_color = self.resolve_color(color)
self.push_artist(Artist::AxLine(xy1, direction, @core.style(resolved_color)))
self.add_auto_legend(label, resolved_color, LegendKind::Line)
}
///|
/// Add text through the axes view.
pub fn Axes::text(
self : Axes,
x : Double,
y : Double,
value : String,
color~ : String = "#111827",
) -> Unit raise @core.DataError {
if x.is_nan() || x.is_inf() {
raise @core.DataError::NonFiniteLimit(axis="x")
}
if y.is_nan() || y.is_inf() {
raise @core.DataError::NonFiniteLimit(axis="y")
}
self.push_artist(Artist::Text(x, y, value, @core.style(color)))
}