Go to the previous, next section.
macro in your
`.sm' file is searched for a file `default', and then the
macro startup from that file is executed. At the time of writing of
this manual, startup was defined as:
startup ## macro invoked upon startup
FOREACH 1 { default_font device edit file_type history_char \
macro macro2 overload printer prompt prompt2 SHELL 2 {
DEFINE $1 :
}
FOREACH 1 { TeX_strings case_fold_search fan_compress \
line_up_exponents noclobber overload \
remember_history_line traceback uppercase 2 {
DEFINE $1 :
IF($?$1) {
IF('$$1' == '0') {
DEFINE $1 DELETE
}
}
}
IF($?prompt) { PROMPT $prompt\n DEFINE prompt DELETE
2 ELSE { PROMPT : 2
IF($?device) { DEVICE $device
2 ELSE { DEFINE device nodevice 2
IF($?default_font && $?TeX_strings == 0) {
echo You can only define a default font if you use TeX
}
IF($?history_char) { # use $history_char as history character
IF('$history_char' != '0' && '$history_char' != '1') {
EDIT history_char $history_char
}
EDIT ^ ^
DEFINE history_char DELETE
}
# load the default macros
DEFINE mfiles < stats utils > # $mfiles is used by `sav'
FOREACH f ( mongo $mfiles ) { MACRO READ "$!macro"$f 2
FOREACH var ( x_col y_col data_file ) { DEFINE $var . 2
# load uppercase if defined in .sm file
IF($?uppercase) {
MACRO READ "$!macro"uppercase
}
# and overload keywords such as erase, if so desired
set_overload $?overload
# and some keymaps
IF($?edit) { READ EDIT "$!edit" 2
# and an optional macro file, with macro startup2
IF($?macro2) {
MACRO READ "$!macro2"default
IF(is_set(startup2,1)) { startup2 2 # startup2 is defined
}
# provide a \n after the IF
As this macro is executed every time that you run SM, let us consider
it in some detail. After setting the prompt, it looks for entries for
a number of variables in your `.sm' file. Some (such as printer)
are simply DEFINEd, while some (such as TeX_strings)
are only DEFINEd if they
have a non-zero value. Because some of the values might not be numeric,
the comparison is forced to be done on strings by enclosing the quantities
in single quotes.
An entry prompt is interpreted as a primary prompt, mostly for
compatibility with the use of $prompt2 to set the secondary prompt.
If device is defined it is used to set the default plotting
device, and both it and printer are used by a couple
of macros (hcopy and hmacro) that produce hardcopy.
The variables
TeX_strings and default_fonts are used in producing
labels (see section SM's Fonts).
Because TeX uses ^ for superscripts, we
allow you to put a history_char line in `.sm' to specify a
character to use rather than ^ for history (I use `).
If you use 0, or omit the value (so it is set to 1), no
history character is defined to replace ^.
The variable file_type is used by the IMAGE command to
determine the file format that you use (e.g. C, or unformatted fortran).
Startup doesn't have to check that macro was successfully
defined as it must have been found for startup to have been read
in the first place. Macro specifies where to look for macro libraries,
and startup next sets the variable mfiles containing the
names of some of
the system macros to be loaded, and reads them.
The macro load defined below also maintains the mfiles
list, as does unload. It is used by the
sav macro, which is discussed below the main listing of macros that
follows.
We also set some variables used by the id macro.
As part of our effort to be nice
to users, if you have uppercase 1 in your `.sm' file,
we also load the uppercase macros.
Next startup overloads some keywords if overload is
in your `.sm' file, reads a file of keybindings (if edit
is given in `.sm'), and
finally tries to read a second optional macro directory
macro2, and executes a macro startup2 if it's defined
(that's what the macro is_set is checking).
This is quite important, as it provides a way to customise SM
to your personal taste without convincing the local SM guru
that your taste should be foisted on everyone. If you want a prompt that
is different, or a definition of q that just quits without asking
questions, you can get them by using macro2.
You can see that it is possible
to tailor SM pretty much as you wish without changing a line of
code, just by playing with the startup macro.
SM provides various compatibility
macros, and some to package often-used functions.
The macro files `stats' and `utils', which are read when SM
is started, provide various useful
macros, a few of which are presented here. To see a current list, either
look at the files directly, set VERBOSE to zero and list all the
macros, look at the listing in this manual (see section The System Macro Libraries),
or use lsm to list macro files
(this only works if you are running Unix; try lsm demos).
We give here a number of macros taken from the files `default',
`mongo', `stats', and `utils'.
Among those not listed are those like lin defined to be lines
that are pure
abbreviations, those like xlogarithm defined as
SET x=lg(x) which provide functionality in a perhaps familiar form,
and many more like those that are given here which provide
enhancements (e.g. the macro barhist).
A discussion of a few of the more interesting or obscure follows.
Keywords are written in uppercase, because you might have been playing
tricks with overloading the lowercase equivalents.
Many of these macros, in fact all from `default' and `mongo',
start with ## so as not to show up in listings made when VERBOSE is 0, and so as not to be SAVEd. In the interest of
brevity we have omitted most of these initial comments.
cumulate 2 # Find the cumulative distribution of $1 in $2
DEFINE sum 0 SET $2=0*$1 SET HELP $2 Cumulation of $1
DO i=0,DIMEN($1)-1 {
DEFINE sum ( $sum + $1[$i] )
SET $2[$i] = $sum
}
define sum delete
da 1 DATA "$1"
del1 1 DELETE HISTORY \n
dev 1 del1 DEFINE device $1 DEVICE $1
dra 2 # Draw, accepting expressions
define 1 ($1) define 2 ($2) draw $1 $2
edit_hist # Edit the history list
del1 MACRO all 0 100000 # define "all" from buffer
WRITE STANDARD Editing History Buffer\n
MACRO EDIT all # do the editing
DELETE 0 100000 # empty history buffer
WRITE HISTORY all # replace history by "all"
era del1 ERASE
gauss 1 # Evaluate a Gaussian : N($mean,$sig)
SET $0 = 1/(SQRT(2*PI)*$sig)*EXP(-(($1-$mean)/$sig)**2/2)
get 2 # Syntax: get i j. Read a column from a file.
# Name of vector is jth word of line i.
DEFINE nn READ $1 $2 echo reading $nn\n
READ $nn $2
SET HELP $nn Column $2 from $data_file
DEFINE nn DELETE
hardcopy DEVICE nodevice # close old device
hcopy 13 ## hcopy [printer] [l1] [l2] Make hardcopy of playback buffer
# optionally specify printer ($1) and desired lines ($2-$3)
# if the printer ($1) is omitted (i.e. $1 is missing or a
# number), it will be taken from the value of the environment
# variable PRINTER, if defined.
IF($?printer == 0) {
DEFINE printer ? { what kind of printer? 2
}
IF($?1) {
IF(WHATIS($1) == 0) { # a number
if($?2) { DEFINE 3 $2 2
DEFINE 2 $1
DEFINE 1 DELETE
}
}
IF($?1) {
DEVICE $printer $1
2 ELSE {
IF($?PRINTER == 0) { DEFINE PRINTER : 2 # which one?
IF($?PRINTER) {
DEVICE $printer $PRINTER
2 ELSE {
DEVICE $printer
}
}
IF($?2 == 0) {
DEFINE 2 0 DEFINE 3 10000
2 ELSE {
IF($?3 == 0) { DEFINE 3 $2 2
}
playback $2 $3 \n DEVICE $device
bell
hmacro 12 ## hmacro [macro] [printer] Make hardcopy of a macro
# If only 1 argument is present, it is taken to be the printer
# unless an environment PRINTER variable is defined, when
# that's used as a printer, and the argument is taken to be
# a macro. If no macro is specified, make a temp one
IF($?printer == 0) {
DEFINE printer ? { what kind of printer? 2
}
del1
IF($?2 == 0) { # only one arg
IF($?PRINTER == 0) { DEFINE PRINTER : 2
IF($?PRINTER) {
DEFINE 2 $PRINTER
}
}
IF($?1) {
if($?2) { # 2 args
DEFINE _mac $1
DEFINE _temp 0 # no temp macro
2 ELSE { # 1 arg, take as printer
DEFINE 2 $1 # printer
DEFINE _temp 1 # need temp macro
}
2 ELSE { # no $1
IF($?2 == 0) { DEFINE 2 " " 2
DEFINE _temp 1 # need temp macro
}
IF($_temp) {
DEFINE _mac _mac
echo "Create temporary macro, exit with ^X"
MACRO EDIT $_mac
IF(is_set($_mac,1) == 0) {
DEFINE _mac DELETE DEFINE _temp DELETE
DEFINE _test DELETE
RETURN
}
}
DEVICE $printer $2
$_mac \n DEVICE $device
IF($_temp) { MACRO $_mac DELETE 2
DEFINE _mac DELETE DEFINE _temp DELETE bell
load # load macros in default directory
DEFINE macro : # get default directory
MACRO READ "$!macro"$1 # read macro file
IF($?mfiles == 0) {
DEFINE mfiles $1
2 ELSE {
DEFINE 3 0
FOREACH 2 ( $mfiles ) {
IF('$2' == '$1') { DEFINE 3 1 2
}
IF($3 == 0) { DEFINE mfiles < $mfiles $1 > 2
}
load2 1 # load macros in (second) default directory
DEFINE macro2 : # get directory
IF($?macro2) {
MACRO READ "$!macro2"$1 # read macro file
2 ELSE {
echo Directory macro2 is not defined
}
logerr 3 # logerr x y error, where y is logged, and error isn't
SET _y = 10**$2
SET d_y = LG(_y + $3) - $2 ERRORBAR $1 $2 d_y 2
SET d_y = $2 - LG(_y - $3) ERRORBAR $1 $2 d_y 4
DELETE _y DELETE d_y
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
SET _n = DIMEN($1) # number of points
SET _sx = SUM($1) # Sigma x
SET _sy = SUM($2) # Sigma y
SET _sxy = SUM($1*$2) # Sigma xy
SET _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 ) { DELETE $v 2
playback ## define "all" from buffer, and run it
# with args, only playback those lines
IF($?1 == 0) {
DEFINE 1 0 DEFINE 2 10000
2 ELSE {
IF($?2 == 0) { DEFINE 2 $1 2
}
del1 MACRO all $1 $2 all
read_old 1 del1 # read a Mongo file onto the history buffer
READ OLD temp $1
WRITE HISTORY temp MACRO temp { DELETE 2
rel 2 # Relocate, accepting expressions
define 1 ($1) define 2 ($2) relocate $1 $2
reverse 1 # reverse the order of a vector
SET _i = DIMEN($1),1,-1 SORT < _i $1 > DELETE _i
sav 1 # Save to a file $1, don't save from files `$mfiles'
_save $1
_save 1 # Save to a file $1, don't save from files `$mfiles'
del1
FOREACH 2 ( $mfiles ) { MACRO DELETE "$!macro"$2 2
DEFINE 2 0 define 2 ? { save vectors? 2
SAVE "$!1" 1 $2 1
FOREACH 2 ( $mfiles ) { MACRO READ "$!macro"$2 2
Cumulate is given as a way not to write macros if you can
help it (in this case, I couldn't). A better example is reverse
which reverses the order of
the elements in a vector without resorting to a DO loop.
The macro da could have been defined to be DATA, but there
are various special characters that appear in filenames;
try data /usr/spool/junk or
data disk$data:[ETHELRED]junk.dat. The macro da
provides a set of double quotes to escape these unwanted interpretations.
Incidently, da "/usr/spool/junk" won't work.
DELETE HISTORY deletes the last command on the history buffer, so
del1 alone on a line will delete itself, which can be used to
prevent a command from appearing on the history
list, for example changing devices with dev. Dev also defines
a variable device which is used by the hcopy and hmacro
macros to make hardcopies, while returning you to your initial device. The
startup macro listed above also sets device, if it is specified
in your `.sm' file. You should be careful not to include more
than one del1 macro in any macro that you write yourself, as
each del1
will remove a command from history and you could find commands mysteriously
disappearing.
Gauss evaluates a Gaussian, e.g. SET x=-3,3,0.05 SET g=gauss(x)
lim x g box con x g, an example of using a macro like a function definition.
(For this example to work, you have to define variables mean and
sig first).
There is an example of reading variables from files and using
them in macro get. This reads a word from a line in a file with
the DEFINE nn READ i j command, which sets $nn to be the
jth word on
line i of the current data file. This variable is then used to
READ a
vector, which is given the appropriate name. So if a file looks like:
This is an example file alpha beta gamma delta 1 10 0.1 1e1 2 20 0.2 1e2 3 30 0.3 1e3 4 40 0.4 1e4 5 50 0.5 1e5then the commands
GET 2 1 GET 2 2 GET 2 3 GET 2 4will read `1 2 3 4 5' into vector
alpha, `10 20 30 40 50' into beta and so
forth. Note that
DEFINE READ file_id 1 LABEL $file_idwill write out `This is an example file' to the current position of the plot pointer (see, e.g.
RELOCATE). Incidently, READ ROW omega 5
would set the vector omega to have values `3 30 0.3 1e3'.
The macros hcopy and hmacro make hardcopies of, respectively,
the playback buffer and a macro. Both assume that the variables
device and printer are set. device is set from
your `.sm' file and by the dev macro; printer is assumed
set in `.sm'. (See `startup' file above). If all is well, the macros
switch to device printer (with an argument to specify which
sub-printer is desired. We have so many laser printers here...), execute
the desired commands, and return to the initial device. When the
printer device is closed, hardcopy will result. Note the use of
\n to ensure that no nasty things happen;
if there were no \n and the buffer ended with LABEL Hi, the
plot could appear with a label Hi device tek4010.
The versions of hcopy and hmacro given here
accept a variable number of arguments (`13' means up to 3 arguments).
The first (if present) is
taken to be the desired laser printer
@footnote #{Actually, if the environment (VMS: logical)
`.sm' variable PRINTER is defined the macros pretend that
it was the first argument, so you can simply type hcopy.}
, the next argument is the number
of the first line that you want played back, and the third is the last
line number. (If you omit both line numbers you'll get the whole
buffer; if you omit the second you'll just get the one line).
The macro sees what it has been given by using $? to see which
variables are defined, and acts accordingly. Hmacro is somewhat
similar, except that if you omit an argument it is taken to be the
macro name, and a temporary one is created for you.
The playback macro deals
with its arguments in a similar way, and is discussed further in the examples
at the end of this section.
load enables you to read a set of macros from a directory
specified as macro in your environment file.
Load2 is similar, but it looks in directory macro2. The macro
unload (not listed here) will undefine the loaded macros.
Note that a list of all the loaded macros is kept in $mlist, which is used by the sav macro to avoid SAVEing
lots of system macros. Sav is written in terms of a macro
_save so that it won't itself be forgotten (by MACRO
DELETE) while in the middle of saving macros.
If you want to put errorbars on logarithmic plots, logerr is the macro
you've been looking for. It calculates the correct length for the errorbars,
and plots them de-logging and re-logging as appropriate.
The macros rel and dra illustrate a method of using expressions,
rather than numbers, in the commands RELOCATE and DRAW. There
are Good Reasons why DRAW won't accept an expression
directly (see section The Command Interpreter).
These macros exploit the fact that the arguments to a macro are whitespace
delimited, so a string such as 1+2/$x comprises one argument.
Redefining the arguments means that the macros don't have to define,
and then delete, a couple of variables to hold the expressions.
Now that you have had your appetite whetted, we strongly recommend that you take the time to look through the other macros that are available (see section The System Macro Libraries). Otherwise how would you know that there are macros to draw arrows on plots, do KS and Wilcoxon tests on vectors, and a host of other good things?
Go to the previous, next section.