-
Notifications
You must be signed in to change notification settings - Fork 9
/
core.clj
95 lines (79 loc) · 2.69 KB
/
core.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
(ns gnuplot.core
(:refer-clojure :exclude [format list range run!])
(:require [clojure.core :as c]
[clojure.java.shell :refer [sh]]
[clojure.java.io :as io]
[clojure.string :as str]
[gnuplot.util :as u]))
(defprotocol Command
"Protocol for formatting things as Gnuplot commands."
(format [x] "Format this thing as a Gnuplot command string."))
(extend-protocol Command
clojure.lang.Symbol
(format [x] (name x))
clojure.lang.Keyword
(format [x] (name x))
String
(format [x] (str "'" (str/replace x #"'" "\\'") "'"))
clojure.lang.Seqable
(format [x] (str/join " " (map format x)))
Object
(format [x] (str x)))
(defrecord Literal [^String s]
Command
(format [l] s))
(defn lit
"A literal string, formatted exactly as it is."
[s]
(Literal. s))
(defrecord Range [lower upper]
Command
(format [r] (str "[" (format lower) ":" (format upper) "]")))
(defn range
"A gnuplot range, formatted as [lower:upper]"
[lower upper]
(Range. lower upper))
(defrecord List [xs]
Command
(format [l] (str/join "," (map format xs))))
(defn list
"A gnuplot comma-separated list, rendered as a,b,c"
[& elements]
(List. elements))
(defn run!
"Opens a new gnuplot process, runs the given command string, and feeds it the
given input stream, waits for the process to exit, and returns a map of its
`{:exit code, :out string, and :err string}`.
Asserts that gnuplot exits with 0; if not, throws an ex-info like
`{:type :gnuplot, :exit 123, :out ..., :err ...}`."
[commands input]
; (println "gnuplot data input:")
; (println (bs/convert input String))
(let [results (sh "gnuplot"
"-p"
"-e" commands
:in input
:out-enc "UTF-8")]
(if (zero? (:exit results))
results
(throw (ex-info (str "Gnuplot error:\n" (:err results)
"\n\nCommands:\n"
commands)
(assoc results :type :gnuplot))))))
(def dataset-separator "\ne\n")
(defn raw-plot!
"Writes a plot! Takes a sequence of Commands, and a sequence of datasets,
represented as a sequence of points, each of which is a sequence of numbers."
[commands datasets]
(run! (->> commands
(map format)
(str/join ";\n"))
(-> (mapcat (fn ds-format [dataset]
(concat
(->> dataset
(map (fn point-format [point]
(str/join " " point)))
(interpose "\n"))
(c/list dataset-separator)))
datasets)
(u/strings->input-stream))))