///|
/// The four standard borders around an axes panel.
pub(all) enum SpineSide {
Left
Right
Bottom
Top
}
///|
/// Positioning modes supported by an axes spine.
pub(all) enum SpinePosition {
Axes
Data(Double)
Outward(Double)
}
///|
priv struct SpineState {
mut visible : Bool
mut color : String
mut linewidth : Double
mut position : SpinePosition
mut bounds : (Double, Double)?
}
///|
fn default_spines() -> Array[SpineState] {
[
{
visible: true,
color: "#374151",
linewidth: 1.2,
position: SpinePosition::Axes,
bounds: None,
},
{
visible: true,
color: "#374151",
linewidth: 1.2,
position: SpinePosition::Axes,
bounds: None,
},
{
visible: true,
color: "#374151",
linewidth: 1.2,
position: SpinePosition::Axes,
bounds: None,
},
{
visible: true,
color: "#374151",
linewidth: 1.2,
position: SpinePosition::Axes,
bounds: None,
},
]
}
///|
fn spine_index(side : SpineSide) -> Int32 {
match side {
SpineSide::Left => 0
SpineSide::Right => 1
SpineSide::Bottom => 2
SpineSide::Top => 3
}
}
///|
/// A handle to one of an axes panel's four spines.
pub struct Spine {
axes : Axes
side : SpineSide
}
///|
/// Return the side represented by this spine handle.
pub fn Spine::side(self : Spine) -> SpineSide {
self.side
}
///|
fn Spine::state(self : Spine) -> SpineState {
self.axes.state.val.spines[spine_index(self.side)]
}
///|
/// Return whether this spine is rendered.
pub fn Spine::visible(self : Spine) -> Bool {
self.state().visible
}
///|
/// Set whether this spine is rendered.
pub fn Spine::set_visible(self : Spine, visible : Bool) -> Unit {
self.state().visible = visible
}
///|
/// Return the spine stroke color.
pub fn Spine::color(self : Spine) -> String {
self.state().color
}
///|
/// Set the spine stroke color.
pub fn Spine::set_color(
self : Spine,
color : String,
) -> Unit raise @core.DataError {
if color.length() == 0 {
raise @core.DataError::InvalidTicks(message="spine color must not be empty")
}
self.state().color = color
}
///|
/// Return the spine stroke width.
pub fn Spine::linewidth(self : Spine) -> Double {
self.state().linewidth
}
///|
/// Return this spine's positioning mode.
pub fn Spine::position(self : Spine) -> SpinePosition {
self.state().position
}
///|
/// Set this spine's positioning mode.
pub fn Spine::set_position(
self : Spine,
position : SpinePosition,
) -> Unit raise @core.DataError {
match position {
SpinePosition::Axes => ()
SpinePosition::Data(value) | SpinePosition::Outward(value) =>
if value.is_nan() || value.is_inf() {
raise @core.DataError::InvalidTicks(
message="spine position must be finite",
)
}
}
self.state().position = position
}
///|
/// Return optional data-coordinate bounds for this spine.
pub fn Spine::bounds(self : Spine) -> (Double, Double)? {
self.state().bounds
}
///|
/// Restrict a spine to a finite data-coordinate interval.
pub fn Spine::set_bounds(
self : Spine,
lower : Double,
upper : Double,
) -> Unit raise @core.DataError {
if lower.is_nan() || lower.is_inf() || upper.is_nan() || upper.is_inf() {
raise @core.DataError::InvalidTicks(message="spine bounds must be finite")
}
if lower == upper {
raise @core.DataError::InvalidTicks(
message="spine bounds must span a non-zero interval",
)
}
self.state().bounds = Some((lower, upper))
}
///|
/// Remove an explicit spine interval.
pub fn Spine::clear_bounds(self : Spine) -> Unit {
self.state().bounds = None
}
///|
/// Set the spine stroke width.
pub fn Spine::set_linewidth(
self : Spine,
linewidth : Double,
) -> Unit raise @core.DataError {
if linewidth.is_nan() || linewidth.is_inf() || linewidth <= 0.0 {
raise @core.DataError::InvalidTicks(
message="spine linewidth must be finite and positive",
)
}
self.state().linewidth = linewidth
}
///|
/// Return a handle to the selected spine.
pub fn Axes::spine(self : Axes, side : SpineSide) -> Spine {
{ axes: self, side, }
}
///|
/// Return the four spines in left, right, bottom, top order.
pub fn Axes::spines(self : Axes) -> Array[Spine] {
[
self.spine(SpineSide::Left),
self.spine(SpineSide::Right),
self.spine(SpineSide::Bottom),
self.spine(SpineSide::Top),
]
}
///|
/// Return a selected spine on the default axes panel.
pub fn Figure::spine(self : Figure, side : SpineSide) -> Spine {
self.axes().spine(side)
}
///|
/// Return the default axes panel's four spines.
pub fn Figure::spines(self : Figure) -> Array[Spine] {
self.axes().spines()
}