当我想在 pgfplots 中绘制箱线图,我开始使用 Jake 在上面链接的问题中提出的解决方案。但是,当我想在同一张图中绘制多组箱线图(即使用 groupplots)时,绘图定义很快就变得非常笨拙:addplot
仅箱子就有四个,再加上异常值,addplot
每个图就有 10 多个命令。
我追求的是一种更简单的方法。理想情况下,我希望有一个样式定义,可以处理命令addplot
到目前为止所做的所有相同事情,这样我就可以做一个简单的
\addplot [boxplot] table {testdata.dat};
并完成它,并增加了传递一些额外参数来指定颜色、标记类型等的可能性。我尝试了,\newcommand
它有效,但我无法将选项传递给 pgfplots,所以我开始寻找替代方案。
我认为我需要的是类似于 pgfplots 中绘图中使用的方法scatter
,例如 Jake 的解决方案这个问题,这样我就可以用多个元点来指定箱线和须线的坐标。但是,我找到的解决方案似乎都使用 3 个或 4 个数字来指定图上的每个标记,而对于箱线图,我需要 6 个。
我已经设法通过将与 Jake 编写的命令等效的 TikZ 命令封装到一个@pre marker code
块中来接近目标,但尽管使用了 和 等,我似乎仍然遇到了比例问题disabledatascaling
,据我所知,这应该可以解决问题。这里的问题是,与我链接到的上一个问题不同,(我认为)我无法使用\pgfplotspointmeta
,因为我试图恢复的不仅仅是一个点。不过,我可能找错了对象。
这是一个最小的(不)工作示例:
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{
boxplot/.style={
mark=-,
mark size=0.5em,
scatter,
point meta=0,
only marks,
axis equal,
disabledatascaling,
visualization depends on={\thisrow{boxtop} \as \boxtop},
visualization depends on={\thisrow{boxbottom} \as \boxbottom},
visualization depends on={\thisrow{whiskertop} \as \whiskertop},
visualization depends on={\thisrow{whiskerbottom} \as \whiskerbottom},
visualization depends on={\thisrow{x} \as \bpx},
scatter/@pre marker code/.append code={
\draw % box
(axis cs:\bpx,\boxbottom) -- ++ ( 0.5em, 0pt) |-
(axis cs:\bpx,\boxtop) -- ++ ( -0.5em, 0pt) |-
(axis cs:\bpx,\boxbottom) -- cycle;
\path % top whisker
(axis cs:\bpx,\boxtop) -- (axis cs:\bpx,\whiskertop);
\path % bottom whisker
(axis cs:\bpx,\boxbottom) -- (axis cs:\bpx,\whiskerbottom);
\path % top whisker marker
(axis cs:\bpx,\whiskertop) -- ++ ( 0.25em, 0pt) --
(axis cs:\bpx,\whiskertop) -- ++ (-0.25em, 0pt);
\path % bottom whisker marker
(axis cs:\bpx,\whiskerbottom) -- ++ ( 0.25em, 0pt) --
(axis cs:\bpx,\whiskerbottom) -- ++ (-0.25em, 0pt);
}
}
}
\begin{document}
\begin{figure}
\begin{tikzpicture}
\begin{axis}
\addplot [boxplot] table[y=median] {
x whiskerbottom boxbottom median boxtop whiskertop
1 42 45 47 47 48
2 36 39 40 41 43
3 41 44 45 46 47
4 20 29 31 36 38
5 31 32 34 36 39
};
\end{axis}
\end{tikzpicture}
\end{figure}
\end{document}
问题在于,就像我上面所说的那样,TikZ 命令似乎没有使用相同的轴坐标系(尽管我尝试使用相反的方法axis cs
;实际上,没有它可以获得更好的结果)。
似乎我唯一需要做的就是确保 pgfplots 和 TikZ 都使用相同的比例,但我没有新的想法。可以做到吗?或者这种方法有缺陷,我应该绕过问题而不是寻找解决方案?
答案1
从 1.8 版开始,PGFPlots 原生支持箱线图 看LaTeX 中的箱线图举个例子。
这个答案的其余部分应被视为过时的。
你问这个问题是对的,当前的代码使用起来不是很方便(尽管过去它对我来说非常有用)。
您的方法非常吸引人,因为代码非常简单。但是,当我第一次编写箱线图时,我决定使用几个\addplot
命令,因为这是让 PGFPlots 在计算轴范围时考虑箱线图的最简单方法。
我修改了代码,现在提供了一个新命令。现在您还可以通过设置、等来\boxplot[<optional keys>]{<data table>}
告诉命令箱线图的不同组成部分位于哪些列中。箱线图的宽度可根据问题进行调整box plot median index=<column index>
box plot whisker top index=<column index>
PGFplots 和 boxplots:如何调整箱子的宽度和分离?。
默认情况下,每个箱线图仅创建图例条目。如果您想完全避免为箱线图创建图例条目,可以添加forget plot
到\boxplot
选项中。
使用以下代码(testdata1.dat
是我的格式,testdata2.dat
也是你的格式)
\begin{axis} [box plot width=2mm]
\boxplot [forget plot, red] {testdata.dat}
\boxplot [
forget plot,
box plot whisker bottom index=1,
box plot whisker top index=5,
box plot box bottom index=2,
box plot box top index=4,
box plot median index=3
] {testdata2.dat}
\addplot [domain=-2:6, thick, cyan] {-x+25+rnd}; \addlegendentry{Some line}
\end{axis}
你现在可以得到
完整代码:
\documentclass{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\begin{filecontents}{testdata.dat}
0 10 12 4 15 2
1 20 23 15 27 10
2 7 14 5 19 1
\end{filecontents}
\begin{filecontents}{testdata2.dat}
x whiskerbottom boxbottom median boxtop whiskertop
1 42 45 47 47.5 48
2 36 39 40 41 43
3 41 44 45 46 47
4 20 29 31 36 38
5 31 32 34 36 39
\end{filecontents}
\pgfplotsset{
box plot/.style={
/pgfplots/.cd,
black,
only marks,
mark=-,
mark size=\pgfkeysvalueof{/pgfplots/box plot width},
/pgfplots/error bars/y dir=plus,
/pgfplots/error bars/y explicit,
/pgfplots/table/x index=\pgfkeysvalueof{/pgfplots/box plot x index},
},
box plot box/.style={
/pgfplots/error bars/draw error bar/.code 2 args={%
\draw ##1 -- ++(\pgfkeysvalueof{/pgfplots/box plot width},0pt) |- ##2 -- ++(-\pgfkeysvalueof{/pgfplots/box plot width},0pt) |- ##1 -- cycle;
},
/pgfplots/table/.cd,
y index=\pgfkeysvalueof{/pgfplots/box plot box top index},
y error expr={
\thisrowno{\pgfkeysvalueof{/pgfplots/box plot box bottom index}}
- \thisrowno{\pgfkeysvalueof{/pgfplots/box plot box top index}}
},
/pgfplots/box plot
},
box plot top whisker/.style={
/pgfplots/error bars/draw error bar/.code 2 args={%
\pgfkeysgetvalue{/pgfplots/error bars/error mark}%
{\pgfplotserrorbarsmark}%
\pgfkeysgetvalue{/pgfplots/error bars/error mark options}%
{\pgfplotserrorbarsmarkopts}%
\path ##1 -- ##2;
},
/pgfplots/table/.cd,
y index=\pgfkeysvalueof{/pgfplots/box plot whisker top index},
y error expr={
\thisrowno{\pgfkeysvalueof{/pgfplots/box plot box top index}}
- \thisrowno{\pgfkeysvalueof{/pgfplots/box plot whisker top index}}
},
/pgfplots/box plot
},
box plot bottom whisker/.style={
/pgfplots/error bars/draw error bar/.code 2 args={%
\pgfkeysgetvalue{/pgfplots/error bars/error mark}%
{\pgfplotserrorbarsmark}%
\pgfkeysgetvalue{/pgfplots/error bars/error mark options}%
{\pgfplotserrorbarsmarkopts}%
\path ##1 -- ##2;
},
/pgfplots/table/.cd,
y index=\pgfkeysvalueof{/pgfplots/box plot whisker bottom index},
y error expr={
\thisrowno{\pgfkeysvalueof{/pgfplots/box plot box bottom index}}
- \thisrowno{\pgfkeysvalueof{/pgfplots/box plot whisker bottom index}}
},
/pgfplots/box plot
},
box plot median/.style={
/pgfplots/box plot,
/pgfplots/table/y index=\pgfkeysvalueof{/pgfplots/box plot median index}
},
box plot width/.initial=1em,
box plot x index/.initial=0,
box plot median index/.initial=1,
box plot box top index/.initial=2,
box plot box bottom index/.initial=3,
box plot whisker top index/.initial=4,
box plot whisker bottom index/.initial=5,
}
\newcommand{\boxplot}[2][]{
\addplot [box plot median,#1] table {#2};
\addplot [forget plot, box plot box,#1] table {#2};
\addplot [forget plot, box plot top whisker,#1] table {#2};
\addplot [forget plot, box plot bottom whisker,#1] table {#2};
}
\begin{document}
\begin{tikzpicture}
\begin{axis} [box plot width=2mm]
\boxplot [forget plot, red] {testdata.dat}
\boxplot [
forget plot,
box plot whisker bottom index=1,
box plot whisker top index=5,
box plot box bottom index=2,
box plot box top index=4,
box plot median index=3
] {testdata2.dat}
\addplot [domain=-2:6, thick, cyan] {-x+25+rnd}; \addlegendentry{Some line}
\end{axis}
\end{tikzpicture}
\end{document}