Look at the one at the end.
In the article I just wrote musing about headings, I was gnuplot line plotting lisp forms. Here I am doing one for Common Lisp’s Alexandria. Alexandria is a special package which it is assumed you have always loaded for the most part. For example, the ANSI CL standard doesn’t include flatten
or association-list-to-hash-table, but Alexandria does.
Let’s do one with every form from "~/common-lisp/alexandria/alexandria-1/hash-tables.lisp"
. Er, I’m going to use cl-series.
defun
a call to gnuplotFrom here again. It’s going to need to be modified to be noninteractive, but interactive is fine for now.
(defun gnuplot (title &rest x-y-lists)
(let ((cmd (format
nil
"gnuplot -p -e "~
set title '~a'; ~
unset key; ~
unset xtics; ~
set xrange [~,1f:~,1f]; ~
set yrange [~,1f:~,1f]; ~
plot ~{~1*'-' using 1:2 with lines~^,~^ ~};~
""
title
(apply 'min (mapcar 'car (apply 'append x-y-lists)))
(apply 'max (mapcar 'car (apply 'append x-y-lists)))
(apply 'min (mapcar 'cadr (apply 'append x-y-lists)))
(apply 'max (mapcar 'cadr (apply 'append x-y-lists)))
x-y-lists)))
(with-input-from-string
(in (format nil "~{~{~{~,1f ~,1f~}~%~}e~^~%~}" x-y-lists))
(uiop:run-program cmd :input in))))
From here, a moment ago
(defun atom-heights (form &optional (height 0))
(loop
:for item :in form
:if (atom item) :collect
height :into heights
:else
:nconc (atom-heights item (1+ height)) :into heights
:if (atom item) :collect
item :into items
:else
:nconc (nth-value 1 (atom-heights item)) :into items
:finally
(return (values heights items))))
(setq eepitch-buffer-name "*slime-repl ECL*")
(require :series)
(series::install)
(let* ((current-dir (car (directory #p"./")))
(wild-dir
(make-pathname :directory
'(:relative :wild-inferiors))
)
(wild-here
(merge-pathnames wild-dir current-dir))
(lisp-files
(make-pathname :name :wild :type "lisp"))
(lisp-here (merge-pathnames wild-here lisp-files)))
lisp-here)
(directory *)
(second *)
(scan-file *)
(collect *)
(third *)
(nth-value 0 (atom-heights *))
(let* ((ys (mapcar 'list *))
(xs (loop :for x from 0 :below (length ys)
:collect x)))
(gnuplot "sequence-of-length-p from alexandria"
(pairlis xs ys)))
Neat. This implies
(defun plot-file-heights (file)
(let* ((z (scan-file file))
(exprs (collect z)))
(apply
'gnuplot
(pathname-name file)
(loop :for expr :in exprs
:for heights := (atom-heights expr)
:for ys := (mapcar 'list heights)
:for xs := (loop :for x :below (length ys)
:collect x)
:collect (mapcar 'cons xs ys)))))
#p"alexandria-1/sequences.lisp"
(plot-file-heights
#P"~/common-lisp/alexandria/alexandria-1/sequences.lisp")
I have to say, that was deeply satisfying.
#p"marklib.lisp"
from Arrokoth