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