pgfplots 中更简单的箱线图-这可能吗?

pgfplots 中更简单的箱线图-这可能吗?

当我想在 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}

相关内容