barchart-0.1: src/barchart.hs
{-# LANGUAGE NamedFieldPuns, RecordWildCards, DeriveDataTypeable #-}
import Graphics.BarChart hiding ( Intervals )
import Graphics.BarChart.Types ( readColor )
import Data.Char ( toLower )
import Data.Maybe ( fromMaybe )
import Control.Monad ( when, forM_ )
import System.FilePath
import System.Console.CmdArgs
import qualified Graphics.Rendering.Diagrams as D
data ExecMode
= Blocks { out_file, title, xlabel, ylabel :: String,
file_type :: FileType,
division, colors :: String,
width, height, label_size :: Int,
bar_width :: Double,
in_files :: [String] }
| Intervals { out_file, title, xlabel, ylabel :: String,
file_type :: FileType,
division, colors :: String,
width, height, label_size :: Int,
bar_width :: Double,
in_files :: [String] }
| Criterion { breakdown :: Breakdown,
out_file, title, xlabel, ylabel :: String,
file_type :: FileType,
division, colors :: String,
width, height, label_size :: Int,
bar_width :: Double,
in_files :: [String] }
| Progression { breakdown :: Breakdown,
out_file, title, xlabel, ylabel :: String,
file_type :: FileType,
division, colors :: String,
width, height, label_size :: Int,
bar_width :: Double,
in_files :: [String] }
deriving (Show,Data,Typeable)
data FileType = Guess_File_Type | PNG | SVG | PDF | PS
deriving (Eq,Show,Data,Typeable)
suffixOf :: FileType -> String
suffixOf PNG = "png"
suffixOf SVG = "svg"
suffixOf PDF = "pdf"
suffixOf PS = "ps"
suffixOf _ = ""
fromFileType :: FileType -> D.OutputType
fromFileType PNG = D.PNG
fromFileType SVG = D.SVG
fromFileType PDF = D.PDF
fromFileType PS = D.PS
fromFileType _ = error "fromFileType: cannot convert guessed file type"
replaceUnknownFileType :: FileType -> FileType -> FileType
replaceUnknownFileType Guess_File_Type t = t
replaceUnknownFileType t _ = t
data Breakdown = Summary | Summary_Comparison | Benchmark_Comparison
deriving (Eq,Show,Data,Typeable)
blocksMode =
Blocks {
out_file = outFile conf
&= text "Name of generated file"
& typFile,
file_type = Guess_File_Type `enum`
[Guess_File_Type
&= text "Guess output file type by name (default)",
PNG &= text "Generate .png file",
SVG &= text "Generate .svg file",
PDF &= text "Generate .pdf file",
PS &= text "Generate .ps file"],
title = caption conf
&= text "Title of bar chart"
& typString,
xlabel = xLabel conf
&= text "Label of x axis"
& typString,
ylabel = xLabel conf
&= text "Label of y axis"
& typString,
division = "" &= text "Labels separated by whitespace"
& typStrings,
colors = "" &= text "Color names separated by whitespace"
& typStrings,
width = width
&= text "Width of generated bar chart"
& typ "NUM",
height = height
&= text "Height of generated bar chart"
& typ "NUM",
label_size = 12 &= text "Font size used for labels"
& typ "NUM",
bar_width = barRatio conf
&= text "Bar width between 0 and 1"
& flag "W"
& typ "FLOAT",
in_files = [] &= text "CVS files with data to visualise"
& args }
where (width,height) = dimensions conf
-- cannot reuse flag attributes in cmdargs :(
intervalsMode =
Intervals {
out_file = outFile conf
&= text "Name of generated file"
& typFile,
file_type = Guess_File_Type `enum`
[Guess_File_Type
&= text "Guess output file type by name (default)",
PNG &= text "Generate .png file",
SVG &= text "Generate .svg file",
PDF &= text "Generate .pdf file",
PS &= text "Generate .ps file"],
title = caption conf
&= text "Title of bar chart"
& typString,
xlabel = xLabel conf
&= text "Label of x axis"
& typString,
ylabel = xLabel conf
&= text "Label of y axis"
& typString,
division = "" &= text "Labels separated by whitespace"
& typStrings,
colors = "" &= text "Color names separated by whitespace"
& typStrings,
width = width
&= text "Width of generated bar chart"
& typ "NUM",
height = height
&= text "Height of generated bar chart"
& typ "NUM",
label_size = 12 &= text "Font size used for labels"
& typ "NUM",
bar_width = barRatio conf
&= text "Bar width between 0 and 1"
& flag "W"
& typ "FLOAT",
in_files = [] &= text "CVS files with data to visualise"
& args }
where (width,height) = dimensions conf
criterionMode =
Criterion {
out_file = outFile conf
&= text "Name of generated file"
& typFile,
file_type = Guess_File_Type `enum`
[Guess_File_Type
&= text "Guess output file type by name (default)",
PNG &= text "Generate .png file",
SVG &= text "Generate .svg file",
PDF &= text "Generate .pdf file",
PS &= text "Generate .ps file"],
title = caption conf
&= text "Title of bar chart"
& typString,
xlabel = xLabel conf
&= text "Label of x axis"
& typString,
ylabel = xLabel conf
&= text "Label of y axis"
& typString,
division = "" &= text "Labels separated by whitespace"
& typStrings,
colors = "" &= text "Color names separated by whitespace"
& typStrings,
width = width
&= text "Width of generated bar chart"
& typ "NUM",
height = height
&= text "Height of generated bar chart"
& typ "NUM",
label_size = 12 &= text "Font size used for labels"
& typ "NUM",
bar_width = barRatio conf
&= text "Bar width between 0 and 1"
& flag "W"
& typ "FLOAT",
in_files = [] &= text "CVS files with data to visualise"
& args,
breakdown = Summary `enum`
[Summary
&= text "Show benchmark summary (default)",
Summary_Comparison
&= text "Compare different benchmark summaries"
& flag "s",
Benchmark_Comparison
&= text "Compare different benchmarks"
& flag "b"] }
where (width,height) = dimensions conf
progressionMode =
Progression {
out_file = outFile conf
&= text "Name of generated file"
& typFile,
file_type = Guess_File_Type `enum`
[Guess_File_Type
&= text "Guess output file type by name (default)",
PNG &= text "Generate .png file",
SVG &= text "Generate .svg file",
PDF &= text "Generate .pdf file",
PS &= text "Generate .ps file"],
title = caption conf
&= text "Title of bar chart"
& typString,
xlabel = xLabel conf
&= text "Label of x axis"
& typString,
ylabel = xLabel conf
&= text "Label of y axis"
& typString,
division = "" &= text "Labels separated by whitespace"
& typStrings,
colors = "" &= text "Color names separated by whitespace"
& typStrings,
width = width
&= text "Width of generated bar chart"
& typ "NUM",
height = height
&= text "Height of generated bar chart"
& typ "NUM",
label_size = 12 &= text "Font size used for labels"
& typ "NUM",
bar_width = barRatio conf
&= text "Bar width between 0 and 1"
& flag "W"
& typ "FLOAT",
in_files = [] &= text "CVS files with data to visualise"
& args,
breakdown = Summary_Comparison `enum`
[Summary_Comparison
&= text "Breakdown chart by benchmark summary (default)"
& flag "s",
Benchmark_Comparison
&= text "Breakdown chart by benchmarks"
& flag "b"] }
where (width,height) = dimensions conf
typString = typ "STRING"
typStrings = typ "STRINGS"
execModes = [blocksMode &= defMode,
intervalsMode, criterionMode, progressionMode]
exitIf msg cond = when cond (error msg)
main = do execMode <- cmdArgs "Bar Chart 0.0" (map mode execModes)
exitIf "no input files given" $ null (in_files execMode)
dispatch execMode
dispatch mode@Blocks{..} =
forM_ in_files $ \in_file ->
writeMultiBarChart
(config (guessDefaults in_file mode))
in_file
(words division)
dispatch mode@Intervals{..} =
forM_ in_files $ \in_file ->
writeMultiBarIntervalChart
(config (guessDefaults in_file mode))
in_file
(words division)
dispatch mode@Criterion{..} =
case breakdown of
Summary ->
forM_ in_files $ \in_file ->
writeCriterionChart
(config (guessBenchmarkDefaults in_file mode))
in_file
Summary_Comparison ->
writeComparisonChart False
(config (guessBenchmarkDefaults "summaries.csv" mode))
in_files
Benchmark_Comparison ->
writeComparisonChart True
(config (guessBenchmarkDefaults "benchmarks.csv" mode))
in_files
dispatch mode@Progression{..} =
case breakdown of
Summary_Comparison ->
forM_ in_files $ \in_file ->
writeProgressionChart True
(config (guessBenchmarkDefaults in_file mode))
in_file
(words division)
Benchmark_Comparison ->
forM_ in_files $ \in_file ->
writeProgressionChart False
(config (guessBenchmarkDefaults in_file mode))
in_file
(words division)
guessDefaults :: FilePath -> ExecMode -> ExecMode
guessDefaults in_file = guessColors . guessTitle . guessFileType . guessOutFile
where
guessOutFile mode =
mode { out_file = out_file mode ? replaceExtension in_file suffix }
where suffix = suffixOf (file_type mode) ? ".png"
guessFileType mode =
mode { file_type = replaceUnknownFileType (file_type mode) $
fromMaybe (error $ "unsupported type: " ++ suffix) $
lookup suffix fileTypes }
where suffix = map toLower $ takeExtension (out_file mode)
fileTypes = [(".png",PNG),(".svg",SVG),(".pdf",PDF),(".ps",PS)]
guessTitle mode =
mode { title = title mode ? takeBaseName (out_file mode) }
guessColors mode =
mode { colors = colors mode ? "forestgreen firebrick midnightblue" }
guessBenchmarkDefaults in_file = guessAxis . guessDefaults in_file
where
guessAxis mode = mode { xlabel = xlabel mode ? "benchmark",
ylabel = ylabel mode ? "run time" }
config mode = Config {
outFile = out_file mode,
outputType = fromFileType $ file_type mode,
caption = title mode, xLabel = xlabel mode, yLabel = ylabel mode,
barColors = map readColor . words $ colors mode,
dimensions = (width mode,height mode),
ratio = 1.0,
fontSize = fromIntegral $ label_size mode,
barRatio = bar_width mode }
(?) :: String -> String -> String
"" ? s = s
s ? _ = s