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.