Usage

First import all of the SPlot classes

import xyz.devfortress.splot._

Or in Ammonite-REPL

import $ivy.`xyz.devfortress.splot::splot-core:0.4.0`, xyz.devfortress.splot._

This will bring all of the important implicits into the scope without which this library may not work.

Figure

Central class in the SPlot library is Figure to which plot elements are added and then displayed. Every figure constructor parameter is populated with default values and you can just create it like so

val fig = new Figure()

It is likely, however, that you will not be satisfied with defaults and will supply different values for some of them. For example, following code creates Figure with custom title, labels on both axis, and parameter to display grid.

val fig = new Figure(
  title = "Signal of ...",
  xLabel = "t - time in seconds",
  yLabel = "Signal strength",
  showGrid = true
)

Another common thing to change is figures' domain and range. By default domain and range are set to None, which means that their values are automatically derived from added plot elements. Often, however, you may want to have domain or range fixed. That is acomplished by adding (min, max) tuples to Figure.domain|range values.

val fig = new Figure(
  domain = (-10, 10),
  range = (0.0, 3.0)
)

Ticks on both axis are automatically derived by means of default functions supplied to xTicks and yTicks arguments of Figure constructor. These functions receive range along corresponding axis and return sequence of (Double, String) tuples. First element of these tuples is a position at which tick is to be drawn, and second is corresponding label. Several utility function are available to make it easier to supply custom ticks. To disable all ticks you can supply instance of Ticks created without any arguments.

val fig = new Figure(xTicks = Ticks(), yTicks = Ticks())`

Supplying sequence of numbers or ranges to Ticks(...) will create ticks at predefined positions

val fig new Figure(
  xTicks = Ticks(0, 1, 2, 4, 8, 16),
  yTicks = Ticks(0.0 to 10 by 1.5)
)

Plot elements are added to the figure by calling

fig.add(plotElement: PlotElement)

For many plot elements, however, convenience functions exist in Figure that make adding them much easier.

Line Plot

Like most of the plot elements, line plot is derived from sequence of x-y tuples (Double, Double) where first element is coordinate position along the x-axis and second along the y-axis. Thus given a sequence of data points

val data = Seq((1.0, 1.0), (2.0, 1.3), (3.0, 1.1))

You can plot line plot where every two subsequent points are connected by a line using convenience function Figure::plot(...)

fig.plot(data)

By default black color is used for all plot element, line width is one pixel, and line type is a solid line. That can be changed like so

fig.plot(data, lw = 2, color = "blue", lt = "--")

Parameter lw stands for “line width” and defines width of the line in pixels.

Parameter color is actually of type java.awt.Color but following colors can be passed by implicit conversion from strings "red", "green", "blue", "black", "cyan", "gray" "lightgray", "magenta", "orange", "pink", "white", "yellow".

Likewise, line type (“lt”) is of type LineType and can be one of SOLID, DASHES, DASHES_AND_DOTS, DOTS and that can also be expressed by corresponding strings "-", "--", "-.", "."

Alternatively, you can use LinePlot class, which is a PlotElement, and add it to the figure like so:

fig.add(LinePlot(data))

Scatter Plot

Scatter plot display data as set of points. It can be added by using PointPlot class:

fig.add(PointPlot(...))

or using convenience function Figure::scatter(...)

fig.scatter(data)

Several different point types/shapes can be used with it. Default is PointType.Dot. For example, following will plot scatter-plot using unfilled circles of radius 9 pixels:

fig.scatter(data, pt = "o", ps = 9)

Parameter pt stands for “point type”, ps for “point size”. Like for color, for point type there should be in scope explicit conversion from string into PointType instances, which are Dot, Cross, X, Square, Diamond and Circle and their corresponding string names ".", "+", "x", "s", "d" and "o". Square, diamond and circle are drawn as unfilled shapes, which means that they are drawn as outlines and parameter color refers to the color of that outline. To make them filled objects one needs to set fc (fill color) parameter which by default is set to None. In addition you can set transparency of the fill color by changing fa (fill alpha) which varies from 0.0 (full transparency) to 1.0 (fully opaque, default value). This value of alpha however does not affect transparency of outline. If outline is too obscuring, it can be made filly transparent while fill a semi-transparent like so:

fig.scatter(data, pt = "d", ps = 9, fc = "blue", fa = 0.01, color = new Color(0, 0, 0, 0))

The 4th parameter passed to Color constructor is alpha; 0 value meaning fully transparent.

PointType.Dot is a special type drawn as just filled square without outline and setting fa for such plots does affect its transparency while fc parameter has no effect.

ZScatter Plot

Similar to scatter plot, color of the point is derived from supplied colormap and zValue array.

Rectangle

Rectangle plot is a variant of Shape plot that draws rectangles. At minimum one needs to supply anchor point (lower left corner of rectangle), and rectangle width and height.

fig.rectangle(anchor = (5, 6), width = 2, height = 3)

By default rectangle will be drawn as outline of solid blue line with width of one pixel. All of these parameters can be explicitly set

fig.rectangle(
  anchor = (5, 6),
  width = 2,
  height = 3,
  lw = 2,
  lt = "-.", // dashes and dots
  fillColor = "yellow",
  alpha = 0.2 // semi-transparent
)

Bar Plot

Bar plot is a composite plot assembled from many rectangles. In order to display properly it is required to pass data sequence sorted along the x-axis. For each point it draws filled rectangle from 0 on the y-axis up to the y value for this point. By default width of these bars/rectangles fills up to the next point, i.e. there are no gaps between bars.

fig.barplot(data)

Default fill color is yellow and edge color is black drawn as solid lines of one pixel width. Fill color is fully opaque. Like for other plots default parameters can be overriden, as in the following example:

fig.barplot(data, color = "cyan", edgeColor = "blue", edgeWidth = 2, alpha = 0.1)

Notice that here color parameter sets fill color. By setting edgeWidth to 0 one can remove outline altogether.

Width of the bars and if there is gap between them is controlled by width parameter which is a function that returns width of the bar when called. For each bar it receives distance to the next data point and returns distance to be used for drawing current bar. Default function is identity, which means that bars are drawn edge to edge without any space between bars. Thus we can introduce fixed width for bars like so

fig.barplot(data, width = _ => 0.7)

and flexible gap between bars like so

fig.barplot(data, width = w => 0.7 * w)

Heat-map Plot

Heatmap like plot is made by adding ZMapPlot object to the figure or using convenience function map(...). This plot is defined at minimum by supplying f: (Double, Double) => Double function that maps arbitrary point in xy-plane into some value and parameters xDomain: (Double, Double) and yDomain: (Double, Double) that define rectangular overarching domain on which supplied function f(x, y) is assumed to be defined. This domain can farther be shaped by use of inDomain function (see below).

At any zoom level for every pixel of the plot x and y coordinates are computed and, assuming that they fall within defined domain, z value f(x,y) is computed and a color picked from provided colormap (default is viridis).Thus, assuming that f(x,y) function is defined, the simplest map plot defined on a certain rectangle can be drawn like so

def f(x: Double, y:Double): Double = { ... }

fig.map(f, xDomain = (0, 10), yDomain = (0, 1))

By default at the time of plotting this plot range of the z-values will be recorded and complete color map range will be mapped to this range. This sometimes can lead to abrupt changes in color when varying configuration parameters of f function. To fix mapping of z values to colormap range one can pass explicitly zRange value. For example, following code maps range of z-values from 0 to 10 into provided colormap.

fig.map(f, xDomain = (0, 10), yDomain = (0, 1), zRange = (0, 10))

Note that doing so clips color value derived from z-values that fell outsize of this range to the lower and upper bounds of colormap.

Colormap is a function Double => java.awt.Color that maps numbers in range [0,1] into some color. By default map(...) receives viridis colormap. The only other available colormap is inferno. It can be set like so:

fig.map(f, xDomain = (0, 10), yDomain = (0, 1),  colorMap = colormaps.inferno)

Setting inDomain parameter to custom function allow users to farther restrict domain of the plot and make it non-rectangular. For example, we can define square domain with round hole of diameter 1 like so:

fig.map(
    f, xDomain = (-10, 10), yDomain = (-10, 10),
    inDomain = (x, y) => x * x + y * y > 1
)

Shape Plot

Arbitrary closed shapes can be drawn by adding Shape objects to Figure. No convenience function exist to aid in their creation.