Angara.Chart


Angara.Chart

An F# data visualization library. Supports visualization of uncertain values. Powered by JavaScript library InteractiveDataDisplay.

The Angara.Chart library can be installed from NuGet:
PM> Install-Package Angara.Chart

Example

The example builds a chart consisting of the line and markers plots:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
#r "Angara.Chart.dll"

open Angara.Charting

open System

let x = [| for i in 0..99 -> float(i) / 10.0 |]
let y = x |> Array.map (fun x -> sin x)
let z = x |> Array.map (fun x -> cos x)

let chart = [ Plot.line(x, y); Plot.markers(x, z) ] |> Chart.ofList

Plot Gallery

This section is a gallery of plots supported by the Angara.Chart. Here we use Angara.Table to load sample data which then is displayed with Angara.Chart.

Preparing data

The code loads several tables that will be used in the following charts.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
#r "Angara.Table.dll"
#r "System.Collections.Immutable.dll"
open Angara.Data
open System.Linq

let wheat = Table.Load("../files/data/wheat.csv")
let uwheat = Table.Load("../files/data/uwheat.csv")
let site = Table.Load("../files/data/site.csv")
let npz = Table.Load("../files/data/npz.csv")
let grid = Table.Load("../files/data/grid.csv")
let ugrid = Table.Load("../files/data/ugrid.csv")

// This function returns a float array of the given table column 
let col (colName:string) (t:Table) : float[] = t.[colName].Rows.AsReal.ToArray()
// This function returns an array of records representing quantiles,
// so instead of a value it gives an information about its uncertainty.
let quantiles prefix table = 
    { median = table |> col (prefix + "_median")
      lower68 = table |> col (prefix + "_lb68")
      upper68 = table |> col (prefix + "_ub68")
      lower95 = table |> col (prefix + "_lb95")
      upper95 = table |> col (prefix + "_ub95") }

Line and uncertainty bands

The functions Plot.lineallow to define a plot displayed straight line segments connecting a series of data points.

It is enough to provide just y data series to define a line plot:

1: 
2: 
3: 
let y = Array.init 100 (fun i -> let x = float(i-50)/10.0 in x*x)

let line_y = [ Plot.line(y) ] |> Chart.ofList

The following plot takes both x and y series, defines stroke color, line thickness and axis titles. See the API Reference for other optional parameteres of the line plot.

1: 
2: 
3: 
4: 
5: 
6: 
let t = site |> col "t"
let p = site |> col "p"

let line_tp = 
  [ Plot.line(t, p, stroke = "#00007F", thickness = 2.0, titles = Titles.line("time", "p")) ] 
  |> Chart.ofList

If a variable that determines the position on the vertical axis is uncertain, bands corresponding to the given quantiles of the uncertain values are displayed in addition to the line segments, which represent median values.

1: 
2: 
3: 
4: 
5: 
let y_uncertain = npz |> quantiles "p"

let line_uncertain = 
  [ Plot.line(LineX.Values t, LineY.UncertainValues y_uncertain, titles = Titles.line("time", "p")) ] 
  |> Chart.ofList

Area

1: 
2: 
3: 
4: 
5: 
6: 
let y1 = npz |> col "p_lb68"
let y2 = npz |> col "p_ub68"

let area = 
  [ Plot.area(t, y1, y2, titles = Titles.area("time", "p - lower bound", "p - upper bound")) ] 
  |> Chart.ofList

Markers

It is a plot which displays data as a collection of points, each having the value of one data series determining the position on the horizontal axis and the value of the other data series determining the position on the vertical axis. Also data series can be bound to marker size and color, and other appearance settings.

Markers plot has default collection of supported shapes such as box, circle, cross, triangle etc, but still it allows creating new shapes.

1: 
2: 
3: 
4: 
5: 
let lon = wheat |> col "Lon"
let lat = wheat |> col "Lat"
let wheat = wheat |> col "wheat"

let markers = [ Plot.markers(lon, lat, displayName = "wheat") ] |> Chart.ofList
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let markers_colors =
  [ Plot.markers(lon, lat, 
      color = MarkersColor.Values wheat, 
      colorPalette = "0=Red=Green=Yellow=Blue=10",
      borderColor = "black", 
      shape = MarkersShape.Circle, 
      displayName = "wheat",
      titles = Titles.markers("lon", "lat", color = "wheat production")) ] 
  |> Chart.ofList
        
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let markers_colors_sizes = 
  [ Plot.markers(lon, lat, 
      color = MarkersColor.Values wheat, colorPalette = "Red,Green,Yellow,Blue", 
      size = MarkersSize.Values wheat, sizePalette = MarkersSizePalette.Normalized(5.0, 15.0), 
      shape = MarkersShape.Diamond, 
      displayName = "wheat",
      titles = Titles.markers(color = "wheat production", size = "wheat production")) ] 
  |> Chart.ofList

The shapes petals, bull-eye, boxwhisker allow drawing data
if one of the properties is uncertain. Uncertain variable is represented as a set of quantiles. Particular qualities for each shape are described below.

Petals is a kind of markers when shape indicates level of uncertainty. Data series size is a set of quantiles which must contain lower95 and upper95.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let wheat_uncertain = uwheat |> quantiles "w"

let markers_petals =
  [ Plot.markers(lon, lat, 
      color = MarkersColor.Values wheat_uncertain.median,
      size = MarkersSize.UncertainValues wheat_uncertain, sizePalette = MarkersSizePalette.Normalized(5.0, 15.0),
      displayName = "wheat")] 
  |> Chart.ofList

Bull-eyes is a kind of markers when outer and inner colors indicate level of uncertainty. Data series size is a size in pixels, same for all markers; color is an array of quantiles which must contains median, lower95 and upper95.

1: 
2: 
3: 
4: 
5: 
6: 
let markers_bulleyes =
  [ Plot.markers(lon, lat, 
      color = MarkersColor.UncertainValues wheat_uncertain,
      size = MarkersSize.Value 15.0,
      displayName = "wheat")] 
  |> Chart.ofList

Box-and-whisker plot is displayed if y is uncertain and given as an array of quantiles, which may contain all or some of properties median, lower95, upper95, lower68 and upper68. )

1: 
2: 
3: 
4: 
5: 
let markers_box =
  [ Plot.markers(MarkersX.Values t, MarkersY.UncertainValues y_uncertain, 
    displayName = "p",
    titles = Titles.markers("time", "p"))] 
  |> Chart.ofList

Heatmap displays a graphical representation of data where the individual values contained in a matrix are represented as colors. If the values are uncertain, it allows to see quantiles of each point and highlight regions with similar values. The plot supports NaN as all other plots; corresponding cells are colored with transparent grey.

1: 
2: 
3: 
4: 
5: 
let grid_lon = grid |> col "lon"
let grid_lat = grid |> col "lat"
let grid_value = grid |> col "value"

let heatmap_gradient = [ Plot.heatmap(grid_lon, grid_lat, grid_value) ] |> Chart.ofList
1: 
2: 
3: 
let heatmap_matrix = 
  [ Plot.heatmap(grid_lon, grid_lat, grid_value, treatAs = HeatmapTreatAs.Discrete) ] 
  |> Chart.ofList

Heatmap values also can be uncertain, if they are defined as quantiles containing median, lower68, upper68. The plot displays median values, but if a probe is pulled on the heatmap, the probe card contains "Highlight similar" checkbox which highlights areas of the heatmap with values similar to the value under the probe.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
let ugrid_lon = ugrid |> col "lon"
let ugrid_lat = ugrid |> col "lat"
let ugrid_value = ugrid |> quantiles "value"

let heatmap_uncertain = 
  [ Plot.heatmap(ugrid_lon, ugrid_lat, 
      HeatmapValues.TabularUncertainValues ugrid_value, 
      colorPalette = "blue,white,yellow,orange") ] 
  |> Chart.ofList

See more details about plots here.

Contributing and copyright

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

The library is available under Public Domain license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

Fork me on GitHub