ndhistogram/axis/mod.rs
1//! Axis for ND histograms
2//!
3//! This module contains implementations of [Axis] that are used to represent the axes of
4//! an N-dimensional [Histogram](crate::Histogram).
5//!
6mod bininterval;
7pub use bininterval::bininterval::BinInterval;
8pub use bininterval::singlevaluebininterval::SingleValueBinInterval;
9mod uniformcyclic;
10pub use uniformcyclic::UniformCyclic;
11mod variablecyclic;
12pub use variablecyclic::VariableCyclic;
13mod uniform;
14pub use uniform::Uniform;
15mod uniformnoflow;
16pub use uniformnoflow::UniformNoFlow;
17mod category;
18pub use category::Category;
19mod categorynoflow;
20pub use categorynoflow::CategoryNoFlow;
21mod variable;
22pub use variable::Variable;
23mod variablenoflow;
24pub use variablenoflow::VariableNoFlow;
25
26type Iter<'a, BinInterval> = Box<dyn Iterator<Item = (usize, BinInterval)> + 'a>;
27type Indices = Box<dyn Iterator<Item = usize>>;
28type Bins<'a, BinInterval> = Box<dyn Iterator<Item = BinInterval> + 'a>;
29
30/// An binned axis corresponding to one dimension of an N-dimensional [Histogram](crate::Histogram).
31///
32/// An Axis is composed of a map from some coordinate space to linear bin number, and the inverse map.
33/// For examples see:
34/// - [Uniform],
35/// - [UniformNoFlow],
36/// - [UniformCyclic],
37/// - [Variable],
38/// - [VariableNoFlow],
39/// - [VariableCyclic],
40/// - [Category]
41/// - and [CategoryNoFlow].
42///
43/// Most use cases should be covered by the builtin Axis implementations.
44/// However, you may implement the Axis trait if you have specialist needs.
45///
46/// # Examples
47///
48/// ## Parity Axis
49/// Imagine we wanted an 2-bin axis where even values where mapped to one bin
50/// and odd values to another bin. We could implement this with the following:
51/// ```rust
52/// use ndhistogram::axis::Axis;
53/// use ndhistogram::{ndhistogram, Histogram};
54/// enum Parity {
55/// Even,
56/// Odd
57/// }
58///
59/// struct ParityAxis {}
60///
61/// impl Axis for ParityAxis {
62/// type Coordinate = i32;
63///
64/// type BinInterval = Parity;
65///
66/// fn index(&self, coordinate: &Self::Coordinate) -> Option<usize> {
67/// if coordinate % 2 == 0 { Some(0) } else { Some(1) }
68/// }
69///
70/// fn num_bins(&self) -> usize {
71/// 2
72/// }
73///
74/// fn bin(&self, index: usize) -> Option<Self::BinInterval> {
75/// if index == 0 { Some(Parity::Even) } else { Some(Parity::Odd) }
76/// }
77/// }
78///
79/// let mut hist = ndhistogram!(ParityAxis{}; i32);
80/// hist.fill(&1);
81/// hist.fill_with(&2, 4);
82/// assert_eq!(hist.value(&1), Some(&1));
83/// assert_eq!(hist.value(&2), Some(&4));
84/// ```
85///
86pub trait Axis {
87 /// The type representing a location on this axis.
88 type Coordinate;
89 /// The type of an interval representing the set of Coordinates that correspond to a histogram bin
90 type BinInterval;
91
92 /// Map from coordinate to bin number.
93 /// Returns an option as not all valid coordinates are necessarily contained within a bin.
94 fn index(&self, coordinate: &Self::Coordinate) -> Option<usize>;
95 /// The number of bins in this axis, including underflow and overflow.
96 fn num_bins(&self) -> usize;
97
98 /// Map from bin number to axis to the interval covering the range of coordinates that this bin contains.
99 /// Returns an option in case an index >= [Axis::num_bins] is given.
100 fn bin(&self, index: usize) -> Option<Self::BinInterval>;
101
102 /// An iterator over bin numbers
103 fn indices(&self) -> Indices {
104 Box::new(0..self.num_bins())
105 }
106
107 /// An iterator over bin numbers and bin intervals
108 fn iter(&self) -> Iter<'_, Self::BinInterval> {
109 Box::new(self.indices().map(move |it| {
110 (
111 it,
112 self.bin(it)
113 .expect("indices() should only produce valid indices"),
114 )
115 }))
116 }
117
118 /// An iterator over bin intervals.
119 fn bins(&self) -> Bins<'_, Self::BinInterval> {
120 Box::new(self.indices().map(move |it| {
121 self.bin(it)
122 .expect("indices() should only produce valid indices")
123 }))
124 }
125
126 /// The number of dimensions that this object corresponds to.
127 /// For most Axis types this will simply be 1.
128 /// However, [Axes](crate::Axes) (i.e. a set of [Axis]) also implement [Axis]
129 /// and should return the number of [Axis] that it contains.
130 fn num_dim(&self) -> usize {
131 1
132 }
133}