(defun distogram (d0 &key header (lwidth 5) (decimals 2) (rwidth 5) (shrink 1) (str t)) (let ((d (as-dist d0))) (unless (dist-sorted d) (dist-sort d)) (let ((sum (dist-sum d)) (bars (dist-bars d)) (min (dist-min d)) (max (dist-max d)) (n (dist-n d)) (fuzz (dist-fuzz d)) (percentSum 0) (fmt (format nil " ~~~a,~af * ~~~ad = ~~3d% ~~a " lwidth decimals rwidth))) (if header (format t "~a~%" header)) (dolist (bar bars t) (let* ((key (car bar)) (value (cdr bar)) (percent (floor (* 100 (/ value n)))) (stars (round (/ value shrink))) (halfp (< percentSum 50))) (incf percentSum percent) (format str fmt (+ key (/ fuzz 2)) value percent (if halfp "<" ">")) (format str "~a~%" (nchars stars "*"))))))) (defun demo-distogram () (let ((log (make-dist :fuzz 2))) (reset-seed) (dotimes (i 1000) (dist-add (sqrt (my-random-int 100)) log)) (with-output-to-string (s) (distogram log :shrink 10 :str s)) )) (deftest test-distogram () (check (samep (demo-distogram) " 1.00 * 12 = 1% < * 3.00 * 68 = 6% < ******* 5.00 * 163 = 16% < **************** 7.00 * 222 = 22% < ********************** 9.00 * 327 = 32% < ********************************* 11.00 * 208 = 20% > *********************")))