use svg;
use axis;
use utils::PairWise;
use svg_render;
use text_render;
use representation::Representation;
use style;
#[derive(Debug, Default)]
pub struct Style {
fill: Option<String>,
}
impl Style {
pub fn new() -> Self {
Style { fill: None }
}
pub fn overlay(&mut self, other: &Self) {
if let Some(ref v) = other.fill {
self.fill = Some(v.clone())
}
}
}
impl style::Bar for Style {
fn fill<T>(&mut self, value: T) -> &mut Self
where
T: Into<String>,
{
self.fill = Some(value.into());
self
}
fn get_fill(&self) -> &Option<String> {
&self.fill
}
}
#[derive(Debug)]
pub struct Histogram {
pub bin_bounds: Vec<f64>, pub bin_counts: Vec<u32>, pub bin_densities: Vec<f64>, style: Style,
}
impl Histogram {
pub fn from_vec(v: &[f64], num_bins: u32) -> Histogram {
let max = v.iter().fold(-1. / 0., |a, &b| f64::max(a, b));
let min = v.iter().fold(1. / 0., |a, &b| f64::min(a, b));
let num_bins = num_bins as usize;
let mut bins = vec![0; num_bins];
let range = max - min;
let bin_width = (max - min) / num_bins as f64;
let mut bounds: Vec<f64> = (0..num_bins)
.map(|n| (n as f64 / num_bins as f64) * range + min)
.collect();
bounds.push(max);
let bounds = bounds;
for &val in v.iter() {
let bin = bounds
.pairwise()
.enumerate()
.skip_while(|&(_, (&l, &u))| !(val >= l && val <= u))
.map(|(i, (_, _))| i)
.next()
.unwrap();
bins[bin] += 1;
}
let density_per_bin = bins.iter().map(|&x| x as f64 / bin_width).collect();
Histogram {
bin_bounds: bounds,
bin_counts: bins,
bin_densities: density_per_bin,
style: Style::new(),
}
}
pub fn num_bins(&self) -> usize {
self.bin_counts.len()
}
fn x_range(&self) -> (f64, f64) {
(
*self.bin_bounds.first().unwrap(),
*self.bin_bounds.last().unwrap(),
)
}
fn y_range(&self) -> (f64, f64) {
let max = *self.bin_counts.iter().max().unwrap();
(0., max as f64)
}
pub fn style(mut self, style: &Style) -> Self {
self.style.overlay(style);
self
}
pub fn get_style(&self) -> &Style {
&self.style
}
}
impl Representation for Histogram {
fn range(&self, dim: u32) -> (f64, f64) {
match dim {
0 => self.x_range(),
1 => self.y_range(),
_ => panic!("Axis out of range"),
}
}
fn to_svg(
&self,
x_axis: &axis::Axis,
y_axis: &axis::Axis,
face_width: f64,
face_height: f64,
) -> svg::node::element::Group {
svg_render::draw_face_bars(self, x_axis, y_axis, face_width, face_height, &self.style)
}
fn to_text(
&self,
x_axis: &axis::Axis,
y_axis: &axis::Axis,
face_width: u32,
face_height: u32,
) -> String {
text_render::render_face_bars(self, x_axis, y_axis, face_width, face_height)
}
}