packages feed

hackage-plot-0.2: Main.hs

--------------------------------------------------------------------
-- |
-- Module    : Generate gnuplot graphs of hackage activity
-- Copyright : (c) Don Stewart 2008
-- License   : BSD3
--
-- Maintainer: Don Stewart <dons@galois.com>
-- 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