module Graphics.Rendering.Chart.Axis.Int(
defaultIntAxis,
scaledIntAxis,
autoScaledIntAxis
) where
import Data.List(genericLength)
import Graphics.Rendering.Chart.Geometry
import Graphics.Rendering.Chart.Axis.Types
import Graphics.Rendering.Chart.Axis.Floating
instance PlotValue Int where
toValue = fromIntegral
fromValue = round
autoAxis = autoScaledIntAxis defaultIntAxis
instance PlotValue Integer where
toValue = fromIntegral
fromValue = round
autoAxis = autoScaledIntAxis defaultIntAxis
defaultIntAxis :: (Show a) => LinearAxisParams a
defaultIntAxis = LinearAxisParams {
_la_labelf = show,
_la_nLabels = 5,
_la_nTicks = 10
}
autoScaledIntAxis :: (Integral i, PlotValue i) =>
LinearAxisParams i -> AxisFn i
autoScaledIntAxis lap ps = scaledIntAxis lap rs ps
where
rs = (minimum ps,maximum ps)
scaledIntAxis :: (Integral i, PlotValue i) =>
LinearAxisParams i -> (i,i) -> AxisFn i
scaledIntAxis lap (minI,maxI) ps =
makeAxis (_la_labelf lap) (labelvs,tickvs,gridvs)
where
range [] = (0,1)
range _ | minI == maxI = (fromIntegral $ minI1, fromIntegral $ minI+1)
| otherwise = (fromIntegral minI, fromIntegral maxI)
labelvs = stepsInt (fromIntegral $ _la_nLabels lap) r
tickvs = stepsInt (fromIntegral $ _la_nTicks lap)
( fromIntegral $ minimum labelvs
, fromIntegral $ maximum labelvs )
gridvs = labelvs
r = range ps
stepsInt :: Integral a => a -> Range -> [a]
stepsInt nSteps range = bestSize (goodness alt0) alt0 alts
where
bestSize n a (a':as) = let n' = goodness a' in
if n' < n then bestSize n' a' as else a
bestSize _ _ [] = []
goodness vs = abs (genericLength vs nSteps)
(alt0:alts) = map (\n -> steps n range) sampleSteps'
sampleSteps' = let rangeMag = ceiling (snd range fst range)
(s1,s2) = span (< (rangeMag `div` nSteps)) sampleSteps
in ((reverse . take 5 . reverse) s1) ++ s2
sampleSteps = [1,2,5] ++ sampleSteps1
sampleSteps1 = [10,20,25,50] ++ map (*10) sampleSteps1
steps size (minV,maxV) = takeWhile (<b) [a,a+size..] ++ [b]
where
a = (floor (minV / fromIntegral size)) * size
b = (ceiling (maxV / fromIntegral size)) * size