Skip to content
37 changes: 30 additions & 7 deletions src/components/scatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: Display, U: Display> {
label_position: PointLabelPosition,
label_visible: bool,
label_visibility: LabelVisibility,
point_visible: bool,
marker_type: MarkerType,
marker_size: usize,
Expand All @@ -50,13 +68,13 @@ impl<T: Display, U: Display> ScatterPoint<T, U> {
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,
Expand Down Expand Up @@ -132,13 +150,18 @@ impl<T: Display, U: Display> DatumRepresentation for ScatterPoint<T, U> {
_ => {},
};

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 {
Expand Down Expand Up @@ -188,4 +211,4 @@ impl<T: Display, U: Display> DatumRepresentation for ScatterPoint<T, U> {

Ok(group)
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
16 changes: 8 additions & 8 deletions src/views/area.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<AreaSeries<T, U>>,
Expand All @@ -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(),
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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::<Vec<ScatterPoint<T, U>>>();

let y_origin = {
Expand All @@ -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()));

Expand Down
20 changes: 14 additions & 6 deletions src/views/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<LineSeries<T, U>>,
Expand All @@ -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(),
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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::<Vec<ScatterPoint<T, U>>>();

self.entries.push(LineSeries::new(points, self.color_map.get(key).unwrap().clone()));
Expand Down
12 changes: 6 additions & 6 deletions src/views/scatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<ScatterPoint<T, U>>,
Expand All @@ -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(),
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
Expand Down