带有多色对角条纹的甘特图

带有多色对角条纹的甘特图

我曾经pgfgantt为我的项目工作包制作过一个简单的甘特图:

\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}

我想根据每个工作包分配的工作人员对条形进行颜色编码。总共有六名工作人员,每人都有一种独特的颜色。每个工作包最多有三名工作人员。理想情况下,我想用对角条纹来显示这一点,因为水平条纹可能太细而看不清,而垂直条纹会与时间细分的分配混淆。基本上,我希望能够像这样给条形着色,每个条形使用一种、两种或三种颜色:

甘特图显示实线或两种或三种交替颜色条纹

我在这里找到了一些双色条纹的例子,但它们似乎不容易适应三色条纹。

答案1

Tikz(或 pgf)模式可以解决您的问题。

使用 n 色条纹 (n >= 2) 填充无色图案(也称为“仅形式”),您必须应用模式 n-1 次,因为无色模式只能有一种颜色,由选项指定pattern color

注意链接答案使用普通填充和无色图案来postaction实现双色条纹。因此,三色条纹将需要两个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}

使用无色图案的三色条纹

要使用彩色图案,以下示例中定义了一个新模式Stripes。它类似于Linestikz 库中的模式patterns.meta,但有一个新选项color series={<comma list of colors>}。该line width选项无效,现在自动计算为 的 1/n,distance其中 n 是 的长度color series。因此distance=6pt, color series={red, blue},对于 ,线宽为 3pt;对于distance=6pt, color series={red, green, blue},线宽为 2pt。

color series具有初始值和默认值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}

在此处输入图片描述

相关内容