* mu-stats.scm: add beginning of gnuplot support

This commit is contained in:
djcb
2011-11-27 16:22:16 +02:00
parent dce908cf93
commit 372a819d8a

View File

@ -20,6 +20,7 @@
;; message store. ;; message store.
(use-modules (ice-9 optargs)) ;; for guile 1.x compatibility (use-modules (ice-9 optargs)) ;; for guile 1.x compatibility
(use-modules (ice-9 popen)) ;; for interfacing with gnuplot
;; note, this is a rather inefficient way to calculate the number; for ;; note, this is a rather inefficient way to calculate the number; for
@ -69,8 +70,8 @@ optional EXPR is provided, only consider messages that match it.\n"
(set! table (assoc-set! table val (set! table (assoc-set! table val
(+ 1 (if (eq? freq #f) 0 freq)))))) vals))) EXPR) (+ 1 (if (eq? freq #f) 0 freq)))))) vals))) EXPR)
table)) table))
(define* (mu:stats:per-weekday #:optional (EXPR "")) (define* (mu:stats:per-weekday #:optional (EXPR ""))
"Count the total number of messages for each weekday (0-6 for "Count the total number of messages for each weekday (0-6 for
Sun..Sat). If the optional EXPR is provided, only count the messages Sun..Sat). If the optional EXPR is provided, only count the messages
@ -79,13 +80,61 @@ that match it. The result is a list of pairs (weekday . frequency).\n"
(lambda (msg) (tm:wday (localtime (mu:msg:date msg)))) EXPR))) (lambda (msg) (tm:wday (localtime (mu:msg:date msg)))) EXPR)))
(sort stats (lambda(a b) (< (car a) (car b)))))) ;; in order of weekday (sort stats (lambda(a b) (< (car a) (car b)))))) ;; in order of weekday
(define* (mu:plot:per-weekday #:optional (EXPR ""))
(let* ((datafile (mu:stats:export (mu:stats:per-weekday EXPR)))
(gnuplot (open-pipe "gnuplot -p" OPEN_WRITE)))
;; note, we cannot use the weekday "%a" support in gnuplot because
;; demands the field to be a date field ('set xdata time' etc.)
;; for that to work, but we cannot use that since gnuplot does not
;; support weekdays ('%w') as a date field in its input
(display (string-append
"reset\n"
"set xtics (\"Sun\" 0, \"Mon\" 1, \"Tue\" 2, \"Wed\" 3,"
"\"Thu\" 4, \"Fri\" 5, \"Sat\" 6);\n"
"set xlabel \"Weekday\"\n"
"set ylabel \"# of messages\"\n"
"set boxwidth 0.9\n") gnuplot)
(display (string-append "plot \"" datafile "\" using 1:2 with boxes fs solid\n")
gnuplot)
(close-pipe gnuplot)))
(define* (mu:stats:per-month #:optional (EXPR "")) (define* (mu:stats:per-month #:optional (EXPR ""))
"Count the total number of messages for each month (0-11 for "Count the total number of messages for each month (1-12 for
Jan..Dec). If the optional EXPR is provided, only count the messages Jan..Dec). If the optional EXPR is provided, only count the messages
that match it. The result is a list of pairs (month . frequency).\n" that match it. The result is a list of pairs (month . frequency).\n"
(let* ((stats (mu:stats:frequency (let* ((stats (mu:stats:frequency
(lambda (msg) (tm:mon (localtime (mu:msg:date msg)))) EXPR))) (lambda (msg) ;; note the 1+
(sort stats (lambda(a b) (< (car a) (car b)))))) ;; in order of month (1+ (tm:mon (localtime (mu:msg:date msg))))) EXPR)))
(sort stats
(lambda(a b)
(< (car a) (car b)))))) ;; in order ofmonth
;; (define* (mu:plot:per-month #:optional (EXPR ""))
;; (let* ((data
;; (map ;; add 1 to the month numbers, since gnuplot counts
;; ;; months from 1, not 0
;; (lambda (cell)
;; (cons (1+ (car cell)) (cdr cell)))
;; (mu:stats:per-month EXPR)))
;; (datafile (mu:stats:export data))
;; (gnuplot (open-pipe "gnuplot -p" OPEN_WRITE)))
;; ;; note, we cannot use the weekday "%a" support in gnuplot because
;; ;; demands the field to be a date field ('set xdata time' etc.)
;; ;; for that to work, but we cannot use that since gnuplot does not
;; ;; support weekdays ('%w') as a date field in its input
;; (display (string-append
;; "reset\n"
;; "set xtics (\"Sun\" 0, \"Mon\" 1, \"Tue\" 2, \"Wed\" 3,"
;; "\"Thu\" 4, \"Fri\" 5, \"Sat\" 6);\n"
;; "set xlabel \"Weekday\"\n"
;; "set ylabel \"# of messages\"\n"
;; "set boxwidth 0.9\n") gnuplot)
;; (display (string-append "plot \"" datafile "\" using 1:2 with boxes fs solid\n")
;; gnuplot)
;; (close-pipe gnuplot)))
(define* (mu:stats:per-hour #:optional (EXPR "")) (define* (mu:stats:per-hour #:optional (EXPR ""))
"Count the total number of messages for each weekday (0-6 for "Count the total number of messages for each weekday (0-6 for
@ -95,7 +144,7 @@ that match it. The result is a list of pairs (weekday . frequency).\n"
(lambda (msg) (tm:hour (localtime (mu:msg:date msg)))) EXPR))) (lambda (msg) (tm:hour (localtime (mu:msg:date msg)))) EXPR)))
(sort stats (lambda(a b) (< (car a) (car b)))))) ;; in order of hour (sort stats (lambda(a b) (< (car a) (car b)))))) ;; in order of hour
(define* (mu:stats:per-year #:optional (EXPR "")) (define* (mu:stats:per-year #:optional (EXPR ""))
"Count the total number of messages for each year since 1970. If the "Count the total number of messages for each year since 1970. If the
optional EXPR is provided, only count the messages that match it. The optional EXPR is provided, only count the messages that match it. The
@ -136,7 +185,7 @@ that match it."
(lambda (msg) (mu:msg:subject msg)) N EXPR)) (lambda (msg) (mu:msg:subject msg)) N EXPR))
(define* (mu:stats:table pairs #:optional (port (current-output-port))) (define* (mu:stats:table pairs #:optional (port (current-output-port)))
"display a list of PAIRS in a table-like fashion" "Display a list of PAIRS in a table-like fashion."
(let ((maxlen 0)) (let ((maxlen 0))
(for-each ;; find the widest in the first col (for-each ;; find the widest in the first col
(lambda (pair) (lambda (pair)
@ -146,14 +195,24 @@ that match it."
(lambda (pair) (lambda (pair)
(let ((first (format #f "~s" (car pair))) (let ((first (format #f "~s" (car pair)))
(second (format #f "~s" (cdr pair)))) (second (format #f "~s" (cdr pair))))
(display (format #f "~A~v_~A\n" (display (format #f "~A~v_~A\n"
first (- maxlen (string-length first)) second) port))) first (- maxlen (string-length first)) second) port)))
pairs))) pairs)))
;; (define* (mu:stats:histogram pairs #:optional (port (current-output-port)))
;; "Display a histogram of the list of cons pairs; the car of each pair
;; is used for the x-asxis, while the cdr represents the y value."
;; (let ((pairs ;; pairs may be unsorted, so let's sort first
;; (sort (pairs) (lambda(x1 x2) (< x1 x2)))))
(define (mu:stats:export pairs) (define (mu:stats:export pairs)
"Export PAIRS to a temporary file, return its name. The data can "Export PAIRS to a temporary file, return its name. The data can
then be used in, e.g., R and gnuplot." then be used in, e.g., R and gnuplot."
(let* ((datafile (tmpnam)) (let* ((datafile (tmpnam))
(output (open datafile (logior O_CREAT O_WRONLY) #O0644))) (output (open datafile (logior O_CREAT O_WRONLY) #O0644)))
(mu:stats:table pairs output) (mu:stats:table pairs output)
(close output)
datafile)) datafile))