tdigest-Chart (empty) → 0
raw patch · 7 files changed
+371/−0 lines, 7 filesdep +Chartdep +Chart-diagramsdep +basesetup-changed
Dependencies added: Chart, Chart-diagrams, base, base-compat, colour, lens, mwc-random, semigroupoids, semigroups, statistics, tdigest, tdigest-Chart, vector
Files
- CHANGELOG.md +5/−0
- LICENSE +30/−0
- README.md +38/−0
- Setup.hs +2/−0
- example/Examples.hs +55/−0
- src/Graphics/Rendering/Chart/Plot/TDigest.hs +178/−0
- tdigest-Chart.cabal +63/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+## 0++- initial version+- compatible with `tdigest-0.1`+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016 Futurice Oy++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Oleg Grenrus nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,38 @@+# tdigest-Chart++A [`Chart`](http://hackage.haskell.org/package/Chart) plotting of [`tdigest`](http://hackage.haskell.org/package/tdigest)++## Examples++These are outputs of the test-suite++```sh+inkscape --export-png=example1.png --export-dpi=80 --export-background-opacity=0 --without-gui example1.svg+inkscape --export-png=example2.png --export-dpi=80 --export-background-opacity=0 --without-gui example2.svg+```++### Standard normal distribution++```haskell+Chart.layout_title Chart..= "Normal distribution"+Chart.plot $ do+ p <- Chart.tdigestPlot "tdigest" td+ return $ Chart.tdigestToPlot $ p+ & Chart.plot_tdigest_normalize .~ True+ & Chart.plot_tdigest_deviations .~ Just 3+```++++### Chi-squared distribution, k = 5++```haskell+Chart.layout_title Chart..= "Chi-squared distribution, k = 5"+Chart.plot $ do+ p <- Chart.tdigestPlot "tdigest" td+ return $ Chart.tdigestToPlot $ p+ & Chart.plot_tdigest_normalize .~ True+ & Chart.plot_tdigest_quantiles .~ [0.5, 0.9, 0.999]+```++
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ example/Examples.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE DataKinds #-}+module Main (main) where++import Prelude ()+import Prelude.Compat+import Control.Lens ((&), (.~))+import Control.Monad (replicateM)+import Data.TDigest++import Statistics.Distribution (ContGen (..))+import Statistics.Distribution.ChiSquared (chiSquared)+import Statistics.Distribution.Normal (standard)++import qualified Graphics.Rendering.Chart.Backend.Diagrams as Chart+import qualified Graphics.Rendering.Chart.Easy as Chart+import qualified Graphics.Rendering.Chart.Plot.TDigest as Chart+import qualified System.Random.MWC as MWC++example1 :: IO ()+example1 = do+ xs <- randomStream standard+ let td = tdigest xs :: TDigest 10+ Chart.toFile Chart.def "example1.svg" $ do+ Chart.layout_title Chart..= "Normal distribution"+ Chart.plot $ do+ p <- Chart.tdigestPlot "tdigest" td+ return $ Chart.tdigestToPlot $ p+ & Chart.plot_tdigest_normalize .~ True+ & Chart.plot_tdigest_deviations .~ Just 3++example2 :: IO ()+example2 = do+ xs <- randomStream $ chiSquared 5+ let td = tdigest xs :: TDigest 10+ Chart.toFile Chart.def "example2.svg" $ do+ Chart.layout_title Chart..= "Chi-squared distribution, k = 5"+ Chart.plot $ do+ p <- Chart.tdigestPlot "tdigest" td+ return $ Chart.tdigestToPlot $ p+ & Chart.plot_tdigest_normalize .~ True+ & Chart.plot_tdigest_quantiles .~ [0.5, 0.9, 0.999]++main :: IO ()+main = do+ example1+ example2++-------------------------------------------------------------------------------+-- Helpers+-------------------------------------------------------------------------------++randomStream :: ContGen d => d -> IO [Double]+randomStream d = do+ g <- MWC.create+ replicateM 100000 (genContVar d g)
+ src/Graphics/Rendering/Chart/Plot/TDigest.hs view
@@ -0,0 +1,178 @@+module Graphics.Rendering.Chart.Plot.TDigest where++import Prelude ()+import Prelude.Compat+import Control.Lens+import Data.Colour (opaque, black)+import Data.Foldable (toList, for_)+import Data.Semigroup (Max (..))+import Data.Semigroup.Foldable (foldMap1)+import Data.TDigest+import Data.TDigest.Postprocess+import Numeric (showFFloat)++import Graphics.Rendering.Chart.Drawing+import Graphics.Rendering.Chart.Geometry+import Graphics.Rendering.Chart.Plot.Types+import Graphics.Rendering.Chart.Layout+import Graphics.Rendering.Chart.State++data PlotTDigest comp = PlotTDigest+ { _plot_tdigest_data :: TDigest comp -- ^ Plot tdigest, i.e .data+ , _plot_tdigest_normalize :: Bool -- ^ Normalize histogram so total weight is 1.+ , _plot_tdigest_title :: String -- ^ Plot tile+ , _plot_tdigest_fill_style :: FillStyle -- ^ Fill style of the bins+ , _plot_tdigest_line_style :: LineStyle -- ^ Line style of the bin outlines+ , _plot_tdigest_quantiles :: [Double] -- ^ Which quantile lines to plot+ , _plot_tdigest_q_line_style :: LineStyle -- ^ Line style of quantile lines+ , _plot_tdigest_deviations :: Maybe Int -- ^ Which stddev lines to plot+ , _plot_tdigest_d_line_style :: LineStyle -- ^ Line style of deviation lines+ }++-- | Construct a bar chart with the given title and tdigest, using the next available colors+tdigestPlot :: String -> TDigest comp -> EC l (PlotTDigest comp)+tdigestPlot title td = do+ color <- takeColor+ pure $ PlotTDigest+ { _plot_tdigest_data = td+ , _plot_tdigest_normalize = False+ , _plot_tdigest_title = title+ , _plot_tdigest_fill_style = solidFillStyle color+ , _plot_tdigest_line_style = solidLine 1.0 $ opaque black+ , _plot_tdigest_quantiles = []+ , _plot_tdigest_q_line_style = dashedLine 1.0 [1,1] $ opaque black+ , _plot_tdigest_deviations = Nothing+ , _plot_tdigest_d_line_style = dashedLine 1.0 [5,5] $ opaque black+ }++tdigestPlot' :: String -> TDigest comp -> EC (Layout Double Double) ()+tdigestPlot' title td = plot (fmap tdigestToPlot (tdigestPlot title td))++tdigestToPlot :: PlotTDigest comp -> Plot Double Double+tdigestToPlot ptd = Plot+ { _plot_render = renderHistogram+ , _plot_legend =+ [(_plot_tdigest_title ptd, renderLegend)] +++ [(quantileTitle q, renderQuantileLegend) | q <- _plot_tdigest_quantiles ptd] +++ maybe [] deviationLegend (_plot_tdigest_deviations ptd)+ , _plot_all_points = unzip allPoints+ }+ where+ td = _plot_tdigest_data ptd+ hist' = histogram td+ hist = foldMap toList hist'+ lineStyle = _plot_tdigest_line_style ptd+ fillStyle = _plot_tdigest_fill_style ptd+ qLineStyle = _plot_tdigest_q_line_style ptd+ dLineStyle = _plot_tdigest_d_line_style ptd++ showFFloat' = showFFloat (Just 6)++ tw' = totalWeight td+ tw | _plot_tdigest_normalize ptd = tw'+ | otherwise = 1.0++ maxy = maxy' * 1.1+ maxy' = maybe 1.0 (getMax . foldMap1 (Max . f)) hist'+ where+ f (HistBin mi ma _ w _) = w / (ma - mi) / tw++ somex = 0++ sigma = maybe 0 (sqrt . variance') hist'+ mu = maybe 9 mean' hist'+++ allPoints = ((somex, maxy) :) $ flip map hist $ \(HistBin mi ma x w _) ->+ let d = ma - mi+ y = w / d / tw+ in (x, y)++ -- Mean & Variance++ deviationLegend _ = [ (t, renderDeviationLegend) ]+ where+ t = showString "mean = "+ . showFFloat' mu+ . showString ", stddev = "+ . showFFloat' sigma+ $ ""++ renderDeviationLegend (Rect p1 p2) = withLineStyle dLineStyle $ do+ let y = (p_y p1 + p_y p2) / 2+ strokePath $ moveTo' (p_x p1) y `mappend` lineTo' (p_x p2) y++ renderDeviation pmap d = withLineStyle dLineStyle $ do+ let x = mu + fromIntegral d * sigma+ let path = moveTo (mapXY pmap (x, 0)) `mappend` lineTo (mapXY pmap (x, maxy))+ alignStrokePath path >>= strokePath++ -- Quantiles++ quantileTitle q+ = showFFloat' q+ . showString "q = "+ . showFFloat' (maybe 0 (quantile' q tw') hist')+ $ ""++ renderQuantileLegend (Rect p1 p2) = withLineStyle qLineStyle $ do+ let y = (p_y p1 + p_y p2) / 2+ strokePath $ moveTo' (p_x p1) y `mappend` lineTo' (p_x p2) y++ renderQuantile pmap q = withLineStyle qLineStyle $ do+ let x = maybe 0 (quantile' q tw') hist'+ let path = moveTo (mapXY pmap (x, 0)) `mappend` lineTo (mapXY pmap (x, maxy))+ alignStrokePath path >>= strokePath++ -- Histogram++ renderLegend r = withLineStyle lineStyle $ withFillStyle fillStyle $ do+ let path = rectPath r+ fillPath path+ strokePath path++ renderHistogram pmap = do+ withLineStyle lineStyle $ withFillStyle fillStyle $ do+ for_ hist $ \(HistBin mi ma _ w _) -> do+ let d = ma - mi+ y = w / d / tw+ path = rectPath $ Rect+ (mapXY pmap (mi,0))+ (mapXY pmap (ma,y))+ alignFillPath path >>= fillPath+ alignStrokePath path >>= strokePath++ for_ (_plot_tdigest_quantiles ptd) $ renderQuantile pmap+ for_ (_plot_tdigest_deviations ptd) $ \maxd ->+ for_ [-maxd .. maxd] $ renderDeviation pmap++-------------------------------------------------------------------------------+-- Lenses+-------------------------------------------------------------------------------++plot_tdigest_title :: Lens' (PlotTDigest comp) String+plot_tdigest_title = lens _plot_tdigest_title $ \s x -> s { _plot_tdigest_title = x }++plot_tdigest_quantiles :: Lens' (PlotTDigest comp) [Double]+plot_tdigest_quantiles = lens _plot_tdigest_quantiles $ \s x -> s { _plot_tdigest_quantiles = x }++plot_tdigest_q_line_style :: Lens' (PlotTDigest comp) LineStyle+plot_tdigest_q_line_style = lens _plot_tdigest_q_line_style $ \s x -> s { _plot_tdigest_q_line_style = x }++plot_tdigest_normalize :: Lens' (PlotTDigest comp) Bool+plot_tdigest_normalize = lens _plot_tdigest_normalize $ \s x -> s { _plot_tdigest_normalize = x }++plot_tdigest_line_style :: Lens' (PlotTDigest comp) LineStyle+plot_tdigest_line_style = lens _plot_tdigest_line_style $ \s x -> s { _plot_tdigest_line_style = x }++plot_tdigest_fill_style :: Lens' (PlotTDigest comp) FillStyle+plot_tdigest_fill_style = lens _plot_tdigest_fill_style $ \s x -> s { _plot_tdigest_fill_style = x }++plot_tdigest_deviations :: Lens' (PlotTDigest comp) (Maybe Int)+plot_tdigest_deviations = lens _plot_tdigest_deviations $ \s x -> s { _plot_tdigest_deviations = x }++plot_tdigest_data :: Lens (PlotTDigest comp) (PlotTDigest comp') (TDigest comp) (TDigest comp')+plot_tdigest_data = lens _plot_tdigest_data $ \s x -> s { _plot_tdigest_data = x }++plot_tdigest_d_line_style :: Lens' (PlotTDigest comp) LineStyle+plot_tdigest_d_line_style = lens _plot_tdigest_d_line_style $ \s x -> s { _plot_tdigest_d_line_style = x }
+ tdigest-Chart.cabal view
@@ -0,0 +1,63 @@+name: tdigest-Chart+version: 0+synopsis: Chart generation from tdigest+description:+ Chart generation from tdigest.+ .+ @+ ...+ @+category: Numeric, Graphics+homepage: https://github.com/futurice/haskell-tdigest#readme+bug-reports: https://github.com/futurice/haskell-tdigest/issues+author: Oleg Grenrus <oleg.grenrus@iki.fi>+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>+license: BSD3+license-file: LICENSE+tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1, GHC==8.0.2+build-type: Simple+cabal-version: >= 1.10++extra-source-files:+ README.md+ CHANGELOG.md++source-repository head+ type: git+ location: https://github.com/futurice/haskell-tdigest++library+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ base >=4.7 && <4.10+ , base-compat >=0.9.1 && <0.10+ , colour >=2.3.3 && <2.4+ , semigroups >=0.18.2 && <0.19+ , semigroupoids >=5.1 && <5.2+ , tdigest >=0.1 && <0.2+ , lens >=4 && <4.16+ , Chart >=1.8.1 && <1.9+ exposed-modules:+ Graphics.Rendering.Chart.Plot.TDigest+ default-language: Haskell2010++test-suite tdigest-chart-examples+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: Examples.hs+ ghc-options: -Wall -threaded+ hs-source-dirs: example++ build-depends:+ base,+ base-compat,+ Chart,+ lens,+ tdigest,+ tdigest-Chart,+ vector,+ Chart-diagrams >=1.8.1 && <1.9,+ mwc-random >=0.13.4.0 && <0.14,+ statistics >=0.13.3.0 && <0.14