Node:X Axis Tic Marks, Previous:Similarities differences, Up:print-X-axis

The first function should print the X axis tic marks. We must specify the tic marks themselves and their spacing:

(defvar X-axis-label-spacing (if (boundp 'graph-blank) (* 5 (length graph-blank)) 5) "Number of units from one X axis label to next.")

(Note that the value of `graph-blank`

is set by another
`defvar`

. The `boundp`

predicate checks whether it has
already been set; `boundp`

returns `nil`

if it has not.
If `graph-blank`

were unbound and we did not use this conditional
construction, in GNU Emacs 21, we would enter the debugger and see an
error message saying
`Debugger entered--Lisp error: (void-variable graph-blank)`

.)

Here is the `defvar`

for `X-axis-tic-symbol`

:

(defvar X-axis-tic-symbol "|" "String to insert to point to a column in X axis.")

The goal is to make a line that looks like this:

| | | |

The first tic is indented so that it is under the first column, which is indented to provide space for the Y axis labels.

A tic element consists of the blank spaces that stretch from one tic to
the next plus a tic symbol. The number of blanks is determined by the
width of the tic symbol and the `X-axis-label-spacing`

.

The code looks like this:

;;; X-axis-tic-element ... (concat (make-string ;; Make a string of blanks. (- (* symbol-width X-axis-label-spacing) (length X-axis-tic-symbol)) ? ) ;; Concatenate blanks with tic symbol. X-axis-tic-symbol) ...

Next, we determine how many blanks are needed to indent the first tic
mark to the first column of the graph. This uses the value of
`full-Y-label-width`

passed it by the `print-graph`

function.

The code to make `X-axis-leading-spaces`

looks like this:

;; X-axis-leading-spaces ... (make-string full-Y-label-width ? ) ...

We also need to determine the length of the horizontal axis, which is the length of the numbers list, and the number of tics in the horizontal axis:

;; X-length ... (length numbers-list) ;; tic-width ... (* symbol-width X-axis-label-spacing) ;; number-of-X-tics (if (zerop (% (X-length tic-width))) (/ (X-length tic-width)) (1+ (/ (X-length tic-width))))

All this leads us directly to the function for printing the X axis tic line:

(defun print-X-axis-tic-line (number-of-X-tics X-axis-leading-spaces X-axis-tic-element) "Print tics for X axis." (insert X-axis-leading-spaces) (insert X-axis-tic-symbol) ; Under first column. ;; Insert second tic in the right spot. (insert (concat (make-string (- (* symbol-width X-axis-label-spacing) ;; Insert white space up to second tic symbol. (* 2 (length X-axis-tic-symbol))) ? ) X-axis-tic-symbol)) ;; Insert remaining tics. (while (> number-of-X-tics 1) (insert X-axis-tic-element) (setq number-of-X-tics (1- number-of-X-tics))))

The line of numbers is equally straightforward:

First, we create a numbered element with blank spaces before each number:

(defun X-axis-element (number) "Construct a numbered X axis element." (let ((leading-spaces (- (* symbol-width X-axis-label-spacing) (length (number-to-string number))))) (concat (make-string leading-spaces ? ) (number-to-string number))))

Next, we create the function to print the numbered line, starting with the number "1" under the first column:

(defun print-X-axis-numbered-line (number-of-X-tics X-axis-leading-spaces) "Print line of X-axis numbers" (let ((number X-axis-label-spacing)) (insert X-axis-leading-spaces) (insert "1") (insert (concat (make-string ;; Insert white space up to next number. (- (* symbol-width X-axis-label-spacing) 2) ? ) (number-to-string number))) ;; Insert remaining numbers. (setq number (+ number X-axis-label-spacing)) (while (> number-of-X-tics 1) (insert (X-axis-element number)) (setq number (+ number X-axis-label-spacing)) (setq number-of-X-tics (1- number-of-X-tics)))))

Finally, we need to write the `print-X-axis`

that uses
`print-X-axis-tic-line`

and
`print-X-axis-numbered-line`

.

The function must determine the local values of the variables used by both
`print-X-axis-tic-line`

and `print-X-axis-numbered-line`

, and
then it must call them. Also, it must print the carriage return that
separates the two lines.

The function consists of a varlist that specifies five local variables, and calls to each of the two line printing functions:

(defun print-X-axis (numbers-list) "Print X axis labels to length of NUMBERS-LIST." (let* ((leading-spaces (make-string full-Y-label-width ? )) ;; symbol-width is provided by graph-body-print (tic-width (* symbol-width X-axis-label-spacing)) (X-length (length numbers-list)) (X-tic (concat (make-string ;; Make a string of blanks. (- (* symbol-width X-axis-label-spacing) (length X-axis-tic-symbol)) ? ) ;; Concatenate blanks with tic symbol. X-axis-tic-symbol)) (tic-number (if (zerop (% X-length tic-width)) (/ X-length tic-width) (1+ (/ X-length tic-width))))) (print-X-axis-tic-line tic-number leading-spaces X-tic) (insert "\n") (print-X-axis-numbered-line tic-number leading-spaces)))

You can test `print-X-axis`

:

- Install
`X-axis-tic-symbol`

,`X-axis-label-spacing`

,`print-X-axis-tic-line`

, as well as`X-axis-element`

,`print-X-axis-numbered-line`

, and`print-X-axis`

. - Copy the following expression:
(progn (let ((full-Y-label-width 5) (symbol-width 1)) (print-X-axis '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))))

- Switch to the
`*scratch*`

buffer and place the cursor where you want the axis labels to start. - Type
`M-:`(`eval-expression`

). - Yank the test expression into the minibuffer
with
`C-y`(`yank)`

. - Press <RET> to evaluate the expression.

Emacs will print the horizontal axis like this:

| | | | | 1 5 10 15 20