aboutsummaryrefslogtreecommitdiff
path: root/src/series/histogram.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/series/histogram.rs')
-rw-r--r--src/series/histogram.rs129
1 files changed, 49 insertions, 80 deletions
diff --git a/src/series/histogram.rs b/src/series/histogram.rs
index 75c2fb2..477e4ad 100644
--- a/src/series/histogram.rs
+++ b/src/series/histogram.rs
@@ -1,13 +1,13 @@
use std::collections::{hash_map::IntoIter as HashMapIter, HashMap};
-use std::hash::Hash;
use std::marker::PhantomData;
use std::ops::AddAssign;
use crate::chart::ChartContext;
-use crate::coord::{DiscreteRanged, Ranged, RangedCoord};
-use crate::drawing::DrawingBackend;
+use crate::coord::cartesian::Cartesian2d;
+use crate::coord::ranged1d::{DiscreteRanged, Ranged};
use crate::element::Rectangle;
use crate::style::{Color, ShapeStyle, GREEN};
+use plotters_backend::DrawingBackend;
pub trait HistogramType {}
pub struct Vertical;
@@ -20,32 +20,30 @@ impl HistogramType for Horizontal {}
pub struct Histogram<'a, BR, A, Tag = Vertical>
where
BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
A: AddAssign<A> + Default,
Tag: HistogramType,
{
style: Box<dyn Fn(&BR::ValueType, &A) -> ShapeStyle + 'a>,
margin: u32,
- iter: HashMapIter<BR::ValueType, A>,
- baseline: Box<dyn Fn(BR::ValueType) -> A + 'a>,
- br_param: BR::RangeParameter,
- _p: PhantomData<(BR, Tag)>,
+ iter: HashMapIter<usize, A>,
+ baseline: Box<dyn Fn(&BR::ValueType) -> A + 'a>,
+ br: BR,
+ _p: PhantomData<Tag>,
}
impl<'a, BR, A, Tag> Histogram<'a, BR, A, Tag>
where
- BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
+ BR: DiscreteRanged + Clone,
A: AddAssign<A> + Default + 'a,
Tag: HistogramType,
{
- fn empty(br_param: BR::RangeParameter) -> Self {
+ fn empty(br: &BR) -> Self {
Self {
style: Box::new(|_, _| GREEN.filled()),
margin: 5,
iter: HashMap::new().into_iter(),
baseline: Box::new(|_| A::default()),
- br_param,
+ br: br.clone(),
_p: PhantomData,
}
}
@@ -75,7 +73,7 @@ where
}
/// Set a function that defines variant baseline
- pub fn baseline_func(mut self, func: impl Fn(BR::ValueType) -> A + 'a) -> Self {
+ pub fn baseline_func(mut self, func: impl Fn(&BR::ValueType) -> A + 'a) -> Self {
self.baseline = Box::new(func);
self
}
@@ -87,68 +85,33 @@ where
}
/// Set the data iterator
- pub fn data<I: IntoIterator<Item = (BR::ValueType, A)>>(mut self, iter: I) -> Self {
- let mut buffer = HashMap::<BR::ValueType, A>::new();
+ pub fn data<TB: Into<BR::ValueType>, I: IntoIterator<Item = (TB, A)>>(
+ mut self,
+ iter: I,
+ ) -> Self {
+ let mut buffer = HashMap::<usize, A>::new();
for (x, y) in iter.into_iter() {
- *buffer.entry(x).or_insert_with(Default::default) += y;
+ if let Some(x) = self.br.index_of(&x.into()) {
+ *buffer.entry(x).or_insert_with(Default::default) += y;
+ }
}
self.iter = buffer.into_iter();
self
}
}
-pub trait UseDefaultParameter: Default {
- fn new() -> Self {
- Default::default()
- }
-}
-
-impl UseDefaultParameter for () {}
-
impl<'a, BR, A> Histogram<'a, BR, A, Vertical>
where
- BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
+ BR: DiscreteRanged + Clone,
A: AddAssign<A> + Default + 'a,
{
- /// Create a new histogram series.
- ///
- /// - `iter`: The data iterator
- /// - `margin`: The margin between bars
- /// - `style`: The style of bars
- ///
- /// Returns the newly created histogram series
- #[allow(clippy::redundant_closure)]
- pub fn new<S: Into<ShapeStyle>, I: IntoIterator<Item = (BR::ValueType, A)>>(
- iter: I,
- margin: u32,
- style: S,
- ) -> Self
- where
- BR::RangeParameter: UseDefaultParameter,
- {
- let mut buffer = HashMap::<BR::ValueType, A>::new();
- for (x, y) in iter.into_iter() {
- *buffer.entry(x).or_insert_with(Default::default) += y;
- }
- let style = style.into();
- Self {
- style: Box::new(move |_, _| style.clone()),
- margin,
- iter: buffer.into_iter(),
- baseline: Box::new(|_| A::default()),
- br_param: BR::RangeParameter::new(),
- _p: PhantomData,
- }
- }
-
pub fn vertical<ACoord, DB: DrawingBackend + 'a>(
- parent: &ChartContext<DB, RangedCoord<BR, ACoord>>,
+ parent: &ChartContext<DB, Cartesian2d<BR, ACoord>>,
) -> Self
where
ACoord: Ranged<ValueType = A>,
{
- let dp = parent.as_coord_spec().x_spec().get_range_parameter();
+ let dp = parent.as_coord_spec().x_spec();
Self::empty(dp)
}
@@ -156,17 +119,16 @@ where
impl<'a, BR, A> Histogram<'a, BR, A, Horizontal>
where
- BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
+ BR: DiscreteRanged + Clone,
A: AddAssign<A> + Default + 'a,
{
pub fn horizontal<ACoord, DB: DrawingBackend>(
- parent: &ChartContext<DB, RangedCoord<ACoord, BR>>,
+ parent: &ChartContext<DB, Cartesian2d<ACoord, BR>>,
) -> Self
where
ACoord: Ranged<ValueType = A>,
{
- let dp = parent.as_coord_spec().y_spec().get_range_parameter();
+ let dp = parent.as_coord_spec().y_spec();
Self::empty(dp)
}
}
@@ -174,18 +136,22 @@ where
impl<'a, BR, A> Iterator for Histogram<'a, BR, A, Vertical>
where
BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
A: AddAssign<A> + Default,
{
type Item = Rectangle<(BR::ValueType, A)>;
fn next(&mut self) -> Option<Self::Item> {
- if let Some((x, y)) = self.iter.next() {
- let nx = BR::next_value(&x, &self.br_param);
- let base = (self.baseline)(BR::previous_value(&nx, &self.br_param));
- let style = (self.style)(&x, &y);
- let mut rect = Rectangle::new([(x, y), (nx, base)], style);
- rect.set_margin(0, 0, self.margin, self.margin);
- return Some(rect);
+ while let Some((x, y)) = self.iter.next() {
+ if let Some((x, Some(nx))) = self
+ .br
+ .from_index(x)
+ .map(|v| (v, self.br.from_index(x + 1)))
+ {
+ let base = (self.baseline)(&x);
+ let style = (self.style)(&x, &y);
+ let mut rect = Rectangle::new([(x, y), (nx, base)], style);
+ rect.set_margin(0, 0, self.margin, self.margin);
+ return Some(rect);
+ }
}
None
}
@@ -194,19 +160,22 @@ where
impl<'a, BR, A> Iterator for Histogram<'a, BR, A, Horizontal>
where
BR: DiscreteRanged,
- BR::ValueType: Eq + Hash,
A: AddAssign<A> + Default,
{
type Item = Rectangle<(A, BR::ValueType)>;
fn next(&mut self) -> Option<Self::Item> {
- if let Some((y, x)) = self.iter.next() {
- let ny = BR::next_value(&y, &self.br_param);
- // With this trick we can avoid the clone trait bound
- let base = (self.baseline)(BR::previous_value(&ny, &self.br_param));
- let style = (self.style)(&y, &x);
- let mut rect = Rectangle::new([(x, y), (base, ny)], style);
- rect.set_margin(self.margin, self.margin, 0, 0);
- return Some(rect);
+ while let Some((y, x)) = self.iter.next() {
+ if let Some((y, Some(ny))) = self
+ .br
+ .from_index(y)
+ .map(|v| (v, self.br.from_index(y + 1)))
+ {
+ let base = (self.baseline)(&y);
+ let style = (self.style)(&y, &x);
+ let mut rect = Rectangle::new([(x, y), (base, ny)], style);
+ rect.set_margin(0, 0, self.margin, self.margin);
+ return Some(rect);
+ }
}
None
}