emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: TEC <tecosaur@gmail.com>
To: org-mode-email <emacs-orgmode@gnu.org>
Cc: Eric Schulte <schulte.eric@gmail.com>
Subject: WIP: Org-plot work
Date: Thu, 09 Jul 2020 05:36:16 +0800	[thread overview]
Message-ID: <875zaxlmeo.fsf@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 0 bytes --]



[-- Attachment #2.1: Type: text/plain, Size: 410 bytes --]

Hi All,

I've just finished re-working my modifications to org-plot into 
what I hope is a
form that may (in 9.5?) be merged at some point.
I stayed up later that I wanted getting this finished, so I'll 
save the monolouge
on what I've done for later, but I thought I'd share the current 
state of my
efforts for anyone interested.

If that's you, please let me know what you think :)

All the best,

Timothy.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.2: 0001-Replace-inconsistent-indentation-in-org-plot.patch --]
[-- Type: text/x-patch, Size: 1414 bytes --]

From 28a7513494f17be0b2219482ebc55f0ce22a0c67 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Wed, 8 Jul 2020 18:34:46 +0800
Subject: [PATCH 1/8] Replace inconsistent indentation in org-plot Only 6 of
 355 lines used spaces instead of tabs. Change those 6 lines in
 `org-plot/gnuplot' to use tabs.

---
 lisp/org-plot.el | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index a23195d2a..b211e0403 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -333,12 +333,12 @@ line directly before or after the table."
       (with-temp-buffer
 	(if (plist-get params :script)	; user script
 	    (progn (insert
-                    (org-plot/gnuplot-script data-file num-cols params t))
-                   (insert "\n")
-                   (insert-file-contents (plist-get params :script))
-                   (goto-char (point-min))
-                   (while (re-search-forward "\\$datafile" nil t)
-                     (replace-match data-file nil nil)))
+		    (org-plot/gnuplot-script data-file num-cols params t))
+		   (insert "\n")
+		   (insert-file-contents (plist-get params :script))
+		   (goto-char (point-min))
+		   (while (re-search-forward "\\$datafile" nil t)
+		     (replace-match data-file nil nil)))
 	  (insert (org-plot/gnuplot-script data-file num-cols params)))
 	;; Graph table.
 	(gnuplot-mode)
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.3: 0002-Add-new-org-plot-argument-transpose.patch --]
[-- Type: text/x-patch, Size: 2551 bytes --]

From 495307540ff757b8b4f6f756e456b0bed90801a0 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Wed, 8 Jul 2020 19:26:07 +0800
Subject: [PATCH 2/8] Add new org-plot argument, transpose By modifying
 `org-plot/add-options-to-plist' and `org-plot/gnuplot' now #+PLOT recognises
 a transpose:{yes,y,t,*} argument which performs a basic transposition of the
 table data prior to processing. This is rather useful in some plot types like
 radar charts.

---
 lisp/org-plot.el | 41 +++++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index b211e0403..25a0f605b 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -50,19 +50,21 @@
   "Parse an OPTIONS line and set values in the property list P.
 Returns the resulting property list."
   (when options
-    (let ((op '(("type"    . :plot-type)
-		("script"  . :script)
-		("line"    . :line)
-		("set"     . :set)
-		("title"   . :title)
-		("ind"     . :ind)
-		("deps"    . :deps)
-		("with"    . :with)
-		("file"    . :file)
-		("labels"  . :labels)
-		("map"     . :map)
-		("timeind" . :timeind)
-		("timefmt" . :timefmt)))
+    (let ((op '(("type"      . :plot-type)
+		("script"    . :script)
+		("line"      . :line)
+		("set"       . :set)
+		("title"     . :title)
+		("ind"       . :ind)
+		("deps"      . :deps)
+		("with"      . :with)
+		("file"      . :file)
+		("labels"    . :labels)
+		("map"       . :map)
+		("timeind"   . :timeind)
+		("timefmt"   . :timefmt)
+		("trans"     . :transpose)
+		("transpose" . :transpose)))
 	  (multiples '("set" "line"))
 	  (regexp ":\\([\"][^\"]+?[\"]\\|[(][^)]+?[)]\\|[^ \t\n\r;,.]*\\)")
 	  (start 0))
@@ -289,7 +291,18 @@ line directly before or after the table."
 	(setf params (plist-put params (car pair) (cdr pair)))))
     ;; collect table and table information
     (let* ((data-file (make-temp-file "org-plot"))
-	   (table (org-table-to-lisp))
+	   (table (let ((tbl (org-table-to-lisp)))
+		    (when (pcase (plist-get params :transpose)
+			    ('y   t)
+			    ('yes t)
+			    ('t   t))
+		      (if (memq 'hline tbl)
+			  (setq tbl (apply #'cl-mapcar #'list tbl))
+			;; When present, remove hlines as they can't (currentily) be easily transposed.
+			(setq tbl (apply #'cl-mapcar #'list
+					 (remove 'hline tbl)))
+			(push 'hline (cdr tbl))))
+		    tbl))
 	   (num-cols (length (if (eq (nth 0 table) 'hline) (nth 1 table)
 			       (nth 0 table)))))
       (run-with-idle-timer 0.1 nil #'delete-file data-file)
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.4: 0003-Add-org-plot-custom-to-add-content-to-all-plots.patch --]
[-- Type: text/x-patch, Size: 1857 bytes --]

From 253b9d22ebee26ae89127de9071cac0ee6bfbd23 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Wed, 8 Jul 2020 22:26:21 +0800
Subject: [PATCH 3/8] Add org-plot custom to add content to all plots Adds a
 new custom: `org-plot/gnuplot-script-preamble' which can be either a string
 or function (which is called to produce a string). This allows for the user
 to add gnuplot script to the code generated by `org-plot/gnuplot', setting
 say the font/colour-scheme, default precision, etc.

---
 lisp/org-plot.el | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index 25a0f605b..5a36fd624 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -181,6 +181,13 @@ and dependent variables."
 	  (setf back-edge "") (setf front-edge ""))))
     row-vals))
 
+(defcustom org-plot/gnuplot-script-preamble ""
+  "String or function which provides content to be inserted into the GNUPlot
+script before the plot command. Not that this is in addition to, not instead of
+other content generated in `org-plot/gnuplot-script'."
+  :group 'org-plot
+  :type '(choice string function))
+
 (defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
   "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.
 NUM-COLS controls the number of columns plotted in a 2-d plot.
@@ -213,6 +220,12 @@ manner suitable for prepending to a user-specified script."
     (when file				; output file
       (funcall ats (format "set term %s" (file-name-extension file)))
       (funcall ats (format "set output '%s'" file)))
+
+    (funcall ats
+	     (if (stringp org-plot/gnuplot-script-preamble)
+		 org-plot/gnuplot-script-preamble
+	       (org-plot/gnuplot-script-preamble)))
+
     (pcase type				; type
       (`2d ())
       (`3d (when map (funcall ats "set map")))
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.5: 0004-Extract-org-plot-presets-to-custom-variable.patch --]
[-- Type: text/x-patch, Size: 4165 bytes --]

From 4db0363ed85c02ec7938450083cc9013e0c00138 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Thu, 9 Jul 2020 04:27:18 +0800
Subject: [PATCH 4/8] Extract org-plot presets to custom variable. Prior to
 this commit, the plot presets type:{2d,3d,grid} were hardcoded in
 `org-plot/gnuplot-script'. By extracting them to a custom variable, users are
 able to create their own presets for frequently used setups. Note that while
 this moves the most significant hardcoding of the 2d, 3d, and grid types in
 `org-plot/gnuplot-script', there are still a few minor fragments that I am
 not sure how to best address.

---
 lisp/org-plot.el | 71 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 48 insertions(+), 23 deletions(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index 5a36fd624..95ed17f8e 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -188,6 +188,49 @@ other content generated in `org-plot/gnuplot-script'."
   :group 'org-plot
   :type '(choice string function))
 
+(defcustom org-plot/preset-plot-types
+  '((2d (lambda (data-file num-cols params plot-str)
+	  (let* ((type (plist-get params :plot-type))
+		 (with (if (eq type 'grid) 'pm3d (plist-get params :with)))
+		 (ind (plist-get params :ind))
+		 (deps (if (plist-member params :deps) (plist-get params :deps)))
+		 (text-ind (plist-get params :textind))
+		 (col-labels (plist-get params :labels))
+		 res)
+	    (dotimes (col num-cols res)
+	      (unless (and (eq type '2d)
+			   (or (and ind (equal (1+ col) ind))
+			       (and deps (not (member (1+ col) deps)))))
+		(setf res
+		      (cons
+		       (format plot-str data-file
+			       (or (and ind (> ind 0)
+					(not text-ind)
+					(format "%d:" ind)) "")
+			       (1+ col)
+			       (if text-ind (format ":xticlabel(%d)" ind) "")
+			       with
+			       (or (nth col col-labels)
+				   (format "%d" (1+ col))))
+		       res)))))))
+    (3d (lambda (data-file num-cols params plot-str)
+	  (let* ((type (plist-get params :plot-type))
+		 (with (if (eq type 'grid) 'pm3d (plist-get params :with))))
+	    (list (format "'%s' matrix with %s title ''"
+			  data-file with)))))
+    (grid (lambda (data-file num-cols params plot-str)
+	    (let* ((type (plist-get params :plot-type))
+		   (with (if (eq type 'grid) 'pm3d (plist-get params :with))))
+	    (list (format "'%s' with %s title ''"
+			  data-file with))))))
+  "List of plot presets with the type name as the car, and a function
+which yeilds plot-lines (a list of strings) as the cdr.
+The parameters of `org-plot/gnuplot-script' and PLOT-STR are passed to
+that function. i.e. it is called with the following arguments:
+  DATA-FILE NUM-COLS PARAMS PLOT-STR"
+  :group 'org-plot
+  :type '(alist :value-type (symbol group)))
+
 (defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
   "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.
 NUM-COLS controls the number of columns plotted in a 2-d plot.
@@ -254,29 +297,11 @@ manner suitable for prepending to a user-specified script."
 			   (or timefmt	; timefmt passed to gnuplot
 			       "%Y-%m-%d-%H:%M:%S") "\"")))
     (unless preface
-      (pcase type			; plot command
-	(`2d (dotimes (col num-cols)
-	       (unless (and (eq type '2d)
-			    (or (and ind (equal (1+ col) ind))
-				(and deps (not (member (1+ col) deps)))))
-		 (setf plot-lines
-		       (cons
-			(format plot-str data-file
-				(or (and ind (> ind 0)
-					 (not text-ind)
-					 (format "%d:" ind)) "")
-				(1+ col)
-				(if text-ind (format ":xticlabel(%d)" ind) "")
-				with
-				(or (nth col col-labels)
-				    (format "%d" (1+ col))))
-			plot-lines)))))
-	(`3d
-	 (setq plot-lines (list (format "'%s' matrix with %s title ''"
-					data-file with))))
-	(`grid
-	 (setq plot-lines (list (format "'%s' with %s title ''"
-					data-file with)))))
+      (let ((type-func (cadr (assoc type org-plot/preset-plot-types))))
+	(when type-func
+	  (setq plot-lines
+		(funcall type-func data-file num-cols params plot-str))))
+
       (funcall ats
 	       (concat plot-cmd " " (mapconcat #'identity
 					       (reverse plot-lines)
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.6: 0005-Add-some-utility-functions-to-org-plot-axis-ticks.patch --]
[-- Type: text/x-patch, Size: 5860 bytes --]

From 9563381eaa15ae0f9714709d4c1de3bcf3e4edda Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Thu, 9 Jul 2020 04:47:40 +0800
Subject: [PATCH 5/8] Add some utility functions to org-plot axis ticks It can
 be useful to attempt to determine a sensible number of ticks to have on an
 axis. This turns out to be harder than expected, and so a number of functions
 are used to attempt to do so. The essence of the method used, is to round
 values and find their prime decompositions. From this we try to select the
 most common components to give a reasonable step size. We also add a 'ticks'
 parameter for manually setting the number of ticks, and (y)min/max parameters
 similarly.

---
 lisp/org-plot.el | 100 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index 95ed17f8e..0bc7ae309 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -63,6 +63,11 @@ Returns the resulting property list."
 		("map"       . :map)
 		("timeind"   . :timeind)
 		("timefmt"   . :timefmt)
+		("min"       . :ymin)
+		("max"       . :ymax)
+		("ymin"      . :ymin)
+		("xmax"      . :xmax)
+		("ticks"     . :ticks)
 		("trans"     . :transpose)
 		("transpose" . :transpose)))
 	  (multiples '("set" "line"))
@@ -181,6 +186,101 @@ and dependent variables."
 	  (setf back-edge "") (setf front-edge ""))))
     row-vals))
 
+(defun org--plot/values-stats (nums &optional hard-min hard-max)
+  "From a list of NUMS return a plist containing some rudamentry statistics on the
+values, namely regarding the range."
+  (let* ((minimum (or hard-min (apply #'min nums)))
+	 (maximum (or hard-max (apply #'max nums)))
+	 (range (- maximum minimum))
+	 (rangeOrder (ceiling (- 1 (log10 range))))
+	 (range-factor (expt 10 rangeOrder))
+	 (nice-min (/ (float (floor (* minimum range-factor))) range-factor))
+	 (nice-max (/ (float (ceiling (* maximum range-factor))) range-factor)))
+    `(:min ,minimum :max ,maximum :range ,range
+      :range-factor ,range-factor
+      :nice-min ,nice-min :nice-max ,nice-max :nice-range ,(- nice-max nice-min))))
+
+(defun org--plot/sensible-tick-num (table &optional hard-min hard-max)
+  "From a the values in a TABLE of data, attempt to guess an appropriate number of ticks."
+  (let* ((row-data
+	  (mapcar (lambda (row) (org--plot/values-stats
+			    (mapcar #'string-to-number (cdr row))
+			    hard-min
+			    hard-max)) table))
+	 (row-normalised-ranges (mapcar (lambda (r-data)
+					  (let ((val (round (*
+							     (plist-get r-data :range-factor)
+							     (plist-get r-data :nice-range)))))
+					    (if (= (% val 10) 0) (/ val 10) val)))
+					row-data))
+	 (range-prime-decomposition (mapcar #'org--plot/prime-factors row-normalised-ranges))
+	 (weighted-factors (sort (apply #'org--plot/merge-alists #'+ 0
+					(mapcar (lambda (factors) (org--plot/item-frequencies factors t))
+						range-prime-decomposition))
+				 (lambda (a b) (> (cdr a) (cdr b))))))
+    (apply #'* (org--plot/nice-frequency-pick weighted-factors))))
+
+(defun org--plot/nice-frequency-pick (frequencies)
+  "From a list of frequences, try to sensibly pick a sample of the most frequent."
+  ;; TODO this mosly works decently, but counld do with some tweaking to work more consistently.
+  (case (length frequencies)
+    (1 (list (car (nth 0 frequencies))))
+    (2 (if (<= 3 (/ (cdr (nth 0 frequencies))
+		    (cdr (nth 1 frequencies))))
+	   (make-list 2
+		      (car (nth 0 frequencies)))
+	 (list (car (nth 0 frequencies))
+	       (car (nth 1 frequencies)))))
+    (t
+     (let* ((total-count (apply #'+ (mapcar #'cdr frequencies)))
+	    (n-freq (mapcar (lambda (freq) `(,(car freq) . ,(/ (float (cdr freq)) total-count))) frequencies))
+	    (f-pick (list (car (car n-freq))))
+	    (1-2-ratio (/ (cdr (nth 0 n-freq))
+			  (cdr (nth 1 n-freq))))
+	    (2-3-ratio (/ (cdr (nth 1 n-freq))
+			  (cdr (nth 2 n-freq))))
+	    (1-3-ratio (* 1-2-ratio 2-3-ratio))
+	    (1-val (car (nth 0 n-freq)))
+	    (2-val (car (nth 1 n-freq)))
+	    (3-val (car (nth 2 n-freq))))
+       (when (> 1-2-ratio 4) (push 1-val f-pick))
+       (when (and (< 1-2-ratio 2-val)
+		  (< (* (apply #'* f-pick) 2-val) 30))
+	 (push 2-val f-pick))
+       (when (and (< 1-3-ratio 3-val)
+		  (< (* (apply #'* f-pick) 3-val) 30))
+	 (push 3-val f-pick))
+       f-pick))))
+
+(defun org--plot/merge-alists (function default alist1 alist2 &rest alists)
+  "Using FUNCTION, combine the elements of all given ALISTS. When an element is
+only present in one alist, DEFAULT is used as the second argument for the FUNCTION."
+  (when (> (length alists) 0)
+    (setq alist2 (apply #'org--plot/merge-alists function default alist2 alists)))
+  (flet ((keys (alist) (mapcar #'car alist))
+	 (lookup (key alist) (or (cdr (assoc key alist)) default)))
+    (loop with keys = (union (keys alist1) (keys alist2) :test 'equal)
+	  for k in keys collect
+	  (cons k (funcall function (lookup k alist1) (lookup k alist2))))))
+
+(defun org--plot/item-frequencies (values &optional normalise)
+  "Return an alist indicating the frequency of values in VALUES list."
+  (let ((normaliser (if normalise (float (length values)) 1)))
+    (cl-loop for (n . m) in (seq-group-by #'identity values)
+	     collect (cons n (/ (length m) normaliser)))))
+
+(defun org--plot/prime-factors (value)
+  "Return the prime decomposition of VALUE, e.g. for 12, '(3 2 2)"
+  (let ((factors '(1)) (i 1))
+    (while (/= 1 value)
+      (setq i (1+ i))
+      (when (eq 0 (% value i))
+	(push i factors)
+	(setq value (/ value i))
+	(setq i (1- i))
+	))
+    (subseq factors 0 -1)))
+
 (defcustom org-plot/gnuplot-script-preamble ""
   "String or function which provides content to be inserted into the GNUPlot
 script before the plot command. Not that this is in addition to, not instead of
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.7: 0006-Allow-for-customisation-of-org-plot-s-term.patch --]
[-- Type: text/x-patch, Size: 1938 bytes --]

From 2d88ddd8d4bb2144bfe7e2608d0379794b51aaf6 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Thu, 9 Jul 2020 05:00:03 +0800
Subject: [PATCH 6/8] Allow for customisation of org-plot's term Adds a custom
 variable (used in `org-plot/gnuplot-script') which allows the user to tweak
 the gnuplot term settings. This allows for setting characteristics such as
 default size, or background colour.

---
 lisp/org-plot.el | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index 0bc7ae309..d6146d23d 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -331,6 +331,13 @@ that function. i.e. it is called with the following arguments:
   :group 'org-plot
   :type '(alist :value-type (symbol group)))
 
+(defcustom org-plot/gnuplot-term-extra ""
+  "String or function which provides the extra term options.
+E.g. a value of \"size 1050,650\" would cause
+\"set term ... size 1050,650\" to be used."
+  :group 'org-plot
+  :type '(choice string function))
+
 (defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
   "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.
 NUM-COLS controls the number of columns plotted in a 2-d plot.
@@ -360,8 +367,15 @@ manner suitable for prepending to a user-specified script."
 	 ;; ats = add-to-script
 	 (ats (lambda (line) (setf script (concat script "\n" line))))
 	 plot-lines)
-    (when file				; output file
-      (funcall ats (format "set term %s" (file-name-extension file)))
+
+
+    ;; handle output file, background, and size
+    (funcall ats (format "set term %s %s"
+			 (if file (file-name-extension file) "GNUTERM")
+			 (if (stringp org-plot/gnuplot-term-extra)
+			     org-plot/gnuplot-term-extra
+			   (org-plot/gnuplot-term-extra))))
+    (when file ; output file
       (funcall ats (format "set output '%s'" file)))
 
     (funcall ats
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.8: 0007-Org-plot-tweak-term-and-preamble-custom-vars.patch --]
[-- Type: text/x-patch, Size: 2196 bytes --]

From c154151fbc3383ff8bcc735542e446c82c18a868 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Thu, 9 Jul 2020 05:05:20 +0800
Subject: [PATCH 7/8] Org-plot: tweak term and preamble custom vars The custom
 variables `org-plot/gnuplot-script-preamble' and
 `org-plot/gnuplot-term-extra' now take the plot type as an argument.

---
 lisp/org-plot.el | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index d6146d23d..3b486fed2 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -284,7 +284,8 @@ only present in one alist, DEFAULT is used as the second argument for the FUNCTI
 (defcustom org-plot/gnuplot-script-preamble ""
   "String or function which provides content to be inserted into the GNUPlot
 script before the plot command. Not that this is in addition to, not instead of
-other content generated in `org-plot/gnuplot-script'."
+other content generated in `org-plot/gnuplot-script'.
+If a function, it is called with the plot type as the argument."
   :group 'org-plot
   :type '(choice string function))
 
@@ -334,7 +335,8 @@ that function. i.e. it is called with the following arguments:
 (defcustom org-plot/gnuplot-term-extra ""
   "String or function which provides the extra term options.
 E.g. a value of \"size 1050,650\" would cause
-\"set term ... size 1050,650\" to be used."
+\"set term ... size 1050,650\" to be used.
+If a function, it is called with the plot type as the argument."
   :group 'org-plot
   :type '(choice string function))
 
@@ -374,14 +376,14 @@ manner suitable for prepending to a user-specified script."
 			 (if file (file-name-extension file) "GNUTERM")
 			 (if (stringp org-plot/gnuplot-term-extra)
 			     org-plot/gnuplot-term-extra
-			   (org-plot/gnuplot-term-extra))))
+			   (org-plot/gnuplot-term-extra type))))
     (when file ; output file
       (funcall ats (format "set output '%s'" file)))
 
     (funcall ats
 	     (if (stringp org-plot/gnuplot-script-preamble)
 		 org-plot/gnuplot-script-preamble
-	       (org-plot/gnuplot-script-preamble)))
+	       (org-plot/gnuplot-script-preamble type)))
 
     (pcase type				; type
       (`2d ())
-- 
2.27.0


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2.9: 0008-Org-plot-add-radar-plot-type.patch --]
[-- Type: text/x-patch, Size: 5733 bytes --]

From a7af0ff66917f92c735735d88eeccb5019937273 Mon Sep 17 00:00:00 2001
From: TEC <tec@tecosaur.com>
Date: Thu, 9 Jul 2020 05:21:44 +0800
Subject: [PATCH 8/8] Org-plot: add radar plot type.

---
 lisp/org-plot.el | 138 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 137 insertions(+), 1 deletion(-)

diff --git a/lisp/org-plot.el b/lisp/org-plot.el
index 3b486fed2..c435ef733 100644
--- a/lisp/org-plot.el
+++ b/lisp/org-plot.el
@@ -323,7 +323,9 @@ If a function, it is called with the plot type as the argument."
 	    (let* ((type (plist-get params :plot-type))
 		   (with (if (eq type 'grid) 'pm3d (plist-get params :with))))
 	    (list (format "'%s' with %s title ''"
-			  data-file with))))))
+			  data-file with)))))
+    (radar (lambda (data-file num-cols params plot-str)
+	     (list (org--plot/radar table params)))))
   "List of plot presets with the type name as the car, and a function
 which yeilds plot-lines (a list of strings) as the cdr.
 The parameters of `org-plot/gnuplot-script' and PLOT-STR are passed to
@@ -332,6 +334,140 @@ that function. i.e. it is called with the following arguments:
   :group 'org-plot
   :type '(alist :value-type (symbol group)))
 
+(defvar org--plot/radar-template
+  "### spider plot/chart with gnuplot
+# also known as: radar chart, web chart, star chart, cobweb chart,
+#                radar plot,  web plot,  star plot,  cobweb plot,  etc. ...
+set datafile separator ' '
+set size square
+unset tics
+set angles degree
+set key bmargin center horizontal
+unset border
+
+# Load data and settup
+load \"%s\"
+
+# General settings
+DataColCount = words($Data[1])-1
+AxesCount = |$Data|-HeaderLines
+AngleOffset = 90
+Max = 1
+d=0.1*Max
+Direction = -1   # counterclockwise=1, clockwise = -1
+
+# Tic settings
+TicCount = %s
+TicOffset = 0.1
+TicValue(axis,i) = real(i)*(word($Settings[axis],3)-word($Settings[axis],2)) \\
+	  / word($Settings[axis],4)+word($Settings[axis],2)
+TicLabelPosX(axis,i) = PosX(axis,i/TicCount) + PosY(axis, TicOffset)
+TicLabelPosY(axis,i) = PosY(axis,i/TicCount) - PosX(axis, TicOffset)
+TicLen = 0.03
+TicdX(axis,i) = 0.5*TicLen*cos(alpha(axis)-90)
+TicdY(axis,i) = 0.5*TicLen*sin(alpha(axis)-90)
+
+# Label
+LabOffset = 0.10
+LabX(axis) = PosX(axis+1,Max+2*d) + PosY(axis, LabOffset)
+LabY(axis) = PosY($0+1,Max+2*d)
+
+# Functions
+alpha(axis) = (axis-1)*Direction*360.0/AxesCount+AngleOffset
+PosX(axis,R) = R*cos(alpha(axis))
+PosY(axis,R) = R*sin(alpha(axis))
+Scale(axis,value) = real(value-word($Settings[axis],2))/(word($Settings[axis],3)-word($Settings[axis],2))
+
+# Spider settings
+set style arrow 1 dt 1 lw 1.0 @fgal head filled size 0.06,25     # style for axes
+set style arrow 2 dt 2 lw 0.5 @fgal nohead   # style for weblines
+set style arrow 3 dt 1 lw 1 @fgal nohead     # style for axis tics
+set samples AxesCount
+set isosamples TicCount
+set urange[1:AxesCount]
+set vrange[1:TicCount]
+set style fill transparent solid 0.2
+
+set xrange[-Max-4*d:Max+4*d]
+set yrange[-Max-4*d:Max+4*d]
+plot \\
+    '+' u (0):(0):(PosX($0,Max+d)):(PosY($0,Max+d)) w vec as 1 not, \\
+    $Data u (LabX($0)): \\
+	(LabY($0)):1 every ::HeaderLines w labels center enhanced @fgt not, \\
+    for [i=1:DataColCount] $Data u (PosX($0+1,Scale($0+1,column(i+1)))): \\
+	(PosY($0+1,Scale($0+1,column(i+1)))) every ::HeaderLines w filledcurves lt i title word($Data[1],i+1), \\
+%s
+#    '++' u (PosX($1,$2/TicCount)-TicdX($1,$2/TicCount)): \\
+#        (PosY($1,$2/TicCount)-TicdY($1,$2/TicCount)): \\
+#        (2*TicdX($1,$2/TicCount)):(2*TicdY($1,$2/TicCount)) \\
+#        w vec as 3 not, \\
+### end of code
+")
+
+(defvar org--plot/radar-ticks
+  "    '++' u (PosX($1,$2/TicCount)):(PosY($1,$2/TicCount)): \\
+	(PosX($1+1,$2/TicCount)-PosX($1,$2/TicCount)):  \\
+	(PosY($1+1,$2/TicCount)-PosY($1,$2/TicCount)) w vec as 2 not, \\
+    '++' u (TicLabelPosX(%s,$2)):(TicLabelPosY(%s,$2)): \\
+	(sprintf('%%g',TicValue(%s,$2))) w labels font ',8' @fgat not")
+
+(defvar org--plot/radar-setup-template
+  "# Data
+$Data <<HEREHAVESOMEDATA
+%s
+HEREHAVESOMEDATA
+HeaderLines = 1
+
+# Settings for scale and offset adjustments
+# axis min max tics axisLabelXoff axisLabelYoff
+$Settings <<EOD
+%s
+EOD
+")
+
+(defun org--plot/radar (table params)
+  (let* ((data
+	  (concat "\"" (s-join "\" \"" (plist-get params :labels)) "\""
+		  "\n"
+		  (s-join "\n"
+			  (mapcar (lambda (row)
+				    (format
+				     "\"%s\" %s"
+				     (car row)
+				     (s-join " " (cdr row))))
+				  table))))
+	 (ticks (or (plist-get params :ticks)
+		    (org--plot/sensible-tick-num table
+						 (plist-get params :ymin)
+						 (plist-get params :ymax))))
+	 (settings
+	  (s-join "\n"
+		  (mapcar (lambda (row)
+			    (let ((data (org--plot/values-stats
+					 (mapcar #'string-to-number (cdr row)))))
+			      (format
+			       "\"%s\" %s %s %s"
+			       (car row)
+			       (or (plist-get params :ymin)
+				   (plist-get data :nice-min))
+			       (or (plist-get params :ymax)
+				   (plist-get data :nice-max))
+			       (if (eq ticks 0) 2 ticks)
+			       )))
+			  table)))
+	 (setup-file (make-temp-file "org-plot-setup")))
+    (f-write-text (format org--plot/radar-setup-template data settings)
+		  'utf-8 setup-file)
+    (format org--plot/radar-template
+	    setup-file
+	    (if (eq ticks 0) 2 ticks)
+	    (if (eq ticks 0) ""
+	      (apply #'format org--plot/radar-ticks
+		     (make-list 3 (if (and (plist-get params :ymin)
+					   (plist-get params :ymax))
+				      ;; FIXME multi-drawing of tick labels with "1"
+				      "1" "$1")))))))
+
 (defcustom org-plot/gnuplot-term-extra ""
   "String or function which provides the extra term options.
 E.g. a value of \"size 1050,650\" would cause
-- 
2.27.0


[-- Attachment #2.10.1: Type: text/html, Size: 2356 bytes --]

[-- Attachment #3.1: Type: text/html, Size: 5762 bytes --]

             reply	other threads:[~2020-07-08 22:07 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-08 21:36 TEC [this message]
2020-07-30  5:17 ` WIP: Org-plot work TEC
2020-09-05  7:29   ` Bastien
2020-09-05 15:35     ` TEC
2020-09-06  5:34       ` Bastien
2020-09-06  5:39         ` TEC
  -- strict thread matches above, loose matches on Subject: below --
2020-09-07 18:54 Mario Frasca
2020-09-08  3:21 ` TEC

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=875zaxlmeo.fsf@gmail.com \
    --to=tecosaur@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --cc=schulte.eric@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).