diff --git a/src/components/scatter.rs b/src/components/scatter.rs index f9b632d..0cf0014 100644 --- a/src/components/scatter.rs +++ b/src/components/scatter.rs @@ -23,14 +23,32 @@ pub enum PointLabelPosition { S, SW, W, - NW + NW, +} + +/// Define the possible visibility types of a point's label. +#[derive(Debug, Copy, Clone)] +pub enum LabelVisibility { + None, + XCoordinate, + YCoordinate, + BothCoordinates, +} + +impl LabelVisibility { + fn is_visible(&self) -> bool { + match *self { + Self::None => false, + _ => true, + } + } } /// Represents a point in a scatter plot. #[derive(Debug)] pub struct ScatterPoint { label_position: PointLabelPosition, - label_visible: bool, + label_visibility: LabelVisibility, point_visible: bool, marker_type: MarkerType, marker_size: usize, @@ -50,13 +68,13 @@ impl ScatterPoint { x_label: T, y_label: U, label_position: PointLabelPosition, - label_visible: bool, + label_visibility: LabelVisibility, point_visible: bool, color: String ) -> Self { Self { label_position, - label_visible, + label_visibility, point_visible, marker_type, marker_size, @@ -132,13 +150,18 @@ impl DatumRepresentation for ScatterPoint { _ => {}, }; - if self.label_visible { + if self.label_visibility.is_visible() { let mut point_label = Text::new() .set("dy", ".35em") .set("font-family", "sans-serif") .set("fill", "#333") .set("font-size", "14px") - .add(TextNode::new(format!("({}, {})", self.x_label, self.y_label))); + .add(match self.label_visibility { + LabelVisibility::BothCoordinates => TextNode::new(format!("({}, {})", self.x_label, self.y_label)), + LabelVisibility::XCoordinate => TextNode::new(format!("{}", self.x_label)), + LabelVisibility::YCoordinate => TextNode::new(format!("{}", self.y_label)), + LabelVisibility::None => TextNode::new(String::new()), + }); let label_offset = self.marker_size as isize; match self.label_position { @@ -188,4 +211,4 @@ impl DatumRepresentation for ScatterPoint { Ok(group) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index c9d4815..4a38c95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ pub use crate::views::datum::{BarDatum, PointDatum}; pub use crate::axis::{Axis, AxisPosition}; pub use crate::components::bar::BarLabelPosition; pub use crate::components::line::LineSeries; -pub use crate::components::scatter::{MarkerType, PointLabelPosition}; +pub use crate::components::scatter::{MarkerType, PointLabelPosition, LabelVisibility}; pub use crate::colors::Color; #[cfg(test)] diff --git a/src/views/area.rs b/src/views/area.rs index 1aa3a0b..da0a8b8 100644 --- a/src/views/area.rs +++ b/src/views/area.rs @@ -1,6 +1,6 @@ use svg::node::Node; use svg::node::element::Group; -use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition}; +use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition, LabelVisibility}; use crate::colors::Color; use crate::Scale; use crate::views::datum::PointDatum; @@ -12,7 +12,7 @@ use crate::components::area::AreaSeries; /// A View that represents data as a scatter plot. pub struct AreaSeriesView<'a, T: Display + Clone, U: Display + Clone> { - labels_visible: bool, + labels_visibility: LabelVisibility, label_position: PointLabelPosition, marker_type: MarkerType, entries: Vec>, @@ -26,7 +26,7 @@ impl<'a, T: Display + Clone, U: Display + Clone> AreaSeriesView<'a, T, U> { /// Create a new empty instance of the view. pub fn new() -> Self { Self { - labels_visible: true, + labels_visibility: LabelVisibility::BothCoordinates, label_position: PointLabelPosition::NW, marker_type: MarkerType::Circle, entries: Vec::new(), @@ -68,8 +68,8 @@ impl<'a, T: Display + Clone, U: Display + Clone> AreaSeriesView<'a, T, U> { } /// Set labels visibility. - pub fn set_label_visibility(mut self, label_visibility: bool) -> Self { - self.labels_visible = label_visibility; + pub fn set_label_visibility(mut self, label_visibility: LabelVisibility) -> Self { + self.labels_visibility = label_visibility; self } @@ -112,7 +112,7 @@ impl<'a, T: Display + Clone, U: Display + Clone> AreaSeriesView<'a, T, U> { let mut points = data.iter().map(|datum| { let scaled_x = self.x_scale.unwrap().scale(&datum.get_x()); let scaled_y = self.y_scale.unwrap().scale(&datum.get_y()); - ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visible, true, self.colors[0].as_hex()) + ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visibility, true, self.colors[0].as_hex()) }).collect::>>(); let y_origin = { @@ -124,8 +124,8 @@ impl<'a, T: Display + Clone, U: Display + Clone> AreaSeriesView<'a, T, U> { }; let first = data.first().unwrap(); let last = data.last().unwrap(); - points.push(ScatterPoint::new(self.x_scale.unwrap().scale(&last.get_x()) + x_bandwidth_offset, y_origin, self.marker_type, 5, data[0].get_x(), data[0].get_y(), self.label_position, false, false, "#fff".to_string())); - points.push(ScatterPoint::new(self.x_scale.unwrap().scale(&first.get_x()) + x_bandwidth_offset, y_origin, self.marker_type, 5, data[0].get_x(), data[0].get_y(), self.label_position, false, false, "#fff".to_string())); + points.push(ScatterPoint::new(self.x_scale.unwrap().scale(&last.get_x()) + x_bandwidth_offset, y_origin, self.marker_type, 5, data[0].get_x(), data[0].get_y(), self.label_position, LabelVisibility::None, false, "#fff".to_string())); + points.push(ScatterPoint::new(self.x_scale.unwrap().scale(&first.get_x()) + x_bandwidth_offset, y_origin, self.marker_type, 5, data[0].get_x(), data[0].get_y(), self.label_position, LabelVisibility::None, false, "#fff".to_string())); self.entries.push(AreaSeries::new(points, self.colors[0].as_hex())); diff --git a/src/views/line.rs b/src/views/line.rs index b3c7c8e..bb7811a 100644 --- a/src/views/line.rs +++ b/src/views/line.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::fmt::Display; use svg::node::Node; use svg::node::element::Group; -use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition}; +use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition, LabelVisibility}; use crate::colors::Color; use crate::{Scale, LineSeries}; use crate::views::datum::PointDatum; @@ -12,7 +12,8 @@ use crate::components::legend::{LegendEntry, LegendMarkerType}; /// A View that represents data as a scatter plot. pub struct LineSeriesView<'a, T: Display, U: Display> { - labels_visible: bool, + labels_visibility: LabelVisibility, + marker_visible: bool, label_position: PointLabelPosition, marker_type: MarkerType, entries: Vec>, @@ -28,7 +29,8 @@ impl<'a, T: Display, U: Display> LineSeriesView<'a, T, U> { /// Create a new empty instance of the view. pub fn new() -> Self { Self { - labels_visible: true, + labels_visibility: LabelVisibility::BothCoordinates, + marker_visible: true, label_position: PointLabelPosition::NW, marker_type: MarkerType::Circle, entries: Vec::new(), @@ -78,8 +80,14 @@ impl<'a, T: Display, U: Display> LineSeriesView<'a, T, U> { } /// Set labels visibility. - pub fn set_label_visibility(mut self, label_visibility: bool) -> Self { - self.labels_visible = label_visibility; + pub fn set_label_visibility(mut self, label_visibility: LabelVisibility) -> Self { + self.labels_visibility = label_visibility; + self + } + + /// Set marker visibility. + pub fn set_marker_visibility(mut self, marker_visibility: bool) -> Self { + self.marker_visible = marker_visibility; self } @@ -134,7 +142,7 @@ impl<'a, T: Display, U: Display> LineSeriesView<'a, T, U> { self.x_scale.unwrap().bandwidth().unwrap() / 2_f32 } }; - ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visible, true,self.color_map.get(&datum.get_key()).unwrap().clone()) + ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visibility, self.marker_visible, self.color_map.get(&datum.get_key()).unwrap().clone()) }).collect::>>(); self.entries.push(LineSeries::new(points, self.color_map.get(key).unwrap().clone())); diff --git a/src/views/scatter.rs b/src/views/scatter.rs index f6cd431..ff9f1e0 100644 --- a/src/views/scatter.rs +++ b/src/views/scatter.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::fmt::Display; use svg::node::Node; use svg::node::element::Group; -use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition}; +use crate::components::scatter::{ScatterPoint, MarkerType, PointLabelPosition, LabelVisibility}; use crate::colors::Color; use crate::Scale; use crate::views::datum::PointDatum; @@ -12,7 +12,7 @@ use crate::components::legend::{LegendEntry, LegendMarkerType}; /// A View that represents data as a scatter plot. pub struct ScatterView<'a, T: Display, U: Display> { - labels_visible: bool, + labels_visibility: LabelVisibility, label_position: PointLabelPosition, marker_type: MarkerType, entries: Vec>, @@ -28,7 +28,7 @@ impl<'a, T: Display, U: Display> ScatterView<'a, T, U> { /// Create a new empty instance of the view. pub fn new() -> Self { Self { - labels_visible: true, + labels_visibility: LabelVisibility::BothCoordinates, label_position: PointLabelPosition::NW, marker_type: MarkerType::Circle, entries: Vec::new(), @@ -78,8 +78,8 @@ impl<'a, T: Display, U: Display> ScatterView<'a, T, U> { } /// Set labels visibility. - pub fn set_label_visibility(mut self, label_visibility: bool) -> Self { - self.labels_visible = label_visibility; + pub fn set_label_visibility(mut self, label_visibility: LabelVisibility) -> Self { + self.labels_visibility = label_visibility; self } @@ -132,7 +132,7 @@ impl<'a, T: Display, U: Display> ScatterView<'a, T, U> { self.x_scale.unwrap().bandwidth().unwrap() / 2_f32 } }; - self.entries.push(ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visible, true, self.color_map.get(&datum.get_key()).unwrap().clone())); + self.entries.push(ScatterPoint::new(scaled_x + x_bandwidth_offset, scaled_y + y_bandwidth_offset, self.marker_type, 5, datum.get_x(), datum.get_y(), self.label_position, self.labels_visibility, true, self.color_map.get(&datum.get_key()).unwrap().clone())); } Ok(self)