-------------------------------------------------------------------- -- | -- Module : Generate gnuplot graphs of hackage activity -- Copyright : (c) Don Stewart 2008 -- License : BSD3 -- -- Maintainer: Don Stewart -- Stability : provisional -- Portability: -- -------------------------------------------------------------------- import Data.List import Data.Maybe import System.Directory import System.FilePath import System.Locale import System.Time import System.Time.Parse import Text.HTML.Download import Graphics.Gnuplot.Simple import qualified Data.IntMap as I url = "http://hackage.haskell.org/packages/archive/log" main = do xs <- gettime let ys = [ (i,d) | ((_,d), i) <- zip xs [1..] ] zs = sliding ys [1.. length ys] plotList [Key Nothing ,YRange (0,maximum (map snd zs) + 1) ,XLabel "Days since launch of Hackage" ,YLabel "Unique uploads" ,Title "Daily uploads (90 day moving average) to http://hackage.haskell.org" ,PNG "/tmp/hackage-daily-graph.png"] (map snd zs) print "Output written to: /tmp/hackage-daily-graph.png" -- sliding average window window :: Int window = 90 -- -- compute the 7-day sliding average, starting with a sparse sequence -- -- sliding :: [(Int,Int)] -> [Int] -> [(Int,Double)] sliding [] _ = [] sliding xs days = [ (i,slidingAv i) | i <- days' ] where m = window `div` 2 -- 1/2 n days' = drop m . take (max 0 (length days - window+m+1)) $ days table = I.fromList xs :: I.IntMap Int -- to handle missing elems easily slidingAv :: Int -> Double slidingAv i = fromIntegral (sum seqN) / fromIntegral window where seqN = map (\j -> I.findWithDefault 0 j table) [i-m..i+(window-m-1)] gettime :: IO [(CalendarTime, Int)] gettime = do pwd <- getCurrentDirectory src <- openURL url let dates = catMaybes . sort . map parse . lines $ src let days = groupBy day $ dates return [ (head d, length d) | d <- days ] where parse = parseCalendarTime defaultTimeLocale "%c" month a b = ctYear a == ctYear b && ctMonth a == ctMonth b day a b = month a b && ctDay a == ctDay b