@@ -27,11 +27,11 @@ import qualified Data.Map as M
2727import Data.Map (Map )
2828import qualified Data.Set as S
2929import Data.Set (Set , member )
30- import Data.Maybe (catMaybes , maybe , fromJust , isNothing )
30+ import Data.Maybe (catMaybes , maybe , fromJust , isNothing , fromMaybe )
3131import qualified Data.Text.ICU as ICU
3232import Data.Text.ICU (Regex )
3333import Control.Monad (foldM )
34- import Data.List (foldl' , unzip )
34+ import Data.List (foldl' , unzip , intercalate )
3535
3636type BenchmarkName = Text
3737type DataName = Text
@@ -48,19 +48,23 @@ data CmdArguments = CmdArguments { inputDataFile :: String
4848 , filterData :: [Text ]
4949 , plotSize :: (Double , Double )
5050 , addSpeedupFrom :: [(Text ,Text ,Text )]
51+ , labelOverBarRotation :: Maybe Int
52+ , labelOverBarOffset :: Maybe Int
5153 } deriving (Show , Data )
5254
5355
5456cmdLineParser :: IO (CmdArguments )
5557cmdLineParser = do
5658 progName <- getProgName
5759 return $ CmdArguments { inputDataFile = mempty &= (ARG. argPos 0 ) &= ARG. typ " InputDataFile"
58- , outFile = mempty &= ARG. name " o" &= ARG. help " Output file name"
59- , mplStyle = mempty &= ARG. name " S" &= ARG. help " Matplotlib style"
60+ , outFile = Nothing &= ARG. name " o" &= ARG. help " Output file name"
61+ , mplStyle = Nothing &= ARG. name " S" &= ARG. help " Matplotlib style"
6062 , filterBench = mempty &= ARG. name " b" &= ARG. help " Match only bench line name by regex (e.g., -b a -b b to mach a or b)"
6163 , filterData = mempty &= ARG. name " d" &= ARG. help " Match only data column name by regex (e.g., -d a -d b to mach a or b)"
6264 , plotSize = (210 , 297 ) &= ARG. name " p" &= ARG. help " Plot size (x,y) in mm"
6365 , addSpeedupFrom = mempty &= ARG. name " s" &= ARG. help " Compute the speedup of (a,b,c), where a is the column selector, b is the row of reference and c is helps selecting the rows from which to compute the speedup from"
66+ , labelOverBarRotation = Nothing &= ARG. name " r" &= ARG. help " Rotation in degrees of the label over the bar"
67+ , labelOverBarOffset = Nothing &= ARG. name " l" &= ARG. help " Rotation in degrees of the label over the bar"
6468 } &= ARG. summary " GatherScript v1.0"
6569 &= ARG. program progName
6670
@@ -80,7 +84,7 @@ main = do
8084 speedupRegex <- mapM compileSpeedup $ addSpeedupFrom args
8185 dataMapWithSpeedup <- foldM addSpeedupTo dataMap speedupRegex
8286 pure $ (benchRegex, dataRegex ++ regexForSpeedup (addSpeedupFrom args), dataMapWithSpeedup)
83- either printErrorAndFail (plotDataAsBar plotInchSize (mplStyle args) outputFile) eitherDataMapWithSpeedup
87+ either printErrorAndFail (plotDataAsBar plotInchSize (mplStyle args) outputFile (labelOverBarRotation args) (labelOverBarOffset args) ) eitherDataMapWithSpeedup
8488 where
8589 printErrorAndFail str = printError str >> exitFailure
8690 printError = hPutStrLn stderr
@@ -172,14 +176,18 @@ textToDouble txt = case Data.Text.Read.double txt of
172176 Left a -> Left $ " The gathered data values should be floating point: " `mappend` a
173177 Right (dval , _) -> Right dval
174178
175- plotDataAsBar :: (Double , Double ) -> Maybe PlotStyle -> Maybe String -> ([BenchFilterRegex ], [DataFilterRegex ], DataMap ) -> IO ()
176- plotDataAsBar (sizeX, sizeY) pltStyle outputFile (benchNamePattern, dataNamePattern, dmap) = plotProcessor
177- $ plotStyle
178- % PLT. figure @@ [o2 " num" (1 :: Int ), o2 " clear" True ]
179- % genMultiBarPlots numPlotRows numPlotCols dataNames benchNames dmap
180- % PLT. setSizeInches sizeX sizeY
181- % PLT. tightLayout
179+ plotDataAsBar :: (Double , Double ) -> Maybe PlotStyle -> Maybe String -> Maybe Int -> Maybe Int -> ([BenchFilterRegex ], [DataFilterRegex ], DataMap ) -> IO ()
180+ plotDataAsBar (sizeX, sizeY) pltStyle outputFile
181+ labelOverRotate labelOverOffset
182+ (benchNamePattern, dataNamePattern, dmap) = plotProcessor
183+ $ plotStyle
184+ % labelOverBarHelperFun @@ [o2 " rotation" labelRotate]
185+ % PLT. figure @@ [o2 " num" (1 :: Int ), o2 " clear" True ]
186+ % genMultiBarPlots numPlotRows numPlotCols labelOverOffset dataNames benchNames dmap
187+ % PLT. setSizeInches sizeX sizeY
188+ % PLT. tightLayout
182189 where
190+ labelRotate = fromMaybe 90 labelOverRotate
183191 plotProcessor = maybe PLT. onscreen (\ file -> (\ pdef -> PLT. file file pdef >> return mempty )) outputFile
184192 -- plotProcessor a = PLT.code a >>= \b -> putStrLn b
185193 filterByName [] = id
@@ -191,21 +199,56 @@ plotDataAsBar (sizeX, sizeY) pltStyle outputFile (benchNamePattern, dataNamePatt
191199
192200barWithErrs :: (ToJSON x , ToJSON y , ToJSON err ) => x -> y -> err -> Matplotlib
193201barWithErrs xlabel height err = PLT. readData (xlabel, height, err) % PLT. mp # " ax.bar(data[0], data[1], yerr=data[2] " ## " )"
202+ % PLT. mp # " ax.set_xticklabels(data[0]" ## " )" @@ [o2 " rotation" (40 :: Int ), o2 " horizontalalignment" " right" , o2 " family" " sans-serif" ]
194203
195- genMultiBarPlots :: Int -> Int -> [DataName ] -> [BenchmarkName ] -> DataMap -> Matplotlib
196- genMultiBarPlots nRows nCols dns bns dmap =
204+ genMultiBarPlots :: Int -> Int -> Maybe Int -> [DataName ] -> [BenchmarkName ] -> DataMap -> Matplotlib
205+ genMultiBarPlots nRows nCols labelOffset dns bns dmap =
197206 mconcat [ PLT. addSubplot nRows nCols plotId
198207 % PLT. title (T. unpack plotTitle)
199- % barWithErrs labels ((flip (-) bottomPlot ) <$> meanData) stdErrData @@ [o2 " bottom" bottomPlot ]
200- % PLT. axisXTickLabels ( PLT. raw . T. unpack <$> labels) @@ [o2 " rotation " ( 40 :: Int ), o2 " horizontalalignment " " right " , o2 " family " " sans-serif " ]
208+ % barWithErrs labels ((flip (-) bottomOffset ) <$> meanData) stdErrData @@ [o2 " bottom" bottomOffset ]
209+ % plotLabelOverBar labelOffset bottomOffset
201210 | (plotId, plotTitle) <- ([1 .. ] :: [Int ]) `zip` dns
202211 , let (labels, dataVals) = unzip . catMaybes $ dataFrom bns plotTitle
203212 , let currData = toStatData <$> dataVals
204213 , let meanData = rawMean <$> currData
205214 , let stdErrData = errorBarValues <$> currData
206- , let bottomPlot = max 0 (minimum (zipWith (-) meanData stdErrData) - (maximum meanData - minimum meanData) * 0.1 )
215+ , let bottomOffset = max 0 (minimum (zipWith (-) meanData stdErrData) - (maximum meanData - minimum meanData) * 0.1 )
207216 ]
208217 where
209218 dataFrom :: [Text ] -> Text -> [Maybe (Text , Vector Double )]
210219 dataFrom benchNames dataName = [Just ((,) bName) <*> (M. lookup (bName,dataName) dmap) | bName <- benchNames]
211220 errorBarValues = (maybe 0 statStdDev) . multiRawStat
221+ 222+ labelOverBarHelperFun :: Matplotlib
223+ labelOverBarHelperFun = PLT. mp # intercalate " \n " [ " def add_value_labels(ax, xVals, yVals, bottomOffset, spacing=5):"
224+ , " (y_min,y_max) = ax.get_ylim()"
225+ , " for x_value, y_value in zip(xVals,yVals):"
226+ , " space = spacing"
227+ , " if y_value < 0:"
228+ , " if y_value < 0.25 * (y_max - y_min):"
229+ , " va = 'bottom'"
230+ , " else:"
231+ , " space = -space"
232+ , " va = 'top'"
233+ , " else:"
234+ , " if y_value > 0.75 * (y_max - y_min):"
235+ , " va = 'top'"
236+ , " space = -space"
237+ , " else:"
238+ , " va = 'bottom'"
239+ , " y_value = y_value + bottomOffset"
240+ , " y_abs = abs(y_value)"
241+ , " if y_abs >= 10 and y_abs < 1000:"
242+ , " label = \" {:.2f}\" .format(y_value)"
243+ , " elif y_abs >= 100 and y_abs < 10000:"
244+ , " label = \" {:.1f}\" .format(y_value)"
245+ , " else:"
246+ , " label = \" {:.3g}\" .format(y_value)"
247+ , " ax.annotate(label, (x_value, y_value), xytext=(0, space), textcoords=\" offset points\" , ha='right', va=va"
248+ ]
249+ ## " )"
250+ 251+ plotLabelOverBar :: Maybe Int -> Double -> Matplotlib
252+ plotLabelOverBar pointSpace bottomOffset = PLT. mp # " add_value_labels(ax, data[0], data[1], " # bottomOffset # " , spacing=" # spaceVal # " )"
253+ where spaceVal = fromMaybe 5 pointSpace
254+
0 commit comments