Not being a gnuplot expert (last time I used it was like 25 years ago) and having had some useful applications of Common Lisps :vgplot
package, this time I wanted to create a heatmap and - to my surprise - I could not find out, how to do it - even after 2 hours of googling and tinkering.
I use sbcl in the usual emacs-slime combo on a debian system.
Loading vgplot
:
(ql:quickload :vgplot)
From reading the sources on github and from googling for heatmap examples for "naked" gnuplot, I deduced, that I probably have to use the (vgplot:surf)
function, which uses splot
under the hood.
And indeed - I see a 3d mesh plot, when running the function bla
below:
(defun bla ()
(let* ((xy-range (vgplot:range 0 10))
(xx (vgplot:meshgrid-x xy-range xy-range))
(yy (vgplot:meshgrid-y xy-range xy-range))
(zz (vgplot:meshgrid-map #'+ xx yy)))
(vgplot:surf xx yy zz)))
From reading the gnuplot google results, some "pm3d" thing showed up without explanation and I think I need to use (vgplot:format-plot nil "<something>")
to turn the figure into a heatmap but I could not find out, what exactly I need to do.
Hoping I am not the only one using vgplot
, I am optimistic, that it is an easy answer for anyone who uses this regularly.
You probably want to use the palette-mapped three-dimensional mode pm3d
of gnuplot. This mode maps three-dimensional data to a color palette, and you can set the view
to the map
option to place the viewpoint above the surface.
Here is an example from the vgplot documentation which has been adapted to display as a heatmap:
;; Adapted from vgplot documentation for SURF function.
;; Example 3: Plot a function z = f(x,y), e.g. the sombrero function:
(defun example-3-heatmap ()
(let* ((eps double-float-epsilon)
(fun #'(lambda (x y)
(/ (sin (sqrt (+ (* x x) (* y y) eps)))
(sqrt (+ (* x x) (* y y) eps)))))
(x (vgplot:range -8 8 0.2))
(y (vgplot:range -8 8 0.2))
(xx (vgplot:meshgrid-x x y))
(yy (vgplot:meshgrid-y x y))
(zz (vgplot:meshgrid-map fun xx yy)))
;; Set color palette:
(vgplot:format-plot
nil
"set palette model RGB defined ( -1 'web-green', 0 'goldenrod', 1 'red' )")
;; Put gnuplot in pm3d mode:
(vgplot:format-plot nil "set pm3d")
(vgplot:format-plot nil "set hidden3d") ; render opaque surface
(vgplot:format-plot nil "set view map") ; view from above
(vgplot:surf xx yy zz)))
Here format-plot
is used to send a command to gnuplot
that sets up a palette, then format-plot
is used to put gnuplot
into pm3d
mode, rendering an opaque surface viewed from above.
Philipp Janert has a good book called Gnuplot in Action with a section about creating false-color plots (which are heatmaps).
Here is sample output from the above example code: