///|
/// Histogram counts and bin edges produced by `Figure::hist`.
pub struct Histogram {
  counts : Array[Double]
  edges : Array[Double]
  artists : Array[Artist]
}

///|
pub fn Histogram::counts(self : Histogram) -> Array[Double] {
  self.counts.copy()
}

///|
pub fn Histogram::edges(self : Histogram) -> Array[Double] {
  self.edges.copy()
}

///|
/// Return copies of the bar artists generated for the histogram bins.
pub fn Histogram::artists(self : Histogram) -> Array[Artist] {
  let result = Array(capacity=self.artists.length())
  for artist in self.artists {
    result.push(copy_artist(artist))
  }
  result
}

///|
/// Matplotlib-style alias for the histogram bar artists.
pub fn Histogram::patches(self : Histogram) -> Array[Artist] {
  self.artists()
}

///|
fn finite_values(values : Array[Double]) -> Array[Double] {
  let result = Array(capacity=values.length())
  for value in values {
    if !value.is_nan() && !value.is_inf() {
      result.push(value)
    }
  }
  result
}

///|
/// Compute a histogram and add its bars to the figure.
pub fn Figure::hist(
  self : Figure,
  values : Array[Double],
  bins~ : Int32 = 10,
  color~ : String = "",
  label~ : String = "",
) -> Histogram raise @core.DataError {
  self.axes().hist(values, bins~, color~, label~)
}

///|
/// Compute and draw a histogram on this axes panel.
pub fn Axes::hist(
  self : Axes,
  values : Array[Double],
  bins~ : Int32 = 10,
  color~ : String = "",
  label~ : String = "",
) -> Histogram raise @core.DataError {
  if bins <= 0 {
    raise @core.DataError::InvalidBins
  }
  let finite = finite_values(values)
  let mut minimum = 0.0
  let mut maximum = 1.0
  if finite.length() > 0 {
    minimum = finite[0]
    maximum = finite[0]
    for i in 1..= bins {
      bins - 1
    } else {
      raw_index
    }
    counts[index] += 1.0
  }
  let points = Array(capacity=bins)
  for index in 0..