blob: 97fd0cbeaee66b8e9ca5aebd22bdfcbc5d558448 [file] [log] [blame]
//! Coordinate axis
use std::borrow::Cow;
use std::iter::IntoIterator;
use crate::map;
use crate::traits::{Configure, Data, Set};
use crate::{
grid, Axis, Default, Display, Grid, Label, Range, Scale, ScaleFactor, Script, TicLabels,
};
/// Properties of the coordinate axes
#[derive(Clone)]
pub struct Properties {
grids: map::grid::Map<grid::Properties>,
hidden: bool,
label: Option<Cow<'static, str>>,
logarithmic: bool,
range: Option<(f64, f64)>,
scale_factor: f64,
tics: Option<String>,
}
impl Default for Properties {
fn default() -> Properties {
Properties {
grids: map::grid::Map::new(),
hidden: false,
label: None,
logarithmic: false,
range: None,
scale_factor: 1.,
tics: None,
}
}
}
impl Properties {
/// Hides the axis
///
/// **Note** The `TopX` and `RightY` axes are hidden by default
pub fn hide(&mut self) -> &mut Properties {
self.hidden = true;
self
}
/// Makes the axis visible
///
/// **Note** The `BottomX` and `LeftY` axes are visible by default
pub fn show(&mut self) -> &mut Properties {
self.hidden = false;
self
}
}
impl Configure<Grid> for Properties {
type Properties = grid::Properties;
/// Configures the gridlines
fn configure<F>(&mut self, grid: Grid, configure: F) -> &mut Properties
where
F: FnOnce(&mut grid::Properties) -> &mut grid::Properties,
{
if self.grids.contains_key(grid) {
configure(self.grids.get_mut(grid).unwrap());
} else {
let mut properties = Default::default();
configure(&mut properties);
self.grids.insert(grid, properties);
}
self
}
}
impl Set<Label> for Properties {
/// Attaches a label to the axis
fn set(&mut self, label: Label) -> &mut Properties {
self.label = Some(label.0);
self
}
}
impl Set<Range> for Properties {
/// Changes the range of the axis that will be shown
///
/// **Note** All axes are auto-scaled by default
fn set(&mut self, range: Range) -> &mut Properties {
self.hidden = false;
match range {
Range::Auto => self.range = None,
Range::Limits(low, high) => self.range = Some((low, high)),
}
self
}
}
impl Set<Scale> for Properties {
/// Sets the scale of the axis
///
/// **Note** All axes use a linear scale by default
fn set(&mut self, scale: Scale) -> &mut Properties {
self.hidden = false;
match scale {
Scale::Linear => self.logarithmic = false,
Scale::Logarithmic => self.logarithmic = true,
}
self
}
}
impl Set<ScaleFactor> for Properties {
/// Changes the *scale factor* of the axis.
///
/// All the data plotted against this axis will have its corresponding coordinate scaled with
/// this factor before being plotted.
///
/// **Note** The default scale factor is `1`.
fn set(&mut self, factor: ScaleFactor) -> &mut Properties {
self.scale_factor = factor.0;
self
}
}
impl<P, L> Set<TicLabels<P, L>> for Properties
where
L: IntoIterator,
L::Item: AsRef<str>,
P: IntoIterator,
P::Item: Data,
{
/// Attaches labels to the tics of an axis
fn set(&mut self, tics: TicLabels<P, L>) -> &mut Properties {
let TicLabels { positions, labels } = tics;
let pairs = positions
.into_iter()
.zip(labels.into_iter())
.map(|(pos, label)| format!("'{}' {}", label.as_ref(), pos.f64()))
.collect::<Vec<_>>();
if pairs.is_empty() {
self.tics = None
} else {
self.tics = Some(pairs.join(", "));
}
self
}
}
impl<'a> Script for (Axis, &'a Properties) {
fn script(&self) -> String {
let &(axis, properties) = self;
let axis_ = axis.display();
let mut script = if properties.hidden {
return format!("unset {}tics\n", axis_);
} else {
format!("set {}tics nomirror ", axis_)
};
if let Some(ref tics) = properties.tics {
script.push_str(&format!("({})", tics))
}
script.push('\n');
if let Some(ref label) = properties.label {
script.push_str(&format!("set {}label '{}'\n", axis_, label))
}
if let Some((low, high)) = properties.range {
script.push_str(&format!("set {}range [{}:{}]\n", axis_, low, high))
}
if properties.logarithmic {
script.push_str(&format!("set logscale {}\n", axis_));
}
for (grid, properties) in properties.grids.iter() {
script.push_str(&(axis, grid, properties).script());
}
script
}
}
impl crate::ScaleFactorTrait for Properties {
fn scale_factor(&self) -> f64 {
self.scale_factor
}
}