Go to the previous, next section.

X Axis Tic Marks

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, we would receive an error message saying `Symbol's value as variable is void'.)

(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
@dots{}
(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)
@dots{}

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
@dots{}
(make-string full-Y-label-width ? )
@dots{}

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 
@dots{}
(length numbers-list)              

;; tic-width
@dots{}
(* 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 (int-to-string number)))))
    (concat (make-string leading-spaces ? )
            (int-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)
              ? )
             (int-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 :

  1. 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 .

  2. 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))))
    

  3. Switch to the `*scratch*' buffer and place the cursor where you want the axis labels to start.

  4. Type M-ESC ( eval-expression ).

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

  6. Press RET to evaluate the expression.

Emacs will print the horizontal axis like this:

     |   |    |    |    |
     1   5   10   15   20

Go to the previous, next section.