In this tutorial section, the prompt ; -> will indicate output from
gnudl (I will not reproduce most output here, just interesting output
lines); lines in the
example typeface
without ; -> are lines you should type. You can cut the example
sections from this manual and paste them into gnudl.
You can invoke gnudl by typing
gnudl
Also: the demos in this tutorial are all stored in the file "demo.scm",
so you can type (load "demo") in gnudl and it will tell you how
you can run the individual demos.
(define x (indgen 30)) ; -> x x ; -> #(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29)
(indgen n) returns a vector of n numbers, each set equal
to its index in the array. Note the #(0 1 2 3 ...) notation for
vectors used by gnudl:
(define y #(3 2 9.1 4.4)) ; -> y y ; -> #(3 2 9.1 4.4)
(define x (span -10 10 400)) ; -> x x ; -> #(-10 -9.95 -9.9 -9.85 -9.8 -9.75 -9.7 -9.65 -9.6 -9.55 -9.5 -9.45 - ...)
(span min max n-points) returns an array of n-points
numbers, evenly spaced, between min and max.
y by applying the sin function
to the array x:
(define y (sin x)) ; -> y y ; -> #(544.02111088937e-3 501.4051281792e-3 457.53589377532e-3 412.52305791709e-3 ...)Notice how gnudl performs operations on entire vectors with a single instruction by just invoking
(sin x).
(plot x y)The
plot instruction takes arrays of x-y data and plots them in
the graphics window.
(define y (times (sin (times x 8)) (exp (minus (divide x 3))))) (plot x y)
p-multi
instruction:
(p-multi 2 2) (define x (span -4 4 200)) (plot x (sin x)) (plot x (exp x)) (plot x (tan x) '(yrange .(-10 . 10))) (plot x (exp (divide 1 (plus 1 (times x x)))))
Gnudl provides, in the proto4 snapshot, a very elementary surface
plotting mechanism. If you have a height matrix a, which you
could form with
(define a (make-matrix-index (lambda (x y) (* (exp (- (/ (+ (* (- x 5) (- x 5)) (* (- y 5) (- y 5))) 30))) (sin (/ x 2)))) 20 20))
then you can render a surface wire mesh plot with hidden lines using:
(surface a)
Notice that the height matrix a was formed with the
make-matrix-index procedure, which makes a matrix of the given
size (20x20), and fills it with the given procedure:
(lambda (x y)
(* (exp (- (/ (+ (* (- x 5) (- x 5))
(* (- y 5) (- y 5))) 30)))
(sin (/ x 2))))
The procedure is applied to the matrix indices, and it scales down the x and y values (since they are integers).
Right now there are no options for shifting the view angle (should be
easy to add), or for shading the wire mesh (probably harder). The
surface call is a trivial call to gnuplot's splot command,
with the hidden line removal option.
[NOTE: I am still looking for someone to take the lead on 3D work for Gnudl. Talk to Mark Galassi (rosalia@nis.lanl.gov) if you are interested.]
You can also draw a contour plot of the same height matrix with
(contour m)
If you want more contour levels (the default is 6), use
(contour m n-levels)
Like surface, contour is just a pipe to ghostscript right
now, and pretty unsophisticated.
Gnudl provides several routines that generate vectors filled with random numbers satisfying various probability distributions.
p(x) = (1/gamma) * exp(-gamma*x)) is uniquely characterized by
its mean, and the standard deviation is equal to the mean. The gaussian
distribution is given by p(x) = 1/(2*PI*sigma) *
exp(-x*x/(2*sigma*sigma)), and is the classic "bell shaped curve".
(p-multi 2 3) (plot (rnd-vector 100)) (plot (rnd-vector 1000)) (plot (poisson-rnd-vector 100 2.2)) (plot (poisson-rnd-vector 1000 2.2)) (plot (gauss-rnd-vector 100 2.2 1.1 10)) (plot (gauss-rnd-vector 1000 2.2 1.1 10))
(p-multi 3 2) (plot (poisson-rnd-vector 100 2.1)) (plot (poisson-rnd-vector 1000 2.1)) (plot (histogram (poisson-rnd-vector 1000 2.1) 100)) (plot (gauss-rnd-vector 100 2.2 1.1 10)) (plot (gauss-rnd-vector 1000 2.2 1.1 10)) (plot (histogram (gauss-rnd-vector 1000 2.2 1.1 10) 100))
It is nice to create vectors online and play with them, but most of the time experimental scientists will be reading in data from a file. We provide a sample data file with the gnudl distribution, called hete_sample.dat. This file contains actual data from the HETE satellite experiment, organized as X and Y columns of numbers.
(define th-data (read-xy "sample_data/hete_sample.dat")) (p-multi 1 5) ; to see long narrow plots (plot th-data) (plot (car th-data) (smooth (cdr th-data) 7))
read-cols procedure will read from a
file or a pipe if the filename ends with the | (pipe) symbol.
read-cols accepts a format string specifying how the columns
should be interpreted, and returns a list of vectors containing the
various columns of data.
(define th-cols (read-cols "sample_data/hete_time_hist.dat" "%s %s %f %f")) (define th-time (caddr th-cols)) (define th-counts (cadddr th-cols)) (p-multi 1 3) (plot th-time th-counts) (plot th-time (smooth th-counts 3)) (plot (histogram th-counts 300))Notice how we discard the first two columns of data (read in with \%s options) and are picking out using the next two columns of data with the scheme
caddr and cadddr procedures.
The file hete.scm shows a more complete example of data analysis
for the HETE data.
Gnudl has facilities for incorporating pre-made images in a variety of formats into its plotting window. Here are some examples, based on two GIF files supplied with the software:
(p-multi 2 3) (image-gif "t.gif") (image-gif "l.gif")
pov, the
persistence of view raytracer. If you have a .pov file
called file.pov, you can simply run
(image-pov "file.pov")We are considering to use POV raytrace rendering to render 3-dimensional surface plots with shading and hidden lines.
So far you have seen gnudl operate in a mode where it shows x columns
and y rows of plots. But gnudl can have very general plot screens of
all sorts of shapes and sizes: the p-multi procedure is simply a
short cut for more general plot-list management routines.
The underlying mechanism to add a plot to the plot-list is the
plot-list-add procedure. To demonstrate its use, try resetting
the plot list to only have a background plot:
(plot-list-reinit)
now add a plot in the rectangle (100 100 400 300:
(set! default-plot-list (plot-list-add default-plot-list '(100 100 400 300) '() #f '()))
The arguments '() #f '() specify, respectively, that there is no
"hook" procedure to be invoked for this plot; that this plot is
not to be skipped by plot, and that we start with no list
of postscript instructions.
Now add a second plot rectangle
(set! default-plot-list (plot-list-add '(400 400 550 600) '() #f '()))
and reset the current-plot variable with
(reset-current-plot!)
and refresh the screen by typing
(refreshD)
Now try making some new plots:
(define (new-func x) (times (cos x) (sin x))) (define x-vals (span -10 10 500)) (plot (new-func x-vals)) (plot (sin x-vals) (new-func x-vals))
As you see, these plots went into the two rectangles defined with
plot-list-add.
There is another much more general routine for manipulating the
plot-list: boxl->plot-listD takes a box list describing a
full screen layout and uses it to add several plots to the
default-plot-list. The box matrix is a list of nested lists that
describe how many columns and rows should be nested in the various areas
of the plot list.
Box lists are best explained by example; try pasting these in (notice that new-func and x-vals are defined in previous examples):
(boxl->plot-listD '(1)) (plot (times (sin (times 4 x-vals)) (exp (divide x-vals -4))))
(boxl->plot-listD '(3 1 2)) (plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3)))) (plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals)) (plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals)) (plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3)))) (plot ((lambda (x) (times (sin (times 4 x)) (divide 1 (plus 1 (times x x))))) x-vals)) (plot (times (sin (times 4 x-vals)) (exp (divide x-vals 3))))
This will set the plot screen to have three plots in the top row, one in the middle row and two on the bottom row, and show some sample data in those plots.
Try some more complicated box matrices with nested sub-boxes, such as:
(define boxl '( (2 1) (1 3) (1 (1 1)) 1 ((1 2) 1 1)) ) (boxl->plot-listD boxl)
and then make various plots in it (there are 16 plots in this box list).
Gnudl provides a large library (actually it's pretty small right now) of numerical routines that can be applied to data or to functions. More routines can be added by programming them in C or scheme, but in this tutorial I only describe the use of some analysis routines that we provide with guile.
(define v (span -5 5 200)) (define scv (plus (plus (sin v) (sin (times 7 v))) (plus (cos v) (times (sin v) (cos v))))) (define scv-hat (dft scv 1)) (define scv-hat-hat (dft scv-hat -1)) (p-multi 2 2) (plot scv) (plot scv-hat) (plot scv-hat-hat)(there is something weird here).
You have noticed how arithmetic operations and transcendental functions can all be applied to vector data as well as single numbers.
There two more operations which make vector manipulatio powerful and flexible: the where operator and subscripting with a list of indices.
(where vec condition?) returns a list of indices
for which (condition? vec[i]) is true. For example, try:
(define v #(1 10 2 4 12 39 0.8 -5 22.9)) (where v (lambda (z) (> z 2.5))) ; -> (1 3 4 5 8)This tells us that the entries
v[1], v[3], v[4], v[5], v[8] are
greater than 2.5.
vector-ref has been enhanced in
gnudl so that it will take a list or a vector of indices as an argument.
This allows the where operator to become truly powerful.
Continuing where the previous example left off:
(define v #(1 10 2 4 12 39 0.8 -5 22.9)) (define index-list (where v (lambda (z) (> z 2.5)))) (vector-ref v index-list) ; -> #(10 4 12 39 22.9)
(p-multi 2 2) (define pi 3.141592654) (define v (span -7 7 1000)) (define sv (sin v)) (define chopped-ind-list (where sv (lambda (z) (< z 0.7)))) (define new-v (vector-ref v chopped-ind-list)) (define new-sv (vector-ref sv chopped-ind-list)) (plot new-v new-sv) (define gap-ind-list (where v (lambda (z) (or (< z (- pi)) (> z (/ pi 2)))))) (plot (vector-ref sv gap-ind-list))
Gnudl has a command (ps-snapshot plot-list file-name) for saving
postscript
Apart from the standard "x-y plotting" possibilities, gnudl also allows you to splatter arbitrary shapes onto into a plot rectangle. In this mode the coordinates of the objects you draw always range from (0, 0) to (1, 1).
(p-multi 3 3) (add-rect 0 0 0.5 0.5 'blue) (add-rectR 0 0.5 0.6 0.6 'red) ; the R means you refresh after drawing (add-segmentR 0 0 1 1 'green) (add-boxR 0.3 0.3 0.4 0.4 'purple)
Another example shows the use of bar charts:
(p-multi 1 10) (bar-chart-flat (span 0 20 20)) ; all rectangles are the same height (bar-chart (span 0 20 20)) ; height is proportional to the value (bar-chart-flat (sin (span 0 200 200))) (bar-chart (span -10 10 200)) (bar-chart (times 30 (sin (span -10 10 200)))) (bar-chart (times 30 (sin (span -10 10 200))) 'red) ;; now do some bar charts of histograms (define b (span -2 4 2000)) (define esb (times (exp (divide b (- 2))) (sin (times b 8)))) (define hesb500 (histogram esb 500)) (bar-chart (cdr hesb500)) ; the histogram puts the actual data in the cdr (bar-chart (cdr hesb500) 'blue) (define hesb250 (histogram esb 250)) (bar-chart (cdr hesb250)) ; the histogram puts the actual data in the cdr (bar-chart (cdr hesb250) 'blue)
Mark Galassi wrote a package which allows some displaying of cellular
automata as well as displaying results from his ga_ca project. Take a
look at the file ca.scm to see how special-plot and other
constructs are used together to make vignettes of many types of data.