![带有多色对角条纹的甘特图](https://linux22.com/image/444306/%E5%B8%A6%E6%9C%89%E5%A4%9A%E8%89%B2%E5%AF%B9%E8%A7%92%E6%9D%A1%E7%BA%B9%E7%9A%84%E7%94%98%E7%89%B9%E5%9B%BE.png)
我曾经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
。它类似于Lines
tikz 库中的模式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}