using Gaston
Tutorial
If you have not installed Gaston yet, then run the following commands in the Julia REPL:
import Pkg.add
Pkg.add("Gaston")
Load Gaston with:
The plots below have been rendered in a png
terminal with the following configuration:
= "pngcairo font ',10' size 640,480" Gaston.config.term
We need to specify that the plot examples below will be rendered to a document and not a GUI window:
= :echo Gaston.config.output
In addition, gnuplot’s startup file is as described in the Introduction.
Getting started
Let’s start with a simple sine wave plot:
= range(0, 0.5, length = 100)
x = sin.(2*pi*10*x)
y plot(x, y)
Now, let us add a grid and some annotations:
@plot {grid, title = Q"{/:Bold A sine wave}", xlabel = Q"Time", ylabel = Q"Volts"} x y
Here we have used @plot
instead of plot
, which allows us to specify the plot settings as a list of keyword arguments. These arguments can be stored in a “theme” using the @gpkw
macro:
= @gpkw {grid, title = Q"{/:Bold A sine wave}", xlabel = Q"Time", ylabel = Q"Volts"} settings
In addition, we have used the Q
string macro to avoid typing single quotes; Q"Time"
is converted to "'Time'"
.
Now let us change the line color and markers:
@plot settings x y {with = "lp", lc = Q"sea-green", pt = :ecircle, pn = -16, ps = 1.5}
Parameters that affect how the curve is plotted are specified after the data. These can also be stored and reused, so that
= @gpkw {with = "lp", lc = Q"sea-green", pt = :ecircle, pn = -16, ps = 1.5}
plotline @plot settings x y plotline
would produce the exact same plot. Settings and plotline parameters can also be specified as strings; see the Manual for all the details. Gaston also has a number of built-in plot styles, showcased below.
One of the keyword arguments used above is a little peculiar: pt = :ecircle
. Gnuplot wants point types to be specified as integers, so :ecircle
(stands for “empty circle”) should not be valid. The explanation is that Gaston parses some keyword arguments to provide a more comfortable syntax. In this case, Gaston converts point types specified as symbols according to the table provided here. It is easier to remember that an empty circle is specified as :ecircle
(or a full square as :fsquare
) than as “6” (or “5”).
A plot
command can only generate a single curve. Use plot!
or @plot!
to append a curve:
@plot(settings,
= Q"Two sinusoids", key = "columns 1", key = "box outside right top"},
{title
x, y,= "'sin'"})
plotline, {title = cos.(2*pi*10*x)
y2 @plot! x y2 {dashtype = Q".-.", lw = 2, lc = Q"orchid", title = Q"cos"}
Here we see how multiple settings and plotline arguments can be combined. Note that any axis settings used in plot!
are ignored.
Plotting functions
In the examples above, the data given to plot
is stored in vectors. Functions can be plotted directly, with a given range and number of samples, as follows:
g(x) = exp(-abs(x/5))*cos(x) # function to plot
= "set title 'g = x -> exp(-abs(x/5))*cos(x))'"
tt plot(tt, (-10, 10, 200), g) # plot of g from x = -10 to 10, using 200 samples
Ranges can be specified in the following alternative ways:
plot(g) # 101 samples, from -10 to 10
plot((a, b), g) # 101 samples, from a to b
plot((a, b, c), g) # c samples, from a to b
plot(x, g) # g.(x)
A note on side effects
Plot commands return a value of type Gaston.Figure
. When values of this type are displayed, Julia’s display system calls gnuplot behind the scenes to generate the actual plot. Plots are never generated as side effects the way they are, for example, in Matlab.
This means that, for example, the following code does not display any plots:
= 1
i while (i < 10)
plot(x, i.*y)
+= 1
i end
Calling the function g
below does not produce any plots either:
function g(x, y)
plot(x, y)
println("Done.")
end
The easiest way to “force” a piece of code to generate a plot is to call display
explicitly:
= 1
i while (i < 10)
plot(x, i.*y) |> display
+= 1
i end
Variables that store plots
Naturally, values of type Figure
can be stored in variables and manipulated as any other Julia value:
function g(x, y)
= plot(x, y)
f println("Done.")
return f
end
Internally, Gaston keeps references to all Figure
values it has produced. If there are one or more, one of them is active in the sense that all subsequent plot
and plot!
commands will target that figure. The active figure can be obtained with:
figure()
and the figure f
can be made active with:
figure(f)
A new empty figure can be instantiated with the Figure
constructor, as in f = Figure()
. The new figure is automatically made the active figure.
Multiplots
A convenient, automatic method to create multiplot figures is provided. First, instantiate a new figure like this:
= Figure(multiplot = "title 'Auto Layout'"); f
When a figure contains more than one axis, it is rendered using set multiplot
. The multiplot
keyword argument provides a flexible way to specify additional settings specific to multiplots. The figure f
will be rendered by gnuplot using
set multiplot title 'Auto Layout'
Axes can be added by indexing into the figure:
plot(f[1], x, y) # plot x vs y in the first axis
plot(f[2], x, sinc.(10x)) # plot sinc(10x) in the second axis
It is possible to have empty “slots”:
plot(f[4], x, sinc.(20x), "w lp pn 12") # the third axis is empty
Note that Gaston tries to keep a square figure aspect ratio as more and more axes are included.
Add another curve to an axis using indexing:
plot!(f[2], x, 0.3randn(length(x))) # add noise curve to second axis
A different way to generate a multiplot is to call plot
on two or more figures, creating a new figure that contains the axes of all arguments, as in this example:
= Figure()
f1 = Figure()
f2 plot(f1, "set title 'sin'", sin)
plot(f2, "set title 'cos'", cos)
plot(f1, f2)
A trick that may be useful in some cases is pushing an axis from one figure to a different figure:
plot(f1, "set title 'sin'", sin)
plot(f2, "set title 'cos'", cos)
plot(f2[2], "set title 'tan'", tan)
push!(f1, f2[2]) # inserts plot of tan into f1
To get full control of the layout, pass the argument autolayout = false
to Figure
:
= Figure("title 'Arbitrary multiplot layout demo'", autolayout = false)
f = randn(100)
x = randn(100)
y @plot(f[1], {margins = (0.1, 0.65, 0.1, 0.65)},
x, y,"w p pt '+' lc 'dark-green'")
@gpkw histogram(f[2],
= (0.7, 0.95, 0.1, 0.65), tics = false},
{margins
y,= Q"dark-green"}, nbins = 10, horizontal = true)
{lc @gpkw histogram(f[3],
= (0.1, 0.65, 0.7, 0.9), boxwidth = "1 relative"},
{margins
x,= Q"dark-green"}, nbins = 10) {lc
Note that the margins
keyword followed by a tuple is parsed as (see here):
"""set lmargin at screen 0.7
set rmargin at screen 0.95
set bmargin at screen 0.1
set tmargin at screen 0.65
"""
Closing figures
We can close all figures created so far with
closeall()
This command closes all gnuplot processes started by Gaston and closes all figures. Close figure f
with
close(f)
3-D Plots
Plotting in 3-D is similar to 2-D, except that splot
(and @splot
, splot!
, @splot!
) are used instead of plot
. This example shows how to plot the surface defined by function s
:
= y = -15:0.2:15
x = (x,y) -> @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
s @splot "set title 'Sombrero'" "set hidden3d" {palette = :cool} x y s "w pm3d"
The palette cool
is defined in ColorSchemes. Together with the palette
keywork, any color scheme from that package can be used simply by prepending its name with :
.
Plotting in text terminals
It is often convenient to generate plots directly in the terminal. Gnuplot supports a few different ways to do this:
sixelgd
uses sixels to generate plots almost identical to those produced by regular GUI terms:block
uses Unicode characters to draw a plot in the terminal:
Note that, in all cases, Gaston must be configured for terminal output with
= :echo Gaston.config.output
There are other text terms, such as dumb
, but in general those produce output of worse quality than sixelgd
and block
.
Plotting with strings and dates
Besides numerical arrays and ranges, Gaston can also plot arrays of strings, as shown in the following example:
= 10*rand(10)
x = 10*rand(10)
y = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]
w plot(x, y, w, "w labels")
Julia’s Date
type can be plotted by converting it to strings, and using gnuplot’s date support. The following code is inspired in this example.
using Dates
= Date(2018, 1, 1):Day(1):Date(2019, 12, 31)
dates = 0.5*rand(length(dates))
ta = "%Y-%m-%d"
timefmt = "%Y-%m-%d"
pfmt = string.(dates) # convert dates to strings
tempo = "2018-02-01"
xmin1 = "2019-04-01"
xmax1
@gpkw settings = {xdata = "time",
= "'$(timefmt)'",
timefmt
grid,= "x '$(pfmt)'",
format = "rotate by -35",
xtics = "['$(xmin1)':'$(xmax1)']",
xrange = (-0.25, 0.75)}
yrange plot(settings, tempo, ta, "u 1:2 w l t 'Activity per day'")
Plotting using Latex
Gnuplot provides a few different ways to interface with Latex. This example shows how to do it using the cairolatex
terminal. The process is as follows: first, generate a plot and save it using term = cairolatex
. This generates two files: the plot without any text, tics, or markings, in pdf format, and a .tex
file that can be included in a Latex document. This file will add text to the pdf image using Latex, resulting in a plot that integrates well with the rest of the document.
First, generate the plot. Note that the Latex string equation
is added as a label to the plot, causing Latex to render it.
= raw"""\begin{minipage}[c]{\textwidth}\begin{equation*}""" *
equation raw"""\sin(x) = \sum_0^{+\infty} \frac{(-1)^n}{(2n + 1)!} x^{2n+1}""" *
raw"""\end{equation*} \end{minipage}"""
= @gpkw { title = Q"Polynomial approximation of sin(x)",
s = "fill transparent solid 0.6 noborder",
style = (positions = [-pi, -pi/2, 0, pi/2, pi],
xtics = [raw"$-\pi$", raw"$-\pi/2$", "0", raw"$\pi/2$", raw"$\pi$"]),
labels = (-3.8, 3.8),
xrange = (-1.5, 1.5),
yrange = "box opaque left horiz",
key = :YlOrBr_7,
linetype = "front",
grid = "at graph 0.62,0.2 front center '$equation'" }
label = range(-2pi, 2pi, 1000)
x = sin.(x)
y @plot s x y x "w filledcurve t 'n=0' lt 1"
@plot! x y x .- x.^3/6 "w filledcurve t 'n=1' lt 2"
@plot! x y x .- x.^3/6 .+ x.^5/120 "w filledcurve t 'n=2' lt 3"
@plot! x y x .- x.^3/6 .+ x.^5/120 .- x.^7/5040 "w filledcurve t 'n=3' lt 4"
@plot! x y "w l t 'sin(x)' lw 2 lc rgb 'black'"
save(term="cairolatex pdf input color dashed size 5in,3.3in", filename = "test.tex")
This code creates two files, test.tex
and test.pdf
, which can be used to generate a final pdf plot by compiling the following script with pdflatex
:
\documentclass{article}
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage{color}
\begin{document}
\begin{figure}
\input{test.tex}
\end{figure}
\end{document}
The finished plot looks like this:
Other gnuplot terminals, such as tikz
, epslatex
, etc, can be used with similar workflows. This example is inspired in this code.
Gnuplot datasets and tables
Some kinds of plots require a way to specify exactly what points to plot in a specific format (instead of relying on Gaston to format the data the right way). This can be accomplished with Gaston.Datatable
, which wraps IOBuffer
. The contents of Datatable
are provided to gnuplot without any further processing.
One example is drawing contour lines on a heatmap (taken from this gnuplot blog post). The function Gaston.plotwithtable
returns a Gaston.DataBlock
, which can be used as an argument to plot
.
# define function to plot
= y = range(-5, 5, 100)
x f4(x,y) = sin(1.3x) * cos(0.9y) + cos(0.8x) * sin(1.9y) + cos(0.2x*y)
# obtain function contours using 'plot with table'
= """set contour base
settings set cntrparam level incremental -3, 0.5, 3
unset surface"""
= Gaston.plotwithtable(settings, x, y, f4)
contours
# calculate meshgrid for heatmap plot
= Gaston.meshgrid(x, y, f4)
z
# plot heatmap and contours
plot("""unset key
unset colorbox
set palette rgbformulae 33,13,10""",
"with image")
x, y, z, plot!(contours, "w l lw 1.5 lc 'slategray'")
Another example is drawing polygons or polytopes, where the data provided to gnuplot are the coordinates of the vertices of each face, and faces are separated by newlines. The following example (adapted from the demos in gnuplot’s official site) draws an icosahedron using the plotline with polygon
.
# The icosahedron has twelve vertices, given by these coordinates
= (1 + sqrt(5)) / 2
phi = ( ( 0, 1, phi), #1
ico 0, 1, -phi), #2
( 0, -1, phi), #3
( 0, -1, -phi), #4
( 1, phi, 0), #5
( 1, -phi, 0), #6
( -1, phi, 0), #7
(-1, -phi, 0), #8
(0, 1), #9
( phi, -phi, 0, 1), #10
(0, -1), #11
( phi, -phi, 0, -1) #12
(
)# plot settings
= """unset border
s unset key
set view equal xyz
unset xtics
unset ytics
unset ztics
set pm3d depthorder
set pm3d interpolate 1,1 flush begin noftriangles border linecolor rgb "black" linewidth 2 dashtype solid corners2color mean
set title "An icosahedron drawn as 20 individual faces"
set style fill transparent solid 0.8
set view 69, 33
"""
# write the vertices that make up each face in a Datatable
= Gaston.DataBlock(stack([ico[i] for i in (1, 5, 7)], dims=1),
faces stack([ico[i] for i in (1, 7, 10)], dims=1),
stack([ico[i] for i in (1, 10, 3)], dims=1),
stack([ico[i] for i in (1, 3, 9)], dims=1),
stack([ico[i] for i in (1, 9, 5)], dims=1),
stack([ico[i] for i in (2, 5, 11)], dims=1),
stack([ico[i] for i in (2, 11, 4)], dims=1),
stack([ico[i] for i in (2, 4, 12)], dims=1),
stack([ico[i] for i in (2, 12, 7)], dims=1),
stack([ico[i] for i in (2, 7, 5)], dims=1),
stack([ico[i] for i in (8, 3, 10)], dims=1),
stack([ico[i] for i in (8, 10, 12)], dims=1),
stack([ico[i] for i in (8, 12, 4)], dims=1),
stack([ico[i] for i in (8, 4, 6)], dims=1),
stack([ico[i] for i in (8, 6, 3)], dims=1),
stack([ico[i] for i in (7, 12, 10)], dims=1),
stack([ico[i] for i in (6, 4, 11)], dims=1),
stack([ico[i] for i in (5, 9, 11)], dims=1),
stack([ico[i] for i in (9, 6, 11)], dims=1),
stack([ico[i] for i in (9, 3, 6)], dims=1))
# plotline
= "with polygons fc rgb 'gray'"
wp # splot is used since the icosahedron is 3-D
splot(s, faces, wp)
Gaston provides a few Datatable
constructors, described in the Manual.
Animations
Animations require using a terminal that support them; the gif
or webp
terminals are the most popular ones (make sure your notebook supports the image/webp
MIME type before using it).
Creating an animation is similar to multiplotting: multiple axes are drawn on the same figure. When the gnuplot terminal contains the animate
option, however, the plot is rendered as an animation.
Note that gnuplot will output a message to STDERR
indicating how many frames were recorded; this message is purely informative and not actually an error.
The following examples illustrate how to create and display animations, in this case with a background image:
= 75 # number of animation frames
frames # new, empty figure
= Figure()
f # create a background curve that is shown in all frames
= range(-1, 1, 200) # x values for the background image
x_bckgnd = sin.(2π*2*x_bckgnd)
y_bckgnd = Gaston.Plot(x_bckgnd, y_bckgnd, "lc 'black'") # background curve
bckgnd # generate all frames
= range(-1, 1, frames)
x for i in 1:frames
# first plot the function...
plot(f[i], x[i], sin(2π*2*x[i]), "w p lc 'orange' pt 7 ps 7")
# ... then add the background
push!(f[i], bckgnd)
end
for i in frames:-1:1 # in reverse
plot(f[2frames-i+1], x[i], sin(2π*2*x[i]), "w p lc 'orange' pt 7 ps 7")
push!(f[2frames-i+1], bckgnd)
end
save(f, filename = "2DAnim.webp", term = "webp animate loop 0 size 640,480")
First, an empty figure f
is created with Figure()
. Then, Gaston.Plot
is used to create an object, bckgnd
, which contains a curve (a black sine wave) and which can be inserted into an axis. Every loop iteration, a new axis is inserted into f
with plot(f[i], ...)
with a curve consisting of an orange circle somewhere along the sine wave. Then, the background curve is inserted into the same axis with push!(f[i], bckgnd)
. Finally, the plot is saved in a format that supports animation (webp
in this case).
A difficulty arises when mixing plot formats in a notbook (say, png
and webp
): the terminal is specified in the configuration variable Gaston.config.term
. However, some notebook programs (such as Pluto) execute cells in arbitrary order. This means that changing the terminal in one cell may affect other cells.
To solve this problem, Gaston provides a way to ignore the global terminal configuration when rendering a plot. A figure f
can be rendered with a given terminal by calling animate(f, term)
. The default value of term
is stored in Gaston.config.altterm
and defaults to gif animate loop 0
. Examples are provided in these interactive Pluto notebooks.
Themes
Gaston supports themes, which are pre-configured plot styles. There are two kinds of themes: settings themes, which specify gnuplot set
commands, and plotline themes, which specify how a particular curve is displayed (color, thickness, etc.) Settings themes are stored in the dictionary Gaston.sthemes
, and plotline themes are stored in Gaston.pthemes
. The themes in these dictionaries can be modified, and new themes can be stored in them. Built-in themes used to create common plot styles (such as scatter
and stem
) are described in the next section.
Gaston also includes a few settings themes that conveniently define common configurations:
theme | purpose |
---|---|
:notics |
Remove all tics from the plot. |
:labels |
Label axes using x , y , and z (for splot ) |
:unitranges |
Set x , y , and z ranges to [-1:1] |
:nocb |
Disable the colorbox |
This example shows how to use these themes:
plot(:notics, :labels, "set grid", sin)
Included plot styles
Gaston includes several themes for common plot styles. The easiest way to use them is through the specialized plot commands described below. For more details, see the manual.
The themed commands described below use combinations of these themes to create a specific type of plot.
Note that, in gnuplot, plotlines (as in with lines linecolor 'green'
) are especially difficult to theme, because repeated options (and options given in the wrong order) are errors. It is recommended to keep plotline themes very simple, and specify the plotline manually as part of the plot command.
The following subsections cover all included plot styles, along with the list of built-in themes they rely on, as well as some examples.
Scatter plots
command | settings theme | plotline theme |
---|---|---|
scatter |
none | :scatter |
scatter3 |
:scatter3 |
:scatter |
= randn(20)
xg = randn(20)
yg scatter("set title 'Scatter plot'
",
set key outside
xg, yg,"title 'gaussian'")
= rand(20)
xu = rand(20)
yu scatter!(xu, yu, "title 'uniform'")
A 3-D scatter plot (the default settings theme (:scatter3
) draws all the borders):
scatter3("set title 'A 3-D scatter plot", randn(10), randn(10), randn(10))
Stem plots
command | settings theme | plotline theme |
---|---|---|
stem |
none | :stem , :impulses |
Stem plots are often used in digital signal processing applications to represent a discrete-time (sampled) signal.
stem("set title 'Stem plot'", g)
To generate a stem plot, gnuplot actually plots twice: once with style impulses
and once with points
(set to empty circles). Normally, each of these plots would have a different color. To use the same color for both, use the color
keyword argument:
stem("set title 'Stem plot'", g, color = "'goldenrod'")
The circular marks can be omitted with the onlyimpulses
keyword argument:
stem("set title 'Stem plot with onlyimpulses'", g, onlyimpulses = true)
Bar plots
command | settings theme | plotline theme |
---|---|---|
bar |
:boxplot |
:box |
barerror |
:boxerror |
:box |
bar("set title 'Bar plot'", rand(10), "lc 'turquoise'")
This example shows how to plot two sets of bars, using bar!
:
bar("set title 'Two bar plots'", rand(10), "lc 'dark-violet'")
bar!(1.5:10.5, 0.5*rand(10), "lc 'plum' fill pattern 4")
Error bars are handled by barerror
; there is also barerror!
.
barerror("set title 'Error bars plot'", 1:10, rand(10), 0.1*rand(10).+0.1, "lc 'sandybrown'")
Histograms
command | settings theme | plotline theme |
---|---|---|
histogram |
:histplot |
:box , :horhist (1-D); :image (2-D) |
The histogram
function takes these optional keyword arguments:
nbins
: specifies the number of bins. Defaults to 10.mode::Symbol
: Controls histogram normalization mode; passed toStatsBase.normalize
. Defaults to:none
.edges
: a vector or a range specifying the bin edges; if specified, takes precedence overnbins
. Defaults tonothing
.horizontal::Bool
: iftrue
, the histogram is drawn horizontally. Defaults tofalse
.
histogram
uses the settings theme :histplot
, and plotline themes :box
or :horhist
. 2-D histograms are supported, by passing two datasets.
Using nbins
:
histogram("set title 'Histogram (nbins)'",
randn(10_000),
= 20, mode = :pdf) nbins
Using edges
:
histogram("set title 'Histogram (edges)'",
0.75*randn(10_000),
= -2:0.75:3, "lc 'dark-khaki'") edges
A horizontal histogram:
histogram("set title 'horizontal histogram'",
rand(1000),
= 15, horizontal = true, "lc 'orchid'") nbins
In the case of 2-D histograms, nbins
or egdes
may be a tuple; otherwise, both axes use the same settings. The plotline theme is :image
.
= 2.5*randn(100_000)
x = 2.5*randn(100_000)
y = @gpkw {palette = :matter, colorbox = false, title = Q"2-D histogram",
th = (-10, 10), yrange = (-10, 10)}
xrange histogram(th, x, y, nbins = 50, mode = :pdf)
Images
command | settings theme | plotline theme |
---|---|---|
imagesc |
:imagesc |
:image , :rgbimage |
Arrays may be plotted as images using imagesc
. Note that, in contrast to other plotting packages, the first data row is plotted horizontally and at the top.
= [0 1 2 3;
X 0 3 2 1;
0 2 2 0;
3 0 0 0]
imagesc("unset xtics", "unset ytics", X)
To display the image as grayscale, use the gray
palette.
using Images, TestImages
= testimage("lake_gray");
img = channelview(img)[1,:,:].*255;
ii @gpkw imagesc({palette = :gray}, ii)
An RGB image is a plot of a 3-D array, where [1,;,:]
is the red channel, [2,:,:]
is the green channel, and [3,:,:]
is the blue channels.
= testimage("lake_color")
img @gpkw imagesc({size = "square", autoscale = "fix"}, channelview(img).*255)
Surfaces
command | settings theme | plotline theme |
---|---|---|
wireframe |
:hidden3d |
none |
surf |
:hidden3d |
:pm3d |
A surface can be plotted as a “wireframe” (or a “mesh”) with the wireframe
command. By default, hidden3d
is active, so that elements behind the surface are not plotted.
g(x,y) = sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
= @gpkw {title = Q"Sombrero Wireframe", palette = :matter}
th wireframe(th, (-15, 15, 30), g)
Solid surfaces are plotted with surf
:
= @gpkw {title = Q"Sombrero Surface", palette = :matter}
th surf(th, (-15, 15, 200), g)
When plotting a function and a single range (such as (-15, 15, 200)
above) is given, it is used for both x
and y
coordinates. Two ranges may be given as well to control the x
and y
ranges separately:
surf(th, (-15, 15, 200), (-25, 5, 200), g)
Contour plots
command | settings theme | plotline theme |
---|---|---|
contour |
:contour |
:labels |
surfcountour |
:contourproj |
:labels |
By default, contour plots include numerical labels:
h(x,y) = cos(x/2)*sin(y/2)
contour("set title 'Contour Plot'", (-10, 10, 50), h)
To plot contours without labels, use the keyword argument labels = false
:
contour("set title 'Contour Plot Without Labels'", (-10, 10, 50), h, labels = false)
It’s possible to plot a wireframe surface and a contour projected on the base of the plot using surfcountour
:
surfcontour("set title 'Surface With Projected Contours'", (-5, 5, 40), h, "lc 'orange'")
The same plot without contour labels:
surfcontour("set title 'Surface With Contours, No Labels'",
-5, 5, 40), h, "lc 'orange'", labels = false) (
Heatmap plots
command | settings theme | plotline theme |
---|---|---|
heatmap |
:heatmap |
:pm3d |
= @gpkw {palette = :matter, title = Q"Heatmap"}
theme heatmap(theme, :notics, :nocb, :labels, (-10, 10, 70), h)