{-| Simple histograms -} module Graphics.Plotly.Histogram where import Graphics.Plotly.Base hiding (sort) import Data.List (sort, group) import Lens.Micro import Data.Aeson (toJSON) import Data.Text (Text) -- | build a histogram with a given binsize histogram :: Int -- ^ number of bins -> [Double] -- ^ the individual observations -> Trace histogram nbins pts = let (lo, hi) = (minimum pts, maximum pts) binSize = (hi - lo) / realToFrac nbins binToX :: Int -> Double binToX binN = realToFrac binN * binSize + lo binMap :: [(Int, Int)] binMap = getBinMap lo binSize pts in bars & x ?~ map (toJSON . binToX . fst) binMap & y ?~ map (toJSON . snd) binMap histMany :: Int -> [(Text, [Double])] -> [Trace] histMany nbins hdata = let allPts = concat $ map snd hdata (lo, hi) = (minimum allPts, maximum allPts) binSize = (hi - lo) / realToFrac nbins binToX :: Int -> Double binToX binN = realToFrac binN * binSize + lo getTrace (nm,pts) = let binMap = getBinMap lo binSize pts in bars & x ?~ map (toJSON . binToX . fst) binMap & y ?~ map (toJSON . snd) binMap & name ?~ nm in map getTrace hdata goFill :: [(Int,Int)] -> [(Int,Int)] goFill (car@(bin1,_):cdr@((bin2,_):_)) | bin2 == bin1 + 1 = car : goFill cdr | otherwise = car : goFill ((bin1+1,0):cdr) goFill l = l getBinMap :: Double -> Double -> [Double] -> [(Int, Int)] getBinMap lo binSize pts = let binf :: Double -> Int binf xv = floor $ (xv - lo) / binSize bins = group $ sort $ map binf pts binMap :: [(Int, Int)] binMap = goFill $ map (\is -> (head is, length is)) bins in binMap