hp2pretty-0.10: src/Print.hs
module Print (print, printKey) where
import Prelude hiding (print)
import Data.Array.Unboxed (UArray, bounds, (!))
import Data.Text.Lazy (Text, pack, unpack)
import Numeric (showFFloat)
import System.FilePath (replaceExtension)
import Types
import Graphics
import SVG (fillStyleName)
first :: (a -> c) -> (a, b) -> (c, b)
first f (a, b) = (f a, b)
filled0 :: Graphics -> Either PatternID RGB -> [Text] -> [Text]
filled0 gfx c = visual gfx (Just c) Nothing Nothing Nothing
print :: Graphics -> Bool -> Bool -> Bool -> Header -> [Double] -> [Double] -> [Text] -> UArray Int Double -> UArray (Int, Int) Double -> [Text]
print gfx notitle sepkey patterned header sticks vticks labels times coords =
let bands = toPoints (bounds coords) times coords
labels' = reverse labels
filled = filled0 gfx
(colours, defs)
| patterned = first (map Left) . unzip $ map (pattern gfx) labels'
| otherwise = (map (Right . colour) labels', [])
polygons = concat . zipWith (\c ps -> filled c (polygon gfx ps)) colours . map (map p) $ bands
key = concat . zipWith3 (keyBox (gW + border * 2.5) (border * 1.5) (gH / 16)) [(0::Int) ..] colours $ labels'
keyBox x y0 dy i c l =
let y = y0 + fromIntegral i * dy
in (filled c $ rect gfx (x, y + 0.1 * dy) (dy * 0.8, dy * 0.8)) ++
text gfx Nothing Start 15 (x + dy, y + dy * 0.6) [l]
w = 1280
h = 720
gW = (if sepkey then 1280 else 960) - 2 * border
gH = if notitle then 720 - 2 * border else 720 - 3 * border
border = 60
textOffset = 10
(xMin, xMax) = hSampleRange header
(yMin, yMax) = hValueRange header
gRange@((gx0,gy0),(gx1,gy1)) = ((border*1.5, gH + if notitle then border*0.5 else border*1.5), (gW + border*1.5, if notitle then border*0.5 else border*1.5))
p = rescalePoint ((xMin, yMin), (xMax, yMax)) gRange
title = text gfx Nothing Middle 25 (w / 2, border * 0.75) [hJob header, pack " (", hDate header, pack ")"]
background = filled (Right white) $ rect gfx (0,0) (w,h)
box = filled (Right white) $ rect gfx (gx0,gy1) (gW,gH)
leftLabel = text gfx (Just (-90)) Middle 20 (border/2, (gy0 + gy1)/2) [hValueUnit header]
leftTicks = concatMap (\(y,l) -> let { (x1, y1) = p (xMin, y) ; (x2, y2) = p (xMax, y) } in
line gfx (x1 - border/2, y1) (x2, y2) ++
if l then [] else text gfx Nothing End 15 (x1 - textOffset, y1 - textOffset) (showSI y)
) (zip vticks (replicate (length vticks - 1) False ++ [True]))
bottomLabel = text gfx Nothing Middle 20 ((gx0 + gx1)/2, gy0 + border) [hSampleUnit header]
bottomTicks = concatMap (\(x,l) -> let { (x1, y1) = p (x, yMin) ; (x2, y2) = p (x, yMax) } in
line gfx (x1, y1 + border/2) (x2, y2) ++
if l then [] else text gfx Nothing Start 15 (x1 + textOffset, y1+2*textOffset) (showSI x)
) (zip sticks (replicate (length sticks - 1) False ++ [True]))
in document gfx (w,h) (concat defs) . concat $
[ background
, visual gfx (Just (Right black)) Nothing (Just black) (Just 1) $ concat $
(if notitle then [] else [title]) ++
[ leftLabel
, bottomLabel
, leftTicks
, bottomTicks
, visual gfx Nothing (Just 0.7) Nothing Nothing $ concat $
[ box
, polygons
] ++ if sepkey then [] else [key]
]
]
printKey :: Graphics -> Bool {- ^ patterned -} -> Text -> (FilePath, [Text])
printKey gfx True label =
let (pname, pdef) = pattern gfx label
in printKey' gfx pdef (Left pname) label
printKey gfx False label =
let cname = colour label
in printKey' gfx [] (Right cname) label
printKey' :: Graphics -> [Text] -> Either PatternID RGB -> Text -> (FilePath, [Text])
printKey' gfx defs c label =
( replaceExtension (unpack (fillStyleName c)) "svg"
, document gfx (boxSize, boxSize) defs (filled0 gfx c $ rect gfx (0, 0) (boxSize, boxSize))
)
boxSize :: Double
boxSize = 27
toPoints :: ((Int,Int),(Int,Int)) -> UArray Int Double -> UArray (Int,Int) Double -> [[(Double,Double)]]
toPoints ((b0,s0),(b1,s1)) times coords =
[ fwd ++ rwd
| b <- [b1, b1 - 1 .. b0 + 1]
, let fwd = [ (times ! s, coords ! (b - 1, s)) | s <- up b ]
, let rwd = [ (times ! s, coords ! (b, s)) | s <- down b ]
]
where
-- ugly hack to force recomputation instead of sharing a large list
up b = [s0 + b - b .. s1]
down b = [s1 + b - b, s1 - 1 .. s0]
showSI :: Double -> [Text]
showSI x | x < 1e3 = [ showF x "" ]
| x < 1e6 = [ showF (x/1e3 ) "k" ]
| x < 1e9 = [ showF (x/1e6 ) "M" ]
| x < 1e12 = [ showF (x/1e9 ) "G" ]
| x < 1e15 = [ showF (x/1e12) "T" ]
| otherwise = [ showF (x/1e15) "P" ]
where
showF y si = let (xs, ys) = break ('.' ==) $ showFFloat (Just 3) y ""
zs = reverse . dropWhile ('0' ==) . reverse . drop 1 $ ys
in case zs of
"" -> pack $ xs ++ si
ws -> pack $ xs ++ "." ++ ws ++ si