第一个函数应该打印X轴的刻度标记。我们需要指定刻度标记本身及其间距:
(defvar X-axis-label-spacing (if (boundp 'graph-blank) (* 5 (length graph-blank)) 5) "相邻X轴标签之间的单位数。")
(注意,graph-blank
的值由另一个defvar
设置。boundp
谓词检查它是否已经被设置;如果尚未设置graph-blank
,并且我们没有使用此条件构造,将进入调试器,并显示错误消息,其中包含 ‘Debugger entered--Lisp error:
(void-variable graph-blank)’。)
这是X-axis-tic-symbol
的defvar
:
(defvar X-axis-tic-symbol "|" "插入到X轴列的字符串。")
目标是生成如下一行:
| | | |
第一个刻度标记缩进,使其位于第一列下方,该列缩进以提供给Y轴标签留出空间。
刻度元素包括从一个刻度到下一个刻度的空格以及一个刻度符号。空格的数量由刻度符号的宽度和X-axis-label-spacing
确定。
代码如下:
;;; X-axis-tic-element … (concat (make-string ;; 生成空格字符串。 (- (* symbol-width X-axis-label-spacing) (length X-axis-tic-symbol)) ? ) ;; 将空格与刻度符号连接起来。 X-axis-tic-symbol) …
接下来,我们确定需要多少空格来缩进第一个刻度标记以对齐图表的第一列。这使用由print-graph
函数传递的full-Y-label-width
的值。
生成X-axis-leading-spaces
的代码如下:
;; X-axis-leading-spaces … (make-string full-Y-label-width ? ) …
我们还需要确定水平轴的长度,即数字列表的长度,以及水平轴上的刻度数:
;; X-length … (length numbers-list)
;; tic-width … (* symbol-width X-axis-label-spacing)
;; number-of-X-ticks (if (zerop (% (X-length tic-width))) (/ (X-length tic-width)) (1+ (/ (X-length tic-width))))
所有这些直接导致打印X轴刻度线的函数:
(defun print-X-axis-tic-line
(number-of-X-tics X-axis-leading-spaces X-axis-tic-element)
"打印X轴的刻度标记。"
(insert X-axis-leading-spaces)
(insert X-axis-tic-symbol) ; 在第一列下方插入刻度符号。
;; 在正确的位置插入第二个刻度。 (insert (concat (make-string (- (* symbol-width X-axis-label-spacing) ;; 插入到第二个刻度符号的空格。 (* 2 (length X-axis-tic-symbol))) ? ) X-axis-tic-symbol))
;; 插入剩余的刻度标记。
(while (> number-of-X-tics 1)
(insert X-axis-tic-element)
(setq number-of-X-tics (1- number-of-X-tics))))
数字行同样简单:
首先,我们使用空格在每个数字之前创建一个带编号的元素:
(defun X-axis-element (number) "构造带编号的X轴元素。" (let ((leading-spaces (- (* symbol-width X-axis-label-spacing) (length (number-to-string number))))) (concat (make-string leading-spaces ? ) (number-to-string number))))
接下来,我们创建打印带编号行的函数,从数字1开始,位于第一列下方:
(defun print-X-axis-numbered-line (number-of-X-tics X-axis-leading-spaces) "打印X轴数字行" (let ((number X-axis-label-spacing)) (insert X-axis-leading-spaces) (insert "1")
(insert (concat
(make-string
;; 插入到下一个数字的空格。
(- (* symbol-width X-axis-label-spacing) 2)
? )
(number-to-string number)))
;; 插入剩余的数字。
(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)))))
最后,我们需要编写print-X-axis
函数,该函数使用print-X-axis-tic-line
和print-X-axis-numbered-line
。
该函数必须确定两个函数都使用的变量的局部值,然后调用它们。此外,它必须打印分隔两行的换行符。
该函数包含一个varlist,指定了五个局部变量,并调用了两个打印行的函数:
(defun print-X-axis (numbers-list) "打印X轴标签到NUMBERS-LIST的长度。" (let* ((leading-spaces (make-string full-Y-label-width ? ))
;; symbol-width 由 graph-body-print 提供 (tic-width (* symbol-width X-axis-label-spacing)) (X-length (length numbers-list))
(X-tic (concat (make-string
;; 生成空格字符串。
(- (* symbol-width X-axis-label-spacing)
(length X-axis-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)))
您可以测试print-X-axis
:
X-axis-tic-symbol
,X-axis-label-spacing
,print-X-axis-tic-line
以及X-axis-element
,print-X-axis-numbered-line
和print-X-axis
。
(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))))
eval-expression
)。
yank
)将测试表达式粘贴到迷你缓冲区中。
Emacs将打印出水平轴,如下所示:
| | | | | 1 5 10 15 20