packages feed

asciichart 1.0.0 → 1.0.1

raw patch · 4 files changed

+81/−56 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

README.md view
@@ -1,11 +1,12 @@ # asciichart+ [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/madnight/asciichart.svg?branch=master)](https://travis-ci.org/madnight/asciichart) -ASCII line charts in terminal ╭┈╯. Console line charts in pure Haskell.  +ASCII line charts in terminal ╭┈╯. Console line charts in pure Haskell. This is a Haskell port of the Javascript library [kroitor/asciichart](https://github.com/kroitor/asciichart). Free for any usage (MIT License). -![](example.png)+![](https://raw.githubusercontent.com/madnight/asciichart/master/example.png)  ## Usage ```bash@@ -19,7 +20,8 @@ main = plot [1..20] ``` -For more examples e.g. sinus wave see [examples folder](https://github.com/madnight/asciichart/tree/master/examples).+For more examples e.g. sinus wave see [examples folder](https://github.com/madnight/asciichart/tree/master/examples).  +You can also find this package on [Hackage](http://hackage.haskell.org/package/asciichart).  ## References 
asciichart.cabal view
@@ -1,5 +1,5 @@ name:                asciichart-version:             1.0.0+version:             1.0.1 synopsis:            Line charts in terminal license:             MIT license-file:        LICENSE
src/Data/Text/Chart.hs view
@@ -1,39 +1,59 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE Safe #-}+{-# LANGUAGE FlexibleContexts #-} +-----------------------------------------------------------------------------+-- |+-- Module      :  Data.Text.Chart+-- License     :  MIT+-- Maintainer  :  Fabian Beuke <mail@beuke.org>+--+-- This module contains 4 functions. The plot function provides a very simple+-- interface for plotting. It takes a List of Integers and prints out a+-- corresponding chart with a default terminal height of 14 blocks.+-- The 'plot' function is therefore equivalent to @'plotWith'+-- options {height = 14}@. You can find some examples+-- <https://github.com/madnight/asciichart/tree/master/examples here>.+-----------------------------------------------------------------------------+ module Data.Text.Chart-    ( plot+    ( -- * Plot+      plot     , plotWith+      -- * Options     , options     , height     ) where -import Control.Monad (forM_)-import Data.Array.IO (newArray, IOArray, getElems, writeArray)-import Data.Char     (isSpace)-import Data.List     (unfoldr, dropWhileEnd)-import Text.Printf   (printf)- #if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>))+import Control.Applicative     ((<$>))+import Control.Monad.ST.Safe   (ST, runST)+#else+import Control.Monad.ST        (ST, runST) #endif+import Control.Monad           (forM_)+import Data.Array.ST.Safe      (STArray, getElems, writeArray, newArray)+import Data.Char               (isSpace)+import Data.List               (unfoldr, dropWhileEnd)+import Text.Printf             (printf)+import Data.Bool               (bool)  data Options =-  Options { height :: Int }+  Options { height :: Int  -- ^ Allows to set the height of the chart.+          } --- default options+-- | Provides default options: @Options { 'height' = 14 }@. options :: Options options =   Options { height = 14 } -newArray2D :: Integer -> Integer -> IO (IOArray (Integer, Integer) String)+newArray2D :: Integer -> Integer ->+              ST s (STArray s (Integer, Integer) String) newArray2D dimX dimY = newArray ((0,0), (dimX, dimY)) " "  splitEvery :: Int -> [a] -> [[a]] splitEvery n = takeWhile (not . null) . unfoldr (Just . splitAt n) -plot :: [Integer] -> IO ()-plot = plotWith options- pad :: Integral a => [a] -> Int pad series =   let floats = fromIntegral <$> series@@ -41,60 +61,62 @@       toStr = fmap (printf "%0.2f")   in  maximum $ length <$> toStr floats -plotWith :: Options -> [Integer] -> IO ()-plotWith options series = do+plotWith' :: Options -> [Integer] -> [String]+plotWith' opts series =      -- variables and functions     let min' = minimum series-    let max' = maximum series-    let range = abs $ max' - min'-    let offset' = 3-    let height' = height options-    let ratio = fromIntegral height' / fromIntegral range :: Float-    let min2 = fromIntegral min' * ratio-    let max2 = fromIntegral max' * ratio-    let rows = round $ abs $ max2 - min2-    let width = length series + 3-    let pad' = pad series+        max' = maximum series+        range = abs $ max' - min'+        offset = 3+        ratio = fromIntegral (height opts) / fromIntegral range :: Float+        min2 = fromIntegral min' * ratio+        max2 = fromIntegral max' * ratio+        rows = round $ abs $ max2 - min2+        width = toInteger $ length series + 3 +    in runST $ do+     -- array creation-    arr <- newArray2D rows (toInteger width)-    let write arr [x] [y] = writeArray arr (x, y)-    let result = write arr+    arr <- newArray2D rows width+    let result x y = writeArray arr (head x, head y)      -- axis and labels     forM_ [min2..max2] $ \y -> do             let label = fromInteger max' - (y - min2)                       * fromInteger range / fromIntegral rows-            result [round(y - min2)] [maximum [offset' - 5, 0]] $-                   printf ("%"++ show pad' ++".2f") label-            result [round(y - min2)] [offset' - 1] $-                   if y == 0 then "┼" else "┤"+            result [round $ y - min2] [max 0 $ offset - 5] $+                   printf ("%" ++ show (pad series) ++ ".2f") label+            result [round $ y - min2] [offset - 1] . bool "┤" "┼" $ y == 0      -- initial value     let first = fromInteger (head series) * ratio - min2-    result [round(fromInteger rows - first)] [offset' - 1] "┼"+    result [round $ fromInteger rows - first] [offset - 1] "┼"      -- plot the line-    forM_ [0..(length series - 2)] $ \x' -> do-        let x = toInteger x'-        let offset'' = x + offset'-        let y0 = round (fromInteger (series !! (x' + 0)) * ratio) - round min2-        let y1 = round (fromInteger (series !! (x' + 1)) * ratio) - round min2+    forM_ [0..length series - 2] $ \x -> do+        let offset' = toInteger x + offset+        let y' i = round (fromInteger (series !! i) * ratio) - round min2+        let (y0, y1) = (y' x, y' $ x + 1)         if y0 == y1 then-            result [rows - y0] [offset''] "─"+            result [rows - y0] [offset'] "─"         else do-            result [rows - y1] [offset''] $-                   if y0 > y1 then "╰" else "╭"-            result [rows - y0] [offset''] $-                   if y0 > y1 then "╮" else "╯"-            let start = minimum [y0, y1] + 1-            let end = maximum [y0, y1]+            result [rows - y1] [offset'] . bool "╭" "╰" $ y0 > y1+            result [rows - y0] [offset'] . bool "╯" "╮" $ y0 > y1 -            forM_ [start..(end - 1)] $ \y ->-                result [rows - y] [offset''] "│"+            forM_ [min y0 y1 + 1..max y0 y1 - 1] $ \y ->+                result [rows - y] [offset'] "│" -    -- print the results-    elements <- getElems arr-    let result = splitEvery (width + 1) elements-    forM_ result $ putStrLn . dropWhileEnd isSpace . concat+    getElems arr++-- | Takes a List of Integers and prints out a+--   corresponding chart with a default terminal height of 14 blocks.+plot :: [Integer] -> IO ()+plot = plotWith options++-- | Same as plot but it's possible to define custom options.+--   Example: @'plotWith' options { 'height' = 20 }@+plotWith :: Options -> [Integer] -> IO ()+plotWith options' series = forM_ result $+      putStrLn . dropWhileEnd isSpace . concat+    where result = splitEvery (length series + 4) $ plotWith' options' series
test/Test.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-type-defaults #-} {-# LANGUAGE CPP #-} {-# LANGUAGE QuasiQuotes #-}