ndhistogram/histogram/
histogram.rs

1use crate::{axis::Axis, FillWith};
2
3use super::fill::{Fill, FillWithWeighted};
4
5// TODO: Using generic associated types would give a cleaner interface and avoid boxing the iterators
6// https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md
7pub(crate) type Values<'a, V> = Box<dyn Iterator<Item = &'a V> + 'a>;
8pub(crate) type Iter<'a, A, V> =
9    Box<dyn Iterator<Item = Item<<A as Axis>::BinInterval, &'a V>> + 'a>;
10
11pub(crate) type ValuesMut<'a, V> = Box<dyn Iterator<Item = &'a mut V> + 'a>;
12pub(crate) type IterMut<'a, A, V> =
13    Box<dyn Iterator<Item = Item<<A as Axis>::BinInterval, &'a mut V>> + 'a>;
14
15/// A common interface for an ND histograms.
16///
17/// Implementations of this trait should handle storing the histogram bin values
18/// and provide methods to fill and read those values.
19///
20/// The most commonly used implementation is [VecHistogram](crate::VecHistogram).
21/// See [crate::ndhistogram] for examples of its use.
22pub trait Histogram<A: Axis, V> {
23    /// The histogram [Axes](crate::Axes) that map coordinates to bin numbers.
24    fn axes(&self) -> &A;
25
26    /// Read a bin value given an index.
27    /// Return an Option as the given index may not be valid for this histogram.
28    fn value_at_index(&self, index: usize) -> Option<&V>;
29
30    /// Read a bin value given a coordinate.
31    /// Returns an Option as the given coordinate may not be mapped to a bin.
32    fn value(&self, coordinate: &A::Coordinate) -> Option<&V> {
33        let index = self.axes().index(coordinate)?;
34        self.value_at_index(index)
35    }
36
37    /// Iterator over bin values.
38    fn values(&self) -> Values<'_, V>;
39
40    /// Iterator over bin indices, bin interval and bin values.
41    fn iter(&self) -> Iter<'_, A, V>;
42
43    /// Mutable access to a bin value at a given index.
44    fn value_at_index_mut(&mut self, index: usize) -> Option<&mut V>;
45
46    /// Mutable access to a bin value at a given coordinate.
47    #[inline]
48    fn value_mut(&mut self, coordinate: &A::Coordinate) -> Option<&mut V> {
49        let index = self.axes().index(coordinate)?;
50        self.value_at_index_mut(index)
51    }
52
53    /// Mutable iterator over bin values.
54    fn values_mut(&mut self) -> ValuesMut<'_, V>;
55    /// Mutable iterator over bin indices, bin interval and bin values.
56    fn iter_mut(&mut self) -> IterMut<'_, A, V>;
57
58    /// Fill the histogram bin value at coordinate with unit weight.
59    /// If the [Axes](crate::Axes) do not cover that coordinate, do nothing.
60    /// See [Fill](crate::Fill).
61    #[inline]
62    fn fill(&mut self, coordinate: &A::Coordinate)
63    where
64        V: Fill,
65    {
66        if let Some(value) = self.value_mut(coordinate) {
67            value.fill()
68        }
69    }
70
71    /// Fill the histogram bin value at coordinate with some data.
72    /// If the [Axes](crate::Axes) do not cover that coordinate, do nothing.
73    /// See [FillWith](crate::FillWith).
74    #[inline]
75    fn fill_with<D>(&mut self, coordinate: &A::Coordinate, data: D)
76    where
77        V: FillWith<D>,
78        Self: Sized,
79    {
80        if let Some(value) = self.value_mut(coordinate) {
81            value.fill_with(data)
82        }
83    }
84
85    /// Fill the histogram bin value at coordinate with some data.
86    /// If the [Axes](crate::Axes) do not cover that coordinate, do nothing.
87    /// See [FillWithWeighted].
88    #[inline]
89    fn fill_with_weighted<D, W>(&mut self, coordinate: &A::Coordinate, data: D, weight: W)
90    where
91        V: FillWithWeighted<D, W>,
92        Self: Sized,
93    {
94        if let Some(value) = self.value_mut(coordinate) {
95            value.fill_with_weighted(data, weight)
96        }
97    }
98}
99
100/// Struct to be returned when iterating over [Histogram]s bins.
101#[derive(Copy, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub struct Item<T, V> {
104    /// Bin number
105    pub index: usize,
106    /// Bin interval. See [Axis::BinInterval].
107    pub bin: T,
108    /// Bin value.
109    pub value: V,
110}
111
112impl<T, V> Item<T, V> {
113    /// Factory method to create [Item].
114    pub fn new(index: usize, bin: T, value: V) -> Self {
115        Self { index, bin, value }
116    }
117}