I'm looking for a way to use time tracking information from org-mode agenda files to build a timetable. Time spent in different tasks would be indicated, grouped by tag and restricted to a given time-frame, sort of like a clocktable dynamic block, but grouped by tag instead of file/category/headline.
For example, if my agenda contained the following data (possibly scattered among different files):
* TODO project 1
** TODO task 1 :tag1:
:LOGBOOK:
CLOCK: [2013-06-27 Thu 18:00]--[2013-06-27 Thu 19:04] => 1:04
CLOCK: [2013-06-26 Wed 17:00]--[2013-06-26 Wed 17:32] => 0:32
:END:
** TODO task 2 :tag2:
:LOGBOOK:
CLOCK: [2013-06-27 Thu 17:00]--[2013-06-27 Thu 18:00] => 1:00
CLOCK: [2013-06-27 Thu 15:00]--[2013-06-27 Thu 15:50] => 0:50
:END:
* TODO project 2 :tag2:
:LOGBOOK:
CLOCK: [2013-06-27 Thu 19:04]--[2013-06-27 Thu 21:00] => 1:56
CLOCK: [2013-06-27 Thu 15:50]--[2013-06-27 Thu 17:00] => 1:10
:END:
I would like to get this kind of results:
#+BEGIN: clocktable-by-tag :maxlevel 2 :tags ("p1" "p2") :tstart "2013-06-27" :tend "2013-06-28"
| Tag | Headline | Time | |
|------+-----------------+--------+------|
| tag1 | *Tag time* | *1:04* | |
| | TODO project 1 | 1:04 | |
| | \__ TODO task 1 | | 1:04 |
|------+-----------------+--------+------|
| tag2 | *Tag time* | *4:56* | |
| | TODO project 1 | 1:50 | |
| | \__ TODO task 2 | | 1:50 |
| | TODO project 2 | 3:06 | |
#+END:
Is there any standard way to do this with org? If not, I'm thinking of cycling through agenda files and tags, using org-get-table-data to collect clocking information; would there be another, more efficient way of doing things?
Here is what I've come to: https://gist.github.com/ffevotte/5899058
It's not very optimized, but seems to get the job done and should support most of the clocktable dynamic block arguments.
Sample (anonymized) output on my real org agenda files:
#+BEGIN: clocktable-by-tag :tags ("p_f3c" "p_sc") :tstart "2013-01-01" :tend "2013-05-19" :maxlevel 2
| Tag | Headline | Time (h) | | |
| | | <r> | | |
|-------+------------------------------+----------+-------+------|
| p_f3c | *Tag time* | *18.42* | | |
| | File *xxx.org* | 18.42 | | |
| | . xxxxxxxxxxxxxxxxxxx | | 13.03 | |
| | . \__ xxxxxxxxxxxxx | | | 7.78 |
| | . \__ xxxxxxxxxxxxxxxxxxxxx | | | 3.98 |
| | . xxxxxxxxxxxxxxxxxx | | 5.38 | |
| | . \__ xxxxxxxxxxxxxxx | | | 5.38 |
|-------+------------------------------+----------+-------+------|
| p_sc | *Tag time* | *18.90* | | |
| | File *yyyy.org* | 4.42 | | |
| | . xxxxxxxxxxxxxxxxxxxxxx | | 2.83 | |
| | . xxxxxxxxxxxxxxxxxx | | 1.58 | |
| | . \__ xxxxxxxxxxxxxxxxxxxxxx | | | 1.58 |
| | File *todo.org* | 14.48 | | |
| | . xxxxxxxxxxxxxxxx | | 14.48 | |
| | . \__ xxxxxxxxxxx | | | 2.00 |
| | . \__ xxxxxxxxxxxxx | | | 8.48 |
| | . \__ xxxxx | | | 4.00 |
#+END:
I have come up with an improvement of this solution that allows for a :summary t option and better formatting of the hours (using org-duration-from-minutes). You can find it in this gist. The result with summarising enabled looks like this:
#+BEGIN: clocktable-by-tag :tags ("work" "client1") :summary t
| Tag | Headline | Time (h) |
|---------+------------+----------|
| work | *Tag time* | 1:29 |
|---------+------------+----------|
| client1 | *Tag time* | 0:45 |
#+END:
Note: I came up with this solution while answering a similar question.
Related
Suppose such a spreadsheet in org table
|------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------+-------+------------+--------+--------+------------|
| 2019/09/17 | A | 2.64 | 1 | 2.64 | materials |
| | B | 52.67 | 2 | 105.34 | diagnosis |
| | C | 3.08 | 1 | 3.08 | materials |
| | D | 3.85 | 2 | 7.7 | materials |
| | E | 33.66 | 2 | 67.32 | materials |
| | F | 40 | 1 | 40 | treatments |
| | G | 16.5 | 1 | 16.5 | materials |
| | H | 4 | 3 | 12 | treatments |
| | I | 40 | 1 | 40 | bed |
| x | M | 6 | 13 | 78 | treatments |
|------------+-------+------------+--------+--------+------------|
#+TBLFM: $5=$3*$4
I want to sum up the material fees.
Is it possible to calculate it by grouping like vsum(where Categories == materials)?
One way to do this with an elisp expression will be:
|------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------+-------+------------+--------+--------+------------|
| 2019/09/17 | A | 2.64 | 1 | 2.64 | materials |
| | B | 52.67 | 2 | 105.34 | diagnosis |
| | C | 3.08 | 1 | 3.08 | materials |
| | D | 3.85 | 2 | 7.7 | materials |
| | E | 33.66 | 2 | 67.32 | materials |
| | F | 40 | 1 | 40 | treatments |
| | G | 16.5 | 1 | 16.5 | materials |
| | H | 4 | 3 | 12 | treatments |
| | I | 40 | 1 | 40 | bed |
| x | M | 6 | 13 | 78 | treatments |
|------------+-------+------------+--------+--------+------------|
| TOTAL: | | | | 97.24 | |
|------------+-------+------------+--------+--------+------------|
#+TBLFM: $5=$3*$4
#+TBLFM: #12$5='(apply #'+ (cl-mapcar (lambda (num category) (if (eq category 'materials) num 0)) '(#II$5..#III$5) '(#II$6..#III$6)));L
cl-mapcar applies + to cell #12$5 by comparing the list which is column 6 to symbol'materials.
This solution and a `calc solution in emacsSE
Suppose such a spreadsheet in org table
|------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------+-------+------------+--------+--------+------------|
| 2019/09/17 | A | 2.64 | 1 | 2.64 | materials |
| | B | 52.67 | 2 | 105.34 | diagnosis |
| | C | 3.08 | 1 | 3.08 | materials |
| | D | 3.85 | 2 | 7.7 | materials |
| | E | 33.66 | 2 | 67.32 | materials |
| | F | 40 | 1 | 40 | treatments |
| | G | 16.5 | 1 | 16.5 | materials |
| | H | 4 | 3 | 12 | treatments |
| | I | 40 | 1 | 40 | bed |
| | M | 6 | 13 | 78 | treatments |
|------------+-------+------------+--------+--------+------------|
#+TBLFM: $5=$3*$4
How could copy the date 2019/09.17 to the bottom of data column?
The link that #manandearth posted in the comments describes how to duplicate (perhaps with slight modifications) the entries in a column. Briefly, pressing S-RET in a cell duplicates its contents from the cell above (if it is not empty) - if the cell is full and the next cell is empty then it duplicates the full cell to the empty cell. If the contents are numeric, then the "duplication" involves a slight modification: it increases the value by 1. The same happens with a date: it increases the date to next day (but the date has to be in a format that Org mode recognizes: either an active date <YYYY-MM-DD> or an inactive data [YYYY-MM-DD]). The increment by default is 1 in these cases, but can be set to something else by setting the variable org-table-copy-increment to a different value. That's the "interactive" case I mention in my comment.
The other way to fill a column in a table is by using a formula. For example here's a formula to fill the first column with a copy of the first entry in the column:
#+TBLFM: #3$1..#>$1 = #2$1
This says: Set all rows from row 3 (#3) to the last row (#>) of column 1 ($1) to the value of the cell in row 2 (#2), column 1 ($1). Note that row 1 is the header. Press C-c C-c on the table formula line above and ... wait, what happened?
|------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------+-------+------------+--------+--------+------------|
| 2019/09/17 | A | 2.64 | 1 | 2.64 | materials |
| 13.196078 | B | 52.67 | 2 | 105.34 | diagnosis |
| 13.196078 | C | 3.08 | 1 | 3.08 | materials |
| 13.196078 | D | 3.85 | 2 | 7.7 | materials |
| 13.196078 | E | 33.66 | 2 | 67.32 | materials |
| 13.196078 | F | 40 | 1 | 40 | treatments |
| 13.196078 | G | 16.5 | 1 | 16.5 | materials |
| 13.196078 | H | 4 | 3 | 12 | treatments |
| 13.196078 | I | 40 | 1 | 40 | bed |
| 13.196078 | M | 6 | 13 | 78 | treatments |
|------------+-------+------------+--------+--------+------------|
#+TBLFM: #3$1..#>$1 = #2$1
It does not quite work in this case for a technical reason: Org mode uses Calc in table formula calculations and Calc looks at 2019/09/17 and says: "Aha, I have to divide 2019 by 9 and then divide the result by 17", and fills the rest of the column with the result of the divisions: 13.196078. You may have meant 2019/09/17 to be a date, but Org mode does not know that: it gives it to Calc which interprets it as an arithmetic expression. The solution here is the same as in the linked answer: make Org mode aware that it's a date by making it either an active date: <2019-09-17> or an inactive date: [2019-09-17]:
|------------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------------+-------+------------+--------+--------+------------|
| [2019-09-17] | A | 2.64 | 1 | 2.64 | materials |
| [2019-09-17 Tue] | B | 52.67 | 2 | 105.34 | diagnosis |
| [2019-09-17 Tue] | C | 3.08 | 1 | 3.08 | materials |
| [2019-09-17 Tue] | D | 3.85 | 2 | 7.7 | materials |
| [2019-09-17 Tue] | E | 33.66 | 2 | 67.32 | materials |
| [2019-09-17 Tue] | F | 40 | 1 | 40 | treatments |
| [2019-09-17 Tue] | G | 16.5 | 1 | 16.5 | materials |
| [2019-09-17 Tue] | H | 4 | 3 | 12 | treatments |
| [2019-09-17 Tue] | I | 40 | 1 | 40 | bed |
| [2019-09-17 Tue] | M | 6 | 13 | 78 | treatments |
|------------------+-------+------------+--------+--------+------------|
#+TBLFM: #3$1..#>$1 = #2$1
This does not do automatic incrementation but if that's what you want, it's easy to accomplish: Calc can do calculations on dates, so we can increment daily by adding to the date in each row the row number minus 2 (e.g. row 3 would get an increment of 3 - 2 = 1, row 4 would get 4 - 2 = 2, etc). To accomplish this, you have to get the row number of the current row: the idiom is ##. Then the formula becomes:
#+TBLFM: #3$1..#>$1 = #2$1 + ## - 2
and the table becomes:
|------------------+-------+------------+--------+--------+------------|
| Date | Items | Unit Price | Amount | Amount | Categories |
|------------------+-------+------------+--------+--------+------------|
| [2019-09-17] | A | 2.64 | 1 | 2.64 | materials |
| [2019-09-18 Wed] | B | 52.67 | 2 | 105.34 | diagnosis |
| [2019-09-19 Thu] | C | 3.08 | 1 | 3.08 | materials |
| [2019-09-20 Fri] | D | 3.85 | 2 | 7.7 | materials |
| [2019-09-21 Sat] | E | 33.66 | 2 | 67.32 | materials |
| [2019-09-22 Sun] | F | 40 | 1 | 40 | treatments |
| [2019-09-23 Mon] | G | 16.5 | 1 | 16.5 | materials |
| [2019-09-24 Tue] | H | 4 | 3 | 12 | treatments |
| [2019-09-25 Wed] | I | 40 | 1 | 40 | bed |
| [2019-09-26 Thu] | M | 6 | 13 | 78 | treatments |
|------------------+-------+------------+--------+--------+------------|
#+TBLFM: #3$1..#>$1 = #2$1+ ## - 2
The various anomalies of the display of dates (do we include the day of the week? do we include the time?) might be worked around using org-time-stamp-custom-formats but that gets us into waters that I have not explored.
Based on the dataset below, I'm trying to get the lastest cost based on the latest report date.
For example: When the report date=forecast date (column headers) then pick the values as on that report date which can be achived by this formula
IF [Report Date]=[Forecast Date] THEN [Forecasted Cost] END
but I also want to get the subsequent values as of the lastest report date i.e. 2/15/2019. How do I achieve this?
DESIRED OUTPUT
+------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| | 8/15/2018 | 9/15/2018 | 10/15/2018 | 11/15/2018 | 12/15/2018 | 1/15/2019 | 2/15/2019 | 3/15/2019 | 4/15/2019 | 5/15/2019 | 6/15/2019 | 7/15/2019 | 8/15/2019 |
+------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| Final Cost | 646.00 | 646.00 | 620.00 | 620.00 | 550.00 | 445.00 | 361.00 | 332.50 | 315.40 | 296.40 | 290.70 | 285.00 | 279.30 |
+------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
DATASET
+------+-------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| Item | Report Date | 8/15/2018 | 9/15/2018 | 10/15/2018 | 11/15/2018 | 12/15/2018 | 1/15/2019 | 2/15/2019 | 3/15/2019 | 4/15/2019 | 5/15/2019 | 6/15/2019 | 7/15/2019 | 8/15/2019 |
+------+-------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| 4124 | 8/15/2018 | 646.00 | 646.00 | 658.00 | 658.00 | 658.00 | 658.00 | 658.00 | | | | | | |
| 4124 | 9/15/2018 | | 646 | 626 | 626 | 626 | 622 | 622 | 622 | | | | | |
| 4124 | 10/15/2018 | | | 620 | 620 | 620 | 585 | 585 | 585 | 555 | | | | |
| 4124 | 11/15/2018 | | | | 620 | 620 | 610 | 595 | 554.5 | 543.38 | 535.35 | | | |
| 4124 | 12/15/2018 | | | | | 550 | 535 | 505 | 490 | 490 | 490 | 490 | | |
| 4124 | 1/15/2019 | | | | | | 445 | 430 | 420 | 410 | 400 | 390 | 384 | |
| 4124 | 2/15/2019 | | | | | | | 361 | 332.5 | 315.4 | 296.4 | 290.7 | 285 | 279.3 |
+------+-------------+-----------+-----------+------------+------------+------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
First of all, you need to transpose your dataset, i.e. to have 4 columns "Item", "Report Date", "Forecast Date" and "Forecast Cost". Then you create a filter "forecast date >= report date" and show values by forecast date.
Now you will have multiple values for each forecast date. if you only want to get the latest value, then you can use table calculation window_min(date diff).
I have the following table:
| Year (Beginn) | Price | Increase |
|---------------+----------+----------|
| 2016 | 20000.00 | 1000.00 |
| 2017 | | 1000.00 |
| 2018 | | 1000.00 |
| 2019 | | 1000.00 |
| 2020 | | 1000.00 |
| 2021 | | 1000.00 |
| 2022 | | 1000.00 |
| 2023 | | 1000.00 |
| 2024 | | 1000.00 |
| 2025 | | 1000.00 |
| 2026 | | 1000.00 |
| 2027 | | 1000.00 |
| 2028 | | 1000.00 |
| 2029 | | 1000.00 |
| 2030 | | 1000.00 |
|---------------+----------+----------|
I want to compute the price recursively such that the final table looks like this:
| Year (Beginn) | Price | Increase |
|---------------+----------+----------|
| 2016 | 20000.00 | 1000.00 |
| 2017 | 22000.00 | 1000.00 |
| 2018 | 24000.00 | 1000.00 |
| 2019 | 26000.00 | 1000.00 |
| 2020 | 28000.00 | 1000.00 |
| 2021 | 30000.00 | 1000.00 |
| 2022 | 32000.00 | 1000.00 |
| 2023 | 34000.00 | 1000.00 |
| 2024 | 36000.00 | 1000.00 |
| 2025 | 38000.00 | 1000.00 |
| 2026 | 40000.00 | 1000.00 |
| 2027 | 42000.00 | 1000.00 |
| 2028 | 44000.00 | 1000.00 |
| 2029 | 46000.00 | 1000.00 |
| 2030 | 48000.00 | 1000.00 |
|---------------+----------+----------|
After reading a related SO question I tried the formula
#+TBLFM: #<<<..>$2=#<<..>>$2+2*$3
but it doesn't work. It gives an error and also seems to operate on column one instead of the specified column two. Any idea how to correctly compute column two? I am using org-mode version 8.2.5c with Emacs version 24.5.1.
I recommend using the following range formula:
| Year (Beginn) | Price | Increase |
|---------------+----------+----------|
| 2016 | 20000.00 | 1000.00 |
| 2017 | | 1000.00 |
| 2018 | | 1000.00 |
| 2019 | | 1000.00 |
| 2020 | | 1000.00 |
| 2021 | | 1000.00 |
| 2022 | | 1000.00 |
| 2023 | | 1000.00 |
| 2024 | | 1000.00 |
| 2025 | | 1000.00 |
| 2026 | | 1000.00 |
| 2027 | | 1000.00 |
| 2028 | | 1000.00 |
| 2029 | | 1000.00 |
| 2030 | | 1000.00 |
|---------------+----------+----------|
#+TBLFM: #<<<$2..#>$2=#<<$0+2*vsum(#<<$3..#-1$3);%.2f
You could write a recursive formula, but that would propogate one row at a time. Even org-table-iterate (C-u C-u C-c * on any table cell) would have to be called more than once, since it stops after 10 iterations.
GNU Emacs 24.4.1 org-mode
Here is an org-mode table
#+TBLNAME: revenue
| / | < | | < | | < | | | | | | | | | | | |
| Product | Year_SUM | Month_SUM | Platform | Platform_SUM | adwo | AdMob | adChina | adSage | appfigures | appdriver | coco | Domob | Dianru | Limei | guohead | youmi |
| | | | | | | | | | | | | | | | | |
|---------+----------+-----------+----------+------------------+------+-------+---------+--------+------------+-----------+------+-------+--------+-------+---------+-------|
| Jan | | | iOS | #ERROR | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| | | | Android | =vsum($6..$>);NE | | 1 | | 1 | | 1 | | 1 | | 1 | | 1 |
|---------+----------+-----------+----------+------------------+------+-------+---------+--------+------------+-----------+------+-------+--------+-------+---------+-------|
| | | | | | | | | | | | | | | | | |
#+TBLFM: $5=vsum($6..$>);NE
As you see ,the formula $5=vsum($6..$>);NE can't be calculated! Here is debug info:
Substitution history of formula
Orig: vsum($6..$>)
$xyz-> vsum($6..$>)
#r$c-> vsum($6..$>)
$1-> vsum((0)..$>)
--------^
Error: Expected `)'
But if I replace the formula with $5=vsum($6..$17) and then it works ,I can't figure out where is the problem?
I need some help ,appreciate it!