{-# LANGUAGE DeriveDataTypeable        #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE FunctionalDependencies    #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE RecordWildCards           #-}
{-# LANGUAGE TypeFamilies              #-}
{-# LANGUAGE UndecidableInstances      #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Plots.Types.Histogram
-- Copyright   :  (C) 2015 Christopher Chalmers
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Christopher Chalmers
-- Stability   :  experimental
-- Portability :  non-portable

-- A histogram is a graphical representation of the distribution of
-- numerical data. It is an estimate of the probability distribution of
-- a continuous variable.
--
----------------------------------------------------------------------------

module Plots.Types.Histogram
  (
    -- * Histogram plot
    HistogramPlot

    -- ** Already computed histograms
  , computedHistogram

    -- ** Histogram options
  , HistogramOptions
  , HasHistogramOptions (..)

    -- ** Normalisation
  , NormalisationMethod
  , count
  , probability
  , countDensity
  , pdf
  , cumilative
  , cdf

    -- ** Plotting histograms
  , histogramPlot
  , histogramPlot'
  , histogramPlotOf
  , histogramPlotOf'

    -- * Low level constructors
  , mkComputedHistogram
  , mkHistogramPlot
  ) where

import           Control.Monad.State.Lazy

import qualified Data.Foldable               as F
import           Data.Maybe
import           Data.Typeable

import qualified Data.Vector                 as V
import qualified Statistics.Sample.Histogram as Stat

import           Diagrams.Core.Transform     (fromSymmetric)
import           Diagrams.Prelude
import           Linear.V2                   (_yx)

import           Plots.Axis
import           Plots.Style
import           Plots.Types
import           Plots.Util


-- | Construct a rectangle of size $v$ with the bottom left at point $p$.
rectBL :: (InSpace V2 n t, TrailLike t) => Point V2 n -> V2 n -> t
rectBL :: forall n t.
(InSpace V2 n t, TrailLike t) =>
Point V2 n -> V2 n -> t
rectBL Point V2 n
p (V2 n
x n
y) =
  Located (Trail (V t) (N t)) -> t
forall t. TrailLike t => Located (Trail (V t) (N t)) -> t
trailLike (Located (Trail (V t) (N t)) -> t)
-> Located (Trail (V t) (N t)) -> t
forall a b. (a -> b) -> a -> b
$ [Vn (Trail V2 n)] -> Trail V2 n
forall t. TrailLike t => [Vn t] -> t
fromOffsets [n -> n -> V2 n
forall a. a -> a -> V2 a
V2 n
x n
0, n -> n -> V2 n
forall a. a -> a -> V2 a
V2 n
0 n
y, n -> n -> V2 n
forall a. a -> a -> V2 a
V2 (-n
x) n
0] Trail V2 n -> (Trail V2 n -> Trail V2 n) -> Trail V2 n
forall a b. a -> (a -> b) -> b
# Trail V2 n -> Trail V2 n
forall (v :: * -> *) n. Trail v n -> Trail v n
closeTrail Trail V2 n
-> Point (V (Trail V2 n)) (N (Trail V2 n)) -> Located (Trail V2 n)
forall a. a -> Point (V a) (N a) -> Located a
`at` Point (V (Trail V2 n)) (N (Trail V2 n))
Point V2 n
p

------------------------------------------------------------------------
-- GHistogram plot
------------------------------------------------------------------------

-- | Simple histogram type supporting uniform bins.
data HistogramPlot n = HistogramPlot
  { forall n. HistogramPlot n -> n
hWidth  :: n
  , forall n. HistogramPlot n -> n
hStart  :: n
  , forall n. HistogramPlot n -> [n]
hValues :: [n]
  , forall n. HistogramPlot n -> Orientation
hOrient :: Orientation
  } deriving Typeable

type instance V (HistogramPlot n) = V2
type instance N (HistogramPlot n) = n

instance OrderedField n => Enveloped (HistogramPlot n) where
  getEnvelope :: HistogramPlot n
-> Envelope (V (HistogramPlot n)) (N (HistogramPlot n))
getEnvelope HistogramPlot {n
[n]
Orientation
hWidth :: forall n. HistogramPlot n -> n
hStart :: forall n. HistogramPlot n -> n
hValues :: forall n. HistogramPlot n -> [n]
hOrient :: forall n. HistogramPlot n -> Orientation
hWidth :: n
hStart :: n
hValues :: [n]
hOrient :: Orientation
..} =
    -- don't like this redundant code
    Path V2 n -> Envelope (V (Path V2 n)) (N (Path V2 n))
Path V2 n -> Envelope (V (HistogramPlot n)) (N (HistogramPlot n))
forall a. Enveloped a => a -> Envelope (V a) (N a)
getEnvelope (Path V2 n -> Envelope (V (HistogramPlot n)) (N (HistogramPlot n)))
-> (Path V2 n -> Path V2 n)
-> Path V2 n
-> Envelope (V (HistogramPlot n)) (N (HistogramPlot n))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Orientation
-> (Path V2 n -> Path V2 n)
-> (Path V2 n -> Path V2 n)
-> Path V2 n
-> Path V2 n
forall o a. HasOrientation o => o -> a -> a -> a
orient Orientation
hOrient Path V2 n -> Path V2 n
forall (v :: * -> *) n t.
(InSpace v n t, R2 v, Transformable t) =>
t -> t
_reflectXY Path V2 n -> Path V2 n
forall a. a -> a
id (Path V2 n -> Path V2 n)
-> (Path V2 n -> Path V2 n) -> Path V2 n -> Path V2 n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Path v n -> Path v n
forall a. a -> a
forall {v :: * -> *} {n}. Path v n -> Path v n
id :: Path v n -> Path v n) (Path V2 n -> Envelope (V (HistogramPlot n)) (N (HistogramPlot n)))
-> Path V2 n
-> Envelope (V (HistogramPlot n)) (N (HistogramPlot n))
forall a b. (a -> b) -> a -> b
$
      (Int -> n -> Path V2 n) -> [n] -> Path V2 n
forall m a. Monoid m => (Int -> a -> m) -> [a] -> m
forall i (f :: * -> *) m a.
(FoldableWithIndex i f, Monoid m) =>
(i -> a -> m) -> f a -> m
ifoldMap Int -> n -> Path V2 n
drawBar [n]
hValues
    where
      drawBar :: Int -> n -> Path V2 n
drawBar Int
i n
h = Point V2 n -> V2 n -> Path V2 n
forall n t.
(InSpace V2 n t, TrailLike t) =>
Point V2 n -> V2 n -> t
rectBL (n -> n -> Point V2 n
forall n. n -> n -> P2 n
mkP2 n
x n
0) (n -> n -> V2 n
forall a. a -> a -> V2 a
V2 n
hWidth n
h)
        where x :: n
x = n
hStart n -> n -> n
forall a. Num a => a -> a -> a
+ Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i n -> n -> n
forall a. Num a => a -> a -> a
* n
hWidth

instance (TypeableFloat n, Renderable (Path V2 n) b)
    => Plotable (HistogramPlot n) b where
  renderPlotable :: forall (v :: * -> *) n.
InSpace v n (HistogramPlot n) =>
AxisSpec v n
-> PlotStyle b v n -> HistogramPlot n -> QDiagram b v n Any
renderPlotable AxisSpec v n
s PlotStyle b v n
sty HistogramPlot {n
[n]
Orientation
hWidth :: forall n. HistogramPlot n -> n
hStart :: forall n. HistogramPlot n -> n
hValues :: forall n. HistogramPlot n -> [n]
hOrient :: forall n. HistogramPlot n -> Orientation
hWidth :: n
hStart :: n
hValues :: [n]
hOrient :: Orientation
..} =
    (Int -> n -> QDiagram b v n Any) -> [n] -> QDiagram b v n Any
forall m a. Monoid m => (Int -> a -> m) -> [a] -> m
forall i (f :: * -> *) m a.
(FoldableWithIndex i f, Monoid m) =>
(i -> a -> m) -> f a -> m
ifoldMap Int -> n -> QDiagram b v n Any
drawBar [n]
hValues
      # orient hOrient _reflectXY id
      # applyAreaStyle sty
      # transform (s^.specTrans)
    where
      drawBar :: Int -> n -> QDiagram b v n Any
drawBar Int
i n
h = Point V2 n -> V2 n -> QDiagram b v n Any
forall n t.
(InSpace V2 n t, TrailLike t) =>
Point V2 n -> V2 n -> t
rectBL (n -> n -> Point V2 n
forall n. n -> n -> P2 n
mkP2 n
x n
0) (n -> n -> V2 n
forall a. a -> a -> V2 a
V2 n
hWidth n
h)
        where x :: n
x = n
hStart n -> n -> n
forall a. Num a => a -> a -> a
+ Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i n -> n -> n
forall a. Num a => a -> a -> a
* n
hWidth

  defLegendPic :: forall (v :: * -> *) n.
InSpace v n (HistogramPlot n) =>
PlotStyle b v n -> HistogramPlot n -> QDiagram b v n Any
defLegendPic PlotStyle b v n
sty HistogramPlot {n
[n]
Orientation
hWidth :: forall n. HistogramPlot n -> n
hStart :: forall n. HistogramPlot n -> n
hValues :: forall n. HistogramPlot n -> [n]
hOrient :: forall n. HistogramPlot n -> Orientation
hWidth :: n
hStart :: n
hValues :: [n]
hOrient :: Orientation
..}
    = QDiagram b v n Any -> QDiagram b v n Any
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerXY
    (QDiagram b v n Any -> QDiagram b v n Any)
-> (QDiagram b v n Any -> QDiagram b v n Any)
-> QDiagram b v n Any
-> QDiagram b v n Any
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PlotStyle b v n -> QDiagram b v n Any -> QDiagram b v n Any
forall a t b.
(SameSpace a t, HasPlotStyle (Const (PlotStyle b (V a) (N a))) a b,
 HasStyle t) =>
a -> t -> t
applyAreaStyle PlotStyle b v n
sty'
    (QDiagram b v n Any -> QDiagram b v n Any)
-> (QDiagram b v n Any -> QDiagram b v n Any)
-> QDiagram b v n Any
-> QDiagram b v n Any
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Orientation
-> (QDiagram b v n Any -> QDiagram b v n Any)
-> (QDiagram b v n Any -> QDiagram b v n Any)
-> QDiagram b v n Any
-> QDiagram b v n Any
forall o a. HasOrientation o => o -> a -> a -> a
orient Orientation
hOrient QDiagram b v n Any -> QDiagram b v n Any
forall (v :: * -> *) n t.
(InSpace v n t, R2 v, Transformable t) =>
t -> t
_reflectXY QDiagram b v n Any -> QDiagram b v n Any
forall a. a -> a
id
    (QDiagram b v n Any -> QDiagram b v n Any)
-> QDiagram b v n Any -> QDiagram b v n Any
forall a b. (a -> b) -> a -> b
$ QDiagram b v n Any -> QDiagram b v n Any
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB (n -> n -> QDiagram b v n Any
forall n t. (InSpace V2 n t, TrailLike t) => n -> n -> t
rect n
4 n
7) QDiagram b v n Any -> QDiagram b v n Any -> QDiagram b v n Any
forall n a.
(InSpace V2 n a, Juxtaposable a, Semigroup a) =>
a -> a -> a
||| QDiagram b v n Any -> QDiagram b v n Any
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB (n -> n -> QDiagram b v n Any
forall n t. (InSpace V2 n t, TrailLike t) => n -> n -> t
rect n
4 n
10) QDiagram b v n Any -> QDiagram b v n Any -> QDiagram b v n Any
forall n a.
(InSpace V2 n a, Juxtaposable a, Semigroup a) =>
a -> a -> a
||| QDiagram b v n Any -> QDiagram b v n Any
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB (n -> n -> QDiagram b v n Any
forall n t. (InSpace V2 n t, TrailLike t) => n -> n -> t
rect n
4 n
6)
    where
      -- The legend bars don't look right if the line width is too big so we limit it
      sty' :: PlotStyle b v n
sty' = PlotStyle b v n
sty PlotStyle b v n
-> (PlotStyle b v n -> PlotStyle b v n) -> PlotStyle b v n
forall a b. a -> (a -> b) -> b
& LensLike'
  Identity
  (PlotStyle b v n)
  (Style (V (PlotStyle b v n)) (N (PlotStyle b v n)))
(Style V2 n -> Identity (Style V2 n))
-> PlotStyle b v n -> Identity (PlotStyle b v n)
forall (f :: * -> *) a b.
(HasPlotStyle f a b, Settable f) =>
LensLike' f a (Style (V a) (N a))
areaStyle ((Style V2 n -> Identity (Style V2 n))
 -> PlotStyle b v n -> Identity (PlotStyle b v n))
-> ((Measure n -> Identity (Measure n))
    -> Style V2 n -> Identity (Style V2 n))
-> (Measure n -> Identity (Measure n))
-> PlotStyle b v n
-> Identity (PlotStyle b v n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Measure n -> Identity (Measure n))
-> Style V2 n -> Identity (Style V2 n)
forall n (v :: * -> *).
(Typeable n, OrderedField n) =>
Lens' (Style v n) (Measure n)
Lens' (Style V2 n) (Measure n)
_lw ((Measure n -> Identity (Measure n))
 -> PlotStyle b v n -> Identity (PlotStyle b v n))
-> (Measure n -> Measure n) -> PlotStyle b v n -> PlotStyle b v n
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Measure n -> Measure n -> Measure n
forall n. Ord n => Measure n -> Measure n -> Measure n
atMost (n -> Measure n
forall n. Num n => n -> Measure n
local n
0.8)

instance HasOrientation (HistogramPlot n) where
  orientation :: Lens' (HistogramPlot n) Orientation
orientation = (HistogramPlot n -> Orientation)
-> (HistogramPlot n -> Orientation -> HistogramPlot n)
-> Lens' (HistogramPlot n) Orientation
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens HistogramPlot n -> Orientation
forall n. HistogramPlot n -> Orientation
hOrient ((HistogramPlot n -> Orientation -> HistogramPlot n)
 -> Lens' (HistogramPlot n) Orientation)
-> (HistogramPlot n -> Orientation -> HistogramPlot n)
-> Lens' (HistogramPlot n) Orientation
forall a b. (a -> b) -> a -> b
$ \HistogramPlot n
hp Orientation
o -> HistogramPlot n
hp {hOrient = o}

------------------------------------------------------------------------
-- Simple histogram plot
------------------------------------------------------------------------

-- | Plot an already computed histogram with equally sized bins.
computedHistogram
  :: (MonadState (Axis b V2 n) m,
      Plotable (HistogramPlot n) b,
      F.Foldable f)
  => n   -- ^ start of first bin
  -> n   -- ^ width of each bin
  -> f n -- ^ heights of the bins
  -> State (Plot (HistogramPlot n) b) ()
  -> m ()
computedHistogram :: forall b n (m :: * -> *) (f :: * -> *).
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 Foldable f) =>
n -> n -> f n -> State (Plot (HistogramPlot n) b) () -> m ()
computedHistogram n
x0 n
w f n
xs = HistogramPlot n -> State (Plot (HistogramPlot n) b) () -> m ()
forall (c :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace c) n p, MonadState (Axis b c n) m,
 Plotable p b) =>
p -> State (Plot p b) () -> m ()
addPlotable (n -> n -> f n -> HistogramPlot n
forall (f :: * -> *) n.
Foldable f =>
n -> n -> f n -> HistogramPlot n
mkComputedHistogram n
x0 n
w f n
xs)

-- | Construct a 'HistogramPlot' from raw histogram data.
mkComputedHistogram
  :: F.Foldable f
  => n -- ^ start of first bin
  -> n -- ^ width of each bin
  -> f n -- ^ heights of the bins
  -> HistogramPlot n
mkComputedHistogram :: forall (f :: * -> *) n.
Foldable f =>
n -> n -> f n -> HistogramPlot n
mkComputedHistogram n
x0 n
w f n
xs = n -> n -> [n] -> Orientation -> HistogramPlot n
forall n. n -> n -> [n] -> Orientation -> HistogramPlot n
HistogramPlot n
x0 n
w (f n -> [n]
forall a. f a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList f n
xs) Orientation
Horizontal

----------------------------------------------------------------------------
-- Building histograms
----------------------------------------------------------------------------

-- example setup
-- > import Plots
-- > sampleData :: [Double]
-- > sampleData =
-- >   [5.1,4.9,4.7,4.6,5.0,5.4,4.6,5.0,4.4,4.9
-- >   ,5.4,4.8,4.8,4.3,5.8,5.7,5.4,5.1,5.7,5.1
-- >   ,5.4,5.1,4.6,5.1,4.8,5.0,5.0,5.2,5.2,4.7
-- >   ,4.8,5.4,5.2,5.5,4.9,5.0,5.5,4.9,4.4,5.1
-- >   ,5.0,4.5,4.4,5.0,5.1,4.8,5.1,4.6,5.3,5.0
-- >   ,7.0,6.4,6.9,5.5,6.5,5.7,6.3,4.9,6.6,5.2
-- >   ,5.0,5.9,6.0,6.1,5.6,6.7,5.6,5.8,6.2,5.6
-- >   ,5.9,6.1,6.3,6.1,6.4,6.6,6.8,6.7,6.0,5.7
-- >   ,5.5,5.5,5.8,6.0,5.4,6.0,6.7,6.3,5.6,5.5
-- >   ,5.5,6.1,5.8,5.0,5.6,5.7,5.7,6.2,5.1,5.7
-- >   ,6.3,5.8,7.1,6.3,6.5,7.6,4.9,7.3,6.7,7.2
-- >   ,6.5,6.4,6.8,5.7,5.8,6.4,6.5,7.7,7.7,6.0
-- >   ,6.9,5.6,7.7,6.3,6.7,7.2,6.2,6.1,6.4,7.2
-- >   ,7.4,7.9,6.4,6.3,6.1,7.7,6.3,6.4,6.0,6.9
-- >   ,6.7,6.9,5.8,6.8,6.7,6.7,6.3,6.5,6.2,5.9
-- >   ]
--
-- > mkNmExample nm = r2Axis &~ do
-- >   yMin ?= 0
-- >   histogramPlot sampleData $ do
-- >     normaliseSample .= nm
-- > countDia = renderAxis $ mkNmExample count
-- > probabilityDia = renderAxis $ mkNmExample probability
-- > countDensityDia = renderAxis $ mkNmExample countDensity
-- > pdfDia = renderAxis $ mkNmExample pdf
-- > cumilativeDia = renderAxis $ mkNmExample cumilative
-- > cdfDia = renderAxis $ mkNmExample cdf

-- Histogram options ---------------------------------------------------

-- | The way to normalise the data from a histogram. The default method
--   is 'count'.
newtype NormalisationMethod =
  NM { NormalisationMethod
-> forall n. Fractional n => n -> Vector n -> Vector n
runNM :: forall n. Fractional n => n -> V.Vector n -> V.Vector n }
 -- width -> heights -> normalised heights

instance Default NormalisationMethod where
  def :: NormalisationMethod
def = NormalisationMethod
count

-- | The height of each bar is the number of observations. This is the
--   'Default' method.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_countDia.svg#diagram=countDia&height=350>>
count :: NormalisationMethod
count :: NormalisationMethod
count = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
_ Vector n
v -> Vector n
v

-- | The sum of the heights of the bars is equal to 1.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_probabilityDia.svg#diagram=probabilityDia&height=350>>
probability :: NormalisationMethod
probability :: NormalisationMethod
probability = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
_ Vector n
v -> Vector n
v Vector n -> n -> Vector n
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ Vector n -> n
forall a. Num a => Vector a -> a
V.sum Vector n
v

-- | The height of each bar is @n / w@ where @n@ is the number of
--   observations and @w@ is the total width.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_countDensityDia.svg#diagram=countDensityDia&height=350>>
countDensity :: NormalisationMethod
countDensity :: NormalisationMethod
countDensity = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
w Vector n
v -> Vector n
v Vector n -> n -> Vector n
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ n
w

-- | The total area of the bars is @1@. This gives a probability density
--   function estimate.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_pdfDia.svg#diagram=pdfDia&height=350>>
pdf :: NormalisationMethod
pdf :: NormalisationMethod
pdf = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
w Vector n
v -> Vector n
v Vector n -> n -> Vector n
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ (n
w n -> n -> n
forall a. Num a => a -> a -> a
* Vector n -> n
forall a. Num a => Vector a -> a
V.sum Vector n
v)

-- | The height of each bar is the cumulative number of observations in
--   each bin and all previous bins. The height of the last bar is the
--   total number of observations.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_cumilativeDia.svg#diagram=cumilativeDia&height=350>>
cumilative :: NormalisationMethod
cumilative :: NormalisationMethod
cumilative = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
_ -> (n -> n -> n) -> Vector n -> Vector n
forall a. (a -> a -> a) -> Vector a -> Vector a
V.scanl1 n -> n -> n
forall a. Num a => a -> a -> a
(+)

-- | Cumulative density function estimate. The height of each bar is
--   equal to the cumulative relative number of observations in the bin
--   and all previous bins. The height of the last bar is 1.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_cdfDia.svg#diagram=cdfDia&height=350>>
cdf :: NormalisationMethod
cdf :: NormalisationMethod
cdf = (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
NM ((forall n. Fractional n => n -> Vector n -> Vector n)
 -> NormalisationMethod)
-> (forall n. Fractional n => n -> Vector n -> Vector n)
-> NormalisationMethod
forall a b. (a -> b) -> a -> b
$ \n
_ Vector n
v -> (n -> n -> n) -> Vector n -> Vector n
forall a. (a -> a -> a) -> Vector a -> Vector a
V.scanl1 n -> n -> n
forall a. Num a => a -> a -> a
(+) Vector n
v Vector n -> n -> Vector n
forall (f :: * -> *) a.
(Functor f, Fractional a) =>
f a -> a -> f a
^/ Vector n -> n
forall a. Num a => Vector a -> a
V.sum Vector n
v

-- | Options for binning histogram data. For now only very basic
--   histograms building is supported.
data HistogramOptions n = HistogramOptions
  { forall n. HistogramOptions n -> Int
hBins   :: Int
  , forall n. HistogramOptions n -> Maybe (n, n)
hRange  :: Maybe (n, n)
  , forall n. HistogramOptions n -> NormalisationMethod
hNorm   :: NormalisationMethod
  , forall n. HistogramOptions n -> Orientation
oOrient :: Orientation
  }

type instance V (HistogramOptions n) = V2
type instance N (HistogramOptions n) = n

instance Default (HistogramOptions n) where
  def :: HistogramOptions n
def = HistogramOptions
    { hBins :: Int
hBins   = Int
10
    , hRange :: Maybe (n, n)
hRange  = Maybe (n, n)
forall a. Maybe a
Nothing
    , hNorm :: NormalisationMethod
hNorm   = NormalisationMethod
forall a. Default a => a
def
    , oOrient :: Orientation
oOrient = Orientation
Vertical
    }

instance HasOrientation (HistogramOptions n) where
  orientation :: Lens' (HistogramOptions n) Orientation
orientation = (HistogramOptions n -> Orientation)
-> (HistogramOptions n -> Orientation -> HistogramOptions n)
-> Lens' (HistogramOptions n) Orientation
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens HistogramOptions n -> Orientation
forall n. HistogramOptions n -> Orientation
oOrient ((HistogramOptions n -> Orientation -> HistogramOptions n)
 -> Lens' (HistogramOptions n) Orientation)
-> (HistogramOptions n -> Orientation -> HistogramOptions n)
-> Lens' (HistogramOptions n) Orientation
forall a b. (a -> b) -> a -> b
$ \HistogramOptions n
ho Orientation
o -> HistogramOptions n
ho {oOrient = o}

class HasOrientation a => HasHistogramOptions a where
  -- | Options for building the histogram from data.
  histogramOptions :: Lens' a (HistogramOptions (N a))

  -- | The number of bins (bars) to use for the histogram. Must be
  --   positive.
  --
  --   'Default' is @10@.
  numBins :: Lens' a Int
  numBins = (HistogramOptions (N a) -> f (HistogramOptions (N a))) -> a -> f a
forall a. HasHistogramOptions a => Lens' a (HistogramOptions (N a))
Lens' a (HistogramOptions (N a))
histogramOptions ((HistogramOptions (N a) -> f (HistogramOptions (N a)))
 -> a -> f a)
-> ((Int -> f Int)
    -> HistogramOptions (N a) -> f (HistogramOptions (N a)))
-> (Int -> f Int)
-> a
-> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HistogramOptions (N a) -> Int)
-> (HistogramOptions (N a) -> Int -> HistogramOptions (N a))
-> Lens (HistogramOptions (N a)) (HistogramOptions (N a)) Int Int
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens HistogramOptions (N a) -> Int
forall n. HistogramOptions n -> Int
hBins (\HistogramOptions (N a)
ho Int
n -> HistogramOptions (N a)
ho {hBins = n})

  -- | The range of data to consider when building the histogram. Any
  --   data outside the range is ignored.
  --
  --   'Default' is 'Nothing'.
  binRange :: Lens' a (Maybe (N a, N a))
  binRange = (HistogramOptions (N a) -> f (HistogramOptions (N a))) -> a -> f a
forall a. HasHistogramOptions a => Lens' a (HistogramOptions (N a))
Lens' a (HistogramOptions (N a))
histogramOptions ((HistogramOptions (N a) -> f (HistogramOptions (N a)))
 -> a -> f a)
-> ((Maybe (N a, N a) -> f (Maybe (N a, N a)))
    -> HistogramOptions (N a) -> f (HistogramOptions (N a)))
-> (Maybe (N a, N a) -> f (Maybe (N a, N a)))
-> a
-> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HistogramOptions (N a) -> Maybe (N a, N a))
-> (HistogramOptions (N a)
    -> Maybe (N a, N a) -> HistogramOptions (N a))
-> Lens
     (HistogramOptions (N a))
     (HistogramOptions (N a))
     (Maybe (N a, N a))
     (Maybe (N a, N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens HistogramOptions (N a) -> Maybe (N a, N a)
forall n. HistogramOptions n -> Maybe (n, n)
hRange (\HistogramOptions (N a)
ho Maybe (N a, N a)
r -> HistogramOptions (N a)
ho {hRange = r})

  -- | Should the resulting histogram be normalised so the total area is
  --   1.
  --
  --   'Default' is False.
  normaliseSample :: Lens' a NormalisationMethod
  normaliseSample = (HistogramOptions (N a) -> f (HistogramOptions (N a))) -> a -> f a
forall a. HasHistogramOptions a => Lens' a (HistogramOptions (N a))
Lens' a (HistogramOptions (N a))
histogramOptions ((HistogramOptions (N a) -> f (HistogramOptions (N a)))
 -> a -> f a)
-> ((NormalisationMethod -> f NormalisationMethod)
    -> HistogramOptions (N a) -> f (HistogramOptions (N a)))
-> (NormalisationMethod -> f NormalisationMethod)
-> a
-> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HistogramOptions (N a) -> NormalisationMethod)
-> (HistogramOptions (N a)
    -> NormalisationMethod -> HistogramOptions (N a))
-> Lens
     (HistogramOptions (N a))
     (HistogramOptions (N a))
     NormalisationMethod
     NormalisationMethod
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens HistogramOptions (N a) -> NormalisationMethod
forall n. HistogramOptions n -> NormalisationMethod
hNorm (\HistogramOptions (N a)
ho NormalisationMethod
b -> HistogramOptions (N a)
ho {hNorm = b})

instance HasHistogramOptions (HistogramOptions n) where
  histogramOptions :: Lens'
  (HistogramOptions n) (HistogramOptions (N (HistogramOptions n)))
histogramOptions = (HistogramOptions n -> f (HistogramOptions n))
-> HistogramOptions n -> f (HistogramOptions n)
(HistogramOptions (N (HistogramOptions n))
 -> f (HistogramOptions (N (HistogramOptions n))))
-> HistogramOptions n -> f (HistogramOptions n)
forall a. a -> a
id

instance HasHistogramOptions a => HasHistogramOptions (Plot a b) where
  histogramOptions :: Lens' (Plot a b) (HistogramOptions (N (Plot a b)))
histogramOptions = (a -> f a) -> Plot a b -> f (Plot a b)
forall p p' b. SameSpace p p' => Lens (Plot p b) (Plot p' b) p p'
Lens (Plot a b) (Plot a b) a a
rawPlot ((a -> f a) -> Plot a b -> f (Plot a b))
-> ((HistogramOptions (N a) -> f (HistogramOptions (N a)))
    -> a -> f a)
-> (HistogramOptions (N a) -> f (HistogramOptions (N a)))
-> Plot a b
-> f (Plot a b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HistogramOptions (N a) -> f (HistogramOptions (N a))) -> a -> f a
forall a. HasHistogramOptions a => Lens' a (HistogramOptions (N a))
Lens' a (HistogramOptions (N a))
histogramOptions

-- | Create a histogram by binning the data using the
--   'HistogramOptions'.
mkHistogramPlot
  :: (F.Foldable f, RealFrac n)
  => HistogramOptions n -> f n -> HistogramPlot n
mkHistogramPlot :: forall (f :: * -> *) n.
(Foldable f, RealFrac n) =>
HistogramOptions n -> f n -> HistogramPlot n
mkHistogramPlot HistogramOptions {Int
Maybe (n, n)
Orientation
NormalisationMethod
hBins :: forall n. HistogramOptions n -> Int
hRange :: forall n. HistogramOptions n -> Maybe (n, n)
hNorm :: forall n. HistogramOptions n -> NormalisationMethod
oOrient :: forall n. HistogramOptions n -> Orientation
hBins :: Int
hRange :: Maybe (n, n)
hNorm :: NormalisationMethod
oOrient :: Orientation
..} f n
xs =
  HistogramPlot
    { hWidth :: n
hWidth  = n
w
    , hStart :: n
hStart  = n
a
    , hValues :: [n]
hValues = Vector n -> [n]
forall a. Vector a -> [a]
V.toList (Vector n -> [n]) -> Vector n -> [n]
forall a b. (a -> b) -> a -> b
$ NormalisationMethod
-> forall n. Fractional n => n -> Vector n -> Vector n
runNM NormalisationMethod
hNorm n
w Vector n
ns
    , hOrient :: Orientation
hOrient = Orientation
Vertical
    }
  where
    w :: n
w     = (n
b n -> n -> n
forall a. Num a => a -> a -> a
- n
a) n -> n -> n
forall a. Fractional a => a -> a -> a
/ Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
hBins
    ns :: Vector n
ns    = Int -> n -> n -> Vector n -> Vector n
forall b a (v0 :: * -> *) (v1 :: * -> *).
(Num b, RealFrac a, Vector v0 a, Vector v1 b) =>
Int -> a -> a -> v0 a -> v1 b
Stat.histogram_ Int
hBins n
a n
b Vector n
v
    v :: Vector n
v     = [n] -> Vector n
forall a. [a] -> Vector a
V.fromList (f n -> [n]
forall a. f a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList f n
xs)
    (n
a,n
b) = (n, n) -> Maybe (n, n) -> (n, n)
forall a. a -> Maybe a -> a
fromMaybe (Int -> Vector n -> (n, n)
forall n. (Ord n, Fractional n) => Int -> Vector n -> (n, n)
range Int
hBins Vector n
v) Maybe (n, n)
hRange

-- Taken from Statistics, which was limited to 'Double'.
range :: (Ord n, Fractional n)
      => Int                    -- ^ Number of bins (must be positive).
      -> V.Vector n             -- ^ Sample data (cannot be empty).
      -> (n, n)
range :: forall n. (Ord n, Fractional n) => Int -> Vector n -> (n, n)
range Int
nBins Vector n
xs
    | Int
nBins Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 = [Char] -> (n, n)
forall a. HasCallStack => [Char] -> a
error [Char]
"Plots.Types.Histogram: invalid bin count"
    | Vector n -> Bool
forall a. Vector a -> Bool
V.null Vector n
xs = [Char] -> (n, n)
forall a. HasCallStack => [Char] -> a
error [Char]
"Plots.Types.Histogram: empty sample"
    | n
lo n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
hi  = case n -> n
forall a. Num a => a -> a
abs n
lo n -> n -> n
forall a. Fractional a => a -> a -> a
/ n
10 of
                    n
a | n
a n -> n -> Bool
forall a. Ord a => a -> a -> Bool
< n
1e-6   -> (-n
1,n
1)
                      | Bool
otherwise  -> (n
lo n -> n -> n
forall a. Num a => a -> a -> a
- n
a, n
lo n -> n -> n
forall a. Num a => a -> a -> a
+ n
a)
    | Bool
otherwise = (n
lon -> n -> n
forall a. Num a => a -> a -> a
-n
d, n
hin -> n -> n
forall a. Num a => a -> a -> a
+n
d)
  where
    d :: n
d | Int
nBins Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1 = n
0
      | Bool
otherwise  = (n
hi n -> n -> n
forall a. Num a => a -> a -> a
- n
lo) n -> n -> n
forall a. Fractional a => a -> a -> a
/ ((Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nBins n -> n -> n
forall a. Num a => a -> a -> a
- n
1) n -> n -> n
forall a. Num a => a -> a -> a
* n
2)
    (n
lo,n
hi)        = Getting (Endo (Endo (V2 n))) (Vector n) n -> Vector n -> (n, n)
forall a s.
(Fractional a, Ord a) =>
Getting (Endo (Endo (V2 a))) s a -> s -> (a, a)
minMaxOf Getting (Endo (Endo (V2 n))) (Vector n) n
forall (f :: * -> *) a. Foldable f => IndexedFold Int (f a) a
IndexedFold Int (Vector n) n
folded Vector n
xs
{-# INLINE range #-}

-- |
-- mkWeightedHistogram
--   :: (F.Foldable f, OrderdField n)
--   => HistogramOptions n -> [(n, n)] -> HistogramPlot n
-- mkWeightedHistogram

------------------------------------------------------------------------
-- Histogram
------------------------------------------------------------------------

-- $ histogram
-- Histograms display data as barplot of x data, bin y data.
-- Box plots have the following lenses:
--
-- @
-- * 'setBin' :: 'Lens'' ('BoxPlot' v n) 'Double' - 10
-- @

-- | Add a 'HistogramPlot' to the 'AxisState' from a data set.
--
-- === __Example__
--
-- <<diagrams/src_Plots_Types_Histogram_histogramExample.svg#diagram=histogramExample&height=350>>
--
-- > import Plots
-- > histogramAxis :: Axis B V2 Double
-- > histogramAxis = r2Axis &~ do
-- >   histogramPlot sampleData $ do
-- >     key "histogram"
-- >     plotColor .= blue
-- >     areaStyle . _opacity .= 0.5
--
-- > histogramExample = renderAxis histogramAxis
histogramPlot
  :: (MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b, F.Foldable f, RealFrac n)
  => f n -- ^ data
  -> State (Plot (HistogramOptions n) b) () -- ^ changes to plot options
  -> m () -- ^ add plot to axis
histogramPlot :: forall b n (m :: * -> *) (f :: * -> *).
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 Foldable f, RealFrac n) =>
f n -> State (Plot (HistogramOptions n) b) () -> m ()
histogramPlot f n
ns State (Plot (HistogramOptions n) b) ()
s = Plot (HistogramPlot n) b -> m ()
forall (c :: * -> *) n p b (m :: * -> *).
(InSpace (BaseSpace c) n p, MonadState (Axis b c n) m,
 Plotable p b) =>
Plot p b -> m ()
addPlot (Plot (HistogramOptions n) b
hoPlot Plot (HistogramOptions n) b
-> (Plot (HistogramOptions n) b -> Plot (HistogramPlot n) b)
-> Plot (HistogramPlot n) b
forall a b. a -> (a -> b) -> b
& (HistogramOptions n -> Identity (HistogramPlot n))
-> Plot (HistogramOptions n) b
-> Identity (Plot (HistogramPlot n) b)
forall p p' b. SameSpace p p' => Lens (Plot p b) (Plot p' b) p p'
Lens
  (Plot (HistogramOptions n) b)
  (Plot (HistogramPlot n) b)
  (HistogramOptions n)
  (HistogramPlot n)
rawPlot ((HistogramOptions n -> Identity (HistogramPlot n))
 -> Plot (HistogramOptions n) b
 -> Identity (Plot (HistogramPlot n) b))
-> (HistogramOptions n -> HistogramPlot n)
-> Plot (HistogramOptions n) b
-> Plot (HistogramPlot n) b
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ \HistogramOptions n
ho -> HistogramOptions n -> f n -> HistogramPlot n
forall (f :: * -> *) n.
(Foldable f, RealFrac n) =>
HistogramOptions n -> f n -> HistogramPlot n
mkHistogramPlot HistogramOptions n
ho f n
ns)
  where hoPlot :: Plot (HistogramOptions n) b
hoPlot = HistogramOptions n -> Plot (HistogramOptions n) b
forall p b. (Additive (V p), Num (N p)) => p -> Plot p b
mkPlot HistogramOptions n
forall a. Default a => a
def Plot (HistogramOptions n) b
-> State (Plot (HistogramOptions n) b) ()
-> Plot (HistogramOptions n) b
forall s a. s -> State s a -> s
&~ State (Plot (HistogramOptions n) b) ()
s

-- | Make a 'HistogramPlot' without changes to the plot options.
histogramPlot'
  :: (MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b, F.Foldable f, RealFrac n)
  => f n -- ^ data
  -> m () -- ^ add plot to axis
histogramPlot' :: forall b n (m :: * -> *) (f :: * -> *).
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 Foldable f, RealFrac n) =>
f n -> m ()
histogramPlot' f n
d = f n -> State (Plot (HistogramOptions n) b) () -> m ()
forall b n (m :: * -> *) (f :: * -> *).
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 Foldable f, RealFrac n) =>
f n -> State (Plot (HistogramOptions n) b) () -> m ()
histogramPlot f n
d (() -> State (Plot (HistogramOptions n) b) ()
forall a. a -> StateT (Plot (HistogramOptions n) b) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- | Add a 'HistogramPlot' using a fold over the data.
histogramPlotOf
  :: (MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b, RealFrac n)
  => Fold s n -- ^ fold over the data
  -> s        -- ^ data to fold
  -> State (Plot (HistogramOptions n) b) () -- ^ change to the plot
  -> m () -- ^ add plot to the 'Axis'
histogramPlotOf :: forall b n (m :: * -> *) s.
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 RealFrac n) =>
Fold s n -> s -> State (Plot (HistogramOptions n) b) () -> m ()
histogramPlotOf Fold s n
f s
s = [n] -> State (Plot (HistogramOptions n) b) () -> m ()
forall b n (m :: * -> *) (f :: * -> *).
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 Foldable f, RealFrac n) =>
f n -> State (Plot (HistogramOptions n) b) () -> m ()
histogramPlot (Getting (Endo [n]) s n -> s -> [n]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf Getting (Endo [n]) s n
Fold s n
f s
s)

-- | Same as 'histogramPlotOf' without any changes to the plot.
histogramPlotOf'
  :: (MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b, RealFrac n)
  => Fold s n -> s -> m ()
histogramPlotOf' :: forall b n (m :: * -> *) s.
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 RealFrac n) =>
Fold s n -> s -> m ()
histogramPlotOf' Fold s n
f s
s = Fold s n -> s -> State (Plot (HistogramOptions n) b) () -> m ()
forall b n (m :: * -> *) s.
(MonadState (Axis b V2 n) m, Plotable (HistogramPlot n) b,
 RealFrac n) =>
Fold s n -> s -> State (Plot (HistogramOptions n) b) () -> m ()
histogramPlotOf (n -> f n) -> s -> f s
Fold s n
f s
s (() -> State (Plot (HistogramOptions n) b) ()
forall a. a -> StateT (Plot (HistogramOptions n) b) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- temporary functions that will be in next lib release

_reflectionXY :: (Additive v, R2 v, Num n) => Transformation v n
_reflectionXY :: forall (v :: * -> *) n.
(Additive v, R2 v, Num n) =>
Transformation v n
_reflectionXY = (v n :-: v n) -> Transformation v n
forall (v :: * -> *) n.
(Additive v, Num n) =>
(v n :-: v n) -> Transformation v n
fromSymmetric ((v n :-: v n) -> Transformation v n)
-> (v n :-: v n) -> Transformation v n
forall a b. (a -> b) -> a -> b
$ ((V2 n -> Identity (V2 n)) -> v n -> Identity (v n)
forall a. Lens' (v a) (V2 a)
forall (t :: * -> *) a. R2 t => Lens' (t a) (V2 a)
_xy ((V2 n -> Identity (V2 n)) -> v n -> Identity (v n))
-> (V2 n -> V2 n) -> v n -> v n
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Getting (V2 n) (V2 n) (V2 n) -> V2 n -> V2 n
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (V2 n) (V2 n) (V2 n)
Lens' (V2 n) (V2 n)
forall (t :: * -> *) a. R2 t => Lens' (t a) (V2 a)
_yx) (v n -> v n) -> (v n -> v n) -> v n :-: v n
forall u v. (u -> v) -> (v -> u) -> u :-: v
<-> ((V2 n -> Identity (V2 n)) -> v n -> Identity (v n)
forall a. Lens' (v a) (V2 a)
forall (t :: * -> *) a. R2 t => Lens' (t a) (V2 a)
_xy ((V2 n -> Identity (V2 n)) -> v n -> Identity (v n))
-> (V2 n -> V2 n) -> v n -> v n
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Getting (V2 n) (V2 n) (V2 n) -> V2 n -> V2 n
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (V2 n) (V2 n) (V2 n)
Lens' (V2 n) (V2 n)
forall (t :: * -> *) a. R2 t => Lens' (t a) (V2 a)
_yx)

_reflectXY :: (InSpace v n t, R2 v, Transformable t) => t -> t
_reflectXY :: forall (v :: * -> *) n t.
(InSpace v n t, R2 v, Transformable t) =>
t -> t
_reflectXY = Transformation (V t) (N t) -> t -> t
forall t. Transformable t => Transformation (V t) (N t) -> t -> t
transform Transformation v n
Transformation (V t) (N t)
forall (v :: * -> *) n.
(Additive v, R2 v, Num n) =>
Transformation v n
_reflectionXY