From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id oMSKH6dDBl9IcQAA0tVLHw (envelope-from ) for ; Wed, 08 Jul 2020 22:07:35 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id iBJtG6dDBl/nEAAAbx9fmQ (envelope-from ) for ; Wed, 08 Jul 2020 22:07:35 +0000 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id BAACC940215 for ; Wed, 8 Jul 2020 22:07:33 +0000 (UTC) Received: from localhost ([::1]:35514 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jtIE0-0004P7-Le for larch@yhetil.org; Wed, 08 Jul 2020 18:07:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:36724) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jtHjv-0003mW-V0 for emacs-orgmode@gnu.org; Wed, 08 Jul 2020 17:36:27 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]:36462) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jtHjs-0003GP-JH for emacs-orgmode@gnu.org; Wed, 08 Jul 2020 17:36:27 -0400 Received: by mail-pf1-x42f.google.com with SMTP id 207so52876pfu.3 for ; Wed, 08 Jul 2020 14:36:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=user-agent:from:to:cc:subject:message-id:date:mime-version; bh=NvR2rhALCjoDUqzXCxzn2erWilZaYUoC1aBQWNoKqY0=; b=WCFlIUp5Yy5VmL4T6qWn079kWwmo76N/08qAmhY1wV8hMi1KBegzgzlt9q9yQVotU2 GRVcpPfAnt0v5O8c4ehIgaXx4+XnbKk9Q5YaFLT35mlfCyE1RMOy7Ak93OJrL8Voenwo C+nnL4MkVEIRNiW25gcZC1bT3DElHv4ieZXrJH7cEHAyW1Bs5EX/YTnd6ZhRGOKfykTi WFw9y7rj+bnScWIkVJ0froh01bG/yGytdKM1IFmRe2sUqOiVbql5qRkQGlek38RDgiqS Svi+BdsSgnQSdE5kpRtfmIITce/tnuW481VcTrENDvld2NETUuTwtMLTmpzSzRodc7QP W7Yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:user-agent:from:to:cc:subject:message-id:date :mime-version; bh=NvR2rhALCjoDUqzXCxzn2erWilZaYUoC1aBQWNoKqY0=; b=shHvD6K64Yb657zZLkhKHU4S/Je+7VXaH/eOklT54Aqw/Haomz7DSMVVdBA2Y6V57r jY0IjKuc7k8O7iy4eyxoDspLgswy6lR0EWkbWMUUPwTBrEZ9247RU5+eQhUpdXTjVXel oVoFuNJC2kzJsEIzZA/eMkewFlRNSsCTaS5pJztkSmt3xr5C87lprvwfTSef+V7IbnmQ ZSaFgVsVpOl8frUz2DLy+QBTefRvWCWpJdScUSjkJc+fYmFW4fC2O+ZNlOABpd+/0jED Q88J5jPnUbeBBGujxWivWmBYgPT4VxcMqurLd5OxMpN0ykQl3psCopB2UkTN6lC/hybC a73Q== X-Gm-Message-State: AOAM531PlfAsZbRnBskZeukEp0aRPxOi1cKH6aIBaq7lXKG/bF3cz0YF bOuyOlbnTHWJeyZIQ/SJxfEHp0BP X-Google-Smtp-Source: ABdhPJxlq57rFsKqW1GOP2GKbjG2snf8EeMrRy5y84wKbqs7y852ee8Oqeqf/Zn5SxMa4ChQgUc0EA== X-Received: by 2002:a63:9d87:: with SMTP id i129mr51849292pgd.412.1594244182663; Wed, 08 Jul 2020 14:36:22 -0700 (PDT) Received: from localhost (180-150-91-8.b4965b.per.nbn.aussiebb.net. [180.150.91.8]) by smtp.gmail.com with ESMTPSA id y6sm428544pji.2.2020.07.08.14.36.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 08 Jul 2020 14:36:21 -0700 (PDT) User-agent: mu4e 1.4.10; emacs 26.3 From: TEC To: org-mode-email Subject: WIP: Org-plot work Message-ID: <875zaxlmeo.fsf@gmail.com> Date: Thu, 09 Jul 2020 05:36:16 +0800 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::42f; envelope-from=tecosaur@gmail.com; helo=mail-pf1-x42f.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -6 X-Spam_score: -0.7 X-Spam_bar: / X-Spam_report: (-0.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, HTML_OBFUSCATE_05_10=0.26, MPART_ALT_DIFF_COUNT=1.112, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eric Schulte Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Scanner: scn0 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20161025 header.b=WCFlIUp5; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of emacs-orgmode-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=emacs-orgmode-bounces@gnu.org X-Spam-Score: -1.71 X-TUID: K5W6Eky1xFxL --=-=-= Content-Type: text/plain --=-=-= Content-Type: multipart/alternative; boundary="==-=-=" --==-=-= Content-Type: text/plain; format=flowed 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. --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Replace-inconsistent-indentation-in-org-plot.patch >From 28a7513494f17be0b2219482ebc55f0ce22a0c67 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-Add-new-org-plot-argument-transpose.patch >From 495307540ff757b8b4f6f756e456b0bed90801a0 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-Add-org-plot-custom-to-add-content-to-all-plots.patch >From 253b9d22ebee26ae89127de9071cac0ee6bfbd23 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-Extract-org-plot-presets-to-custom-variable.patch >From 4db0363ed85c02ec7938450083cc9013e0c00138 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-Add-some-utility-functions-to-org-plot-axis-ticks.patch >From 9563381eaa15ae0f9714709d4c1de3bcf3e4edda Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0006-Allow-for-customisation-of-org-plot-s-term.patch >From 2d88ddd8d4bb2144bfe7e2608d0379794b51aaf6 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0007-Org-plot-tweak-term-and-preamble-custom-vars.patch >From c154151fbc3383ff8bcc735542e446c82c18a868 Mon Sep 17 00:00:00 2001 From: TEC 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 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0008-Org-plot-add-radar-plot-type.patch >From a7af0ff66917f92c735735d88eeccb5019937273 Mon Sep 17 00:00:00 2001 From: TEC 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 < 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.
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0001-Replace-inconsistent-indentation-in-org-plot.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0002-Add-new-org-plot-argument-transpose.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0003-Add-org-plot-custom-to-add-content-to-all-plots.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0004-Extract-org-plot-presets-to-custom-variable.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0005-Add-some-utility-functions-to-org-plot-axis-ticks.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0006-Allow-for-customisation-of-org-plot-s-term.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0007-Org-plot-tweak-term-and-preamble-custom-vars.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0008-Org-plot-add-radar-plot-type.patch” disposition=attachment>
<#/part>

--===-=-=-- --==-=-=-- --=-=-= Content-Type: multipart/related; boundary="====-=-=" --====-=-= Content-Type: text/html

<#multipart type=alternative><#part type=text/plain>
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.
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0001-Replace-inconsistent-indentation-in-org-plot.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0002-Add-new-org-plot-argument-transpose.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0003-Add-org-plot-custom-to-add-content-to-all-plots.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0004-Extract-org-plot-presets-to-custom-variable.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0005-Add-some-utility-functions-to-org-plot-axis-ticks.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0006-Allow-for-customisation-of-org-plot-s-term.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0007-Org-plot-tweak-term-and-preamble-custom-vars.patch” disposition=attachment>
<#/part>
<#part type=“text/x-patch” filename=“home/tec.emacs.d/.local/straight/repos/org-mode/0008-Org-plot-add-radar-plot-type.patch” disposition=attachment>
<#/part>
<#multipart type=related><#part type=text/html><p>
Hi All,<br />
</p>

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

<p>
If that&rsquo;s you, please let me know what you think :)<br />
</p>

<p>
All the best,<br />
</p>

<p>
Timothy.<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0001-Replace-inconsistent-indentation-in-org-plot.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0002-Add-new-org-plot-argument-transpose.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0003-Add-org-plot-custom-to-add-content-to-all-plots.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0004-Extract-org-plot-presets-to-custom-variable.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0005-Add-some-utility-functions-to-org-plot-axis-ticks.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0006-Allow-for-customisation-of-org-plot-s-term.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0007-Org-plot-tweak-term-and-preamble-custom-vars.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br >
&lt;#part type=&ldquo;text/x-patch&rdquo; filename=&ldquo;<i>home/tec</i>.emacs.d
.local/straight/repos/org-mode/0008-Org-plot-add-radar-plot-type.patch&rdquo; disposition=attachment&gt;<br />
&lt;#/part&gt;<br />
</p>
<#/multipart>
<#/multipart>

--====-=-=-- --=-=-=--