prettychart 0.1.0 → 0.1.1.0
raw patch · 7 files changed
+533/−46 lines, 7 filesdep ~asyncdep ~boxdep ~bytestring
Dependency ranges changed: async, box, bytestring, chart-svg, containers, flatparse, lucid, mealy, numhask-space, optics-core, profunctors, time
Files
- ChangeLog.md +5/−0
- prettychart.cabal +89/−28
- readme.org +427/−0
- src/Prettychart.hs +0/−1
- src/Prettychart/Any.hs +4/−4
- src/Prettychart/Charts.hs +6/−11
- src/Prettychart/ExampleData.hs +2/−2
+ ChangeLog.md view
@@ -0,0 +1,5 @@+0.1.1+===++- bump for numhask-0.11 changes+- pragma cleanup
prettychart.cabal view
@@ -1,6 +1,6 @@-cabal-version: 2.4+cabal-version: 3.0 name: prettychart-version: 0.1.0+version: 0.1.1.0 synopsis: Pretty print charts from ghci. description: Serve and print charts from ghci, with automatic formatting. category: project@@ -8,48 +8,109 @@ maintainer: tonyday567@gmail.com copyright: Tony Day (c) 2023 license: BSD-3-Clause-homepage: https://github.com/tonyday567/prettycharts#readme-bug-reports: https://github.com/tonyday567/prettycharts/issues+tested-with: GHC == 8.10.7 || ==9.2.8 || ==9.4.5 || ==9.6.2+homepage: https://github.com/tonyday567/prettychart#readme+bug-reports: https://github.com/tonyday567/prettychart/issues build-type: Simple extra-doc-files:- other/*.svg+ other/*.svg,+ readme.org,+ ChangeLog.md source-repository head type: git- location: https://github.com/tonyday567/prettycharts+ location: https://github.com/tonyday567/prettychart -library- hs-source-dirs:- src- default-extensions:+common ghc2021-stanza+ if impl(ghc >=9.2)+ default-language:+ GHC2021+ if impl(ghc <9.2)+ default-language:+ Haskell2010+ default-extensions:+ BangPatterns+ BinaryLiterals+ ConstrainedClassMethods+ ConstraintKinds+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveLift+ DeriveTraversable+ DoAndIfThenElse+ EmptyCase+ EmptyDataDecls+ EmptyDataDeriving+ ExistentialQuantification+ ExplicitForAll+ FlexibleContexts+ FlexibleInstances+ ForeignFunctionInterface+ GADTSyntax+ GeneralisedNewtypeDeriving+ HexFloatLiterals+ ImplicitPrelude+ InstanceSigs+ KindSignatures+ MonomorphismRestriction+ MultiParamTypeClasses+ NamedFieldPuns+ NamedWildCards+ NumericUnderscores+ PatternGuards+ PolyKinds+ PostfixOperators+ RankNTypes+ RelaxedPolyRec+ ScopedTypeVariables+ StandaloneDeriving+ StarIsType+ TraditionalRecordSyntax+ TupleSections+ TypeApplications+ TypeOperators+ TypeSynonymInstances+ if impl(ghc <9.2) && impl(ghc >=8.10)+ default-extensions:+ ImportQualifiedPost+ StandaloneKindSignatures++common ghc-options-stanza ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints+ -Widentities+ -Wpartial-fields++library+ import: ghc2021-stanza+ import: ghc-options-stanza+ hs-source-dirs:+ src build-depends:- async,+ async ^>=2.2.4, base >=4.7 && <5,- box,- bytestring,- chart-svg >= 0.4,- containers,- flatparse,- formatn >= 0.3 && < 0.4,- lucid,- mealy,- numhask-space,- optics-core,- profunctors,- text >= 1.2 && < 2.1,- time >= 1.9,- web-rep >= 0.10.1 && < 0.11,+ box >=0.9 && <0.10,+ bytestring >=0.11.3 && <0.13,+ chart-svg >=0.4 && <0.5,+ containers ^>=0.6,+ flatparse >=0.4 && <0.6,+ formatn >=0.3 && <0.4,+ lucid >=2.9 && <2.12,+ mealy >=0.4 && <0.5,+ numhask-space ^>=0.11,+ optics-core ^>=0.4,+ profunctors ^>=5.6.2,+ text >=1.2 && <2.1,+ time >=1.9 && <1.14,+ web-rep >=0.10.1 && < 0.11, exposed-modules: Prettychart Prettychart.Any Prettychart.Charts Prettychart.Server Prettychart.ExampleData- other-modules:- default-language: Haskell2010-
+ readme.org view
@@ -0,0 +1,427 @@+* prettychart++[[https://hackage.haskell.org/package/prettychart][https://img.shields.io/hackage/v/prettychart.svg]]++This library contains:++- A chart server, for use in conjunction with ghci, or other live coding situations. (See Chartpretty.Server)+- anyChart, which attempts to convert text (of numbers) to a chart. (See Chartpretty.Any)+- Some useful chart patterns that didn't make the cut in chart-svg (See Chartpretty.Charts)++* Usage+** ghci integration++Add this to your .ghci.conf file to automatically go into :prettychart mode.++#+begin_src haskell :results output+-- :set -package prettychart+:{+:def! prettychart \_ -> pure $ unlines [+ "import Prettychart",+ "(sendChart, quitChartServer) <- startChartServer",+ "printc=printChart False sendChart",+ ":set -interactive-print printc"+ ]+:}++:{+:def! noprettychart \_ -> pure $ unlines [+ "quitChartServer",+ ":set -interactive-print print"+ ]+:}++:prettychart+#+end_src++#+begin_src haskell :results output+[1..200]+#+end_src++#+begin_src haskell :results output+:noprettychart+#+end_src++** live coding++The server can also be used to view and develop chart-svg charts.++#+begin_src haskell :results output+> (sendChart, quitChartServer) <- startChartServer+Setting phaser>s to stun... (port 9160) (ctrl-c to quit)++-- open localhost:9160+-- developing and sending a chart to the server++> import Chart.Examples+> sendChart $ lineExample++> quitServer+> [1..10]+[1,2,3,4,5,6,7,8,9,10]++#+end_src++* Development++#+begin_src haskell :results output+:r+:set prompt "> "+:set -Wno-type-defaults+:set -Wno-name-shadowing+:set -XOverloadedStrings+:set -XTupleSections+:set -XOverloadedLabels+import Chart hiding (quantiles)+import Optics.Core+import Prettychart.Charts+import Prettychart.Any+import Prettychart.ExampleData+import Prettychart.Server+import Web.Rep+import Box+import FlatParse.Basic hiding (take)+import Data.Time.Calendar+import Data.Mealy+import Data.Maybe+import Data.Bifunctor+import NumHask.Space hiding (quantiles)+import qualified Data.Map as Map+import Data.FormatN+import Data.Text (Text,pack)+import qualified Data.Text as Text+import qualified Data.Text.IO as Text+import Data.Time+import Data.Mealy.Quantiles+import qualified Data.List as List+import Control.Category ((>>>))+import Data.Profunctor+print "ok"+#+end_src++#+RESULTS:+: [1 of 5] Compiling Prettychart.Charts ( src/Prettychart/Charts.hs, interpreted ) [Source file changed]+: Ok, five modules loaded.+: >+: >+: >+: ok++* Prettychart.Any Examples+** single list++*** 10 or less elements => bar chart++#+begin_src haskell+xs = [0..9]+#+end_src++#+RESULTS:++#+begin_src haskell :file other/list1a.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/list1a.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/list1a.svg]]++#+begin_src haskell :results output+either Text.putStrLn (writeChartOptions "other/list1a.svg") $ anyChart (pack . show $ xs)+#+end_src++*** >1000 elements => histogram++#+begin_src haskell+xs = sin <$> [0..2000]+#+end_src++#+RESULTS:++#+begin_src haskell :file other/list1b.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/list1b.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/list1b.svg]]++*** < 1000 && > 10 => line chart++In between goes for a line chartIn between goes for a line chart.++#+begin_src haskell+xs = sin . (/100) <$> [0..500]+#+end_src++#+begin_src haskell :file other/list1c.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/list1c.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/list1c.svg]]++** double list+*** < 4 lists && < 10 values per list => bar chart+++#+begin_src haskell :results output+xs = [(1+) . sin <$> [0..8], (1+) . cos <$> [0..8]]+xs+#+end_src++#+RESULTS:+: [[1.0,1.8414709848078965,1.9092974268256817,1.1411200080598671,0.2431975046920718,4.1075725336861546e-2,0.7205845018010741,1.656986598718789,1.989358246623382],[2.0,1.5403023058681398,0.5838531634528576,1.0007503399554585e-2,0.34635637913638806,1.2836621854632262,1.960170286650366,1.7539022543433047,0.8544999661913865]]++#+begin_src haskell :file other/dlista.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/dlista.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/dlista.svg]]++*** square => surface chart++#+begin_src haskell :results output+iter2 f xs ys = f <$> xs <&> flip fmap ys -- or (\a -> f a <$> ys) <$> xs+xs = iter2 (*) (fmap sin [1..20]) (fmap cos [1..20]) :: [[Double]]+:t xs+length xs+fmap length xs+#+end_src++#+RESULTS:+: xs :: [[Double]]+: 20+: [20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20]+++#+begin_src haskell :file other/dlistb.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/dlistb.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/dlistb.svg]]++** tuple list [(Double, Double)] => scatter++#+begin_src haskell :results output+xs = zip (fmap (sin . (0.06*)) [1..100]) (fmap (cos . (0.06*)) [1..100])+:t xs+#+end_src++#+RESULTS:+: xs+: :: (TrigField b1, TrigField b2, Fractional b1, Fractional b2,+: Enum b1, Enum b2) =>+: [(b1, b2)]++#+begin_src haskell :file other/dtuple.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/dtuple.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/dtuple.svg]]++** double tuple list [(Double, Double)] => scatter+++#+begin_src haskell :results output+iter2 f xs ys = f <$> xs <&> flip fmap ys -- or (\a -> f a <$> ys) <$> xs+++xs = iter2 (\s (x,y) -> (s*x, s*y)) ((0.1*) <$> [1..10]) (zip (fmap (sin . (0.06*)) [1..100]) (fmap (cos . (0.06*)) [1..100]))+:t xs+#+end_src++#+RESULTS:+: > >+: xs :: (Fractional b, Enum b, TrigField b) => [[(b, b)]]++#+begin_src haskell :file other/dtupleb.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/dtupleb.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/dtupleb.svg]]++** (Text, Double) tuple list++#+begin_src haskell+xs = (\x -> (show x, x)) <$> [0..9]+#+end_src++#+RESULTS:+#+begin_src haskell :file other/tdtuple.svg :results output graphics file :exports both+either Text.putStrLn (writeChartOptions "other/tdtuple.svg") $ anyChart (pack . show $ xs)+#+end_src++#+RESULTS:+[[file:other/tdtuple.svg]]++* Prettychart.Charts Examples+** Example data++#+begin_src haskell :results output+r <- getReturns+length r+accret = scan (second' (dipure (+))) r+decay = 0.004+rs = snd <$> r+xma = scan (ma decay) rs+xstd = scan (std decay) rs+#+end_src++#+RESULTS:+: 10897++#+begin_src haskell :results output+xify [1..3]+#+end_src++#+RESULTS:+: [Point 0.0 1.0,Point 1.0 2.0,Point 2.0 3.0]++** simpleLineChart++#+begin_src haskell :results output+c = simpleLineChart 0.01 (palette1 2) (snd <$> accret)+xaxis = (5, timeXAxis 8 ((\x -> UTCTime x 0) . fst <$> accret))+yaxis = (5, defaultAxisOptions & #place .~ PlaceLeft & #ticks % #style .~ TickRound (FormatN FSPercent (Just 2) 4 True True) 6 TickExtend)+h = defaultHudOptions & #titles .~ (titles3 8 ("Simple Line Example", "", "accumulated return")) & #axes .~ [xaxis, yaxis]+simpleLine = mempty & #charts .~ named "line" [c] & #hudOptions .~ h :: ChartOptions+#+end_src++#+RESULTS:++#+begin_src haskell :file other/simpleline.svg :results output graphics file :exports both+writeChartOptions "other/simpleline.svg" simpleLine+#+end_src++#+RESULTS:+[[file:other/simpleline.svg]]++** histChart++#+begin_src haskell :file other/hist.svg :results output graphics file :exports both+writeChartOptions "other/hist.svg" $ histChart (Range (-0.04) 0.04) 40 xma+#+end_src++#+RESULTS:+[[file:other/hist.svg]]++** scatterChart++#+begin_src haskell+maVstd = zipWith Point (taker 500 xma) (taker 500 xstd)+#+end_src++#+RESULTS:++#+begin_src haskell :results output+c = scatterChart [maVstd]+xaxis = (5, defaultAxisOptions & #place .~ PlaceBottom & #ticks % #style .~ TickRound (FormatN FSPercent (Just 2) 4 True True) 6 TickExtend)+yaxis = (5, defaultAxisOptions & #place .~ PlaceLeft & #ticks % #style .~ TickRound (FormatN FSPercent (Just 2) 4 True True) 6 TickExtend)+h = defaultHudOptions & #titles .~ (titles3 8 ("scatter", "ma", "std")) & #axes .~ [xaxis, yaxis]+xsChart = mempty & #charts .~ unnamed c & #hudOptions .~ h :: ChartOptions+#+end_src++#+RESULTS:++#+begin_src haskell :file other/scatter.svg :results output graphics file :exports both+writeChartOptions "other/scatter.svg" xsChart+#+end_src++#+RESULTS:+[[file:other/scatter.svg]]+** quantileChart++#+begin_src haskell :results output+qs = [0.01, 0.1, 0.5, 0.9, 0.99]+qss = fmap (taker 1000) $ List.transpose $ scan (Data.Mealy.Quantiles.quantiles 0.99 qs) (snd <$> r)+c = quantileChart (quantileNames qs) ( blendMidLineStyles (length qss) 0.005 (Colour 0.7 0.1 0.3 0.5, Colour 0.1 0.4 0.8 1)) qss+xaxis = (5, timeXAxis 8 (taker 1000 $ (\x -> UTCTime x 0) . fst <$> accret))+yaxis = (5, defaultAxisOptions & #place .~ PlaceLeft & #ticks % #style .~ TickRound (FormatN FSPercent (Just 2) 4 True True) 6 TickExtend)+c' = c & (#hudOptions % #axes) .~ [xaxis,yaxis]+#+end_src++#+RESULTS:++#+begin_src haskell :file other/quantile.svg :results output graphics file :exports both+writeChartOptions "other/quantile.svg" c'+#+end_src++#+RESULTS:+[[file:other/quantile.svg]]++** quantileHistChart++#+begin_src haskell :results output+qs = [0.01, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.99]+qslast = Data.Mealy.fold (Data.Mealy.Quantiles.quantiles 0.99 qs) (snd <$> r)+c = quantileHistChart (Just $ quantileNames qs) qs qslast+#+end_src++#+RESULTS:++#+begin_src haskell :file other/qhist.svg :results output graphics file :exports both+writeChartOptions "other/qhist.svg" c+#+end_src++#+RESULTS:+[[file:other/qhist.svg]]++** digitChart++#+begin_src haskell :results output+qs = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]+digits = scan (digitize 0.99 qs) (snd <$> taker 1000 r)+c = digitChart ((\x -> UTCTime x 0) . fst <$> taker 1000 r) (fromIntegral <$> digits) (quantileNames qs)+#+end_src++#+RESULTS:++#+begin_src haskell :file other/digit.svg :results output graphics file :exports both+writeChartOptions "other/digit.svg" c+#+end_src++#+RESULTS:+[[file:other/digit.svg]]++** digitSurfaceChart++ #+begin_src haskell :results output+qs = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]+d1 = ((,) <$> (ma 0.95 >>> digitize 0.99 qs) <*> (std 0.95 >>> digitize 0.99 qs))+:t d1+ #+end_src++#+RESULTS:+: d1 :: Mealy Double (Int, Int)++#+begin_src haskell :results output+ds = taker 5000 $ scan d1 (snd <$> r)+c = digitSurfaceChart defaultSurfaceStyle (defaultSurfaceLegendOptions dark "") ("ma versus std", "ma", "std") (quantileNames qs) ds+#+end_src++#+RESULTS:++#+begin_src haskell :file other/digitsurface.svg :results output graphics file :exports both+writeChartOptions "other/digitsurface.svg" $ mempty & #charts .~ c+#+end_src++#+RESULTS:+[[file:other/digitsurface.svg]]+++#+begin_src haskell :results output+import Data.Foldable+mapCount = foldl' (\m x -> Map.insertWith (+) x 1.0 m) Map.empty ds+#+end_src++#+begin_src haskell :results output+mapCount+#+end_src+++#+RESULTS:+: fromList [((1,1),10.0),((1,2),12.0),((1,3),14.0),((1,4),21.0),((1,5),30.0),((1,6),42.0),((1,7),47.0),((1,8),45.0),((1,9),77.0),((1,10),195.0),((2,1),28.0),((2,2),29.0),((2,3),44.0),((2,4),51.0),((2,5),47.0),((2,6),58.0),((2,7),54.0),((2,8),46.0),((2,9),75.0),((2,10),99.0),((3,1),58.0),((3,2),53.0),((3,3),49.0),((3,4),45.0),((3,5),75.0),((3,6),37.0),((3,7),43.0),((3,8),45.0),((3,9),47.0),((3,10),45.0),((4,1),97.0),((4,2),65.0),((4,3),45.0),((4,4),49.0),((4,5),68.0),((4,6),37.0),((4,7),47.0),((4,8),41.0),((4,9),31.0),((4,10),34.0),((5,1),141.0),((5,2),88.0),((5,3),57.0),((5,4),48.0),((5,5),47.0),((5,6),45.0),((5,7),38.0),((5,8),43.0),((5,9),29.0),((5,10),28.0),((6,1),129.0),((6,2),101.0),((6,3),55.0),((6,4),39.0),((6,5),51.0),((6,6),43.0),((6,7),43.0),((6,8),28.0),((6,9),24.0),((6,10),23.0),((7,1),103.0),((7,2),73.0),((7,3),61.0),((7,4),51.0),((7,5),49.0),((7,6),38.0),((7,7),34.0),((7,8),24.0),((7,9),14.0),((7,10),8.0),((8,1),117.0),((8,2),99.0),((8,3),56.0),((8,4),62.0),((8,5),43.0),((8,6),35.0),((8,7),40.0),((8,8),29.0),((8,9),19.0),((8,10),9.0),((9,1),108.0),((9,2),65.0),((9,3),76.0),((9,4),49.0),((9,5),53.0),((9,6),48.0),((9,7),27.0),((9,8),15.0),((9,9),11.0),((9,10),9.0),((10,1),75.0),((10,2),37.0),((10,3),60.0),((10,4),55.0),((10,5),37.0),((10,6),80.0),((10,7),59.0),((10,8),23.0),((10,9),9.0),((10,10),5.0)]+
src/Prettychart.hs view
@@ -1,4 +1,3 @@-{-# OPTIONS_GHC -Wall #-} {-# OPTIONS_HADDOCK prune #-} -- | A haskell library to serve charts via ghci.
src/Prettychart/Any.hs view
@@ -123,14 +123,14 @@ anySurfaceChart :: [[Double]] -> ChartOptions anySurfaceChart xss = mempty & #charts .~ ct where- ct = runHud (aspect 1) (h0 <> h1) (unnamed c)+ ct = runHud (aspect 1) h0 (unnamed c) (h0, _) = toHuds (anySurfaceHud nrows ncols) gr gr = Rect 0 (fromIntegral nrows :: Double) 0 (fromIntegral ncols)- (c, h1) =- surfacefl+ (c, _) =+ surfacef (\(Point x y) -> (xss' !! floor x) !! floor y) (SurfaceOptions defaultSurfaceStyle (Point nrows ncols) gr)- (defaultSurfaceLegendOptions dark "")+ -- (defaultSurfaceLegendOptions dark "") nrows = rows xss ncols = length xss xss' = appendZeros xss
src/Prettychart/Charts.hs view
@@ -1,9 +1,5 @@ {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-}-{-# HLINT ignore "Eta reduce" #-}-{-# HLINT ignore "Use ?~" #-}-{-# LANGUAGE TupleSections #-}-{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} {-# OPTIONS_GHC -fno-warn-name-shadowing #-} -- | Various common chart patterns.@@ -28,7 +24,7 @@ import Chart hiding (abs) import Data.Bifunctor import Data.Foldable-import qualified Data.Map.Strict as Map+import Data.Map.Strict qualified as Map import Data.Maybe import Data.Text (Text) import Data.Time (UTCTime (..))@@ -100,7 +96,7 @@ & #hudOptions % #axes .~ [(5, defaultAxisOptions & #ticks % #ltick .~ Nothing & #ticks % #style .~ TickRound (FormatN FSCommaPrec (Just 2) 4 True True) 5 NoTickExtend)] & #hudOptions % #frames .~ [(20, defaultFrameOptions & #buffer .~ 0.05)] where- hcuts = gridSensible OuterPos False r (fromIntegral g)+ hcuts = gridSensible OuterPos False r g h = fill hcuts xs rects = filter (\(Rect _ _ _ y') -> y' /= 0) $@@ -256,8 +252,8 @@ [Text] -> [(Int, Int)] -> ChartTree-digitSurfaceChart pixelStyle plo ts names ps =- runHud (aspect 1) (hs0 <> hs1) (unnamed cs1)+digitSurfaceChart pixelStyle _ ts names ps =+ runHud (aspect 1) hs0 (unnamed cs1) where l = length names - 1 pts = Point l l@@ -267,11 +263,10 @@ f :: Point Double -> Double f (Point x y) = fromMaybe 0 $ Map.lookup (floor (1 + x), floor (1 + y)) mapCount (hs0, _) = toHuds (qvqHud ts names) gr- (cs1, hs1) =- surfacefl+ (cs1, _) =+ surfacef f (SurfaceOptions pixelStyle pts gr)- plo qvqHud :: (Text, Text, Text) -> [Text] -> HudOptions qvqHud ts labels =
src/Prettychart/ExampleData.hs view
@@ -8,8 +8,8 @@ where import Chart.FlatParse-import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as C+import Data.ByteString qualified as BS+import Data.ByteString.Char8 qualified as C import Data.Time.Calendar import FlatParse.Basic (Parser, Result (OK), char, runParser)