Fix low-high estimates

* doc/org.texi (Column attributes): Emphasize estimates format.
  Document degenerate case of plain numbers.
* lisp/org-colview.el (org-columns-compute): Properly sum estimates.
(org-columns-string-to-number): Recognize estimates containing an
unit.
(org-estimate-mean-and-var, org-estimate-print): Allow numbers as
a degenerate case of estimates.

Reported-by: yary <not.com@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/93505>
This commit is contained in:
Nicolas Goaziou 2014-12-16 23:48:41 +01:00
parent 389274c1c4
commit c1558d34d7
2 changed files with 29 additions and 18 deletions

View File

@ -5569,7 +5569,7 @@ optional. The individual parts have the following meaning:
@{@@min@} @r{Minimum age (in days/hours/mins/seconds).} @{@@min@} @r{Minimum age (in days/hours/mins/seconds).}
@{@@max@} @r{Maximum age (in days/hours/mins/seconds).} @{@@max@} @r{Maximum age (in days/hours/mins/seconds).}
@{@@mean@} @r{Arithmetic mean of ages (in days/hours/mins/seconds).} @{@@mean@} @r{Arithmetic mean of ages (in days/hours/mins/seconds).}
@{est+@} @r{Add low-high estimates.} @{est+@} @r{Add @samp{low-high} estimates.}
@end example @end example
@noindent @noindent
@ -5578,11 +5578,12 @@ include. Subsequent columns referencing the same property will all display the
same summary information. same summary information.
The @code{est+} summary type requires further explanation. It is used for The @code{est+} summary type requires further explanation. It is used for
combining estimates, expressed as low-high ranges. For example, instead combining estimates, expressed as @samp{low-high} ranges or plain numbers.
of estimating a particular task will take 5 days, you might estimate it as For example, instead of estimating a particular task will take 5 days, you
5--6 days if you're fairly confident you know how much work is required, or might estimate it as 5--6 days if you're fairly confident you know how much
1--10 days if you don't really know what needs to be done. Both ranges work is required, or 1--10 days if you don't really know what needs to be
average at 5.5 days, but the first represents a more predictable delivery. done. Both ranges average at 5.5 days, but the first represents a more
predictable delivery.
When combining a set of such estimates, simply adding the lows and highs When combining a set of such estimates, simply adding the lows and highs
produces an unrealistically wide result. Instead, @code{est+} adds the produces an unrealistically wide result. Instead, @code{est+} adds the

View File

@ -952,8 +952,12 @@ display, or in the #+COLUMNS line of the current buffer."
valflag (and val (string-match "\\S-" val))) valflag (and val (string-match "\\S-" val)))
(cond (cond
((< level last-level) ((< level last-level)
;; put the sum of lower levels here as a property ;; Put the sum of lower levels here as a property. If
(setq sum (+ (if (and (/= last-level inminlevel) ;; values are estimate, use an appropriate sum function.
(setq sum (funcall
(if (eq fun 'org-estimate-combine) #'org-estimate-combine
#'+)
(if (and (/= last-level inminlevel)
(aref lvals last-level)) (aref lvals last-level))
(apply fun (aref lvals last-level)) 0) (apply fun (aref lvals last-level)) 0)
(if (aref lvals inminlevel) (if (aref lvals inminlevel)
@ -1071,6 +1075,9 @@ display, or in the #+COLUMNS line of the current buffer."
(while l (while l
(setq sum (+ (string-to-number (pop l)) (/ sum 60)))) (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
sum)) sum))
((memq fmt '(checkbox checkbox-n-of-m checkbox-percent))
(if (equal s "[X]") 1. 0.000001))
((memq fmt '(estimate)) (org-string-to-estimate s))
((string-match (concat "\\([0-9.]+\\) *\\(" ((string-match (concat "\\([0-9.]+\\) *\\("
(regexp-opt (mapcar 'car org-effort-durations)) (regexp-opt (mapcar 'car org-effort-durations))
"\\)") s) "\\)") s)
@ -1079,9 +1086,6 @@ display, or in the #+COLUMNS line of the current buffer."
(while l (while l
(setq sum (+ (string-to-number (pop l)) (/ sum 60)))) (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
sum)) sum))
((memq fmt '(checkbox checkbox-n-of-m checkbox-percent))
(if (equal s "[X]") 1. 0.000001))
((memq fmt '(estimate)) (org-string-to-estimate s))
(t (string-to-number s))))) (t (string-to-number s)))))
(defun org-columns-uncompile-format (cfmt) (defun org-columns-uncompile-format (cfmt)
@ -1509,7 +1513,10 @@ This will add overlays to the date lines, to show the summary for each day."
(defun org-estimate-mean-and-var (v) (defun org-estimate-mean-and-var (v)
"Return the mean and variance of an estimate." "Return the mean and variance of an estimate."
(let* ((low (float (car v))) (let* ((v (cond ((consp v) v)
((numberp v) (list v v))
(t (error "Invalid estimate type"))))
(low (float (car v)))
(high (float (cadr v))) (high (float (cadr v)))
(mean (/ (+ low high) 2.0)) (mean (/ (+ low high) 2.0))
(var (/ (+ (expt (- mean low) 2.0) (expt (- high mean) 2.0)) 2.0))) (var (/ (+ (expt (- mean low) 2.0) (expt (- high mean) 2.0)) 2.0)))
@ -1532,8 +1539,11 @@ and variances (respectively) of the individual estimates."
(defun org-estimate-print (e &optional fmt) (defun org-estimate-print (e &optional fmt)
"Prepare a string representation of an estimate. "Prepare a string representation of an estimate.
This formats these numbers as two numbers with a \"-\" between them." This formats these numbers as two numbers with a \"-\" between them."
(if (null fmt) (set 'fmt "%.0f")) (let ((fmt (or fmt "%.0f"))
(format "%s" (mapconcat (lambda (n) (format fmt n)) e "-"))) (e (cond ((consp e) e)
((numberp e) (list e e))
(t (error "Invalid estimate type")))))
(format "%s" (mapconcat (lambda (n) (format fmt n)) e "-"))))
(defun org-string-to-estimate (s) (defun org-string-to-estimate (s)
"Convert a string to an estimate. "Convert a string to an estimate.