packages feed

ansigraph (empty) → 0.1.0.0

raw patch · 10 files changed

+638/−0 lines, 10 filesdep +ansi-terminaldep +basesetup-changed

Dependencies added: ansi-terminal, base

Files

+ LICENSE view
@@ -0,0 +1,22 @@+The MIT License (MIT)++Copyright (c) 2015 Cliff Harvey++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ansigraph.cabal view
@@ -0,0 +1,65 @@+name:                ansigraph+version:             0.1.0.0+synopsis:            Terminal-based graphing via ANSI and Unicode++description:         Ansigraph is an ultralightweight terminal-based graphing utility. It uses+                     Unicode characters and ANSI escape codes to display and animate colored graphs+                     of vectors/functions in real and complex variables.+                     .++                     This functionality is provided by a 'Graphable' type class, whose method+                     'graphWith' draws a graph at the terminal. Another function 'animateWith' takes+                     a list of Graphable elements and displays an animation by rendering them in+                     sequence. Both of these functions take an options record as an argument. The+                     'graph' and 'animate' functions are defined to use the default options, and the+                     user can define similar functions based on their own settings.+                     .++                     There are two main ways to use the package.++                     Importing "System.Console.Ansigraph" provides all the functionality we+                     typically use. This includes the /FlexibleInstances/ extension, which makes it+                     marginally more convenient to use graphing functions by allowing instances like+                     'Graphable [Double]'.+                     .++                     If you want to use the package without activating /FlexibleInstances/ then you+                     can import "System.Console.Ansigraph.Core", which provides everything except+                     these instances. Then you must use one of a few newtype wrappers, namely:+                     'Graph', 'PosGraph', 'CGraph', 'Mat', 'CMat'. These wrappers are also+                     available from the standard 'Ansigraph' module.+                     .++                     The "System.Console.Ansigraph.Examples" module contains examples of all the+                     graph types with animations of various plane waves, and also shows the+                     available ANSI colors.+++homepage:            https://github.com/BlackBrane/ansigraph+license:             MIT+license-file:        LICENSE+author:              Cliff Harvey+maintainer:          cs.hbar+hs@gmail.com+copyright:           2015+category:            Graphics+build-type:          Simple++cabal-version:       >=1.10++source-repository head+  type:     git+  location: git://github.com/BlackBrane/ansigraph.git++library+  exposed-modules:     System.Console.Ansigraph,+                       System.Console.Ansigraph.Core,+                       System.Console.Ansigraph.Examples++  other-modules:       System.Console.Ansigraph.Internal.Core,+                       System.Console.Ansigraph.Internal.FlexInstances,+                       System.Console.Ansigraph.Internal.Horizontal,+                       System.Console.Ansigraph.Internal.Matrix++  build-depends:       base >=4.8 && <4.9, ansi-terminal >=0.6 && <0.7+  hs-source-dirs:      src+  default-language:    Haskell2010
+ src/System/Console/Ansigraph.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE FlexibleInstances #-}++-- | This is the primary module to import for use of the ansigraph package, which provides+--   terminal-based graphing for vectors and matrices of real and complex numbers.+--+--   This functionality is implemented via a 'Graphable' type class.+--+--   __Ansigraph is intended to be used in on of two ways:__+--+--   * __By importing "System.Console.Ansigraph"__.+--   This provides all the functionality we typically use, including the FlexibleInstances+--   extension which makes it easier to use graphing functions by allowing instances like+--   'Graphable [Double]'. It also provides "System.Console.AnsiGraph.Core" which provides all the+--   core functionality. See the Haddock page for that module for more details.+--+--   * __By directly importing "System.Console.Ansigraph.Core"__, which does not activate+--   FlexibleInstances but includes everything else provided by the other module. This just means+--   you must use one of a handful of newtype wrappers, namely: 'Graph', 'PosGraph', 'CGraph',+--   'Mat', 'CMat'. These wrappers are also available from the standard module.+module System.Console.Ansigraph (+    module System.Console.Ansigraph.Internal.FlexInstances+  , module System.Console.Ansigraph.Core+) where+++import System.Console.Ansigraph.Core+import System.Console.Ansigraph.Internal.FlexInstances
+ src/System/Console/Ansigraph/Core.hs view
@@ -0,0 +1,173 @@+-- | This module provides the core functionality of the ansigraph package:+--   terminal-based graphing for vectors and matrices of real and complex numbers.+--+--   This is implemented via a 'Graphable' type class.+--+--   __Ansigraph is intended to be used in on of two ways:__+--+--   * __By importing "System.Console.Ansigraph"__.+--   This provides all the functionality we typically use, including the FlexibleInstances+--   extension which makes it easier to use graphing functions by allowing instances like+--   'Graphable [Double]'.+--+--+--   * __By directly importing "System.Console.Ansigraph.Core"__, which does not activate FlexibleInstances but+--   includes everything else provided by the other module. This just means you must use one of a+--   handful of newtype wrappers, namely: 'Graph', 'PosGraph', 'CGraph', 'Mat', 'CMat'.+--   These wrappers are also available from the standard module.+module System.Console.Ansigraph.Core (++  -- * Core Functionality+  -- *** The Graphable class+    Graphable (graphWith)+  , graph+  , animateWith+  , animate++  -- *** Graphing options+  , AGSettings (..)++  -- *** Default options+  , graphDefaults+  , blue, pink, white++  -- *** ANSI data+  , AnsiColor (..)+  , Coloring (..)++-- *** ANSI helpers+  , realColors+  , imagColors+  , colorSets+  , invert+  , setFG+  , setBG+  , lineClear+  , clear+  , applyColor+  , colorStr+  , colorStrLn++  -- * Graphable wrapper types+  , Graph (..)+  , CGraph (..)+  , PosGraph (..)+  , Mat (..)+  , CMat (..)++  -- * Graphing+  -- *** Horizontal vector graphing+  , displayRV+  , displayCV+  , displayPV+  , simpleRender+  , simpleRenderR++  -- *** Matrix graphing+  , matShow+  , displayMat+  , displayCMat++-- *** Simple (non-ANSI) graphing for strictly-positive data+  , posgraph+  , posanim++) where++import System.Console.Ansigraph.Internal.Core+import System.Console.Ansigraph.Internal.Horizontal+import System.Console.Ansigraph.Internal.Matrix++import System.Console.ANSI+import System.IO (hFlush,stdout)+import Control.Concurrent (threadDelay)+import Data.List (intersperse,transpose)+import Data.Complex (Complex,realPart,imagPart,magnitude)+++-- | Things that ansigraph knows how to render at the terminal are+--   instances of this class.+class Graphable a where+  graphWith :: AGSettings -> a -> IO ()++-- | Invokes the 'Graphable' type class method 'graphWith' with the+--   default 'AGSettings' record, 'graphDefaults'.+graph :: Graphable a => a -> IO ()+graph = graphWith graphDefaults+++---- IO / ANSI helpers ----++-- | Pauses for the specified number of µs.+pauseFor :: Int -> IO ()+pauseFor n = hFlush stdout >> threadDelay n++-- | 'pauseFor' some time interval, then clear screen and set the cursor at (0,0).+next :: Int -> IO ()+next n = do pauseFor n+            clearScreen+            setCursorPosition 0 0++-- | For some number of frames per second, return the corresponding time delta in microseconds.+deltaFromFPS :: Int -> Int+deltaFromFPS fps = 1000000 `div` fps+++---- Animation ----++-- | Any list of a 'Graphable' type can be made into an animation, by+--   'graph'ing each element with a time delay and screen-clear after each.+--   'AGSettings' are used to determine the time delta and any coloring/scaling options.+animateWith :: Graphable a => AGSettings -> [a] -> IO ()+animateWith s xs = let delta = deltaFromFPS $ framerate s in+  sequence_ $ intersperse (next delta) (graphWith s <$> xs)++-- | Perform 'animateWith' using default options. Equivalent to 'graph'ing each member+--   of the supplied list with a short delay and screen-clear after each.+animate :: Graphable a => [a] -> IO ()+animate = animateWith graphDefaults+++---- Wrappers to avoid needing FlexibleInstances ----++-- | Wrapper type for graph of a real vector/function+newtype Graph = Graph { unGraph :: [Double] }++-- | Wrapper type for graph of a complex vector/function+newtype CGraph = CGraph { unCGraph :: [Complex Double] }++-- | Wrapper type for graph of a non-negative real vector/function+newtype PosGraph = PosGraph { unPosGraph :: [Double] }++-- | Wrapper type for graph of a real two-index vector/two-argument function+newtype Mat = Mat { unMat :: [[Double]] }++-- | Wrapper type for graph of a complex two-index vector/two-argument function+newtype CMat = CMat { unCMat :: [[Complex Double]] }+++instance Graphable Graph where+  graphWith s = displayRV s . unGraph++instance Graphable CGraph where+  graphWith s = displayCV s . unCGraph++instance Graphable PosGraph where+  graphWith s = displayPV s . unPosGraph++instance Graphable Mat where+  graphWith s = displayMat s . unMat++instance Graphable CMat where+  graphWith s = displayCMat s . unCMat+++---- helpers for graphing/animating strictly-positive real functions ----++-- | Display a graph of the supplied (non-negative) real vector.+posgraph :: [Double] -> IO ()+posgraph = graph . PosGraph++-- | Display an animation of the supplied list of (non-negative) real vectors.+posanim :: [[Double]] -> IO ()+posanim = animate . map PosGraph
+ src/System/Console/Ansigraph/Examples.hs view
@@ -0,0 +1,68 @@+-- | A module that exports some simple demonstrations of how to use the package.+module System.Console.Ansigraph.Examples (+    waveDemo+  , waveDemoR+  , waveDemoP+  , showColors+  , demo+  , wave+) where++import System.Console.Ansigraph+import System.Console.ANSI+import Control.Monad (forM_)+import Data.Complex+++---- Wave Demo ----++wave :: [Complex Double]+wave = cis . (*) (pi/20) <$> [0..79]++deltas :: [Double]+deltas = (*) (-pi/10) <$> [0..50]++waves :: [[Complex Double]]+waves = zipWith (\z -> map (* z)) (cis <$> deltas) $ replicate 50 wave++pwave :: PosGraph+pwave = PosGraph $ (+1) . realPart <$> wave++rwaves :: [[Double]]+rwaves = map (map realPart) waves++pwaves :: [PosGraph]+pwaves = PosGraph . map (+1) <$> rwaves++-- | Display an animation of the positive real function /p(x,t) = cos(x-t) + 1/ in some units.+waveDemoP :: IO ()+waveDemoP = animate pwaves++-- | Display an animation of the real function /r(x,t) = cos(x-t)/ in the standard style, i.e. with both+--   positive and negative regions.+waveDemoR :: IO ()+waveDemoR = animate rwaves++-- | Display an animation of the complex wave /z(x,t) = exp(ix - it)/ in some units.+waveDemo :: IO ()+waveDemo = animate waves+++---- Show ANSI Colors ----++colors = [Black,Red,Green,Yellow,Blue,Magenta,Cyan,White]+intensities = [Dull,Vivid]++-- | Show all of the available 'AnsiColor's and corresponding 'ColorIntensity', 'Color' pairs.+showColors = do+  putStrLn "\n Available colors:"+  forM_ colors $ \clr -> do+     forM_ intensities $ \inten -> do+       setSGR [SetColor Foreground inten clr]+       putStr $ replicate 20 '█'+       setSGR [Reset]+       putStrLn $ "  " ++ show inten ++ " " ++ show clr+  setSGR [Reset]++-- | Run all of the demos in sequence.+demo = sequence_ [waveDemoP,waveDemoR,waveDemo,showColors]
+ src/System/Console/Ansigraph/Internal/Core.hs view
@@ -0,0 +1,107 @@+module System.Console.Ansigraph.Internal.Core (+    AnsiColor (..)+  , AGSettings (..)+  , blue, pink, white+  , graphDefaults+  , Coloring (..)+  , realColors+  , imagColors+  , colorSets+  , invert+  , setFG+  , setBG+  , lineClear+  , clear+  , applyColor+  , colorStr+  , colorStrLn+) where++import System.Console.ANSI+import System.IO (hFlush, stdout)++---- Basics ----++-- | ANSI colors are characterized by a 'Color' and a 'ColorIntensity'. This+--   data type holds one of each.+data AnsiColor = AnsiColor ColorIntensity Color deriving Show++-- | Record that holds graphing options.+data AGSettings =+  AGSettings+    {+      -- | Foreground color for real number component+      realColor :: AnsiColor+      -- | Foreground color for imaginary number component.+    , imagColor :: AnsiColor+      -- | Background color for real number component.+    , realBG    :: AnsiColor+      -- | Background color for imaginary number component.+    , imagBG    :: AnsiColor+    -- | Framerate in fps.+    , framerate :: Int+    -- | How to rescale the size of a vector before displaying it+    --   (which is not implemented yet).+    , scaling   :: (Int -> Int)+    }++blue   = AnsiColor Vivid Blue+pink   = AnsiColor Vivid Magenta+white  = AnsiColor Vivid White++graphDefaults = AGSettings blue pink white white 15 (max 150)++-- | Holds two 'AnsiColor's representing foreground and background colors for display via ANSI.+data Coloring = Coloring AnsiColor AnsiColor deriving Show++-- | Projection retrieving foreground and background colors+--   for real number graphs in the form of a 'Coloring'.+realColors :: AGSettings -> Coloring+realColors sets = Coloring (realColor sets) (realBG sets)++-- | Projection retrieving foreground and background colors+--   for imaginary component of complex number graphs in the form of a 'Coloring'.+imagColors :: AGSettings -> Coloring+imagColors sets = Coloring (imagColor sets) (imagBG sets)++-- | Retrieves a pair of 'Coloring's for real and imaginary graph components respectively.+colorSets :: AGSettings -> (Coloring,Coloring)+colorSets s = (Coloring (realColor s) (realBG s), Coloring (imagColor s) (imagBG s))++-- | Swaps foreground and background colors within a 'Coloring'.+invert :: Coloring -> Coloring+invert (Coloring fg bg) = Coloring bg fg++-- | 'SGR' command to set the foreground to the specified 'AnsiColor'.+setFG :: AnsiColor -> SGR+setFG (AnsiColor ci c) = SetColor Foreground ci c++-- | 'SGR' command to set the background to the specified 'AnsiColor'.+setBG :: AnsiColor -> SGR+setBG (AnsiColor ci c) = SetColor Background ci c++-- | Clear any SGR settings, then print a new line and flush stdout.+lineClear :: IO ()+lineClear = setSGR [Reset] >> putStrLn "" >> hFlush stdout++-- | Clear any SGR settings and then flush stdout.+clear :: IO ()+clear = setSGR [Reset] >> hFlush stdout++-- | Apply both foreground and background color.+applyColor :: Coloring -> IO ()+applyColor (Coloring fg bg) = setSGR [setFG fg, setBG bg]++-- | Use a particular ANSI 'Coloring' to print a string at the terminal (without a newline),+--   then clear all ANSI SGR codes and flush stdout.+colorStr :: Coloring -> String -> IO ()+colorStr c s = do applyColor c+                  putStr s+                  clear++-- | Use a particular ANSI 'Coloring' to print a string at the terminal,+--   then clear all ANSI SGR codes, print a newline and flush stdout.+colorStrLn :: Coloring -> String -> IO ()+colorStrLn c s = do applyColor c+                    putStr s+                    lineClear
+ src/System/Console/Ansigraph/Internal/FlexInstances.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE FlexibleInstances #-}++module System.Console.Ansigraph.Internal.FlexInstances where++import System.Console.Ansigraph.Core+import Data.Complex+++instance Graphable [Double] where+  graphWith = displayRV++instance Graphable [Complex Double] where+  graphWith = displayCV++instance Graphable [[Double]] where+  graphWith = displayMat++instance Graphable [[Complex Double]] where+  graphWith = displayCMat
+ src/System/Console/Ansigraph/Internal/Horizontal.hs view
@@ -0,0 +1,94 @@+module System.Console.Ansigraph.Internal.Horizontal (+    displayRV+  , displayCV+  , displayPV+  , simpleRender+  , simpleRenderR+) where++import System.Console.Ansigraph.Internal.Core+import Data.Complex+import System.IO (hFlush, stdout)++---- Graphing Infrastructure  ----++barChars = "█▇▆▅▄▃▂▁"++-- These values delineate regions for rounding to the nearest 1/8.+barVals :: [Double]+barVals = (+ 0.0625) . (/8) <$> [7,6..0]+     -- = [15/16, 13/16, 11/16, 9/16, 7/16, 5/16, 3/16, 1/16]++{- forward and reverse versions of unicode bar selection+   for positive and negative graph regions respectively -}++bars, barsR :: [(Double,Char)]+bars  = zipWith (,) barVals barChars++barsR = zipWith (,) barVals (reverse barChars)+++selectBar, selectBarR :: Double -> Char+selectBar x = let l = filter (\p -> fst p < x) bars in case l of+  []     -> ' '+  (p:ss) -> snd p++selectBarR x = let l = filter (\p -> fst p < x) barsR in case l of+  []     -> '█'+  (p:ss) -> snd p++-- | Simple vector rendering. Yields a string of unicode chars representing graph bars+--   varying in units of 1/8. To be primarily invoked via 'graph', 'graphWith',+--   'animate', 'animateWith'.+simpleRender :: [Double] -> String+simpleRender xs = let mx = maximum xs in+                  (selectBar . (/mx)) <$> xs++-- | Simple vector rendering – inverted version. Rarely used directly.+--   It is needed to render negative graph regions.+simpleRenderR :: [Double] -> String+simpleRenderR xs = let mx = maximum xs in+                   (selectBarR . (/mx)) <$> xs+++renderCV :: [Complex Double] -> (String,String,String,String)+renderCV l = let rp = realPart <$> l+                 rm = negate   <$> rp+                 ip = imagPart <$> l+                 im = negate   <$> ip+                 mx = maximum $ rp ++ rm ++ ip ++ im+  in (selectBar  . (/mx) <$> rp,+      selectBarR . (/mx) <$> rm,+      selectBar  . (/mx) <$> ip,+      selectBarR . (/mx) <$> im)++renderRV :: [Double] -> (String,String)+renderRV l = let rp = l+                 rm = negate <$> rp+                 mx = maximum $ rp ++ rm+  in (selectBar  . (/mx) <$> rp,+      selectBarR . (/mx) <$> rm)++-- | ANSI based display for complex vectors. To be primarily invoked via 'graph', 'graphWith',+--   'animate', 'animateWith'.+displayCV :: AGSettings -> [Complex Double] -> IO ()+displayCV s l = let (rp,rm,ip,im) = renderCV l+                    (rcol,icol) = colorSets s+  in do colorStrLn rcol          rp+        colorStrLn (invert rcol) rm+        colorStrLn icol          ip+        colorStrLn (invert icol) im++-- | ANSI based display for real vectors. To be primarily invoked via 'graph', 'graphWith',+--   'animate', 'animateWith'.+displayRV :: AGSettings -> [Double] -> IO ()+displayRV s l = let (rp,rm) = renderRV l+                    rcol = realColors s+  in do colorStrLn rcol          rp+        colorStrLn (invert rcol) rm++-- | ANSI based display for positive real vectors. To be primarily invoked via 'graph', 'graphWith',+--   'animate', 'animateWith'.+displayPV :: AGSettings -> [Double] -> IO ()+displayPV s l = let (rp,_) = renderRV l+                    rcol = realColors s in colorStrLn rcol rp
+ src/System/Console/Ansigraph/Internal/Matrix.hs view
@@ -0,0 +1,61 @@+module System.Console.Ansigraph.Internal.Matrix (+    matShow+  , displayMat+  , displayCMat+) where++import System.Console.Ansigraph.Internal.Core+import Data.Complex++---- Matrices ----++mmap :: (a -> b) -> [[a]] -> [[b]]+mmap = map . map++mmax :: (Num a, Ord a) => [[a]] -> a+mmax = maximum . map maximum . mmap abs++densityChars = "█▓▒░"++densityVals :: [Double]+densityVals = (+ 0.125) . (/4) <$> [3,2,1,0]+         -- = [7/8, 5/8, 3/8, 1/8]++blocks, blocksR :: [(Double,Char)]+blocks  = zipWith (,) densityVals densityChars++blocksR = zipWith (,) densityVals (reverse densityChars)+++selectBlock :: Double -> Char+selectBlock x = let l = filter (\p -> fst p < abs x) blocks in case l of+  []     -> ' '+  (p:ss) -> snd p++-- | Given a matrix of Doubles, return the list of strings illustrating the absolute value+--   of each entry relative to the largest, via unicode chars that denote a particular density.+matShow :: [[Double]] -> [String]+matShow m = let mx = mmax m+            in  mmap (selectBlock . (/ mx)) m++-- | Use ANSI coloring (specified by an 'AGSettings') to visually display a Real matrix.+displayMat :: AGSettings -> [[Double]] -> IO ()+displayMat s = mapM_ (colorStrLn (realColors s)) . matShow+++matShow_Imag :: [[Complex Double]] -> [String]+matShow_Imag m = let mx = max (mmax $ mmap realPart m)+                              (mmax $ mmap imagPart m)+                 in  mmap (selectBlock . (/ mx) . imagPart) m++matShow_Real :: [[Complex Double]] -> [String]+matShow_Real m = let mx = max (mmax $ mmap realPart m)+                              (mmax $ mmap imagPart m)+                 in  mmap (selectBlock . (/ mx) . realPart) m++-- | Use ANSI coloring (specified by an 'AGSettings') to visually display a Complex matrix.+displayCMat :: AGSettings -> [[Complex Double]] -> IO ()+displayCMat s m = sequence_ $+  zipWith (\x y -> x >> putStr " " >> y)+          (colorStr   (realColors s) <$> matShow_Real m)+          (colorStrLn (imagColors s) <$> matShow_Imag m)