Programming in Emacs Lisp
Changes for the Final Version
The final version is different from what we planned in two ways:
first, it contains additional values calculated once in the varlist;
second, it carries an option to specify the labels' increment per row.
This latter feature turns out to be essential; otherwise, a graph may
have more rows than fit on a display or on a sheet of paper.
This new feature requires a change to the Yaxiscolumn
function, to add verticalstep
to it. The function looks like
this:
 ;;; Final version.
(defun Yaxiscolumn
(height widthoflabel &optional verticalstep)
"Construct list of labels for Y axis.
HEIGHT is maximum height of graph.
WIDTHOFLABEL is maximum width of label.
VERTICALSTEP, an option, is a positive integer
that specifies how much a Y axis label increments
for each line. For example, a step of 5 means
that each line is five units of the graph."
(let (Yaxis
(numberperline (or verticalstep 1)))
(while (> height 1)
(if (zerop (% height Yaxislabelspacing))
;; Insert label.
(setq Yaxis
(cons
(Yaxiselement
(* height numberperline)
widthoflabel)
Yaxis))
;; Else, insert blanks.
(setq Yaxis
(cons
(makestring widthoflabel ? )
Yaxis)))
(setq height (1 height)))
;; Insert base line.
(setq Yaxis (cons (Yaxiselement
(or verticalstep 1)
widthoflabel)
Yaxis))
(nreverse Yaxis)))

The values for the maximum height of graph and the width of a symbol
are computed by printgraph
in its let
expression; so
graphbodyprint
must be changed to accept them.
 ;;; Final version.
(defun graphbodyprint (numberslist height symbolwidth)
"Print a bar graph of the NUMBERSLIST.
The numberslist consists of the Yaxis values.
HEIGHT is maximum height of graph.
SYMBOLWIDTH is number of each column."
(let (fromposition)
(while numberslist
(setq fromposition (point))
(insertrectangle
(columnofgraph height (car numberslist)))
(gotochar fromposition)
(forwardchar symbolwidth)
;; Draw graph column by column.
(sitfor 0)
(setq numberslist (cdr numberslist)))
;; Place point for X axis labels.
(forwardline height)
(insert "\n")))

Finally, the code for the printgraph
function:
 ;;; Final version.
(defun printgraph
(numberslist &optional verticalstep)
"Print labelled bar graph of the NUMBERSLIST.
The numberslist consists of the Yaxis values.
Optionally, VERTICALSTEP, a positive integer,
specifies how much a Y axis label increments for
each line. For example, a step of 5 means that
each row is five units."
(let* ((symbolwidth (length graphblank))
;; height is both the largest number
;; and the number with the most digits.
(height (apply 'max numberslist))
(heightoftopline
(if (zerop (% height Yaxislabelspacing))
height
;; else
(* (1+ (/ height Yaxislabelspacing))
Yaxislabelspacing)))
(verticalstep (or verticalstep 1))
(fullYlabelwidth
(length
(concat
(numbertostring
(* heightoftopline verticalstep))
Yaxistic))))
(printYaxis
heightoftopline fullYlabelwidth verticalstep)
(graphbodyprint
numberslist heightoftopline symbolwidth)
(printXaxis numberslist)))
