GNU Info

Info Node: (emacs-lisp-intro.info)X Axis Tic Marks

(emacs-lisp-intro.info)X Axis Tic Marks


Prev: Similarities differences Up: print-X-axis
Enter node , (file) or (file)node

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, 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':

  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-:' (`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


automatically generated by info2www version 1.2.2.9