{-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE TypeFamilies #-} module Trend where import Settings import Date import Diagrams.Prelude import Diagrams.Backend.Cairo.CmdLine import Diagrams.TwoD.Shapes import Diagrams.TwoD.Text import Diagrams.TrailLike import Diagrams.Envelope import qualified Data.Map as Map import Data.Time.Clock import Data.List import Control.Monad.Identity import Control.Monad.Error import Control.Monad.Reader --Convenience: type C=Colour Double dot = circle 0.1 # fc black type UTime = UTCTime write :: Show a => a -> Di write c = text(show c) # withEnvelope ( envelope::D R2) where l = fromIntegral $ length(show c) envelope = rect (l+1) 2 push :: Double -> Double -> Di -> Di push x y = translate $ r2(x,y) --Our monad with the error handling --and reader characteristic: type Env a = ReaderT Choices (ErrorT String Identity) a runEnv :: Choices -> Env Di -> Either String Di runEnv choice a = runIdentity ( runErrorT(runReaderT a choice)) -- We will use Env Di in our functions: -- These take a list of points markers :: [P2] -> Env Di markers l = do m <- ask case Map.lookup "markers" m of Nothing -> return $ position (zip l (repeat dot)) Just (Shape s) -> return $ position (zip l (repeat s)) _ -> throwError " Markers input not a shape" drawcurve :: [P2] -> Env Di drawcurve l = do m <- ask curve1 <- case Map.lookup "Curve Width" m of Just( Wdth w) -> return $ curve0 # lwO w _-> return $ curve0 case Map.lookup "Curve Colour" m of Nothing -> return $ curve1 # lc blue Just (Col c) -> return $ curve1 # lc c _ -> throwError "Curve Colour not a colour" where curve0 = fromVertices l -- Order: order :: [(UTime,Double)] -> [(UTime,Double)] order l = sortBy (\ (t1,i1) (t2,i2) -> compare t1 t2 ) l --Avarage difference in time in a list sumdiff :: [NominalDiffTime] -> NominalDiffTime sumdiff [] = 0 sumdiff (_:[]) = 0 sumdiff (x1:x2:xs) = (x2-x1)+sumdiff(x2:xs) meandiff :: [UTCTime] -> NominalDiffTime meandiff t = sumdiff l / (genericLength l) where l = map (\ x -> diffUTCTime x (head t)) t --Transform time into points timeToDouble :: NominalDiffTime -> Double timeToDouble a = realToFrac a timeToPoint:: [(UTime,Double)] -> [P2] timeToPoint l = map p2 p where l' = order l (fi,t) = head l' p = map (\ (time,i) -> (f time, i)) l' mean = meandiff $ map (\(time,i) -> time) l' f time = timeToDouble $ (diffUTCTime time fi )/mean -- yaxis :: Env Di yaxis = do m <- ask case Map.lookup "Y-axis" m of Just (Intervalle l) -> return $ yaxis l <> f' l _ -> return $ yaxis ls <> f' ls where yaxis l = fromVertices $ map p2 [(0,0),(0, last l)] ymark n = hrule 1 <> write n # push (-3) 0 # pad 1.6 f n = (p2(0,n),ymark n) f' list = position $ map f list ls = [0.0 , 20.0 .. 100.0] xaxis :: [(UTime,Double)] -> Env Di xaxis t = do m <- ask case Map.lookup "XAxisFrequency" m of Just(Frequency f) -> return $ axis f _-> return $ circle 01 # fc red <> axis 7 where lnth = length t l = timeToPoint $ map projX t projX (i,_) = (i,0) t' n = indmod n t l' n = indmod n l xmark c = vrule 1 # pad 1.1 <> write (utcToDate c) # pad 1.1 # push 0 (-2) <> circle 0.1 # fc blue m n = map (\ (t,_) -> xmark t) (t' n) axis n = position (zip (l' n) (m n)) indmod :: Int -> [a] -> [a] indmod n list = foldl f [] [0 .. (length list)-1] where f xs x = if x `mod` n == 0 then xs++[list!!x] else xs --Combining the previous functions graph :: [(UTime,Double)] -> Env Di graph t = do marks <- markers l curve <- drawcurve l yax <- yaxis xax <- xaxis t return $ mconcat [marks, curve, yax,xax] where l = timeToPoint t