Go to the previous, next section.

In all these examples, we'll use the `del1`

macro discussed
above to keep commands off the history list.
Let's start with a Fourier series, to demonstrate SM's ability
to manipulate vectors. All keywords are capitalised for clarity.
Start SM, choose a plotting device (with
the `dev`

macro), and erase all the commands on the history (or
playback) buffer with `DELETE 0 10000`

. Then type the following
commands:

SET px=-PI/10,2*PI,PI/200 SET y=SIN(px) + SIN(3*px)/3 + SIN(5*px)/5 + SIN(7*px)/7 SET y=(y>0)?y:0 LIMITS -1 7 y BOX CONNECT px yThe vector

`px`

could just as well have been read from a file. You
should now have a part of a square-wave, truncated at 0.
Now consider a simpler way of doing the same thing. For the present, clear
the history buffer again (`DELETE 0 10000`

), and type:

SET px=-PI/10,2*PI,PI/200 SET y=SIN(px) DO i=1,3 { SET val = 2*$i + 1 SET y = y + SIN(val*px)/val } DELETE val LIMITS -1 7 y BOX CONNECT px yHere we use a vector

`val`

to save a value, an equivalent (but
slower) loop using SM variables would be
DO i=1,3 { DEFINE val (2*$i + 1) DEFINE y = y + SIN($val*px)/$val } DEFINE val DELETE

That is all very well if you only ever wanted to sum the first four terms of the series. Fortunately there is a way to change this, using the macro editor. First define a macro consisting of all the commands on the history list:

del1 MACRO all 0 10000will define the macro

`all`

to be history lines 0-10000.
(You need the `del1`

to avoid having the `MACRO all 0 10000`

in
your macro).
Then you can edit it using
del1 MACRO EDIT allwhen you have made the desired changes (e.g. changing

`DO i=1,3`

to `DO i=1,20`

) use ^X to leave the editor and return to the
command editor. Now you could type `all`

to run your new macro,
or put it back onto the history list. To do the latter, delete the
commands now on the history list (the now-familiar `DELETE 0 10000`

),
then `del1 WRITE HISTORY all`

to put the macro `all`

onto the
list. Now the
`playback`

command will run all those commands, and produce a better
squarewave. (As discussed in a moment, `playback`

is a macro so type it
in lowercase, unless you have defined your own `PLAYBACK`

macro.)
This ability to edit the history buffer is convenient, and there is a macro
provided called `edit_hist`

which goes through exactly the steps that we
took you through. The trick of including a `del1`

in macros is
pretty common, for example `h`

is defined as
`del1 HELP`

so that it won't appear on the history list.
The macro `playback`

is rather similar to `edit_hist`

, but instead
of editing and then writing `all`

, it executes it. We discussed
the possibility of just playing back a limited number of lines while
talking about `hcopy`

, just say `playback n1 n2`

.

Now that you have a set of commands which produce a Fourier plot, it
would be nice to define a macro to make plots, taking the number of
terms as an argument, and then free the history buffer for other things.
After a playback, the macro `all`

is defined, so let's change its
name to `square`

. There is a macro `ed`

defined more-or-less as
`del1 MACRO EDIT`

, so type `ed all`

to enter the macro editor.
Use
or ^P to get to line 0 and
change the number of arguments from 0 to 1, and the name of the macro
from `all`

to `square`

(the space between the name and the : is
required.) Then go to the `DO i=1,20`

line, and change `20`

to
`$1`

. Exit with ^X, clear the screen with `era`

and
type `square 10`

. Now how do you
save your nice macro? `WRITE MACRO square filename`

will write it
to file ``filename'`, and next time you run SM
`MACRO READ filename`

will define it. In fact there is a command `SAVE`

to save everything
which can be a mindless way of proceeding.
A macro similar to this Fourier macro called `square`

is in the file `demos`

in the default macro directory (and was used to
produce the top left box of the cover to this manual). To try it yourself, type
something like `load demos square 20`

. (`20`

is the number of
terms to sum.)

If your wondering why `ed`

is only `more-or-less' defined as `del1 MACRO EDIT`

, it's because the real `ed`

checks to see if you
have provided a macro name, and if you haven't it edits the same macro
as last time.

But enough of macros which fiddle with the history buffer. Here are four
sets of macros which do useful things, and may give some idea of the power
available.
First a macro to use the values of a third vector to mark points, then one
to do least-squares fits to data points, then a macro to join
pairs of points, and finally some macros to handle histograms and Gaussians.
These macros are given in the format that SM would
write them to disk (ready for a `MACRO READ`

), with the name, then the
number of arguments if greater than 0, then the body of the macro.

First the points.

alpha_poi 3 # alpha_poi x y z. Like poi x y, with z as labels for points DO i=0,DIMEN($1)-1 { DEFINE _x ($1[$i]) DEFINE _y ($2[$i]) RELOCATE $_x $_y DEFINE _z ($3[$i]) PUTLABEL 5 $_z } FOREACH v (_x _y _z) { DEFINE $v DELETE 2Here we use the temporary variables

`_x _y _z`

to get around
restrictions on expressions in `RELOCATE`

commands.
Note the `DO`

loop running from `0`

to `DIMEN($1)-1`

, produced
by array indices starting at 0 not 1.
If you wanted to use character strings as labels, this could be done by
using the `DEFINE READ`

command, but this would be a good deal slower as
SM would have to rescan the file for each data-point. The top right
box of this manual's cover was made using this macro.
The use of `alpha_poi`

(and also the macro file called `ascii`

)
has been superceded by the introduction of string-valued vectors into
SM. Nowadays you'd simple read the column that you want to
label the point with as a string (e.g. `READ lab 3.s`

), set the
point type to that string (e.g. `PTYPE lab`

), and plot the points as usual
(e.g. `POINTS x y`

).
The least-squares macro makes heavy use of the `SUM`

operator.
It could be used to find the dimension of a
vector too, but only clumsily, and `DIMEN`

is provided anyway. The macro
is:

lsq 4 # Do a least squares fit to a set of vectors # Syntax: lsq x y x2 y2 Fit line y2=$a*x2+$b to x y DEFINE _n (DIMEN($1)) # number of points DEFINE _sx (SUM($1)) # Sigma x DEFINE _sy (SUM($2)) # Sigma y DEFINE _sxy (SUM($1*$2)) # Sigma xy DEFINE _sxx (SUM($1*$1)) # Sigma xx DEFINE a (($_n*$_sxy - $_sx*$_sy)/($_n*$_sxx - $_sx*$_sx)) DEFINE b (($_sy - $a*$_sx)/$_n) SET $4=$a*$3+$b FOREACH v ( _n _sx _sy _sxy _sxx ) {DEFINE $v DELETE 2This does a linear fit, leaving the coefficients in

`$a`

and `$b`

. It could
be easily generalised to deal with weights, fits constrained to pass
through the origin, quadratics...
Our third example connects pairs of points. This was written to deal with a set of data points before and after a certain correction had been applied.

pairs 4 # pairs x1 y1 x2 y2. Connect (x1,y1) to (x2,y2) DO i=0,DIMEN($1)-1 { DEFINE _x ($1[$i]) DEFINE _y ($2[$i]) RELOCATE $_x $_y DEFINE _x ($3[$i]) DEFINE _y ($4[$i]) DRAW $_x $_y } FOREACH v ( _x _y ) { DEFINE $v DELETE 2After the introduction of vectors for

`ANGLE`

and `EXPAND`

(in version 2.1) this macro can be rewritten to be much faster:
pairs 4 # pairs x1 y1 x2 y2. connect (x1,y1) to (x2,y2) DEFINE 6 { ptype angle expand aspect 2 FOREACH 5 { $!!6 2 { DEFINE $5 | 2 FOREACH 5 {fx1 fx2 fy1 fy2 gx1 gx2 gy1 gy22 { DEFINE $5 DELETE } ASPECT 1 SET _dx$0=($3 - $1)*($gx2 - $gx1)/($fx2 - $fx1) SET _dy$0=($4 - $2)*($gy2 - $gy1)/($fy2 - $fy1) PTYPE 2 0 SET _a$0=(_dx$0 == 0 ? (_dy$0 > 0 ? PI/2 : -PI/2) : \ (_dy$0 > 0 ? ATAN(_dy$0/_dx$0) : ATAN(_dy$0/_dx$0) + PI)) ANGLE 180/pi*_a$0 EXPAND SQRT(1e-5 + _dx$0**2 + _dy$0**2)/(2*128) POINTS (($1 + $3)/2) (($2 + $4)/2) FOREACH 5 { $!!6 2 { $5 $$5 DEFINE $5 DELETE 2 FOREACH 5 ( _a _dx _dy ) { DELETE $5$0 2Note how

`DEFINE name |`

is used to save things like the angle
and expansion, while `DEFINE name DELETE`

is used to ensure that the
up-to-date versions of things like `fx1`

are used (i.e. that they
`!`

).
The name of the macro (`$0`

) is used to
make unique vector names, or at least names like `_dxpairs`

that
are very unlikely to be in use.
SM allows you to plot a pair of vectors as a histogram, but what if you have only got the raw data points, not yet binned together? Fortunately, SM can do this binning for you. Consider the following macro:

get_hist 6 # get_hist input output-x output-y base top width # given $1, get a histogram in $3, with the centres of the # bins in $2. Bins go from $4 to $5, with width $6. SET $2 = $4+$6/2,$5+$6/2,$6 SET HELP $2 X-vector for $3 SET $3=0*$2 SET HELP $3 Histogram from $1, base $4 width $5 DO i=0,DIMEN($1)-1 { DEFINE j ( ($1[$i] - $4)/$6 ) SET $3[$j] = $3[$j] + 1 } DEFINE j DELETESince this was written, a new feature was added to SM, the expression

`HISTOGRAM(x:y)`

, to make histograms. The macro we discussed
above can now be written much more efficiently as:
get_hist 6 # get_hist input output-x output-y base top width # given $1, get a histogram in $3, with the centres of the # bins in $2. Bins go from $4 to $5, with width $6. SET $2 = $4+$6/2,$5+$6/2,$6 SET HELP $2 X-vector for $3 SET $3=HISTOGRAM($1:$3) SET HELP $3 Histogram from $1, base $4 width $5

Suppose that your data is in vector x, for want of a better name, and
it has values between 0 and 20. Then the command@example
get_hist x xx yy 0 20 1
will produce a histogram in `yy`

, bin centres in `xx`

, running
from 0 to 20 with bins 1 unit wide. So you could plot it with
`lim xx yy box hi xx yy `

, and maybe it looks like a Gaussian. So what
is the mean and standard deviation? The command @example
stats x mean sig kurt echo $mean $sig $kurt
will answer that, and find the kurtosis too. (Macro `stats`

consists of lines
such as `define $2 ( sum($1)/dimen($1) ) `

). Then we could use
the macro `gauss`

to plot the corresponding Gaussian,@example
set z=0,20,.1 set gg=gauss(z) set gg=gg*dimen(x) con z gg
The bottom left box of the cover was made this way. What if you don't
like the way that the histogram looks? Try the macro `barhist`

.
Now, if you wanted to plot a lognormal, you'd have to write your own
macro, and you could use `SORT`

to find medians and add another macro
to `utils`

, followed by one to find Wilcoxon statistics...
(Since this was written a `wilcoxon`

macro was donated to `stats`

).

Go to the previous, next section.