# HG changeset patch # User Steve Losh # Date 1481845591 18000 # Node ID 0f2460b0b42e95adcda7a6f85f31737c8df3d8fd # Parent 6f1c9878ddbea8ccc443e0f19c7e245545291014 Hack together `gnuplot` so I can see my math diff -r 6f1c9878ddbe -r 0f2460b0b42e DOCUMENTATION.markdown --- a/DOCUMENTATION.markdown Thu Dec 15 12:36:37 2016 -0500 +++ b/DOCUMENTATION.markdown Thu Dec 15 18:46:31 2016 -0500 @@ -839,6 +839,27 @@ Return whether `n` is evenly divisible by `divisor`. +### `GNUPLOT` (function) + + (GNUPLOT DATA &KEY (FILENAME plot.png) (X #'CAR) (Y #'CDR)) + +Plot `data` to `filename` with gnuplot. + + This will (silently) quickload the `external-program` system to handle the + communication with gnuplot. + + + +### `GNUPLOT-FUNCTION` (function) + + (GNUPLOT-FUNCTION FUNCTION &KEY (START 0.0) (END 1.0) (STEP 0.1)) + +Plot `function` with gnuplot. + + See `plot` for more information. + + + ### `LERP` (function) (LERP FROM TO N) diff -r 6f1c9878ddbe -r 0f2460b0b42e losh.lisp --- a/losh.lisp Thu Dec 15 12:36:37 2016 -0500 +++ b/losh.lisp Thu Dec 15 18:46:31 2016 -0500 @@ -159,6 +159,48 @@ (t value)))) +(defun gnuplot (data &key + (filename "plot.png") + (x #'car) + (y #'cdr)) + "Plot `data` to `filename` with gnuplot. + + This will (silently) quickload the `external-program` system to handle the + communication with gnuplot. + + " + (uiop/package:symbol-call :ql :quickload 'external-program :silent t) + (let* ((process (uiop/package:symbol-call + :external-program :start + "gnuplot" + `("-e" "set terminal png" + "-e" ,(format nil "set output '~A'" filename) + "-e" "plot '-' using 1:2 title 'DATA' with linespoints") + :input :stream + :output nil)) + (in (uiop/package:symbol-call + :external-program :process-input-stream + process))) + (unwind-protect + (progn + (iterate (for item :in data) + (format in "~A ~A~%" (funcall x item) (funcall y item))) + (finish-output in)) + (close in)) + process)) + +(defun gnuplot-function (function &key (start 0.0) (end 1.0) (step 0.1)) + "Plot `function` with gnuplot. + + See `plot` for more information. + + " + (let* ((x (range start end :step step)) + (y (mapcar function x)) + (data (mapcar #'cons x y))) + (gnuplot data))) + + ;;;; Random ------------------------------------------------------------------- (defun-inlineable randomp (&optional (chance 0.5)) "Return a random boolean with `chance` probability of `t`." diff -r 6f1c9878ddbe -r 0f2460b0b42e package.lisp --- a/package.lisp Thu Dec 15 12:36:37 2016 -0500 +++ b/package.lisp Thu Dec 15 18:46:31 2016 -0500 @@ -46,7 +46,10 @@ :lerp :precise-lerp :map-range - :clamp)) + :clamp + + :gnuplot + :gnuplot-function)) (defpackage :losh.random (:documentation "Utilities related to randomness.") diff -r 6f1c9878ddbe -r 0f2460b0b42e vendor/make-quickutils.lisp --- a/vendor/make-quickutils.lisp Thu Dec 15 12:36:37 2016 -0500 +++ b/vendor/make-quickutils.lisp Thu Dec 15 18:46:31 2016 -0500 @@ -16,6 +16,7 @@ :map-tree :mkstr :once-only + :range :rcurry :symb :weave diff -r 6f1c9878ddbe -r 0f2460b0b42e vendor/quickutils.lisp --- a/vendor/quickutils.lisp Thu Dec 15 12:36:37 2016 -0500 +++ b/vendor/quickutils.lisp Thu Dec 15 18:46:31 2016 -0500 @@ -2,7 +2,7 @@ ;;;; See http://quickutil.org for details. ;;;; To regenerate: -;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:COMPOSE :COPY-HASH-TABLE :CURRY :EMPTYP :ENSURE-KEYWORD :ENSURE-LIST :FLATTEN :HASH-TABLE-KEYS :HASH-TABLE-VALUES :MAP-TREE :MKSTR :ONCE-ONLY :RCURRY :SYMB :WEAVE :WITH-GENSYMS) :ensure-package T :package "LOSH.QUICKUTILS") +;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:COMPOSE :COPY-HASH-TABLE :CURRY :EMPTYP :ENSURE-KEYWORD :ENSURE-LIST :FLATTEN :HASH-TABLE-KEYS :HASH-TABLE-VALUES :MAP-TREE :MKSTR :ONCE-ONLY :RANGE :RCURRY :SYMB :WEAVE :WITH-GENSYMS) :ensure-package T :package "LOSH.QUICKUTILS") (eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package "LOSH.QUICKUTILS") @@ -19,7 +19,7 @@ :ENSURE-LIST :FLATTEN :MAPHASH-KEYS :HASH-TABLE-KEYS :MAPHASH-VALUES :HASH-TABLE-VALUES :MAP-TREE :MKSTR - :ONCE-ONLY :RCURRY :SYMB :WEAVE + :ONCE-ONLY :RANGE :RCURRY :SYMB :WEAVE :STRING-DESIGNATOR :WITH-GENSYMS)))) (eval-when (:compile-toplevel :load-toplevel :execute) (defun make-gensym-list (length &optional (x "G")) @@ -248,6 +248,14 @@ ,@forms))))) + (defun range (start end &key (step 1) (key 'identity)) + "Return the list of numbers `n` such that `start <= n < end` and +`n = start + k*step` for suitable integers `k`. If a function `key` is +provided, then apply it to each number." + (assert (<= start end)) + (loop :for i :from start :below end :by step :collecting (funcall key i))) + + (defun rcurry (function &rest arguments) "Returns a function that applies the arguments it is called with and `arguments` to `function`." @@ -319,6 +327,6 @@ (eval-when (:compile-toplevel :load-toplevel :execute) (export '(compose copy-hash-table curry emptyp ensure-keyword ensure-list flatten hash-table-keys hash-table-values map-tree mkstr once-only - rcurry symb weave with-gensyms with-unique-names))) + range rcurry symb weave with-gensyms with-unique-names))) ;;;; END OF quickutils.lisp ;;;;