emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Review of code adding grouping feature to Gantt chart creation
@ 2012-06-13 15:19 julia.jacobson
  0 siblings, 0 replies; only message in thread
From: julia.jacobson @ 2012-06-13 15:19 UTC (permalink / raw)
  To: emacs-orgmode


[-- Attachment #1.1: Type: text/plain, Size: 1547 bytes --]

Dear Orgmode Community,

Some time ago, Eric Fraga wrote a lisp function and some LaTeX code to generate Gantt charts from within orgmode and posted it to this mailing list.
This code proved to be very helpful to me and therefore I added a feature for indicating the progress of a task, which has also been posted to this list.
Some project management tools like Microsoft Project or Taskjuggler allow to visually summarize neighboring tasks in a group by aligning them under a limiting bar. I tried to implement this feature in Eric Fraga's code, too, and hope that some of you might find it helpful. 
Moreover, the attachment of this post contains an improvement of the progress bar feature, which I added previously.
Please don't hesitate to write me if you discover a bug in my code or have any ideas for improvement.
Maybe someone is even willing to add it to org-mode's the library of babel.
Finally, I would like to put up for discussion, whether it makes to add new features for generating Gantt charts like this.
After all, there is already the possibility to create very elaborate Gantt charts from an orgmode file by exporting to taskjuggler.
Furthermore, there's a LaTeX package called pgfgantt, which simplifies the creation of Gantt charts.
The advantage of the lisp and LaTeX code is that it doesn't create any additional dependencies (well, maybe except for TikZ which ships with current TeX distributions). 
The best architectural solution might be to write a Orgmode interface for the pgfgantt LaTeX package.

Kind regards,
Julia

[-- Attachment #2: group_prog.org --]
[-- Type: application/octet-stream, Size: 10146 bytes --]

#+TITLE:     Gantt charts with feature for grouping
#+AUTHOR:    Julia Jacobson
#+EMAIL:     julia.jacobson@arcor.de
#+DATE:      \today
#+LASTCHANGE:      2012.06.13 15:30:00
#+DESCRIPTION: 
#+KEYWORDS: 
#+LANGUAGE:  en
#+OPTIONS:   H:3 num:nil toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
#+OPTIONS:   TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
#+EXPORT_SELECT_TAGS: export
#+EXPORT_EXCLUDE_TAGS: noexport
#+LINK_UP:   
#+LINK_HOME: 

#+latex_header: \usepackage{pgf, pgfarrows, pgfnodes}
#+latex_header: \usepackage{tikz}

#+latex_header: \newcommand\ganttline[4]{% line, tag, start end
#+latex_header:   \node at (0,#1) [anchor=base east] {#2};
#+latex_header:   \fill[black!20!white] (#3/20,#1-.2) rectangle (#4/20,#1+.2);}

* Table of tasks and milestones   :noexport:

  An additional type ''group'' for grouping tasks is added.

#+tblname: gantttesttable
    |    | type      |   label | activity           | depends | start | duration | end | align | progress |
    |----+-----------+---------+--------------------+---------+-------+----------+-----+-------+----------|
    |  1 | date      |   Start |                    |         |     0 |          |   0 |       |          |
    |  4 | group     |         | Practical Work     |         |     0 |       14 |  14 |       |          |
    |  2 | task      |     1.1 | Lit survey         |         |     0 |        2 |   2 | right |       75 |
    |  3 | task      |     1.2 | Measurements       |         |     2 |        6 |   8 |       |       40 |
    |  4 | milestone |      M1 | data collected     |       3 |     8 |          |   8 |       |          |
    |  5 | task      |     1.3 | Report             |       3 |     8 |        6 |  14 |       |       30 |
    |  6 | date      | 14 days |                    |         |    14 |          |  14 |       |          |
    |  7 | milestone |      M2 | Release            |       5 |    14 |          |  14 |       |          |
    |----+-----------+---------+--------------------+---------+-------+----------+-----+-------+----------|
    |  4 | group     |         | Post-release tasks |         |    14 |        2 |  16 | left  |          |
    |  8 | task      |     2.1 | Discuss            |       5 |    14 |        1 |  15 | left  |       90 |
    |  9 | task      |     2.2 | Correct mistakes   |       8 |    15 |        1 |  16 | left  |       10 |
    | 10 | task      |     2.3 | Add feedback       |       5 |    14 |        2 |  16 | left  |       50 |
    | 11 | date      |     End |                    |         |    16 |          |  16 |       |          |
    |----+-----------+---------+--------------------+---------+-------+----------+-----+-------+----------|
    #+TBLFM: address@hidden::$8=$6+$7::@address@hidden::@address@hidden::@address@hidden::@address@hidden::@address@hidden

* lisp code for creating latex that uses above			   :noexport:
#+name: elispgantt
#+begin_src emacs-lisp :var table=gantttesttable :results raw :export results
(defun esf/generate-gantt-chart (table)
  (let ((dates "")
	(entries (nthcdr 2 table))
	(milestones "")
	(nmilestones 0)
	(ntasks 0)
	(projecttime 0)
	(tasks "")
	(xlength 1)
	(progress 1)
	)
    (message "Initial: %s\n" table)
    (message "Entries: %s\n" entries)
    (while entries
      (let ((entry (first entries)))
	(if (listp entry)
	    (let ((id (first entry))
		  (type (nth 1 entry))
		  (label (nth 2 entry))
		  (task (nth 3 entry))
		  (dependencies (nth 4 entry))
		  (start (nth 5 entry))
		  (duration (nth 6 entry))
		  (end (nth 7 entry))
		  (alignment (nth 8 entry))
		  (progress (nth 9 entry))
		  )
	      (if (> start projecttime) (setq projecttime start))
	      (if (string= type "task")
		  (let ((end (+ start duration))
			(textposition (+ start (/ duration 2)))
			(flush "")
			)
		    (if (string= alignment "left")
			(progn
			  (setq textposition start)
			  (setq flush "[left]"))
		      (if (string= alignment "right")
			  (progn
			    (setq textposition end)
			    (setq flush "[right]"))
			)
		      )
		    (setq tasks (format "%s  \\gantttask{%s}{%s}{%d}{%d}{%d}{%s}{%d}\n" tasks label task start end textposition flush progress))
		    (setq ntasks (+ 1 ntasks))
		    (if (> end projecttime)
			(setq projecttime end))
		    )
	      (if (string= type "group")
		  (let ((end (+ start duration))
			(textposition (+ start (/ duration 2)))
			(flush "")
			)
		    (if (string= alignment "left")
			(progn
			  (setq textposition start)
			  (setq flush "[left]"))
		      (if (string= alignment "right")
			  (progn
			    (setq textposition end)
			    (setq flush "[right]"))
			)
		      )
		    (setq tasks (format "%s  \\ganttgroup{%s}{%s}{%d}{%d}{%d}{%s}\n" tasks label task start end textposition flush))
		    (setq ntasks (+ 1 ntasks))
		    (if (> end projecttime)
			(setq projecttime end))
		    )
              ) 
		(if (string= type "milestone")
		    (progn
		      (setq milestones (format "%s  \\ganttmilestone{$\\begin{array}{c}\\mbox{%s}\\\\ \\mbox{%s}\\end{array}$}{%d}\n" milestones label task start))
		      (setq nmilestones (+ 1 nmilestones)))
		  (if (string= type "date")
		      (setq dates (format "%s  \\ganttdateline{%s}{%d}\n" dates label start))
		    (message "Ignoring entry with type %s\n" type)
		    )
		  )
		)
	      )
	  (message "Ignoring non-list entry %s\n" entry)
	  ) ; end if list entry
	(setq entries (cdr entries))
	)
      ) ; end while entries left
    (format "#+begin_latex
\\pgfdeclarelayer{background}
\\pgfdeclarelayer{foreground}
\\pgfsetlayers{background,foreground}
\\renewcommand{\\ganttprojecttime}{%d}
\\renewcommand{\\ganttntasks}{%d}
\\noindent
\\begin{tikzpicture}[y=-0.75cm,x=0.75\\textwidth]
  \\begin{pgfonlayer}{background}
    \\draw[very thin, red!10!white] (0,1+\\ganttntasks) grid [ystep=0.75cm,xstep=1/\\ganttprojecttime] (1,0);
    \\draw[\\ganttdatelinecolour] (0,0) -- (1,0);
    \\draw[\\ganttdatelinecolour] (0,1+\\ganttntasks) -- (1,1+\\ganttntasks);
  \\end{pgfonlayer}
%s
%s
%s
\\end{tikzpicture}
,#+end_latex\n" projecttime ntasks tasks milestones dates)
    )
  )
(esf/generate-gantt-chart table)
#+end_src

* Time line

#+latex_header: \usepackage{tikz}

#+begin_latex
\newcounter{gantttask}
\newcommand{\ganttprogresscolour}{green!75!white}
\newcommand{\ganttremainingcolour}{red!75!white}
\newcommand{\ganttmilestonecolour}{red!50!white}
\newcommand{\ganttdatelinecolour}{black!50!white}
\newcommand{\ganttprojecttime}{1}
\newcommand{\ganttntasks}{1}
\newcommand\gantttask[7]{% label, activity, start, end, labelpos, align, progress
  \begin{pgfonlayer}{foreground}
    \stepcounter{gantttask}
    \node [left] at (0,\thegantttask) {#1};
    \draw[fill=\ganttremainingcolour,draw=no] (#3/\ganttprojecttime,\thegantttask-0.4) rectangle (#4/\ganttprojecttime,\thegantttask + 0.4);
    \draw[fill=\ganttprogresscolour,draw=no] (#3/\ganttprojecttime,\thegantttask-0.3) rectangle (#3/\ganttprojecttime + #7/100 * #4/\ganttprojecttime - #7/100 * #3/\ganttprojecttime,\thegantttask + 0.3);
    \node at (#5/\ganttprojecttime,\thegantttask) #6 {#2};
  \end{pgfonlayer}
}
\newcommand\ganttgroup[6]{% label, activity, start, end, labelpos, align 
  \begin{pgfonlayer}{foreground}
    \stepcounter{gantttask}
    \node [left] at (0,\thegantttask) {#1};
    \fill[blue] (#3/\ganttprojecttime-0.1/\ganttprojecttime,\thegantttask-0.3) rectangle (#4/\ganttprojecttime+0.1/\ganttprojecttime,\thegantttask +0.3);
    \fill[blue] (#3/\ganttprojecttime-0.1/\ganttprojecttime,\thegantttask+0.3) -- (#3/\ganttprojecttime,\thegantttask+0.4) -- (#3/\ganttprojecttime+0.1/\ganttprojecttime,\thegantttask+0.3) -- cycle;
    \fill[blue] (#4/\ganttprojecttime+0.1/\ganttprojecttime,\thegantttask+0.3) -- (#4/\ganttprojecttime,\thegantttask+0.4) -- (#4/\ganttprojecttime-0.1/\ganttprojecttime,\thegantttask+0.3) -- cycle;
    \node at (#5/\ganttprojecttime,\thegantttask) [text=black] #6 {#2};
  \end{pgfonlayer}
}
\newcommand\ganttpoint[3]{% line, tag, date
  \node at (0,#1) [anchor=base east] {#2};
  \fill[black] (#3/\ganttprojecttime,#1) circle (0.1/\ganttprojecttime);
}
\newcommand\ganttdateline[2]{% tag, date
  \begin{pgfonlayer}{background}
    \draw[\ganttdatelinecolour] (#2/\ganttprojecttime,0) -- (#2/\ganttprojecttime,\thegantttask+1);
    \node at (#2/\ganttprojecttime,0) [above] {#1};
  \end{pgfonlayer}
}
\newcommand\ganttmilestone[2]{% tag, date
  \begin{pgfonlayer}{foreground}
    \node at (#2/\ganttprojecttime,\thegantttask+1.0) [below] {#1};
    \draw[black,fill=\ganttmilestonecolour] (#2/\ganttprojecttime-0.1\ganttntasks/\ganttprojecttime,\thegantttask+0.9) rectangle (#2/\ganttprojecttime+0.1\ganttntasks/\ganttprojecttime,\thegantttask+1.1);
  \end{pgfonlayer}
}

#+END_LaTeX

#+RESULTS: elispgantt

#+begin_latex
\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,foreground}
\renewcommand{\ganttprojecttime}{16}
\renewcommand{\ganttntasks}{8}
\noindent
\begin{tikzpicture}[y=-0.75cm,x=0.75\textwidth]
  \begin{pgfonlayer}{background}
    \draw[very thin, red!10!white] (0,1+\ganttntasks) grid [ystep=0.75cm,xstep=1/\ganttprojecttime] (1,0);
    \draw[\ganttdatelinecolour] (0,0) -- (1,0);
    \draw[\ganttdatelinecolour] (0,1+\ganttntasks) -- (1,1+\ganttntasks);
  \end{pgfonlayer}
  \ganttgroup{}{Practical Work}{0}{14}{7}{}
  \gantttask{1.1}{Lit survey}{0}{2}{2}{[right]}{75}
  \gantttask{1.2}{Measurements}{2}{8}{5}{}{40}
  \gantttask{1.3}{Report}{8}{14}{11}{}{30}
  \ganttgroup{}{Post-release tasks}{14}{16}{14}{[left]}
  \gantttask{2.1}{Discuss}{14}{15}{14}{[left]}{90}
  \gantttask{2.2}{Correct mistakes}{15}{16}{15}{[left]}{10}
  \gantttask{2.3}{Add feedback}{14}{16}{14}{[left]}{50}

  \ganttmilestone{$\begin{array}{c}\mbox{M1}\\ \mbox{data collected}\end{array}$}{8}
  \ganttmilestone{$\begin{array}{c}\mbox{M2}\\ \mbox{Release}\end{array}$}{14}

  \ganttdateline{Start}{0}
  \ganttdateline{14 days}{14}
  \ganttdateline{End}{16}

\end{tikzpicture}
#+end_latex
#+   \\draw[help lines, very thin, red!20!white] (0,%s) grid (\\ganttprojecttime,0);

# <<actions>>

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2012-06-13 15:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-13 15:19 Review of code adding grouping feature to Gantt chart creation julia.jacobson

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).