Forráskód Böngészése

org-plot.el: complete transition to softcoded type

* lisp/org-plot.el (org-plot/preset-plot-types): Adapt structure to
cover all type-specific logic within org-plot.
(org-plot/gnuplot-script, org-plot/gnuplot): Replace type-specific logic
with references to properties of the type from
`org-plot/preset-plot-types'.
TEC 4 éve
szülő
commit
1ac45d76e8
1 módosított fájl, 143 hozzáadás és 99 törlés
  1. 143 99
      lisp/org-plot.el

+ 143 - 99
lisp/org-plot.el

@@ -291,7 +291,10 @@ If a function, it is called with the plot type as the argument."
   :type '(choice string function))
 
 (defcustom org-plot/preset-plot-types
-  '((2d (lambda (data-file num-cols params plot-str)
+  '((2d :plot-cmd "plot"
+	:check-ind-type t
+	:plot-func
+	(lambda (_table 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))
@@ -315,23 +318,60 @@ If a function, it is called with the plot type as the argument."
 			       (or (nth col col-labels)
 				   (format "%d" (1+ col))))
 		       res)))))))
-    (3d (lambda (data-file num-cols params plot-str)
+    (3d :plot-cmd "splot"
+	:plot-pre (lambda (_table _data-file _num-cols params _plot-str)
+		    (if (plist-get params :map) "set map"))
+	:plot-func
+	(lambda (_table 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)
+    (grid :plot-cmd "splot"
+	  :plot-pre (lambda (_table _data-file _num-cols params _plot-str)
+		      (if (plist-get params :map) "set pm3d map" "set map"))
+	  :data-dump (lambda (table data-file params _num-cols)
+		       (let ((y-labels (org-plot/gnuplot-to-grid-data
+					table data-file params)))
+			 (when y-labels (plist-put params :ylabels y-labels))))
+	  :plot-func
+	  (lambda (table 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)))))
-    (radar (lambda (data-file num-cols params plot-str)
+	      (list (format "'%s' with %s title ''"
+			    data-file with)))))
+    (radar :plot-func
+	   (lambda (table _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
-that function. i.e. it is called with the following arguments:
-  DATA-FILE NUM-COLS PARAMS PLOT-STR"
+  "List of plists describing the avalible plot types.
+The car is the type name, and the property :plot-func must be set.
+The value of :plot-func is a lambda which yields plot-lines
+(a list of strings) as the cdr.
+
+All lambda functions have the parameters of `org-plot/gnuplot-script' and PLOT-STR passed to them.
+i.e. they are called with the following signature: (TABLE DATA-FILE NUM-COLS PARAMS PLOT-STR)
+
+Potentially useful parameters in PARAMS include:
+ :set :line :map :title :file :ind :timeind :timefmt :textind
+ :deps :labels :xlabels :ylabels :xmin :xmax :ymin :ymax :ticks
+
+In addition to :plot-func, the following optional properties may be set.
+
+- :plot-cmd - A gnuplot command appended to each plot-line.
+  Accepts string or nil. Default value: nil.
+
+- :check-ind-type - Whether the types of ind values should be checked.
+  Accepts boolean.
+
+- :plot-str - the formula string passed to :plot-func as PLOT-STR
+  Accepts string. Default value: \"'%s' using %s%d%s with %s title '%s'\"
+
+- :data-dump - Function to dump the table to a datafile for ease of use.
+  Accepts lambda function. Default lambda body: (org-plot/gnuplot-to-data table data-file params)
+
+- :plot-pre - Gnuplot code to be inserted early into the script, just after term and output have been set.
+   Accepts string, nil, or lambda function which returns string or nil. Defaults to nil.
+"
   :group 'org-plot
   :type '(alist :value-type (symbol group)))
 
@@ -477,89 +517,90 @@ If a function, it is called with the plot type as the argument."
   :group 'org-plot
   :type '(choice string function))
 
-(defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
+(defun org-plot/gnuplot-script (table 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.
 Optional argument PREFACE returns only option parameters in a
 manner suitable for prepending to a user-specified script."
-  (let* ((type (plist-get params :plot-type))
-	 (with (if (eq type 'grid) 'pm3d (plist-get params :with)))
-	 (sets (plist-get params :set))
-	 (lines (plist-get params :line))
-	 (map (plist-get params :map))
-	 (title (plist-get params :title))
-	 (file (plist-get params :file))
-	 (ind (plist-get params :ind))
-	 (time-ind (plist-get params :timeind))
-	 (timefmt (plist-get params :timefmt))
-	 (text-ind (plist-get params :textind))
-	 (deps (if (plist-member params :deps) (plist-get params :deps)))
-	 (col-labels (plist-get params :labels))
-	 (x-labels (plist-get params :xlabels))
-	 (y-labels (plist-get params :ylabels))
-	 (plot-str "'%s' using %s%d%s with %s title '%s'")
-	 (plot-cmd (pcase type
-		     (`2d "plot")
-		     (`3d "splot")
-		     (`grid "splot")))
-	 (script "reset")
-	 ;; ats = add-to-script
-	 (ats (lambda (line) (setf script (concat script "\n" line))))
-	 plot-lines)
-
-
-    ;; 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 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 type)))
-
-    (pcase type				; type
-      (`2d ())
-      (`3d (when map (funcall ats "set map")))
-      (`grid (funcall ats (if map "set pm3d map" "set pm3d"))))
-    (when title (funcall ats (format "set title '%s'" title))) ; title
-    (mapc ats lines)					       ; line
-    (dolist (el sets) (funcall ats (format "set %s" el)))      ; set
-    ;; Unless specified otherwise, values are TAB separated.
-    (unless (string-match-p "^set datafile separator" script)
-      (funcall ats "set datafile separator \"\\t\""))
-    (when x-labels			; x labels (xtics)
-      (funcall ats
-	       (format "set xtics (%s)"
-		       (mapconcat (lambda (pair)
-				    (format "\"%s\" %d" (cdr pair) (car pair)))
-				  x-labels ", "))))
-    (when y-labels			; y labels (ytics)
-      (funcall ats
-	       (format "set ytics (%s)"
-		       (mapconcat (lambda (pair)
-				    (format "\"%s\" %d" (cdr pair) (car pair)))
-				  y-labels ", "))))
-    (when time-ind			; timestamp index
-      (funcall ats "set xdata time")
-      (funcall ats (concat "set timefmt \""
-			   (or timefmt	; timefmt passed to gnuplot
-			       "%Y-%m-%d-%H:%M:%S") "\"")))
-    (unless preface
-      (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))))
+  (let* ((type-name (plist-get params :plot-type))
+	 (type (cdr (assoc type-name org-plot/preset-plot-types))))
+    (unless type
+      (user-error "Org-plot type `%s' is undefined." type-name))
+    (let* ((sets (plist-get params :set))
+	   (lines (plist-get params :line))
+	   (map (plist-get params :map))
+	   (title (plist-get params :title))
+	   (file (plist-get params :file))
+	   (ind (plist-get params :ind))
+	   (time-ind (plist-get params :timeind))
+	   (timefmt (plist-get params :timefmt))
+	   (text-ind (plist-get params :textind))
+	   (deps (if (plist-member params :deps) (plist-get params :deps)))
+	   (col-labels (plist-get params :labels))
+	   (x-labels (plist-get params :xlabels))
+	   (y-labels (plist-get params :ylabels))
+	   (plot-str (or (plist-get type :plot-str)
+			 "'%s' using %s%d%s with %s title '%s'"))
+	   (plot-cmd (plist-get type :plot-cmd))
+	   (plot-pre (plist-get type :plot-pre))
+	   (script "reset")
+	   ;; ats = add-to-script
+	   (ats (lambda (line) (when line (setf script (concat script "\n" line)))))
+	   plot-lines)
+
+
+      ;; 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
+			     (funcall org-plot/gnuplot-term-extra type))))
+      (when file ; output file
+	(funcall ats (format "set output '%s'" file)))
+
+      (when plot-pre
+	(funcall ats (funcall plot-pre table data-file num-cols params plot-str)))
 
       (funcall ats
-	       (concat plot-cmd " " (mapconcat #'identity
-					       (reverse plot-lines)
-					       ",\\\n    "))))
-    script))
+	       (if (stringp org-plot/gnuplot-script-preamble)
+		   org-plot/gnuplot-script-preamble
+		 (funcall org-plot/gnuplot-script-preamble type)))
+
+      (when title (funcall ats (format "set title '%s'" title))) ; title
+      (mapc ats lines)					       ; line
+      (dolist (el sets) (funcall ats (format "set %s" el)))      ; set
+      ;; Unless specified otherwise, values are TAB separated.
+      (unless (string-match-p "^set datafile separator" script)
+	(funcall ats "set datafile separator \"\\t\""))
+      (when x-labels			; x labels (xtics)
+	(funcall ats
+		 (format "set xtics (%s)"
+			 (mapconcat (lambda (pair)
+				      (format "\"%s\" %d" (cdr pair) (car pair)))
+				    x-labels ", "))))
+      (when y-labels			; y labels (ytics)
+	(funcall ats
+		 (format "set ytics (%s)"
+			 (mapconcat (lambda (pair)
+				      (format "\"%s\" %d" (cdr pair) (car pair)))
+				    y-labels ", "))))
+      (when time-ind			; timestamp index
+	(funcall ats "set xdata time")
+	(funcall ats (concat "set timefmt \""
+			     (or timefmt	; timefmt passed to gnuplot
+				 "%Y-%m-%d-%H:%M:%S") "\"")))
+      (unless preface
+	(let ((type-func (plist-get type :plot-func)))
+	  (when type-func
+	    (setq plot-lines
+		  (funcall type-func table data-file num-cols params plot-str))))
+	(funcall ats
+		 (concat plot-cmd
+			 (when plot-cmd " ")
+			 (mapconcat #'identity
+				    (reverse plot-lines)
+				    ",\\\n    "))))
+      script)))
 
 ;;-----------------------------------------------------------------------------
 ;; facade functions
@@ -599,7 +640,13 @@ line directly before or after the table."
 			(push 'hline (cdr tbl))))
 		    tbl))
 	   (num-cols (length (if (eq (nth 0 table) 'hline) (nth 1 table)
-			       (nth 0 table)))))
+			       (nth 0 table))))
+	   (type (assoc (plist-get params :plot-type)
+			org-plot/preset-plot-types)))
+
+      (unless type
+	(user-error "Org-plot type `%s' is undefined." type-name))
+
       (run-with-idle-timer 0.1 nil #'delete-file data-file)
       (when (eq (cadr table) 'hline)
 	(setf params
@@ -609,15 +656,12 @@ line directly before or after the table."
       (save-excursion (while (and (equal 0 (forward-line -1))
 				  (looking-at "[[:space:]]*#\\+"))
 			(setf params (org-plot/collect-options params))))
-      ;; Dump table to datafile (very different for grid).
-      (pcase (plist-get params :plot-type)
-	(`2d   (org-plot/gnuplot-to-data table data-file params))
-	(`3d   (org-plot/gnuplot-to-data table data-file params))
-	(`grid (let ((y-labels (org-plot/gnuplot-to-grid-data
-				table data-file params)))
-		 (when y-labels (plist-put params :ylabels y-labels)))))
+      ;; Dump table to datafile
+      (if-let ((dump-func (plist-get type :data-dump)))
+	  (funcall dump-func table data-file num-cols params)
+	(org-plot/gnuplot-to-data table data-file params))
       ;; Check type of ind column (timestamp? text?)
-      (when (eq `2d (plist-get params :plot-type))
+      (when (plist-get params :check-ind-type)
 	(let* ((ind (1- (plist-get params :ind)))
 	       (ind-column (mapcar (lambda (row) (nth ind row)) table)))
 	  (cond ((< ind 0) nil) ; ind is implicit
@@ -634,13 +678,13 @@ 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))
+		    (org-plot/gnuplot-script table 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)))
+	  (insert (org-plot/gnuplot-script table data-file num-cols params)))
 	;; Graph table.
 	(gnuplot-mode)
 	(gnuplot-send-buffer-to-gnuplot))