4

(To-the-point question at the end of the post) I am using the following snippet to draw Gantt diagrams, taken from this source:

% GanttHeader setups some parameters for the rest of the diagram
% #1 Width of the diagram
% #2 Width of the space reserved for task numbers
% #3 Width of the space reserved for task names
% #4 Number of months in the diagram
% In addition to these parameters, the layout of the diagram is influenced
% by keys defined below, such as y, which changes the vertical scale
\def\GanttHeader#1#2#3#4{%
 \pgfmathparse{(#1-#2-#3)/#4}
 \tikzset{y=7mm, task number/.style={left, font=\bfseries},
     task description/.style={text width=#3,  right, draw=none,
           font=\sffamily, xshift=#2,
           minimum height=2em},
     gantt bar/.style={draw=black, fill=blue!30},
     help lines/.style={draw=black!30, dashed},
     x=\pgfmathresult pt
     }
  \def\totalmonths{#4}
  \node (Header) [task description] at (0,0) {\textbf{\large Tasks}};
  \begin{scope}[shift=($(Header.south east)$)]
    \foreach \x in {1,...,#4}
      \node[above] at (\x,0) {\footnotesize\x};
 \end{scope}
}

% This macro adds a task to the diagram
% #1 Number of the task
% #2 Task's name
% #3 Starting date of the task (month's number, can be non-integer)
% #4 Task's duration in months (can be non-integer)
\def\Task#1#2#3#4{%
\node[task number] at ($(Header.west) + (0, -#1)$) {#1};
\node[task description] at (0,-#1) {#2};
\begin{scope}[shift=($(Header.south east)$)]
  \draw (0,-#1) rectangle +(\totalmonths, 1);
  \foreach \x in {1,...,\totalmonths}
    \draw[help lines] (\x,-#1) -- +(0,1);
  \filldraw[gantt bar] ($(#3, -#1+0.2)$) rectangle +(#4,0.6);
\end{scope}
}

And the result is excellent, I would like to stick with this method rather than using pgfgantt or other packages with which I haven't had it so easy to create a Gantt diagram, here's an exaple of a generated diagram with that snippet in the preamble:

\begin{figure}
\begin{tikzpicture}
  \GanttHeader{textheight}{2ex}{7cm}{7}
  \Task{1}{First task}{0.5}{2.5}
  \Task{2}{Second task}{1.5}{2}
  \Task{3}{Another one}{3}{1}
  \Task{4}{Another one}{4}{1}
  \Task{5}{Yet another one}{5}{2}
\end{tikzpicture}
\caption{My figure's caption.}
\label{fig:gantt}
\end{figure}

The only thing I need is to add an arrow that shows predecessors for some tasks. Let's say an arrow going from the end of task 1, to the beginning of task 4. I have tried to set identifiers for the nodes defined in the \Task definition but I am quite a noob with Tikz.

Sample Gantt from the previously cited source :

enter image description here

How can I add arrows from the end of one rectangle to the start of another? Preferably stair-like arrows (only horizontal and vertical lines). Otherwise, a way to declare \nodes inside the Task definition in the desired places would help a lot!

Fully working example including needed packages:

\documentclass[10pt,a4paper]{article}
\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}

\usepackage{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{graphicx}

% GanttHeader setups some parameters for the rest of the diagram
% #1 Width of the diagram
% #2 Width of the space reserved for task numbers
% #3 Width of the space reserved for task names
% #4 Number of months in the diagram
% In addition to these parameters, the layout of the diagram is influenced
% by keys defined below, such as y, which changes the vertical scale
\def\GanttHeader#1#2#3#4{%
 \pgfmathparse{(#1-#2-#3)/#4}
 \tikzset{y=7mm, task number/.style={left, font=\bfseries},
     task description/.style={text width=#3,  right, draw=none,
           font=\sffamily, xshift=#2,
           minimum height=2em},
     gantt bar/.style={draw=black, fill=blue!30},
     help lines/.style={draw=black!30, dashed},
     x=\pgfmathresult pt
     }
  \def\totalmonths{#4}
  \node (Header) [task description] at (0,0) {\textbf{\large Tasks}};
  \begin{scope}[shift=($(Header.south east)$)]
    \foreach \x in {1,...,#4}
      \node[above] at (\x,0) {\footnotesize\x};
 \end{scope}
}

% This macro adds a task to the diagram
% #1 Number of the task
% #2 Task's name
% #3 Starting date of the task (month's number, can be non-integer)
% #4 Task's duration in months (can be non-integer)
\def\Task#1#2#3#4{%
\node[task number] at ($(Header.west) + (0, -#1)$) {#1};
\node[task description] at (0,-#1) {#2};
\begin{scope}[shift=($(Header.south east)$)]
  \draw (0,-#1) rectangle +(\totalmonths, 1);
  \foreach \x in {1,...,\totalmonths}
    \draw[help lines] (\x,-#1) -- +(0,1);
  \filldraw[gantt bar] ($(#3, -#1+0.2)$) rectangle +(#4,0.6);
\end{scope}
}

\begin{document}
    \begin{figure}
    \begin{tikzpicture}
      \GanttHeader{\textwidth}{2ex}{4cm}{7}
      \Task{1}{First task}{0.5}{2.5}
      \Task{2}{Second task}{1.5}{2}
      \Task{3}{Another one}{3}{1}
      \Task{4}{Another one}{4}{1}
      \Task{5}{Yet another one}{5}{2}
    \end{tikzpicture}
    \caption{My figure's caption.}
    \label{fig:gantt}
    \end{figure}
\end{document}
5
  • Welcome to TeX.SX! Please help us to help you and add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}.
    – user31729
    Commented Jun 9, 2014 at 18:08
  • Take a look at the pgfgantt package, that has macros for creating such arrows in its ganttchart environment. Commented Jun 9, 2014 at 18:20
  • I was thinking the same as @TorbjørnT., I didn't understand what you meant that you don't want to use pgfgantt Commented Jun 9, 2014 at 18:35
  • Oh, I didn't see that you had mentioned pgfgantt. Apologies. Commented Jun 9, 2014 at 18:38
  • The fact is that I'm quite happy with the shown result, I just one to add the arrows to the mix. If necessary I'll switch to pgfgantt, but I think it should be simpler to add the arrows (maybe not) Commented Jun 9, 2014 at 19:32

2 Answers 2

2

If you modify \Task to the following you get named coordinates at the ends of each rectangle, called 1a,1b,2a etc. Na is at the left edge, Nb at the right edge.

\def\Task#1#2#3#4{%
\node[task number] at ($(Header.west) + (0, -#1)$) {#1};
\node[task description] at (0,-#1) {#2};
\begin{scope}[shift=($(Header.south east)$)]
  \draw (0,-#1) rectangle +(\totalmonths, 1);
  \foreach \x in {1,...,\totalmonths}
    \draw[help lines] (\x,-#1) -- +(0,1);
  \filldraw[gantt bar] ($(#3, -#1+0.2)$) rectangle +(#4,0.6);
  \coordinate (#1a) at (#3,-#1+0.5); % coordinate at left end of box
  \coordinate (#1b) at (#3+#4,-#1+0.5);  % coordinate at right end of box
\end{scope}
}

The two last lines in the scope are new.

I started by thinking only of the case where the boxes overlap, in which case the following macro lets you draw arrows easily.

\newcommand\arrowwhereboxesoverlap[3][]{%
  % #1: arrow style
  % #2: number of first task
  % #3: number of second task
  \path (#2b) ++(0.2,-0.5) coordinate (tmpa);
  \path (#3a) ++(-0.2,0) coordinate (tmpb);
  \draw [#1] (#2b) -| (tmpa) -| (tmpb) -- (#3a);
  }

Use e.g.

\startendarrow[thick,red,->]{1}{2}

to draw an arrow from the first to second box.

For the case where there is no overlap, such as from 2 to 4, the drawing is simpler (less corners), so you can do something like

\draw [blue,dashed,very thick,->] (2b) -- ++ (0.2,0) |- (4a);

This can of course also be wrapped in a macro, if desired.

Complete example:

\documentclass[10pt,a4paper]{article}
\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}

\usepackage{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{graphicx}

% GanttHeader setups some parameters for the rest of the diagram
% #1 Width of the diagram
% #2 Width of the space reserved for task numbers
% #3 Width of the space reserved for task names
% #4 Number of months in the diagram
% In addition to these parameters, the layout of the diagram is influenced
% by keys defined below, such as y, which changes the vertical scale
\def\GanttHeader#1#2#3#4{%
 \pgfmathparse{(#1-#2-#3)/#4}
 \tikzset{y=7mm, task number/.style={left, font=\bfseries},
     task description/.style={text width=#3,  right, draw=none,
           font=\sffamily, xshift=#2,
           minimum height=2em},
     gantt bar/.style={draw=black, fill=blue!30},
     help lines/.style={draw=black!30, dashed},
     x=\pgfmathresult pt
     }
  \def\totalmonths{#4}
  \node (Header) [task description] at (0,0) {\textbf{\large Tasks}};
  \begin{scope}[shift=($(Header.south east)$)]
    \foreach \x in {1,...,#4}
      \node[above] at (\x,0) {\footnotesize\x};
 \end{scope}
}

% This macro adds a task to the diagram
% #1 Number of the task
% #2 Task's name
% #3 Starting date of the task (month's number, can be non-integer)
% #4 Task's duration in months (can be non-integer)
\def\Task#1#2#3#4{%
\node[task number] at ($(Header.west) + (0, -#1)$) {#1};
\node[task description] at (0,-#1) {#2};
\begin{scope}[shift=($(Header.south east)$)]
  \draw (0,-#1) rectangle +(\totalmonths, 1);
  \foreach \x in {1,...,\totalmonths}
    \draw[help lines] (\x,-#1) -- +(0,1);
  \filldraw[gantt bar] ($(#3, -#1+0.2)$) rectangle +(#4,0.6);
  \coordinate (#1a) at (#3,-#1+0.5);
  \coordinate (#1b) at (#3+#4,-#1+0.5);
\end{scope}
}

\newcommand\arrowwhereboxesoverlap[3][]{%
  % #1: arrow style
  % #2: number of first task
  % #3: number of second task
  \path (#2b) ++(0.2,-0.5) coordinate (tmpa);
  \path (#3a) ++(-0.2,0) coordinate (tmpb);
  \draw [#1] (#2b) -| (tmpa) -| (tmpb) -- (#3a);
  }

\begin{document}
    \begin{figure}
    \begin{tikzpicture}
      \GanttHeader{\textwidth}{2ex}{4cm}{7}
      \Task{1}{First task}{0.5}{2.5}
      \Task{2}{Second task}{1.5}{2}
      \Task{3}{Another one}{3}{1}
      \Task{4}{Another one}{4}{1}
      \Task{5}{Yet another one}{5}{2}

      \arrowwhereboxesoverlap[thick,red,->]{1}{2}
      \draw [blue,dashed,very thick,->] (2b) -- ++ (0.2,0) |- (4a);
\end{tikzpicture}
    \caption{My figure's caption.}
    \label{fig:gantt}
    \end{figure}
\end{document}

enter image description here

1

How do you feel about this? I'm using the pgfgantt package for the Gantt diagrams and pdflscape to get the landscape mode

\documentclass{report}

\usepackage{pgfgantt}
\usepackage{pdflscape}

\definecolor{barblue}{RGB}{153,204,254} %up to 255

\begin{document}
\pagestyle{empty}
\begin{landscape}
    \begin{figure}
    \centering
        \begin{ganttchart}[%Specs
            y unit title=0.4cm,
            y unit chart=0.5cm,
            canvas/.style={fill=none, draw=black, line width=.75pt},
            vgrid,
            title label anchor/.style={below=-1.6ex},
            title left shift=.05,
            title right shift=-.05,
            title height=1,
            title/.style={fill=none},
            title label font=\bfseries,
            bar/.style={fill=barblue},
            incomplete/.style={fill=white},
            progress label text={},
            bar height=0.7,
            group right shift=0,
            group top shift=.6,
            group height=.3,
            group peaks height=.2]{1}{36}

            %labels
            \gantttitle{2014}{36}\\
            \gantttitle{Jan}{3}
            \gantttitle{Feb}{3}
            \gantttitle{Mar}{3}
            \gantttitle{Apr}{3}
            \gantttitle{May}{3}
            \gantttitle{Jun}{3}
            \gantttitle{Jul}{3}
            \gantttitle{Aug}{3}
            \gantttitle{Set}{3}
            \gantttitle{Oct}{3}
            \gantttitle{Nov}{3}
            \gantttitle{Dec}{3}\\

            % Parameter Selection
            \ganttgroup{Group 1}{2}{18}\\ %elem0
            \ganttbar[progress=0]{Bar}{2}{18}\\
            \ganttmilestone{Mileston}{18}\\\\

            % Testing equipment
            \ganttgroup{Group 2}{2}{18}\\ %elem0
            \ganttbar[progress=0]{Bar}{2}{18}\\
            \ganttmilestone{Milestone}{18}\\\\

            % Testing
            \ganttgroup{Group 3}{19}{35}\\ 
            \ganttbar[progress=0]{Bar}{19}{35}\\
            \ganttbar[progress=0]{Bar}{19}{35}\\
            \ganttmilestone{Milestone}{27}\\
            \ganttmilestone{Milestone}{35}\\

            % Algorithm Development
            \ganttgroup{Group 4}{28}{35}\\ 
            \ganttbar[progress=0]{Bar}{28}{35} \\

            %relations 
            \ganttlink{elem2}{elem6}
            \ganttlink{elem5}{elem6}
            \ganttlink{elem9}{elem11}

        \end{ganttchart}
    \caption{Gantt diagram for the first year (2014)}
    \label{fig:Gantt2014}
    \end{figure}
\end{landscape}

\end{document}

enter image description here

1
  • Thanks a lot for the pgfgantt example, wish I could mark two answers as valid. I find my original method a lot simpler though, even if less complete it offers just what I needed. However, thanks for this complete sample, I will sure use it when I need more complex Gantt diagrams. Commented Jun 9, 2014 at 21:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .