Hack together `gnuplot` so I can see my math
author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 15 Dec 2016 18:46:31 -0500 |
parents |
6f1c9878ddbe
|
children |
c62d7dfcaed7
|
branches/tags |
(none) |
files |
DOCUMENTATION.markdown losh.lisp package.lisp vendor/make-quickutils.lisp vendor/quickutils.lisp |
Changes
--- 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)
--- 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`."
--- 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.")
--- 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
--- 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 ;;;;