1 //! Filled curve plots 2 3 use std::borrow::Cow; 4 use std::iter::IntoIterator; 5 6 use crate::data::Matrix; 7 use crate::traits::{self, Data, Set}; 8 use crate::{Axes, Color, Default, Display, Figure, Label, Opacity, Plot, Script}; 9 10 /// Properties common to filled curve plots 11 pub struct Properties { 12 axes: Option<Axes>, 13 color: Option<Color>, 14 label: Option<Cow<'static, str>>, 15 opacity: Option<f64>, 16 } 17 18 impl Default for Properties { default() -> Properties19 fn default() -> Properties { 20 Properties { 21 axes: None, 22 color: None, 23 label: None, 24 opacity: None, 25 } 26 } 27 } 28 29 impl Script for Properties { script(&self) -> String30 fn script(&self) -> String { 31 let mut script = if let Some(axes) = self.axes { 32 format!("axes {} ", axes.display()) 33 } else { 34 String::new() 35 }; 36 script.push_str("with filledcurves "); 37 38 script.push_str("fillstyle "); 39 40 if let Some(opacity) = self.opacity { 41 script.push_str(&format!("solid {} ", opacity)) 42 } 43 44 // TODO border shoulde be configurable 45 script.push_str("noborder "); 46 47 if let Some(color) = self.color { 48 script.push_str(&format!("lc rgb '{}' ", color.display())); 49 } 50 51 if let Some(ref label) = self.label { 52 script.push_str("title '"); 53 script.push_str(label); 54 script.push('\'') 55 } else { 56 script.push_str("notitle") 57 } 58 59 script 60 } 61 } 62 63 impl Set<Axes> for Properties { 64 /// Select axes to plot against 65 /// 66 /// **Note** By default, the `BottomXLeftY` axes are used set(&mut self, axes: Axes) -> &mut Properties67 fn set(&mut self, axes: Axes) -> &mut Properties { 68 self.axes = Some(axes); 69 self 70 } 71 } 72 73 impl Set<Color> for Properties { 74 /// Sets the fill color set(&mut self, color: Color) -> &mut Properties75 fn set(&mut self, color: Color) -> &mut Properties { 76 self.color = Some(color); 77 self 78 } 79 } 80 81 impl Set<Label> for Properties { 82 /// Sets the legend label set(&mut self, label: Label) -> &mut Properties83 fn set(&mut self, label: Label) -> &mut Properties { 84 self.label = Some(label.0); 85 self 86 } 87 } 88 89 impl Set<Opacity> for Properties { 90 /// Changes the opacity of the fill color 91 /// 92 /// **Note** By default, the fill color is totally opaque (`opacity = 1.0`) 93 /// 94 /// # Panics 95 /// 96 /// Panics if `opacity` is outside the range `[0, 1]` set(&mut self, opacity: Opacity) -> &mut Properties97 fn set(&mut self, opacity: Opacity) -> &mut Properties { 98 self.opacity = Some(opacity.0); 99 self 100 } 101 } 102 103 /// Fills the area between two curves 104 pub struct FilledCurve<X, Y1, Y2> { 105 /// X coordinate of the data points of both curves 106 pub x: X, 107 /// Y coordinate of the data points of the first curve 108 pub y1: Y1, 109 /// Y coordinate of the data points of the second curve 110 pub y2: Y2, 111 } 112 113 impl<X, Y1, Y2> traits::Plot<FilledCurve<X, Y1, Y2>> for Figure 114 where 115 X: IntoIterator, 116 X::Item: Data, 117 Y1: IntoIterator, 118 Y1::Item: Data, 119 Y2: IntoIterator, 120 Y2::Item: Data, 121 { 122 type Properties = Properties; 123 plot<F>(&mut self, fc: FilledCurve<X, Y1, Y2>, configure: F) -> &mut Figure where F: FnOnce(&mut Properties) -> &mut Properties,124 fn plot<F>(&mut self, fc: FilledCurve<X, Y1, Y2>, configure: F) -> &mut Figure 125 where 126 F: FnOnce(&mut Properties) -> &mut Properties, 127 { 128 let FilledCurve { x, y1, y2 } = fc; 129 130 let mut props = Default::default(); 131 configure(&mut props); 132 133 let (x_factor, y_factor) = 134 crate::scale_factor(&self.axes, props.axes.unwrap_or(crate::Axes::BottomXLeftY)); 135 136 let data = Matrix::new(izip!(x, y1, y2), (x_factor, y_factor, y_factor)); 137 self.plots.push(Plot::new(data, &props)); 138 self 139 } 140 } 141