packages feed

chart-svg 0.5.1.0 → 0.5.1.1

raw patch · 4 files changed

+3/−387 lines, 4 filesdep −chart-svgdep −tastydep −tasty-goldenPVP ok

version bump matches the API change (PVP)

Dependencies removed: chart-svg, tasty, tasty-golden, tree-diff

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,6 +1,7 @@ 0.5.0 === * Library split into markup-parse and chart-svg.+* test removed  0.4.1 ===
chart-svg.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: chart-svg-version: 0.5.1.0+version: 0.5.1.1 license: BSD-3-Clause license-file: LICENSE copyright: Tony Day (c) 2017@@ -144,18 +144,3 @@         Data.Colour         Data.Path         Data.Path.Parser--test-suite test-    import: ghc-options-stanza-    import: ghc2021-stanza-    main-is: test.hs-    hs-source-dirs: test-    build-depends:-        , base         >=4.7 && <5-        , bytestring   >=0.11.3 && <0.13-        , chart-svg-        , markup-parse >=0.1 && <0.2-        , tasty        >=1.2 && <1.5-        , tasty-golden >=2.3.1.1 && <2.4-        , tree-diff    >=0.3 && <0.4-    type: exitcode-stdio-1.0
readme.org view
@@ -35,335 +35,4 @@  [[https://github.com/tonyday567/prettychart][prettychart]] - a chart-svg <-> ghci bridge -* ChangeLog-:PROPERTIES:-:EXPORT_FILE_NAME: chart-svg-changelog-:END:--** 0.4--0.4 is a major breaking change to the API, whilst being mostly concerned with plumbing.--The most important change has been the introduction of the Markup type, which represents an abstract markup DSL that could be described as simplified but non-compliant XML.--This will enable diffing of the resultant Markup tree so that ChartOption diffs can be sent over a web socket rather than entire charts.--As a result of his change:-  - Chart.Markup replaces Chart.Svg functionality-  - ChartOptions replaces ChartSvg-  - writeChartOptions replaces writeChartSvg--There now exists an extra step in the chart rendering pipeline, which now goes:-  - from ChartOptions to Markup using markupChartOptions-  - from Markup to ByteString via encodeMarkup, or-  - from Markup to Text via renderMarkup--Changes to dependencies include:-  - lucid removed.-  - tree-diff introduced in the test routines.-  - flatparse replaces attoparsec-  - string-interpolate replaces neat-interpolation--** 0.3--[[https://hackage.haskell.org/package/chart-svg][chart-svg-0.3]] is a major rewrite of a library I've had in the toolkit for a while. This has been a major refactoring and I'd like to share a few highlights.--*** Monomorphic primitives--Chart primitives boil down to a very short list. Charts consist of:--- Rectangles-- Lines-- Glyphs (Geometric Shapes such as circles and arrows)-- Text (specifically positioned on a page) &-- Paths (curves)--The core ~Chart~ type now reflects this and looks like:--#+begin_src haskell-data Chart where-  RectChart :: RectStyle -> [Rect Double] -> Chart-  LineChart :: LineStyle -> [[Point Double]] -> Chart-  GlyphChart :: GlyphStyle -> [Point Double] -> Chart-  TextChart :: TextStyle -> [(Text, Point Double)] -> Chart-  PathChart :: PathStyle -> [PathData Double] -> Chart-  BlankChart :: [Rect Double] -> Chart-  deriving (Eq, Show)--newtype ChartTree = ChartTree {tree :: Tree (Maybe Text, [Chart])} deriving (Eq, Show, Generic)-#+end_src--You can find examples of all of these in Chart.Examples.--Compared to 0.2.3 ...--#+begin_src haskell-data Chart a = Chart-  { -- | annotation style for the data-    annotation :: Annotation,-    -- | list of data elements, either points or rectangles.-    xys :: [XY a]-  }--data Annotation-  = RectA RectStyle-  | TextA TextStyle [Text]-  | GlyphA GlyphStyle-  | LineA LineStyle-  | PathA PathStyle [PathInfo Double]-  | BlankA--data XY a-  = PointXY (Point a)-  | RectXY (Rect a)-#+end_src--... the unification of style via Annotation and data via XY has been ditched, and there is now a simple and tight coupling between style, data type and primitive.--I originally tried for user extensibility of what a Chart was but, in the course of refactoring, the complexity cost started to weigh pretty heavily on the code base. In this particular case, working with a concrete, serializable representation, amenable to optics and pattern matching trumped higher-kinded flexibility.--The new Chart sum type may not cover a useful primitive, or there may be ideas that fall between the GADT definition, but allowing for this just wasn't worth it versus accepting future refactoring costs.--~ChartTree~ is in constrast to the prior usage of a ~[Chart]~ as the basic chart type, and fits in well with the notion of chart as svg, and thus xml tree. The rose-tree bundling and naming of chart components enables easy downstream manipulation with tools like reanimate and CSS.--*** Browser-centric--#+attr_html: :width 400-#+caption: A LineChart-[[file:other/line.svg]]--Existing chart ecosystems, such as excel, [[https://d3js.org/][d3js]] or [[https://github.com/plotly/plotly.js][plotly]], were built in earlier times and don't tend to have regard for modern browser conventions. One addition to the library is to try and fit in with user color scheme preferences. ~Chart-svg~ charts can respect [[https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme][prefers-color-scheme]] and once [[https://github.com/haskell-infra/www.haskell.org/issues/8][this Hackage ticket]] gets done, should look superb in a haddock.---The design flexibility you get from thinking of a chart as primitive shapes to be rendered in a browser also helps expand any definition of what a chart is. A recent example of this can be found in the [[https://hackage.haskell.org/package/dotparse][dotparse]] library which includes production of a [[https://hackage.haskell.org/package/numhask-0.10.1.0][chart]] I added to the numhask docs. Given the constraints of Haddock, the chart is not (yet) clickable, but is clickable in the [[https://hackage.haskell.org/package/numhask-0.10.1.0/docs/other/nh.svg][docs]] ...-This is very difficult to do in other chart libraries outside of direct javascript hacking. Imagine a future where visualisations of class hierarchies help us to tooltip, backlink and navigate complex code bases such as lens.--* Bugz-** styleBox' imprecision--- SVG is, in general, an additive model eg a border adds a constant amount no matter the scale or aspect. Text charts, in particular, can have small data boxes but large style additions to the box.-- rescaling of style here is, in juxtaposition, a multiplicative model.--In practice, this can lead to weird corner cases and unrequited distortion.--The example below starts with the unit chart, and a simple axis bar, with a dynamic overhang, so that the axis bar represents the x-axis extremity.--#+begin_src haskell :results output-exHud h = defaultHudOptions & set #chartAspect ChartAspect & set #axes [(1,defaultAxisOptions & over #bar (fmap (set #overhang h)) & set (#ticks % #ttick) Nothing & set (#ticks % #gtick) Nothing & set (#ticks % #ltick) Nothing)]-:t exHud-x1 h = addHud (exHud h) t1-:t x1-#+end_src--#+begin_src haskell-view styleBox' $ set styleBox' (Just one) (x1 0.1)-#+end_src--#+RESULTS:-: Just Rect -0.5 0.5 -0.5 0.5001171875000001--#+begin_src haskell-view styleBox' $ set styleBox' (Just one) (x1 0)-#+end_src--#+RESULTS:-: Just Rect -0.500049504950495 0.5000495049504949 -0.5 0.5001171875000001--** style elements and the axes--Hud elements (and especially axes) do not take into account the increase in the data area due to style elements.--The structure and interaction of addHud and runHudWith makes implementation problematic.--* Development--This readme is also a nice self-documenting R&D environment.--This import list reflects the current state of library development; flatparse and tree-diff experimentation.--#+begin_src haskell :results output-:reload-:set prompt "> "-:set -XOverloadedLabels-:set -XOverloadedStrings-import Chart-import Chart.Examples-import Optics.Core-#+end_src--#+RESULTS:-#+begin_example-Loaded GHCi configuration from /Users/tonyday/haskell/chart-svg/.ghci-[ 1 of 12] Compiling Chart.Data       ( src/Chart/Data.hs, interpreted )-[ 2 of 12] Compiling Data.Colour      ( src/Data/Colour.hs, interpreted )-[ 3 of 12] Compiling Data.Path        ( src/Data/Path.hs, interpreted )-[ 4 of 12] Compiling Data.Path.Parser ( src/Data/Path/Parser.hs, interpreted )-[ 5 of 12] Compiling Chart.Style      ( src/Chart/Style.hs, interpreted )-[ 6 of 12] Compiling Chart.Primitive  ( src/Chart/Primitive.hs, interpreted )-[ 7 of 12] Compiling Chart.Hud        ( src/Chart/Hud.hs, interpreted )-[ 8 of 12] Compiling Chart.Surface    ( src/Chart/Surface.hs, interpreted )-[ 9 of 12] Compiling Chart.Markup     ( src/Chart/Markup.hs, interpreted )-[10 of 12] Compiling Chart.Bar        ( src/Chart/Bar.hs, interpreted )-[11 of 12] Compiling Chart            ( src/Chart.hs, interpreted )-[12 of 12] Compiling Chart.Examples   ( src/Chart/Examples.hs, interpreted )-Ok, 12 modules loaded.->>Ok, 12 modules loaded.->>-#+end_example--* Test-** ChartOptions ==> Markup ==> ByteString rendering pipeline--#+begin_src haskell :exports both-let c0 = ChartOptions (defaultMarkupOptions & #cssOptions % #preferColorScheme .~ PreferNormal) mempty mempty-c0-#+end_src--#+RESULTS:-: ChartOptions {markupOptions = MarkupOptions {markupHeight = 300.0, cssOptions = CssOptions {shapeRendering = NoShapeRendering, preferColorScheme = PreferNormal, cssExtra = ""}}, hudOptions = HudOptions {chartAspect = FixedAspect 1.5, axes = [], frames = [], legends = [], titles = []}, charts = ChartTree {tree = Node {rootLabel = (Nothing,[]), subForest = []}}}--ChartOptions to Markup--#+begin_src haskell :exports both-markupChartOptions c0-#+end_src--#+RESULTS:-: Markup {standard = Xml, markupTree = [Node {rootLabel = StartTag "svg" [Attr "xmlns" "http://www.w3.org/2000/svg",Attr "xmlns:xlink" "http://www.w3.org/1999/xlink",Attr "width" "450",Attr "height" "300",Attr "viewBox" "-0.75 -0.5 1.5 1.0"], subForest = [Node {rootLabel = StartTag "style" [], subForest = [Node {rootLabel = Content "", subForest = []}]},Node {rootLabel = StartTag "g" [Attr "class" "chart"], subForest = []},Node {rootLabel = StartTag "g" [Attr "class" "hud"], subForest = []}]}]}--Markup to ByteString--#+begin_src haskell :exports both-import MarkupParse-import Data.ByteString qualified as B-B.putStr $ markdown (Indented 4) $ markupChartOptions c0-#+end_src--#+RESULTS:-: <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="450" height="300" viewBox="-0.75 -0.5 1.5 1.0">-:     <style>-:     </style>-:     <g class="chart">-:     </g>-:     <g class="hud">-:     </g>-: </svg>--*** round trip iso for encodeMarkup . parseMarkup--#+begin_src haskell :exports both-fileList fp =  fmap (filter (/= ".DS_Store")) (listDirectory fp)-fps <- fileList "other"-fps-#+end_src--#+RESULTS:-| rect.svg | sbar.svg | debug.svg | unit.svg | path.svg | arrow.svg | arcflags.svg | wheel.svg | hudoptions.svg | ellipse.svg | surface.svg | cubic.svg | gradient.svg | text.svg | bar.svg | line.svg | glyphs.svg | venn.svg | quad.svg | ellipse2.svg | usage.svg | wave.svg | date.svg |-- #+begin_src haskell-:{-isoMarkupParse :: BS.ByteString -> Bool-isoMarkupParse x = case runParser markupP x of-  OK l "" -> encodeMarkup l == x-  _ -> False--isoFile :: FilePath -> IO Bool-isoFile fp = do-  bs <- BS.readFile fp-  pure $ isoMarkupParse bs-:}-- #+end_src---#+begin_src haskell :exports both-fok <- mapM isoFile (("other/"<>) <$> fps)-zip fps fok-#+end_src--#+RESULTS:-| rect.svg       | True |-| sbar.svg       | True |-| debug.svg      | True |-| unit.svg       | True |-| path.svg       | True |-| arrow.svg      | True |-| arcflags.svg   | True |-| wheel.svg      | True |-| hudoptions.svg | True |-| ellipse.svg    | True |-| surface.svg    | True |-| cubic.svg      | True |-| gradient.svg   | True |-| text.svg       | True |-| bar.svg        | True |-| line.svg       | True |-| glyphs.svg     | True |-| venn.svg       | True |-| quad.svg       | True |-| ellipse2.svg   | True |-| usage.svg      | True |-| wave.svg       | True |-| date.svg       | True |--** Markup testing--#+begin_src haskell :results output-bs <- B.readFile "other/unit.svg"-#+end_src--#+RESULTS:-: <interactive>:48:1: warning: [GHC-63397] [-Wname-shadowing]-:     This binding for ‘bs’ shadows the existing binding-:       defined at <interactive>:44:1--#+begin_src haskell :results output-import MarkupParse.Patch-patch (normalize $ markup_ Xml bs) (normalize $ markupChartOptions unitExample)-#+end_src--#+RESULTS:-: Nothing--* chart-svg Hud Refactor--Surface Chart example--#+begin_src haskell :results output-:reload-:set prompt "> "-:set -XOverloadedLabels-:set -XOverloadedStrings-import Chart-import Chart.Examples-import Optics.Core-#+end_src--#+RESULTS:-#+begin_example-Loaded GHCi configuration from /Users/tonyday/haskell/chart-svg/.ghci-[ 1 of 14] Compiling Chart.Data       ( src/Chart/Data.hs, interpreted )-[ 2 of 14] Compiling Chart.FlatParse  ( src/Chart/FlatParse.hs, interpreted )-[ 3 of 14] Compiling Data.Colour      ( src/Data/Colour.hs, interpreted )-[ 4 of 14] Compiling Data.Path        ( src/Data/Path.hs, interpreted )-[ 5 of 14] Compiling Data.Path.Parser ( src/Data/Path/Parser.hs, interpreted )-[ 6 of 14] Compiling Chart.Style      ( src/Chart/Style.hs, interpreted )-[ 7 of 14] Compiling Chart.Primitive  ( src/Chart/Primitive.hs, interpreted )-[ 8 of 14] Compiling Chart.Hud        ( src/Chart/Hud.hs, interpreted )-[ 9 of 14] Compiling Chart.Surface    ( src/Chart/Surface.hs, interpreted )-[10 of 14] Compiling Chart.Markup     ( src/Chart/Markup.hs, interpreted )-[11 of 14] Compiling Chart.Markup.Parser ( src/Chart/Markup/Parser.hs, interpreted )-[12 of 14] Compiling Chart.Bar        ( src/Chart/Bar.hs, interpreted )-[13 of 14] Compiling Chart            ( src/Chart.hs, interpreted )-[14 of 14] Compiling Chart.Examples   ( src/Chart/Examples.hs, interpreted )-Ok, 14 modules loaded.->>Ok, 14 modules loaded.->>-#+end_example--#+begin_src haskell :results output-:t surfaceExample-#+end_src--#+RESULTS:-: surfaceExample :: ChartOptions+[[https://github.com/tonyday567/markup-parse][markup-parse]] - parse and prints markup (eg SVG)
− test/test.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# OPTIONS_GHC -Wno-unused-top-binds #-}--module Main (main) where--import Chart.Examples-import Chart.Markup-import Data.ByteString qualified as BS-import Data.TreeDiff-import MarkupParse-import MarkupParse.Patch-import Test.Tasty (TestTree, defaultMain, testGroup)-import Test.Tasty.Golden.Advanced (goldenTest)-import Prelude--main :: IO ()-main =-  defaultMain $-    testGroup-      "tests"-      [ goldenTests-      ]--goldenTests :: TestTree-goldenTests = testGroup "examples" (testExample <$> pathChartOptions)--testExample :: (FilePath, ChartOptions) -> TestTree-testExample (fp, co) =-  goldenTest-    fp-    (getMarkupFile fp)-    (pure (normalize $ markupChartOptions co))-    (\expected actual -> pure (show . ansiWlEditExpr <$> patch expected actual))-    (\_ -> pure ())--getMarkupFile :: FilePath -> IO Markup-getMarkupFile fp = do-  bs <- BS.readFile fp-  pure $ normalize $ markup_ Xml bs