HORIZON HASKELLDocslts/ghc-9.14.x3e2d5682026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · 3e2d568 · 2026-10-11

Modulegranite-0.7.4.0GHC2021

Granite

A terminal-based plotting library that renders beautiful charts using Unicode Braille characters and ANSI colors. Granite provides a variety of chart types including scatter plots, line graphs, bar charts, pie charts, histograms, heatmaps, and box plots.

Basic Usage

Create a simple scatter plot:

{-# LANGUAGE OverloadedStrings #-}
import Granite
import Data.Text.IO as T

main = do
  let points = [(x, sin x) | x <- [0, 0.1 .. 6.28]]
      chart = scatter [series "sin(x)" points] defPlot
  T.putStrLn chart

Customization

Plots can be customized using record update syntax:

let customPlot = defPlot
      { widthChars = 80
      , heightChars = 30
      , plotTitle = "My Chart"
      , legendPos = LegendBottom
      }

Terminal Requirements

This library requires a terminal that supports:

  • Unicode (specifically Braille patterns U+2800-U+28FF)

  • ANSI color codes

  • Monospace font with proper Braille character rendering

  • 8 types
  • 22 values

Plot Configuration

3 declarations
datadata Plot
#

Plot configuration parameters.

Controls the appearance and layout of generated charts.

Constructors

valuedefPlot :: Plot
#

Default plot configuration.

Creates a 60×20 character plot with reasonable defaults:

defPlot = Plot
  { widthChars   = 60
  , heightChars  = 20
  , leftMargin   = 6
  , bottomMargin = 2
  , titleMargin  = 1
  , xBounds      = (Nothing, Nothing)
  , yBounds      = (Nothing, Nothing)
  , plotTitle    = ""
  , legendPos    = LegendRight
  , colorPalette = [ BrightBlue, BrightMagenta, BrightCyan, BrightGreen, BrightYellow, BrightRed, BrightWhite, BrightBlack]
  , xFormatter   = \ _ _ v -> show v
  , yFormatter   = \ _ _ v -> show v
  , xNumTicks    = 2
  , yNumTicks    = 2
  }

Formatting

20 declarations
datadata Color
#

A 24-bit RGB colour.

Constructors

Instances3Eq, Read, Show
  • Eq ColorDefined in granite-0.7.4.0 · Granite.Color
  • Read ColorDefined in granite-0.7.4.0 · Granite.Color
  • Show ColorDefined in granite-0.7.4.0 · Granite.Color
typetype LabelFormatter = AxisEnv -> Int -> Double -> Text
#

Axis-aware, width-limited, tick-label formatter.

Given:

  • axis context

  • a per-tick width budget (in terminal cells)

  • and the raw tick value.

returns the label to render.

Data Preparation

3 declarations
valueseries
  1. :: Text

    Name of the series (appears in legend)

  2. -> [(Double, Double)]

    List of (x, y) data points

  3. -> (Text, [(Double, Double)])
#

Create a named data series for multi-series plots.

let s1 = series "Dataset A" [(1,2), (2,4), (3,6)]
    s2 = series "Dataset B" [(1,3), (2,5), (3,7)]
    chart = scatter [s1, s2] defPlot
valuebins :: Int -> Double -> Double -> Bins
#

Create a bin configuration for histograms.

bins 10 0 100  -- 10 bins from 0 to 100
bins 20 (-5) 5 -- 20 bins from -5 to 5

Chart Types

8 declarations
valuehistogram
  1. :: Bins

    Binning configuration

  2. -> [Double]

    Raw data values to bin

  3. -> Plot

    Plot configuration

  4. -> Text

    Rendered chart as Text

#

Create a histogram from numerical data.

Data is binned according to the provided Bins configuration.

Example
import System.Random

-- Generate random normal-like distribution
let values = take 1000 $ randomRs (0, 100) gen
    chart = histogram (bins 20 0 100) values defPlot
valuebars
  1. :: [(Text, Double)]

    List of (category, value) pairs

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a bar chart from categorical data.

Each bar is colored differently and labeled with its category name.

Example
let fruits = [("Apple", 45.2), ("Banana", 38.1), ("Orange", 52.7)]
    chart = bars fruits defPlot { plotTitle = "Fruit Sales" }
valuescatter
  1. :: [(Text, [(Double, Double)])]

    List of named data series

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a scatter plot from multiple data series.

Each series is rendered with a different color and pattern. Points are plotted using Braille characters for sub-character resolution.

Example
let points1 = [(x, x^2) | x <- [-3, -2.5 .. 3]]
    points2 = [(x, 2*x + 1) | x <- [-3, -2.5 .. 3]]
    chart = scatter [series "y = x²" points1,
                     series "y = 2x + 1" points2] defPlot
valuepie
  1. :: [(Text, Double)]

    List of (category, value) pairs

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a pie chart showing proportions.

Values are normalized to sum to 100%. Negative values are treated as zero.

Example
let browsers = [("Chrome", 65), ("Firefox", 20), ("Safari", 10), ("Other", 5)]
    chart = pie browsers defPlot { plotTitle = "Browser Market Share" }
valuestackedBars
  1. :: [(Text, [(Text, Double)])]

    Categories with stacked components

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a stacked bar chart.

Each category can have multiple stacked components.

Example
let sales = [("Q1", [("Product A", 100), ("Product B", 150)]),
             ("Q2", [("Product A", 120), ("Product B", 180)])]
    chart = stackedBars sales defPlot
valueheatmap
  1. :: [[Double]]

    2D matrix of values (rows × columns)

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a heatmap visualization of a 2D matrix.

Values are mapped to a color gradient from blue (low) to red (high).

Example
let matrix = [[x * y | x <- [1..10]] | y <- [1..10]]
    chart = heatmap matrix defPlot { plotTitle = "Multiplication Table" }
valuelineGraph
  1. :: [(Text, [(Double, Double)])]

    List of named data series

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a line graph connecting data points.

Similar to scatter but connects consecutive points with lines. Points are automatically sorted by x-coordinate before connecting.

Example
let sine = [(x, sin x) | x <- [0, 0.1 .. 2*pi]]
    cosine = [(x, cos x) | x <- [0, 0.1 .. 2*pi]]
    chart = lineGraph [series "sin" sine, series "cos" cosine] defPlot
valueboxPlot
  1. :: [(Text, [Double])]

    Named datasets

  2. -> Plot

    Plot configuration

  3. -> Text

    Rendered chart as Text

#

Create a box plot showing statistical distributions.

Displays quartiles, median, and min/max values for each dataset.

Example
let data1 = [1.2, 2.3, 2.1, 3.4, 2.8, 4.1, 3.9]
    data2 = [5.1, 4.8, 6.2, 5.9, 7.1, 6.5, 5.5]
    chart = boxPlot [("Group A", data1), ("Group B", data2)] defPlot

The box plot displays:

  • Box: First quartile (Q1) to third quartile (Q3)

  • Line inside box: Median (Q2)

  • Whiskers: Minimum and maximum values

Plotly-Express-style helpers

9 declarations
valuegauss
  1. :: [Double]

    Population sample (used to compute μ and σ)

  2. -> [(Text, Double)]

    Named markers as (label, raw value); the largest z is highlighted

  3. -> Plot

    Plot configuration

  4. -> Text

    Rendered chart as Text

#

Gaussian / normal-distribution chart in standard-deviation (z-score) units.

Given a population sample, gauss computes the mean (μ) and standard deviation (σ), draws the kernel-density estimate of the distribution as a stippled bell curve, and annotates named markers at their z-score positions. The marker with the largest z-score is highlighted as the outlier.

This reproduces the "where does X sit on the curve?" style of chart: a smooth density curve filled with scattered dots, an x-axis labelled in σ units, and lollipop annotations dropping from each named value down to the axis.

Example
let -- goals + assists per 90 for every attacker in the league
    population = ...
    stars =
        [ (Lewandowski, 1.05)
        , (Mbappé,      1.02)
        , (Haaland,     1.10)
        , (Ronaldo,     1.12)
        , (Messi,       1.45)
        ]
chart = gauss population stars defPlot{plotTitle = "g + a per 90"}

Differential flame graphs

4 declarations
valueflameDiff :: FlameNode -> FlameOpts -> Text
#

Render a differential flame graph as a full standalone <svg> document. Rows go top→down by depth; a frame's width is proportional to its churn over the root churn; children are laid left→right sorted by descending churn; frames narrower than foMinPx are dropped and recursion stops past foMaxDepth.