(define (print . x) 
  (display (paste x))
  (newline))
;
; Nice ticmarks
;
(define (trim x ndig) 
"Args: x ndig
Cast number to string with specified number of decimal digits"
  (let ((d (expt 10 ndig))) 
    (number->string (/ (truncate (* d x)) d))))

(define (nicenum x rounded)
  "(nicenum x rounded) closest rounded value to x"
  (let* ((e (floor (log10 x)))
         (f (/ x (expt 10 e)))
         (nf (if rounded
                (cond ((< f 1.5) 1)
                      ((< f 3) 2)
                      ((< f 7) 5)
                      (else 10))
                (cond ((< f 1) 1)
                      ((< f 2) 2)
                      ((< f 5) 5)
                      (else 10)))))
     (* nf (expt 10 e))))

(define (heckbert xmin xmax ntics)
"(heckbert xmin xmax ntics)
Pleasing choice of graph axis tic spacing"
  (let* ((newrange (nicenum (- xmax xmin) #f))
        (stepsize (nicenum (/ newrange (- ntics 1)) #t)))
     (list (* (floor (/ xmin stepsize)) stepsize)
           (* (ceiling (/ xmax stepsize)) stepsize)
           stepsize)))

(define (ppoints n)
"(ppoints n)
Nice percentile points for evaluating and plotting cdf esp Gaussian"
  (let* ((a (if (> n 10) (/ 3 8) (/ 1 2))))
    (map (lambda (x) (/ (- x a) (+ n 1 (* (- 2) a)))) (seq 1 n))))
;
; Transform from data coordinates to screen position
;    (x - xmin) / scale + screen_origin
;
(define (plot-position x xmin xscal xorigin)
"(plot-position x xmin xscal xorigin)
Transform from data coordinates to screen position
    (x - xmin) / scale + screen_origin"
  (+ (* (- x xmin) xscal) xorigin))
;
; Draw bounding box
;
(define (box win xorigin yorigin xmax ymax) 
"(box win xorigin yorigin xmax ymax) 
Draw box around graph"
  (drawrect win xorigin yorigin (- xmax xorigin) (- ymax yorigin))) 
;
; Draw y-axis
;
(define (yaxis win xorigin yorigin ymax scaly niceytics ntics fontsize . ticlabels) 
  "(yaxis win xorigin yorigin ymax scaly niceytics ntics fontsize . ticlabels)"
  (let* ((yrang (- ymax yorigin)) 
         (ttic (caddr niceytics)) 
         (ytic (* ttic scaly))
         (halfh (/ fontsize 2)))
    (drawline win xorigin yorigin xorigin ymax) 
    (if (and (not (null? ticlabels)) (= (length (car ticlabels)) ntics))
      (let loop ((yval (+ yorigin (/ ytic 2.0))) (ticlab (car ticlabels))) 
        (if (not (null? ticlab)) 
          (let* ((lab (car ticlab)) 
                 (wid (* fontsize (string-length lab))))
            (drawstr win (max 0 (- xorigin wid halfh)) (- yval halfh) lab) 
            (loop (+ yval ytic) (cdr ticlab)))))
      (let loop ((yval yorigin) (ticlab (car niceytics)))
        (if (<= yval ymax) 
          (let* ((lab (number->string ticlab)) 
                 (wid (* fontsize (string-length lab))))
            (drawstr win (max 0 (- xorigin wid halfh)) (- yval halfh) lab) 
            (drawline win xorigin yval (- xorigin 5.0) yval) 
            (loop (+ yval ytic) (+ ticlab ttic))))))))

(define (ylab win yorigin ymax label . font)
  "(ylab win yorigin ymax label . font)"
  (let ((fontsize (if (pair? font) (car font) 15)))
    (drawstr win 0 (+ yorigin (/ (- ymax yorigin) 2)) 
             label fontsize)))
;
; Draw x-axis: xrang is length of axis in plotting coord
;
(define (xaxis win xorigin yorigin xmax scalx nicextics ntics fontsize . ticlabels) 
  "(xaxis win xorigin yorigin xmax scalx nicextics ntics fontsize . ticlabels)"
  (let* ((xrang (- xmax xorigin)) 
         (ttic (caddr nicextics)) 
         (xtic (* ttic scalx)))
    (drawline win xorigin yorigin xmax yorigin) 
    (if (and (not (null? ticlabels)) (= (length (car ticlabels)) ntics))
      (let loop ((xval (+ xorigin (/ xtic 2.0))) (ticlab (car ticlabels))) 
        (if (not (null? ticlab)) 
          (begin 
            (drawstr win (- xval fontsize) (- yorigin (* 2 fontsize)) (car ticlab)) 
            (loop (+ xval xtic) (cdr ticlab)))))
      (let loop ((xval xorigin) (ticpos (car nicextics))) 
        (if (<= xval xmax) 
          (let* ((lab (number->string ticpos)) 
                 (wid (* fontsize (string-length lab))))
            (drawstr win (- xval (/ wid 2)) (- yorigin (* 2 fontsize)) lab) 
            (drawline win xval yorigin xval (- yorigin 5.0)) 
            (loop (+ xval xtic) (+ ticpos ttic))))))))

(define (xlab win xorigin xmax label . font)
  "(xlab win xorigin xmax label . font)"
  (let ((fontsize (if (pair? font) (car font) 15)))
    (drawstr win (+ xorigin (/ (- (- xmax xorigin) 
                               (* 0.5 fontsize (string-length label))) 2))
                   5 label fontsize)))
;
; Scatter plot
;
(define (scatter-plot x y) 
"scatter-plot x y"
  (plot x y 500 'points "X" "Y"))
(define (line-plot x y) 
"line-plot x y"
  (plot x y 500 'lines  "X" "Y"))
(define (lp-plot x y) 
"line-and-point plot x y"
  (plot x y 500  'lp  "X" "Y"))


(define (create-plot x y plotsize . labels) 
"create-plot <x> <y> <plotsize> [<xlab> <ylab> <title> <bgcol> <pencol>]" 
  (let* ((plotwidth (if (pair? plotsize) (car plotsize) plotsize))
         (plotheight (if (pair? plotsize) (cadr plotsize) plotsize))
         (xsum (stats x))
         (ysum (stats y))
         (ntics 5)
         (nicextics (heckbert (list-ref xsum 4) (list-ref xsum 5) ntics))
         (niceytics (heckbert (list-ref ysum 4) (list-ref ysum 5) ntics))
         (xmargin 0.10)  
         (ymargin 0.10) 
         (minx (car nicextics))
         (miny (car niceytics))
         (rangx (- (cadr nicextics) minx)) 
         (rangy (- (cadr niceytics) miny)) 
         (xtic (/ rangx plotwidth))
         (ytic (/ rangy plotheight))
         (scalx (/ (* (- 1 (* 2 xmargin)) plotwidth) rangx)) 
         (scaly (/ (* (- 1 (* 2 ymargin)) plotheight) rangy)) 
         (xorigin (* xmargin plotwidth)) 
         (yorigin (* ymargin plotheight)) 
         (xmax (* (- 1 xmargin) plotwidth)) 
         (ymax (* (- 1 ymargin) plotheight))
         (nlabels (length labels))
         (bgcol (if (> nlabels 3) (list-ref labels 3) "white")) 
         (pencol (if (> nlabels 4) (list-ref labels 4) "black")))
    (define win (gopen plotwidth plotheight)) 
    (gsetbgcolor win bgcol) 
    (gclr win) 
    (newpencolor win pencol) 
    (box win xorigin yorigin xmax ymax) 
    (xaxis win xorigin yorigin xmax scalx nicextics ntics 10) 
    (yaxis win xorigin yorigin ymax scaly niceytics ntics 10) 
    (if (> nlabels 0) (xlab win xorigin xmax (car labels)))
    (if (> nlabels 1) (ylab win yorigin ymax (cadr labels)))
    (if (> nlabels 2) (drawstr win (* 0.4 plotwidth) (* 0.95 plotheight) (caddr labels)))
    (list 'plot-1 win plotsize minx scalx xorigin miny scaly yorigin bgcol pencol labels)))
;
; Add a plot to an existing window
;
(define (add-plot x y win plotx ploty plotsize . labels) 
"add-plot win <x> <y> <plotx> <ploty> <plotsize> [<xlab> <ylab> <title> <bgcol> <pencol>]" 
  (let* ((plotwidth (if (pair? plotsize) (car plotsize) plotsize))
         (plotheight (if (pair? plotsize) (cadr plotsize) plotsize))
         (xsum (stats x))
         (ysum (stats y))
         (ntics 5)
         (nicextics (heckbert (list-ref xsum 4) (list-ref xsum 5) ntics))
         (niceytics (heckbert (list-ref ysum 4) (list-ref ysum 5) ntics))
         (xmargin 0.10)  
         (ymargin 0.10) 
         (minx (car nicextics))
         (miny (car niceytics))
         (rangx (- (cadr nicextics) minx)) 
         (rangy (- (cadr niceytics) miny)) 
         (xtic (/ rangx plotwidth))
         (ytic (/ rangy plotheight))
         (scalx (/ (* (- 1 (* 2 xmargin)) plotwidth) rangx)) 
         (scaly (/ (* (- 1 (* 2 ymargin)) plotheight) rangy)) 
         (xorigin (+ plotx (* xmargin plotwidth)))
         (yorigin (+ ploty (* ymargin plotheight)))
         (xmax (+ plotx (* (- 1 xmargin) plotwidth)))
         (ymax (+ ploty (* (- 1 ymargin) plotheight)))
         (nlabels (length labels))
         (bgcol (if (> nlabels 3) (list-ref labels 3) "white")) 
         (pencol (if (> nlabels 4) (list-ref labels 4) "black")))
    (newpencolor win pencol) 
    (box win xorigin yorigin xmax ymax) 
    (xaxis win xorigin yorigin xmax scalx nicextics ntics 10) 
    (yaxis win xorigin yorigin ymax scaly niceytics ntics 10) 
    (if (> nlabels 0) (xlab win xorigin xmax (car labels)))
    (if (> nlabels 1) (ylab win yorigin ymax (cadr labels)))
    (if (> nlabels 2) (drawstr win (* 0.4 plotwidth) (* 0.95 plotheight) (caddr labels)))
    (list 'plot-1 win plotsize minx scalx xorigin miny scaly yorigin bgcol pencol labels)))
;
; Accessors
;
(define (win obj)
   "Return window number"
   (if (or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
     (format "ERROR: In win, ~s is not a plotting object~%" obj)
     (list-ref obj 1)))
;
; Methods 
;
(define (close-plot obj)
  (gclose (win obj)))

(define (add-points obj x y . col)
   "(add-points obj x y . col [point-size])"
   (if (or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
     (format "ERROR: In add-points, ~s is not a plotting object~%" obj)
     (let ((win (list-ref obj 1))
           (minx (list-ref obj 3))
           (scalx (list-ref obj 4))
           (xorigin (list-ref obj 5))
           (miny (list-ref obj 6))
           (scaly (list-ref obj 7))
           (yorigin (list-ref obj 8))
           (pencol (if (> (length col) 0) (car col) (list-ref obj 10)))
           (psize  (if (> (length col) 1) (cadr col) 5)))
       (newpencolor win pencol) 
       (let loop ((xv (car x)) (yv (car y)) 
                  (restx (cdr x)) (resty (cdr y))) 
         (if (and (number? xv) (number? yv))
           (fillcirc win (plot-position xv minx scalx xorigin) 
                         (plot-position yv miny scaly yorigin) psize psize))
         (if (not (null? restx))
            (loop (car restx) (car resty) (cdr restx) (cdr resty))))
       (newpencolor win (list-ref obj 10)))))

(define (add-lines obj x y . col)
   "(add-lines obj x y . col)"
   (if (or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
     (format "ERROR: In add-lines, ~s is not a plotting object~%" obj)
     (let ((win (list-ref obj 1))
           (minx (list-ref obj 3))
           (scalx (list-ref obj 4))
           (xorigin (list-ref obj 5))
           (miny (list-ref obj 6))
           (scaly (list-ref obj 7))
           (yorigin (list-ref obj 8))
           (pencol (if (> (length col) 0) (car col) (list-ref obj 10)))
           (style (if (> (length col) 1) (cadr col) 1)))
       (newpencolor win pencol) 
       (newlinestyle win style)
       (if (and (number? (car x)) (number? (car y)))
         (moveto win (plot-position (car x)  minx scalx xorigin) 
                     (plot-position (car y)  miny scaly yorigin))) 
       (let loop ((xv (car x)) (yv (car y)) 
              (restx (cdr x)) (resty (cdr y))) 
         (lineto win (plot-position xv minx scalx xorigin) 
                     (plot-position yv miny scaly yorigin)) 
         (if (not (null? restx))
           (loop (car restx) (car resty) (cdr restx) (cdr resty))))
       (newpencolor win (list-ref obj 10))
       (newlinestyle win 0))))

(define (add-impulses obj x y . col)
   "(add-impulses obj x y . col)"
   (if (or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
     (format "ERROR: In add-impulses, ~s is not a plotting object~%" obj)
     (let ((win (list-ref obj 1))
           (minx (list-ref obj 3))
           (scalx (list-ref obj 4))
           (xorigin (list-ref obj 5))
           (miny (list-ref obj 6))
           (scaly (list-ref obj 7))
           (yorigin (list-ref obj 8))
           (pencol (if (> (length col) 0) (car col) (list-ref obj 10))))
       (newlinewidth win 3)
       (newpencolor win pencol) 
       (let loop ((xv (car x)) (yv (car y)) 
              (restx (cdr x)) (resty (cdr y))) 
         (if (and (number? xv) (number? yv))
           (drawline win (plot-position xv minx scalx xorigin) 
                         (plot-position yv miny scaly yorigin)  
                         (plot-position xv minx scalx xorigin) 
                         (plot-position miny miny scaly yorigin)))
         (if (not (null? restx))
           (loop (car restx) (car resty) (cdr restx) (cdr resty))))
       (newlinewidth win 1)
       (newpencolor win (list-ref obj 10)))))

(define (add-text obj x y text . fontsize)
   "(add-text obj x y text . fontsize)"
   (cond ((or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
            (format "ERROR: In add-text, ~s is not a plotting object~%" obj))
         ((not (number? x))
            (format "ERROR: In add-text, ~s is not a number~%" x))
         ((not (number? y))
            (format "ERROR: In add-text, ~s is not a number~%" y))
         (else
     (let ((win (list-ref obj 1))
           (minx (list-ref obj 3))
           (scalx (list-ref obj 4))
           (xorigin (list-ref obj 5))
           (miny (list-ref obj 6))
           (scaly (list-ref obj 7))
           (yorigin (list-ref obj 8))
           (size (if (> (length fontsize) 0) (car fontsize) 12)))
       (drawstr win (plot-position x  minx scalx xorigin) 
                    (plot-position y  miny scaly yorigin) 
                    text size)))))
;
;                   +-----------+
; Legend            | ---- xxxx |
;
(define (add-legend obj pos lines widths colours text fontsize)
   (let* ((w (list-ref obj 1))
          (plotsize (list-ref obj 2))
          (plotwidth (if (pair? plotsize) (car plotsize) plotsize))
          (plotheight (if (pair? plotsize) (cadr plotsize) plotsize))
          (minx (list-ref obj 3))
          (scalx (list-ref obj 4))
          (xorigin (list-ref obj 5))
          (miny (list-ref obj 6))
          (scaly (list-ref obj 7))
          (yorigin (list-ref obj 8))
          (xmargin (/ xorigin  plotwidth)) 
          (ymargin (/ yorigin  plotheight)) 
          (xmax (* (- 1 xmargin) plotwidth)) 
          (ymax (* (- 1 ymargin) plotheight))
          (halfw (/ fontsize 2))
          (nlines (length lines))
          (boxheight (* 1.5 fontsize nlines))
          (boxwidth (* 1.5 fontsize (apply max (map string-length text)))) 
          (boxx (- xmax boxwidth))
          (boxy (- ymax boxheight)))
       (drawrect w boxx boxy boxwidth boxheight)
       (let loop ((i 0) (y (- ymax fontsize halfw)))
         (cond ((< i nlines)
                  (newpencolor w (list-ref colours i))
                  (newlinestyle w (list-ref lines i))
                  (newlinewidth win (list-ref widths i))
                  (drawline w boxx (+ y halfw) (+ boxx fontsize) (+ y halfw))
                  (newpencolor w "black")
                  (newlinewidth win 1)
                  (drawstr w (+ boxx fontsize halfw) y (list-ref text i))
                  (loop (+ i 1) (- y fontsize)))
                (else #t)))))
  
(define (plot x y plotsize type . labels) 
  "plot <x> <y> <plotsize> <type> [<xlab <ylab> <title>]" 
  (let ((currplot (create-plot x y plotsize . labels)))
    (if (or (eqv? type 'points) (eqv? type 'lp))
      (add-points currplot x y "red"))
    (if (or (eqv? type 'lines) (eqv? type 'lp))
      (add-lines currplot x y "blue"))
    (gclose (win currplot))))

(define (plot-title obj title)
  (let* ((w (win obj))
         (xrange (list-ref obj 2))
         (ypos (* 0.96 xrange))
         (title-length (* 0.006 xrange (string-length title)))
         (middle (/ xrange 2))
         (xpos (- middle title-length)))
;;  (display "object       ") (display obj) (newline)
;;  (display "Midpoint     ") (display middle) (newline)
;;  (display "Title length ") (display title-length) (newline)
    (drawstr w xpos ypos title)))
;
; add-vline
;
(define (add-vline obj xpos)
"Add vertical line to plot <obj> at x=<xpos>"
  (let* ((bottom (list-ref obj 6))
         (top    (/ (list-ref obj 2) (list-ref obj 7))))
    (add-lines obj (list xpos xpos) (list bottom top))))
;
; Jitter points
;
(define (jitter x . percent)
  "(jitter x . percent)"
  (let* ((range (apply - (list-select (stats x) '(5 4))))
         (amount (* (if (pair? percent) (/ (car percent) 100) 0.02) range)))
    (map (lambda (y) (* (+ 1 (* (- (random) 0.5) amount)) y)) x)))
;
; Lowess plot
;
(define (complete-cases x y)
"complete-cases x y: index for list position where x and y numeric"
   (which (map (lambda (x y) (and (number? x) (number? y))) x y)))
(define (lowess-plot x y) 
"lowess-plot x y draw scatterplot with lowess smoothed line"
  (let* ((idx (complete-cases x y))
         (x (list-select x idx))
         (y (list-select y idx))
         (ys (lowess x y))
        (fig1 (create-plot x y 500 "X" "Y")))
    (add-points fig1 x y "red")
    (add-lines fig1 x ys "blue" 0) 
    (gclose (win fig1))))
;
; QQ plot
;
(define (qqnorm x . labels) 
  (define (stand x mu sd)
    (map (lambda (x) (/ (- x mu) sd)) x))
  (let* ((n (length x))
         (s (stats x))
         (mu (caddr s))
         (sd (sqrt (cadddr s)))
         (x (sort (stand x mu sd)))
         (y (map (lambda (x) (- (qnorm x))) (ppoints n)))
         (ys (lowess x y))
         (nlabels (length labels))
         (title "Q-Q Normality Plot")
         (fig1 (create-plot (list -3 3) (list -3 3)  500 "Exp" "Obs")))
    (if (> nlabels 0) 
       (plot-title fig1 (string-append title ": " (car labels)))
       (plot-title fig1 title))
    (add-points fig1 x y "red")
    (add-lines fig1 x ys "blue" 0) 
    (add-lines fig1 (list -3 3) (list -3 3)  "blue" 1) 
    (gclose (win fig1))))
;
; Bar plot and histogram
;
(define (create-barplot x y plotsize . labels) 
"create-barplot <x> <y> <plotsize> [<xlab> <ylab> <title> <bgcol> <pencol>] 
Prepare axes and tick marks for a bar plot of x & y"
  (let* ((plotwidth (if (pair? plotsize) (car plotsize) plotsize))
         (plotheight (if (pair? plotsize) (cadr plotsize) plotsize))
         (nbars (length x))
         (xvals (seq 1 nbars))
         (ysum (stats y))
         (ntics 5)
         (nicextics (list 1 nbars 1))
         (niceytics (heckbert 0 (list-ref ysum 5) ntics))
         (xmargin 0.05)  
         (ymargin 0.05) 
         (minx (- (car nicextics) 1))
         (miny (car niceytics))
         (rangx (- nbars minx)) 
         (rangy (- (cadr niceytics) miny)) 
         (xtic (/ rangx plotwidth)) 
         (ytic (/ rangy plotheight)) 
         (scalx (/ (* (- 1 (* 2 xmargin)) plotwidth) rangx)) 
         (scaly (/ (* (- 1 (* 2 ymargin)) plotheight) rangy)) 
         (xorigin (* xmargin plotwidth)) 
         (yorigin (* ymargin plotheight)) 
         (xmax (* (- 1 xmargin) plotwidth)) 
         (ymax (* (- 1 ymargin) plotheight))
         (nlabels (length labels))
         (bgcol (if (> nlabels 3) (list-ref labels 3) "white")) 
         (pencol (if (> nlabels 4) (list-ref labels 4) "black")))
    (define win (gopen plotwidth plotheight)) 
    (gsetbgcolor win bgcol) 
    (gclr win) 
    (newpencolor win pencol) 
    (xaxis win xorigin yorigin xmax scalx nicextics nbars 10 x) 
    (yaxis win xorigin yorigin ymax scaly niceytics ntics 10) 
    (if (> nlabels 0) (xlab win xorigin xmax (car labels)))
    (if (> nlabels 1) (ylab win yorigin ymax (cadr labels)))
    (if (> nlabels 2) (drawstr win (* 0.4 plotwidth) (* 0.95 plotheight) (caddr labels)))
    (list 'plot-1 win plotsize minx scalx xorigin miny scaly yorigin bgcol pencol labels)))
;
; Draw bars onto plot
;
(define (add-bars obj x y width . col)
"(add-bars obj x y width . col)
Draw bars for a barplot each with height y"
   (if (or (not (pair? obj)) (not (eqv? (car obj) 'plot-1)))
     (format "ERROR: In add-bars, ~s is not a plotting object~%" obj)
     (let ((win (list-ref obj 1))
           (minx (list-ref obj 3))
           (scalx (list-ref obj 4))
           (xorigin (list-ref obj 5))
           (miny (list-ref obj 6))
           (scaly (list-ref obj 7))
           (yorigin (list-ref obj 8))
           (pencol (if (> (length col) 0) (car col) (list-ref obj 10)))
           (fillcol (if (> (length col) 1) (cadr col) "cornsilk"))
           (halfwid (/ width 2)))
       (newpencolor win pencol) 
       (let loop ((xv (car x)) (yv (car y)) 
              (restx (cdr x)) (resty (cdr y))) 
         (if (and (number? xv) (number? yv))
           (begin 
             (newcolor win fillcol)
             (fillrect win (plot-position (- xv halfwid) minx scalx xorigin) 
                           (plot-position miny miny scaly yorigin)  
                           (* width scalx)
                           (* (- yv miny) scaly))
             (newcolor win "black")
             (drawrect win (plot-position (- xv halfwid) minx scalx xorigin) 
                           (plot-position miny miny scaly yorigin)  
                           (* width scalx)
                           (* (- yv miny) scaly))))
         (if (not (null? restx))
           (loop (car restx) (car resty) (cdr restx) (cdr resty))))
       (newpencolor win (list-ref obj 10)))))

(define (barplot x y)
"(barplot x y)
Draw a bar plot for x & y - eg categories v counts"
  (let ((x2 (map (lambda (x) (- x 0.5)) (seq 1 (length x))))
        (fig1 (create-barplot x y 500)))
     (add-bars fig1 x2 y 1)
     (gclose (win fig1))))

(define (hist-table x n)
"(hist-table x n)
Bin an array of numbers into n equal width intervals"
  (let* ((sx (sort x))
         (nx (length sx))
         (minx (car sx))
         (maxx (+ (list-ref sx (- nx 1)) 0.01))
         (width (/ (- maxx minx) n)))
    (let loop ((sx sx) (intervals (list minx)) (midint '()) (curr 0) (counts '()))
      (cond ((null? sx) (list (reverse intervals) (reverse midint) (cdr (reverse (cons curr counts)))))
            ((< (car sx) (car intervals)) (loop (cdr sx) intervals midint (+ 1 curr) counts))
            (else (loop (cdr sx) (cons (+ (car intervals) width) intervals)
                        (cons (+ (car intervals) (/ width 2)) midint) 1 
                        (cons curr counts)))))))
              
(define (hist x . n)
"(hist x . n)
Draw a histogram for array of numbers"
  (let* ((sx (filter number? x))
         (ncat (if (null? n) (ceiling (+ (log2 (length sx)) 1)) (car n)))
         (t (hist-table x ncat)))
    (barplot (map (lambda (x) (trim x 1)) (cadr t)) (caddr t))))
