2

I have used pgfgantt to produce a simple Gantt chart for the work packages of my project:

\documentclass{article}

\usepackage{pgfgantt}

\begin{document} \begin{ganttchart}[expand chart=\textwidth]{1}{48} \gantttitle[]{Year 1}{12} \gantttitle[]{Year 2}{12} \gantttitle[]{Year 3}{12} \gantttitle[]{Year 4}{12}\

\ganttbar{WP1}{1}{48} \ \ganttbar{WP2}{4}{15} \ \ganttbar{WP3}{10}{30} \ \ganttbar{WP4}{20}{45}
\end{ganttchart}% \end{document}

I want to colour-code the bars according to which staff members will be assigned to each work package. There are six staff members in total, each with a unique colour. Up to three staff members will work on each work package. Ideally I'd like to show this with diagonal stripes, since horizontal stripes might be too thin to make out, and vertical stripes would be confused with allocation to the time subdivisions. Basically I'd like to be able to colour the bars like this, with one, two, or three colours per bar:

Gantt chart showing bars which are either solid or have stripes in two or three alternating colours

I have found a few examples here of two-colour stripes, but they don't seem to be easily adaptable to three-colour stripes.

Psychonaut
  • 3,142

1 Answers1

1

Tikz (or pgf) patterns can solve your problem.

To fill with n-color stripes (n >= 2) using an uncolored pattern (also called "form-only"), you have to apply a pattern n-1 times since an uncolored pattern can only have a single color, which is specified by option pattern color.

Notice how the linked answer uses normal filling and an uncolored pattern in postaction to achieve a two-color stripes. So a three-color stripes will need two postaction.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{patterns.meta}

\begin{document} \begin{tikzpicture} \fill[fill=red, % set line width to 1/3 of the distance % set xshift according to both angle and line width postaction={ pattern={Lines[angle=30, distance=9pt, line width=3pt, xshift=3pt/sin(30)]}, pattern color=green}, postaction={ pattern={Lines[angle=30, distance=9pt, line width=3pt, xshift=-3pt/sin(30)]}, pattern color=blue}, ] (0,0) rectangle +(2,1); \end{tikzpicture} \end{document}

three-color stripes using uncolored pattern

To do the same task using a colored pattern, a new pattern Stripes is defined in the example below. It is similar to the pattern Lines from tikz library patterns.meta, with a new option color series={<comma list of colors>}. The line width option is invalid and now auto computed as 1/n of distance in which n is the length of color series. Hence with distance=6pt, color series={red, blue}, the line width is 3pt; with distance=6pt, color series={red, green, blue}, the line width is 2pt.

color series has initial and default value red, green, blue

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{patterns.meta}

\usepackage{pgfgantt}

\makeatletter \newlength\pgf@pat@distance % or defined by the more portable \newdimen

% based on pattern Lines, defined in pgflibrarypatterns.meta.code.tex \pgfdeclarepattern{ name=Stripes, type=colored, parameters={ \pgfkeysvalueof{/pgf/pattern keys/distance}, \pgfkeysvalueof{/pgf/pattern keys/angle}, \pgfkeysvalueof{/pgf/pattern keys/xshift}, \pgfkeysvalueof{/pgf/pattern keys/yshift}, \pgfkeysvalueof{/pgf/pattern keys/color series}, }, bottom left={% \pgfpoint{-.5\pgf@pat@distance}{-.5\pgf@pat@distance}}, top right={% \pgfpoint{.5\pgf@pat@distance}{.5\pgf@pat@distance}}, tile size={% \pgfpoint {\pgfkeysvalueof{/pgf/pattern keys/distance}}% {\pgfkeysvalueof{/pgf/pattern keys/distance}}}, tile transformation={% \pgftransformshift{% \pgfpoint {\pgfkeysvalueof{/pgf/pattern keys/xshift}}% {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}% \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}}, defaults={ distance/.initial=6pt, angle/.initial=0, xshift/.initial=0pt, yshift/.initial=0pt, color series/.initial={red,green,blue}, }, code={% \pgf@pat@colorseries@parse % set line width \pgfsetlinewidth{\pgf@pat@distance/\pgfutil@tempcnta}% % \pgfutil@tempdima holds the y-coord of a stripe \pgfutil@tempdima=\dimexpr-.5\pgf@pat@distance+.5\pgflinewidth\relax % draw stripes \pgfutil@tempcnta=0 \pgfutil@for\pgf@pat@temp:=\pgf@pat@colorseries\do{% \ifx\pgf@pat@temp\pgfutil@empty \else \pgfsetstrokecolor{\pgf@pat@temp}% \pgfpathmoveto{% \pgfpoint{-.5\pgf@pat@distance}{\pgfutil@tempdima}}% \pgfpathlineto{% \pgfpoint{ .5\pgf@pat@distance}{\pgfutil@tempdima}}% \pgfusepath{stroke}% \advance\pgfutil@tempdima\pgflinewidth \fi }% }, set up code={% \pgfmathsetlength{\pgf@pat@distance}{\pgfkeysvalueof{/pgf/pattern keys/distance}}% } }

% util \def\pgf@pat@colorseries@parse{% % prepare \pgf@pat@colorseries and store its length in \pgfutil@tempcnta \let\pgf@pat@colorseries\pgfutil@empty \pgfutil@tempcnta=0 \pgfkeysgetvalue{/pgf/pattern keys/color series}{\pgf@pat@colorseries@temp}% \pgfutil@for\pgf@temp:=\pgf@pat@colorseries@temp\do{% % strip spaces around color names and skip empty items % the total effect is to convert red, blue,, cyan to red,blue,cyan \expandafter\pgfkeys@spdef\expandafter\pgf@temp\expandafter{\pgf@temp}% \ifx\pgf@temp\pgfutil@empty \else \edef\pgf@pat@colorseries{% \unexpanded\expandafter{\pgf@pat@colorseries},% \unexpanded\expandafter{\pgf@temp}}% \advance\pgfutil@tempcnta by 1 \fi }% % ensure the resulting color series is never empty \ifnum\pgfutil@tempcnta=0 \def\pgf@pat@colorseries{red,green,blue}% \fi } \makeatother

\begin{document} \begin{tikzpicture} \fill[pattern={Lines[angle=30]}] (0,0) rectangle +(2,1);

\fill[pattern={Stripes[angle=30]}] (0,-1.5) rectangle +(2,1); \fill[pattern={Stripes[angle=30, color series={gray, darkgray}]}] (3,-1.5) rectangle +(2,1); \fill[pattern={Stripes[angle=30, distance=12pt, color series={cyan, magenta, yellow, black}]}] (6,-1.5) rectangle +(2,1); \fill[pattern={Stripes[angle=30, distance=12pt, color series={cyan!50!black!50}]}] (9,-1.5) rectangle +(2,1); \end{tikzpicture} \bigskip

% helper option \pgfqkeys{/pgfgantt}{ bar pattern/.style={ bar/.append style={ pattern={Stripes[angle=45,distance=15pt,color series={#1}]} } }, bar pattern/.default={red,green,blue}, }

\noindent \begin{ganttchart}[expand chart=\textwidth]{1}{48} \gantttitle[]{Year 1}{12} \gantttitle[]{Year 2}{12} \gantttitle[]{Year 3}{12} \gantttitle[]{Year 4}{12} \

\ganttbar[bar pattern]{WP1}{1}{48} \ \ganttbar[bar pattern={blue, green}]{WP2}{4}{15} \ \ganttbar[bar pattern={blue, red}]{WP3}{10}{30} \ \ganttbar[bar pattern={red}]{WP4}{20}{45} \end{ganttchart} \end{document}

enter image description here

muzimuzhi Z
  • 26,474
  • Your examples look exactly like what I'm looking for, however they don't look nearly the same when I tried them out (in an otherwise blank document). The tikzpicture is a predominantly red image, with tiny green and blue strips. In the Gantt document, all patterns are predominantly white, with some little squares in colours (e.g. WP1 is white, with larger blue rectangles and smaller green ones). Any chance you could update your working example please? – penelope Feb 21 '24 at 18:22
  • @penelope How did you compile the example? I just got the expected output with pdflatex, latest texlive 2023. – muzimuzhi Z Feb 21 '24 at 18:30
  • I'm using overleaf, but reading other questions with patterns got me even more confused. It seems that in some cases, the issue is my browser (e.g. the example from this question looks horrid in Firefox but fine when I download the PDF https://tex.stackexchange.com/a/643157/10588). On the other hand, your examples both don't look as intended when I download the PDF – penelope Feb 21 '24 at 18:35
  • Even stranger, going from the same example I linked above, it seems that both the rendering in my browser and on the dowloaded PDF look correct when I set the line width to double the line distance (which really shouldn't work, I know!), except that the direction of the pattern is reversed for 90 degrees. – penelope Feb 21 '24 at 18:47
  • @penelope "On the other hand, your examples both don't look as intended when I download the PDF" Compiling examples in this answer and the linked answer on overleaf (texlive 2023 + pdflatex), yes the outputs both look horrid in browser (Chrome), but the downloaded PDFs both look fine in Adobe Acrobat Reader on macOS here. I guess it's a rendering issue specific to PDF viewers/rendering libraries. – muzimuzhi Z Feb 21 '24 at 18:59