Plotting Data

We will use Zach Beane’s vecto library for plotting data with the results written to files. Ideally we would like to have interactive plotting capability but for the purposes of this book I need to support the combinations of all Common Lisp implementations on multiple operating systems. Interactive plotting libraries are usually implementation and OS dependent. We will use the plotlib example we develop in the later chapter Backpropagation Neural Networks.

Implementing the Library

The examples here are all contained in the directory src/plotlib and is packaged as a Quicklisp loadable library. This library will be used in later chapters.

When I work on my macOS laptop, I leave the output graphics file open in the Preview App and whenever I rerun a program producing graphics in the REPL, making the preview App window active refreshes the graphics display.

PNG file generated by running plotlib test

The following listing shows the file plotlib.lisp that is a simple wrapper for the vecto Common Lisp plotting library. Please note that I only implemented wrappers for vecto functionality that I need for later examples in this book, so the following code is not particularly general but should be easy enough for you to extend for the specific needs of your projects.

 1 ;; Misc. plotting examples using the vecto library
 2 
 3 (ql:quickload :vecto) ;; Zach Beane's plotting library
 4 (defpackage #:plotlib
 5   (:use #:cl #:vecto))
 6 
 7 (in-package #:plotlib)
 8 
 9 ;; the coordinate (0,0) is the lower left corner of the plotting area.
10 ;; Increasing the y coordinate is "up page" and increasing x is "to the right"
11 
12 ;; fills a rectangle with a gray-scale value
13 (defun plot-fill-rect (x y width height gscale) ; 0 < gscale < 1
14   (set-rgb-fill gscale gscale gscale)
15   (rectangle x y width height)
16   (fill-path))
17 
18 ;; plots a frame rectangle
19 (defun plot-frame-rect (x y width height)
20   (set-line-width 1)
21   (set-rgb-fill 1 1 1)
22   (rectangle x y width height)
23   (stroke))
24 
25 (defun plot-line(x1 y1 x2 y2)
26   (set-line-width 1)
27   (set-rgb-fill 0 0 0)
28   (move-to x1 y1)
29   (line-to x2 y2)
30   (stroke))
31 
32 (defun plot-string(x y str)
33   (let ((font (get-font "OpenSans-Regular.ttf")))
34     (set-font font 15)
35     (set-rgb-fill 0 0 0)
36     (draw-string x y str)))
37 
38 (defun plot-string-bold(x y str)
39   (let ((font (get-font "OpenSans-Bold.ttf")))
40     (set-font font 15)
41     (set-rgb-fill 0 0 0)
42     (draw-string x y str)))
43 
44 
45 (defun test-plotlib (file)
46   (with-canvas (:width 90 :height 90)
47     (plot-fill-rect 5 10 15 30 0.2) ; black
48     (plot-fill-rect 25 30 30 7 0.7) ; medium gray
49     (plot-frame-rect 10 50 30 7)
50     (plot-line 90 5 10 5)
51     (plot-string 10 65 "test 1 2 3")
52     (plot-string-bold 10 78 "Hello")
53     (save-png file)))
54 
55 ;;(test-plotlib "test-plotlib.png")

This plot library is used in later examples in the chapters on search, backpropagation neural networks and Hopfield neural networks. I prefer using implementation and operating specific plotting libraires for generating interactive plots, but the advantage of writing plot data to a file using the vecto library is that the code is portable across operating systems and Common Lisp implementations.

Packaging as a Quicklisp Project

The two files src/plotlib/plotlib.asd src/plotlib/package.lisp configure the library. The file package.lisp defines the required library vecto and lists the functions that are publicly exported from the library:

1 (defpackage #:plotlib
2   (:use #:cl #:vecto)
3   (:export save-png plot-fill-rect plot-frame-rect
4      plot-size-rect plot-line plot-string plot-string-bold
5      pen-width))

To run the test function provided with this library you load the library and preface exported function names with the package name plotlib: as in this example:

1 (ql:quickload "plotlib")
2 (plotlib::test-plotlib "test-plotlib.png")

In addition to a package.lisp file we also use a file with the extension .asd

1 (asdf:defsystem #:plotlib
2   :description "Describe plotlib here"
3   :author "mark.watson@gmail.com"
4   :license "Apache 2"
5   :depends-on (#:vecto)
6   :components ((:file "package")
7                (:file "plotlib")))

If you have specified a dependency that is not already downloaded to your computer, Quicklisp will install the dependency for you.