我们大多数人创建的图表必须重复多次,而数据只会发生变化。将 DRY(不要重复自己)编程原则应用于此类问题并非易事。要做到这一点,必须将数据来自推介会。这具有为作者提供更好语义的额外优势,并且可以隐藏pgf
和朋友库的冗长内容。它还使图表外观的渐进式编辑变得更容易。
例如考虑下面显示的图表,数据部分由标题、月份标签和两个数据系列组成:
它们是在如下环境中生成的:
\begin{monthlyChart}
\addTitle{AHU (October)}
\addMonth{Oct-11}
\addPlanned{10}{20}{30}{40}
\addActual {9}{18}{31}{39}
\end{monthlyChart}
问题
我如何抽象环境的创建,即将原始条形图视为主模板可以从中定义其他变体——而不是重复该过程。例如,为了创建略有不同的图表,我使用了相同的环境,如下所示:
\begin{monthlyChart}
\addTitle{Turnover $\times 10^3$}
\addMonth{Jan-11}
\addPlanned{300}{400}{500}{600}
\addActual {300}{400}{500}{600}
\end{monthlyChart}
给出的图表现在可以用于其他目的,结果如下:
我正在寻找一种方法来定义一种createNewChartType
命令,它将使用预定义的模板并调整一些参数,更像 Web 开发中使用的模板和主题之间的关系。冗长而冗长的最低限度如下:
\documentclass[12pt]{article}
\usepackage{tikz}
\usetikzlibrary{patterns}
\usepackage{pgfplots}
\makeatletter
\newcommand\progressChart[8]{
\def\week##1##2{
\footnotesize
\begin{tabular}{c}##1\\
##2\\\end{tabular}
}
\begin{tikzpicture}
\begin{axis}[
width=6.9cm,height=5cm,
bar width=0.3cm,
title={\ctitle},
ymin=0,
% ytick={0,25,50,100,125},
ylabel=Total,
ybar=0,symbolic x coords={A, B, C, D},
xtick=data,
xticklabels={
\week{\Month}{week-1},
\week{\Month}{week-2},
\week{\Month}{week-3},
\week{\Month}{week-4}
},enlarge x limits=true,
legend style={
at={(.43,.98)}, font=\footnotesize }],
\addplot[draw=none, fill=gray] coordinates {
(A,#1)
(B,#2)
(C,#3)
(D,#4)
};
\addplot[draw=none,fill=orange!90] coordinates {
(A,#5)
(B,#6)
(C,#7)
(D,#8)
};
\legend{Planned, Actual}
\end{axis}
\end{tikzpicture}}
\newenvironment{monthlyChart}{%
\def\addMonth##1{\def\Month{##1}}
\def\addTitle##1{\def\ctitle{\small\textbf{##1}}}
\def\addPlanned##1##2##3##4{%
\def\one{##1}\def\two{##2}\def\three{##3}\def\four{##4}}
\def\addActual##1##2##3##4{%
\progressChart{\one}{\two}{\three}{\four}{##1}{##2}{##3}{##4}
}%
\parindent0pt}{}
\makeatother
\begin{document}
\begin{monthlyChart}
\addTitle{AHU (October)}
\addMonth{Oct-11}
\addPlanned{10}{20}{30}{40}
\addActual {9}{18}{31}{39}
\end{monthlyChart}
\begin{monthlyChart}
\addTitle{AHU (November)}
\addMonth{Nov-11}
\addPlanned{30}{40}{50}{60}
\addActual {30}{40}{60}{60}
\end{monthlyChart}
\begin{monthlyChart}
\addTitle{AHU (December)}
\addMonth{Dec-11}
\addPlanned{30}{40}{50}{60}
\addActual {30}{50}{58}{70}
\end{monthlyChart}
\begin{monthlyChart}
\addTitle{AHU (January)}
\addMonth{Jan-11}
\addPlanned{30}{40}{50}{60}
\addActual {30}{40}{50}{113}
\end{monthlyChart}
\begin{monthlyChart}
\addTitle{Turnover $\times 10^3$}
\addMonth{Jan-11}
\addPlanned{300}{400}{500}{600}
\addActual {300}{400}{500}{600}
\end{monthlyChart}
\end{document}
答案1
有一种方法可以定义主模板,它并不像你想象的那么困难。它叫做自己的风格这也是 pgfplots 如此强大的原因之一。遗憾的是,关于定义自己的样式的部分与其重要性相比太短,因此很容易被忽视(参见pgfplots 手册)让我们看看它是如何工作的:
\pgfplotsset{actual chart bar/.style={draw=none,fill=orange!90}}
\pgfplotsset{planned chart bar/.style={draw=none, fill=gray}}
这里我们定义了实际和计划图表条的样式。如您所见,我们可以在样式名称中使用空格(无需 untexish 驼峰式大小写 ^^)。我们稍后将使用的轴的样式中已完成许多工作。我只会评论我已更改的元素。大部分内容都是从您的示例中逐字逐句提取的。
\pgfplotsset{monthly chart/.style={
width=6.9cm,height=5cm,
bar width=0.3cm,
ymin=0,
% ytick={0,25,50,100,125},
ylabel=Total,
ybar=0,symbolic x coords={W1, W2, W3, W4},
xtick=data,
xticklabels={
\week{#1}{week-1},
\week{#1}{week-2},
\week{#1}{week-3},
\week{#1}{week-4}
},
我将符号坐标更改为 W1、W2、W3 和 W4,因为我们将在主文档中使用它们,我认为这样更易读。命令\week
与您的相同。这里重要的一点是
#1
它应该是月份(例如 11 月),并且每个图都不同,因此我们不能使用常数。我们稍后会看到这#1
将如何成为实际月份。
x tick label style={font=\footnotesize},
在这里我们改变 xticks 标签的字体大小。
enlarge x limits=true,
legend style={at={(.43,.98)}, font=\footnotesize },
cycle list={
planned chart bar,
actual chart bar
},
循环列表将定义单个绘图的样式,即第一个绘图采用计划的图表条样式,第二个绘图采用实际的图表条样式。
legend entries={Planned, Actual},
我们已经可以在这里定义图例,如果您需要另一个特殊图表的订单,您可以在此图表中覆盖此设置。
title style={font=\small\bfseries}
}}
我们只定义标题的样式。标题本身在具体图表中设置。
现在我们可以在主文档中对每个月度图表使用该样式:
\begin{tikzpicture}
\begin{axis}[monthly chart=Oct-11, title={AHU (October)}]
\addplot coordinates {(W1,10) (W2,20) (W3,30) (W4,40)};
\addplot coordinates {(W1,9) (W2,18) (W3,31) (W4,39)};
\end{axis}
\end{tikzpicture}
标题的设置方式与在任何普通 pgfplot 中设置的方式相同。一般来说,对于以前使用过 pgfplots 的每个人来说,这看起来都非常熟悉。这里唯一的新奇之处是月度图表样式。现在我们还看到了如何
#1
用所需的月份/文本替换。这种方法比您的新环境稍微冗长一些,但它非常灵活且易读。
例如,直接插入第三个数据集:
\begin{tikzpicture}
\begin{axis}[monthly chart=Nov-11, title={AHU (November)}]
\addplot[planned chart bar] coordinates {(W1,14) (W2,20) (W3,50) (W4,60)};
\addplot[draw=none, fill=green] coordinates {(W1,11) (W2, 22) (W3,33) (W4,43)};
\addplot[actual chart bar] coordinates {(W1,15) (W2,21) (W3,60) (W4,60)};
\legend{Planned,Ideal,Actual}
\end{axis}
\end{tikzpicture}
或者如果需要改变图例位置:
\begin{tikzpicture}
\begin{axis}[monthly chart=Dec-11, title={AHU (December)}, legend style={at={(.95,.98)}}]
\addplot coordinates {(W1,65) (W2,40) (W3,40) (W4,36)};
\addplot coordinates {(W1,75) (W2,58) (W3,50) (W4,30)};
\end{axis}
\end{tikzpicture}
或者更改 ylabel:
\begin{tikzpicture}
\begin{axis}[monthly chart=Jan-11, title={AHU (January)}, ylabel=Sold Apples]
\addplot coordinates {(W1,30) (W2,40) (W3,50) (W4,60)};
\addplot coordinates {(W1,30) (W2,40) (W3,50) (W4,113)};
\end{axis}
\end{tikzpicture}
完整代码如下:
\documentclass[12pt]{article}
\usepackage{tikz}
\usetikzlibrary{patterns}
\usepackage{pgfplots}
\def\week#1#2{
\begin{tabular}{c}#1\\
#2\\\end{tabular}
}
\pgfplotsset{actual chart bar/.style={draw=none,fill=orange!90}}
\pgfplotsset{planned chart bar/.style={draw=none, fill=gray}}
\pgfplotsset{monthly chart/.style={
width=6.9cm,height=5cm,
bar width=0.3cm,
ymin=0,
% ytick={0,25,50,100,125},
ylabel=Total,
ybar=0,symbolic x coords={W1, W2, W3, W4},
xtick=data,
xticklabels={
\week{#1}{week-1},
\week{#1}{week-2},
\week{#1}{week-3},
\week{#1}{week-4}
},
x tick label style={font=\footnotesize},
enlarge x limits=true,
legend style={at={(.43,.98)}, font=\footnotesize },
cycle list={
planned chart bar,
actual chart bar
},
legend entries={Planned, Actual},
title style={font=\small\bfseries}
}
}
\begin{document}
\noindent
\begin{tikzpicture}
\begin{axis}[monthly chart=Oct-11, title={AHU (October)}]
\addplot coordinates {(W1,10) (W2,20) (W3,30) (W4,40)};
\addplot coordinates {(W1,9) (W2,18) (W3,31) (W4,39)};
\end{axis}
\end{tikzpicture}
\begin{tikzpicture}
\begin{axis}[monthly chart=Nov-11, title={AHU (November)}]
\addplot[planned chart bar] coordinates {(W1,14) (W2,20) (W3,50) (W4,60)};
\addplot[draw=none, fill=green] coordinates {(W1,11) (W2, 22) (W3,33) (W4,43)};
\addplot[actual chart bar] coordinates {(W1,15) (W2,21) (W3,60) (W4,60)};
\legend{Planned,Ideal,Actual}
\end{axis}
\end{tikzpicture}
\begin{tikzpicture}
\begin{axis}[monthly chart=Dec-11, title={AHU (December)}, legend style={at={(.95,.98)}}]
\addplot coordinates {(W1,65) (W2,40) (W3,40) (W4,36)};
\addplot coordinates {(W1,75) (W2,58) (W3,50) (W4,30)};
\end{axis}
\end{tikzpicture}
\begin{tikzpicture}
\begin{axis}[monthly chart=Jan-11, title={AHU (January)}, ylabel=Sold Apples]
\addplot coordinates {(W1,30) (W2,40) (W3,50) (W4,60)};
\addplot coordinates {(W1,30) (W2,40) (W3,50) (W4,113)};
\end{axis}
\end{tikzpicture}
\end{document}