Plot recipes
A plot recipe is a quicklook visualization procedure aimed at reducing the amount of repetitive code to generate a plot. More specifically, a recipe is a function that convert the plot specs from the "Julia world" into a form suitable to be ingested in gnuplot, namely a Vector{<: AbstractGPSpec})
(see also Gnuplot.jl internals). The latter contain informations on how to create a plot, or a part of it, and can be used directly as arguments in a @gp
or @gsp
call.
There are two kinds of recipes:
explicit recipe: a function which is explicitly invoked by the user. It can have any name and accept any number of arguments and keywords. It is typically used when the visualization of a data type requires some extra information, beside data itself (e.g. to plot data from a
DataFrame
object, see Simple explicit recipe);implicit recipe: a function which is automatically called by Gnuplot.jl. It must extend the
Gnuplot.recipe()
function, and accept exactly one mandatory argument. It is typically used when the visualization is completely determined by the data type itself (e.g. the visualization of aMatrix{ColorTypes.RGB}
object as an image, see Image recipes);
An implicit recipe is invoked whenever the data type of an argument to @gp
or @gsp
is not among the allowed ones (see Gnuplot.parseSpecs
documentation). If a suitable recipe do not exists an error is raised. On the other hand, an explicit recipe needs to be invoked by the user, and the output passed directly to @gp
or @gsp
.
Although recipes provides very efficient tools for data exploration, their use typically hide the details of plot generation. As a consequence they provide less flexibility than the approaches described in Basic usage and Advanced usage.
Currently, the Gnuplot.jl package provides only one explicit recipe (line()
) and a few implicit ones. All recipes are implemented in recipes.jl.
Simple explicit recipe
To generate a plot using the data contained in a DataFrame
object we need, beside the data itself, the name of the columns to use for the X and Y coordinates. The following example shows how to implement an explicit recipe to plot a DataFrame
object:
using RDatasets, DataFrames, Gnuplot
function plotdf(df::DataFrame, colx::Symbol, coly::Symbol; group=nothing)
if isnothing(group)
return Gnuplot.parseSpecs(df[:, colx], df[:, coly], "w p notit",
xlab=string(colx), ylab=string(coly))
end
out = Vector{Gnuplot.AbstractGPSpec}()
append!(out, Gnuplot.parseSpecs(xlab=string(colx), ylab=string(coly)))
for g in sort(unique(df[:, group]))
i = findall(df[:, group] .== g)
if length(i) > 0
append!(out, Gnuplot.parseSpecs(df[i, colx], df[i, coly], "w p t '$g'"))
end
end
return out
end
# Load a DataFrame and plot two of its columns
iris = dataset("datasets", "iris")
@gp plotdf(iris, :SepalLength, :SepalWidth, group=:Species)
Corner plot recipe
The following is a slightly more complex example illustrating how to generate a corner plot:
using RDatasets, DataFrames, Gnuplot
function cornerplot(df::DataFrame; nbins=5, margins="0.1, 0.9, 0.15, 0.9", spacing=0.01, ticscale=1)
numeric_cols = findall([eltype(df[:, i]) <: Real for i in 1:ncol(df)])
out = Vector{Gnuplot.AbstractGPSpec}()
append!(out, Gnuplot.parseSpecs("set multiplot layout $(length(numeric_cols)), $(length(numeric_cols)) margins $margins spacing $spacing columnsfirst downward"))
id = 1
for ix in numeric_cols
for iy in numeric_cols
append!(out, Gnuplot.parseSpecs(id, xlab="", ylab="", "set xtics format ''", "set ytics format ''", "set tics scale $ticscale"))
(iy == maximum(numeric_cols)) && append!(out, Gnuplot.parseSpecs(id, xlab=names(df)[ix], "set xtics format '% h'"))
(ix == minimum(numeric_cols)) && append!(out, Gnuplot.parseSpecs(id, ylab=names(df)[iy]))
xr = extrema(df[:, ix])
yr = extrema(df[:, iy])
if ix == iy
h = hist(df[:, ix], range=xr, nbins=nbins)
append!(out, Gnuplot.parseSpecs(id, "unset ytics", xr=xr, yr=[NaN,NaN], hist_bins(h), hist_weights(h), "w steps notit lc rgb 'black'"))
elseif ix < iy
append!(out, Gnuplot.parseSpecs(id, xr=xr, yr=yr , df[:, ix], df[:, iy], "w p notit"))
else
append!(out, Gnuplot.parseSpecs(id, "set multiplot next")) # skip slot
end
id += 1
end
end
return out
end
# Load a DataFrame and generate a cornerplot
iris = dataset("datasets", "iris")
@gp cornerplot(iris)
Histogram recipes
The object returned by the hist()
function can be readily visualized by means of implicit recipes defined on the StatsBase.Histogram
type (in both 1D and 2D) types:
x = randn(1000);
@gp hist(x)
x = randn(10_000);
y = randn(10_000);
@gp hist(x, y)
Contour lines recipes
The object returned by the contourlines()
function can be readily visualized by means of implicit recipes defined on the Gnuplot.IsoContourLines
types:
x = randn(10_000);
y = randn(10_000);
h = hist(x, y)
clines = contourlines(h, "levels discrete 10, 30, 60, 90");
@gp clines
Image recipes
The Gnuplot.jl package provides implicit recipes to display images in the following formats:
Matrix{ColorTypes.RGB{T}}
;Matrix{ColorTypes.RGBA{T}}
Matrix{ColorTypes.Gray{T}}
;Matrix{ColorTypes.GrayA{T}}
;
To use these recipes simply pass an image to @gp
, e.g.:
using TestImages
img = testimage("lighthouse");
@gp img
All such recipes are defined as:
function recipe(M::Matrix{ColorTypes.RGB{T}}, opt="flipy")
...
end
with only one mandatory argument. In order to exploit the optional keyword we can explicitly invoke the recipe as follows:
img = testimage("walkbridge");
@gp palette(:gray1) Gnuplot.recipe(img, "flipy rot=15deg")
Note that we used both a palette (:gray
, see Palettes and line types) and a custom rotation angle.
The flipy
option is necessary for proper visualization (see discussion in Plot matrix as images).