Next: recursive-graph-body-print, Previous: Columns of a graph, Up: Readying a Graph [Contents][Index]
graph-body-print
FunctionAfter our preparation in the preceding section, the graph-body-print
function is straightforward. The function will print column after column of
asterisks and blanks, using the elements of a numbers’ list to specify the
number of asterisks in each column. This is a repetitive act, which means
we can use a decrementing while
loop or recursive function for the
job. In this section, we will write the definition using a while
loop.
The column-of-graph
function requires the height of the graph as an
argument, so we should determine and record that as a local variable.
This leads us to the following template for the while
loop version of
this function:
(defun graph-body-print (numbers-list) "documentation…" (let ((height … …))
(while numbers-list insert-columns-and-reposition-point (setq numbers-list (cdr numbers-list)))))
We need to fill in the slots of the template.
Clearly, we can use the (apply 'max numbers-list)
expression to
determine the height of the graph.
The while
loop will cycle through the numbers-list
one element
at a time. As it is shortened by the (setq numbers-list (cdr
numbers-list))
expression, the CAR of each instance of the list is the
value of the argument for column-of-graph
.
At each cycle of the while
loop, the insert-rectangle
function
inserts the list returned by column-of-graph
. Since the
insert-rectangle
function moves point to the lower right of the
inserted rectangle, we need to save the location of point at the time the
rectangle is inserted, move back to that position after the rectangle is
inserted, and then move horizontally to the next place from which
insert-rectangle
is called.
If the inserted columns are one character wide, as they will be if single
blanks and asterisks are used, the repositioning command is simply
(forward-char 1)
; however, the width of a column may be greater than
one. This means that the repositioning command should be written
(forward-char symbol-width)
. The symbol-width
itself is the
length of a graph-blank
and can be found using the expression
(length graph-blank)
. The best place to bind the symbol-width
variable to the value of the width of graph column is in the varlist of the
let
expression.
These considerations lead to the following function definition:
(defun graph-body-print (numbers-list) "Print a bar graph of the NUMBERS-LIST. The numbers-list consists of the Y-axis values." (let ((height (apply 'max numbers-list)) (symbol-width (length graph-blank)) from-position)
(while numbers-list (setq from-position (point)) (insert-rectangle (column-of-graph height (car numbers-list))) (goto-char from-position) (forward-char symbol-width)
;; Draw graph column by column.
(sit-for 0)
(setq numbers-list (cdr numbers-list)))
;; Place point for X axis labels.
(forward-line height)
(insert "\n")
))
The one unexpected expression in this function is the (sit-for 0)
expression in the while
loop. This expression makes the graph
printing operation more interesting to watch than it would be otherwise.
The expression causes Emacs to sit or do nothing for a zero length of
time and then redraw the screen. Placed here, it causes Emacs to redraw the
screen column by column. Without it, Emacs would not redraw the screen
until the function exits.
We can test graph-body-print
with a short list of numbers.
graph-symbol
, graph-blank
, column-of-graph
,
which are in
Columns of a graph,
and graph-body-print
.
(graph-body-print '(1 2 3 4 6 4 3 5 7 6 5 2 3))
eval-expression
).
graph-body-print
expression into the minibuffer with
C-y (yank)
.
graph-body-print
expression.
Emacs will print a graph like this:
* * ** * **** *** **** ********* * ************ *************
Next: recursive-graph-body-print, Previous: Columns of a graph, Up: Readying a Graph [Contents][Index]