----------------------------------------------------------------------------- -- | -- Module : Graphics.Rendering.Chart.Axis.Int -- Copyright : (c) Tim Docker 2010, 2014 -- License : BSD-style (see chart/COPYRIGHT) -- -- Calculate and render integer indexed axes 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 $ minI-1, fromIntegral $ minI+1) | otherwise = (fromIntegral minI, fromIntegral maxI) -- labelvs :: [i] 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' -- throw away sampleSteps that are definitely too small as -- they takes a long time to process sampleSteps' = let rangeMag = ceiling (snd range - fst range) (s1,s2) = span (< (rangeMag `div` nSteps)) sampleSteps in ((reverse . take 5 . reverse) s1) ++ s2 -- generate all possible step sizes sampleSteps = [1,2,5] ++ sampleSteps1 sampleSteps1 = [10,20,25,50] ++ map (*10) sampleSteps1 steps size (minV,maxV) = takeWhile (