1 //! Coordinate axis 2 3 use std::borrow::Cow; 4 use std::iter::IntoIterator; 5 6 use crate::map; 7 use crate::traits::{Configure, Data, Set}; 8 use crate::{ 9 grid, Axis, Default, Display, Grid, Label, Range, Scale, ScaleFactor, Script, TicLabels, 10 }; 11 12 /// Properties of the coordinate axes 13 #[derive(Clone)] 14 pub struct Properties { 15 grids: map::grid::Map<grid::Properties>, 16 hidden: bool, 17 label: Option<Cow<'static, str>>, 18 logarithmic: bool, 19 range: Option<(f64, f64)>, 20 scale_factor: f64, 21 tics: Option<String>, 22 } 23 24 impl Default for Properties { default() -> Properties25 fn default() -> Properties { 26 Properties { 27 grids: map::grid::Map::new(), 28 hidden: false, 29 label: None, 30 logarithmic: false, 31 range: None, 32 scale_factor: 1., 33 tics: None, 34 } 35 } 36 } 37 38 impl Properties { 39 /// Hides the axis 40 /// 41 /// **Note** The `TopX` and `RightY` axes are hidden by default hide(&mut self) -> &mut Properties42 pub fn hide(&mut self) -> &mut Properties { 43 self.hidden = true; 44 self 45 } 46 47 /// Makes the axis visible 48 /// 49 /// **Note** The `BottomX` and `LeftY` axes are visible by default show(&mut self) -> &mut Properties50 pub fn show(&mut self) -> &mut Properties { 51 self.hidden = false; 52 self 53 } 54 } 55 56 impl Configure<Grid> for Properties { 57 type Properties = grid::Properties; 58 59 /// Configures the gridlines configure<F>(&mut self, grid: Grid, configure: F) -> &mut Properties where F: FnOnce(&mut grid::Properties) -> &mut grid::Properties,60 fn configure<F>(&mut self, grid: Grid, configure: F) -> &mut Properties 61 where 62 F: FnOnce(&mut grid::Properties) -> &mut grid::Properties, 63 { 64 if self.grids.contains_key(grid) { 65 configure(self.grids.get_mut(grid).unwrap()); 66 } else { 67 let mut properties = Default::default(); 68 configure(&mut properties); 69 self.grids.insert(grid, properties); 70 } 71 72 self 73 } 74 } 75 76 impl Set<Label> for Properties { 77 /// Attaches a label to the axis set(&mut self, label: Label) -> &mut Properties78 fn set(&mut self, label: Label) -> &mut Properties { 79 self.label = Some(label.0); 80 self 81 } 82 } 83 84 impl Set<Range> for Properties { 85 /// Changes the range of the axis that will be shown 86 /// 87 /// **Note** All axes are auto-scaled by default set(&mut self, range: Range) -> &mut Properties88 fn set(&mut self, range: Range) -> &mut Properties { 89 self.hidden = false; 90 91 match range { 92 Range::Auto => self.range = None, 93 Range::Limits(low, high) => self.range = Some((low, high)), 94 } 95 96 self 97 } 98 } 99 100 impl Set<Scale> for Properties { 101 /// Sets the scale of the axis 102 /// 103 /// **Note** All axes use a linear scale by default set(&mut self, scale: Scale) -> &mut Properties104 fn set(&mut self, scale: Scale) -> &mut Properties { 105 self.hidden = false; 106 107 match scale { 108 Scale::Linear => self.logarithmic = false, 109 Scale::Logarithmic => self.logarithmic = true, 110 } 111 112 self 113 } 114 } 115 116 impl Set<ScaleFactor> for Properties { 117 /// Changes the *scale factor* of the axis. 118 /// 119 /// All the data plotted against this axis will have its corresponding coordinate scaled with 120 /// this factor before being plotted. 121 /// 122 /// **Note** The default scale factor is `1`. set(&mut self, factor: ScaleFactor) -> &mut Properties123 fn set(&mut self, factor: ScaleFactor) -> &mut Properties { 124 self.scale_factor = factor.0; 125 126 self 127 } 128 } 129 130 impl<P, L> Set<TicLabels<P, L>> for Properties 131 where 132 L: IntoIterator, 133 L::Item: AsRef<str>, 134 P: IntoIterator, 135 P::Item: Data, 136 { 137 /// Attaches labels to the tics of an axis set(&mut self, tics: TicLabels<P, L>) -> &mut Properties138 fn set(&mut self, tics: TicLabels<P, L>) -> &mut Properties { 139 let TicLabels { positions, labels } = tics; 140 141 let pairs = positions 142 .into_iter() 143 .zip(labels.into_iter()) 144 .map(|(pos, label)| format!("'{}' {}", label.as_ref(), pos.f64())) 145 .collect::<Vec<_>>(); 146 147 if pairs.is_empty() { 148 self.tics = None 149 } else { 150 self.tics = Some(pairs.join(", ")); 151 } 152 153 self 154 } 155 } 156 157 impl<'a> Script for (Axis, &'a Properties) { script(&self) -> String158 fn script(&self) -> String { 159 let &(axis, properties) = self; 160 let axis_ = axis.display(); 161 162 let mut script = if properties.hidden { 163 return format!("unset {}tics\n", axis_); 164 } else { 165 format!("set {}tics nomirror ", axis_) 166 }; 167 168 if let Some(ref tics) = properties.tics { 169 script.push_str(&format!("({})", tics)) 170 } 171 172 script.push('\n'); 173 174 if let Some(ref label) = properties.label { 175 script.push_str(&format!("set {}label '{}'\n", axis_, label)) 176 } 177 178 if let Some((low, high)) = properties.range { 179 script.push_str(&format!("set {}range [{}:{}]\n", axis_, low, high)) 180 } 181 182 if properties.logarithmic { 183 script.push_str(&format!("set logscale {}\n", axis_)); 184 } 185 186 for (grid, properties) in properties.grids.iter() { 187 script.push_str(&(axis, grid, properties).script()); 188 } 189 190 script 191 } 192 } 193 194 impl crate::ScaleFactorTrait for Properties { scale_factor(&self) -> f64195 fn scale_factor(&self) -> f64 { 196 self.scale_factor 197 } 198 } 199