我有 csv 文件1,我想将其绘制为箱线图。我找到了该部分问题的解决方案这里(由杰克提供),这构成了我的 MWE 的很大一部分。
这里的区别是我希望能够从一行中生成每个箱线图姓名而不是数字。这是我的 MWE:
\documentclass{article}
\usepackage{pgfplotstable}
\usepgfplotslibrary{statistics}
\makeatletter
\pgfplotsset{
boxplot prepared from table/.code={
\def\tikz@plot@handler{\pgfplotsplothandlerboxplotprepared}%
\pgfplotsset{
/pgfplots/boxplot prepared from table/.cd,
#1,
}
},
/pgfplots/boxplot prepared from table/.cd,
table/.code={\pgfplotstablecopy{#1}\to\boxplot@datatable},
row/.initial=0,
make style readable from table/.style={
#1/.code={
\pgfplotstablegetelem{\pgfkeysvalueof{/pgfplots/boxplot prepared from table/row}}{##1}\of\boxplot@datatable
\pgfplotsset{boxplot/#1/.expand once={\pgfplotsretval}}
}
},
make style readable from table=lower whisker,
make style readable from table=upper whisker,
make style readable from table=lower quartile,
make style readable from table=upper quartile,
make style readable from table=median,
make style readable from table=lower notch,
make style readable from table=upper notch,
make style readable from table=average
}
\makeatother
\newcommand{\computerowindex}[2]{
\def\xindex{-1}
\pgfplotstableforeachcolumnelement{x}\of#1\as\cell{%
\edef\cellname{#2}
\ifx\cell\cellname\let\xindex\pgfplotstablerow\fi
}
}
\newcommand{\boxplotprepared}[2]{
\computerowindex{#1}{#2}
\expandafter\boxplotpreparedNum\expandafter#1\xindex
}
\newcommand{\boxplotpreparedNum}[2]{
\addplot[boxplot prepared from table={
table=#1,
row=#2,
average=mean,
lower whisker = min,
upper whisker = max,
lower quartile = fq,
upper quartile = tq,
median=median},
boxplot prepared]
coordinates {};
%
}
\begin{document}
\pgfplotstableread{
x min qu2 fq median tq max mean
a1 19.9 21.384 25.175 28.05 31.425 44.6 28.366
a2 22.4 24 26.975 29.4 31.65 45.6 29.509
a3 29.1 29.398 32.1 34.9 38.175 48.9 35.582
b1 33.5 34.494 41.3 46.15 54.725 108.1 49.749
b2 39.2 41.662 52.625 64.1 83.3 126.3 69.364
b3 42.7 45.092 66.2 80.05 102.8 213.2 88.251
c1 54.4 56.76 75.5 107.9 135.45 195.7 109.501
c2 54.7 59 96.8 123.45 152.725 331.2 132.139
c3 64.7 65.99 102.95 139 200.025 348.2 153.915
d1 74.4 86.818 136.9 176.25 221.925 503.4 189.913
d2 80.6 100.508 144.175 191.7 247.5 454.1 205.501
d3 73.3 110.804 174.15 227.5 294.7 632.3 247.584
e1 98.2 111.55 163.1 222.15 300.05 512.4 240.966
e2 110.9 112.768 181.125 236.4 325.975 719.3 266.793
}{\loadedtable}
\begin{tikzpicture}
\begin{axis}[
boxplot/draw direction=y,
boxplot/average={auto},
boxplot/every average/.style={/tikz/mark=*,mark size=1},
ymin=0,ymax=800]
\boxplotprepared{\loadedtable}{a1}
\boxplotprepared{\loadedtable}{a2}
\boxplotprepared{\loadedtable}{a3}
\boxplotprepared{\loadedtable}{b1}
\boxplotprepared{\loadedtable}{b2}
\boxplotprepared{\loadedtable}{b3}
\boxplotprepared{\loadedtable}{c1}
\boxplotprepared{\loadedtable}{c2}
\boxplotprepared{\loadedtable}{c3}
\boxplotprepared{\loadedtable}{d1}
\boxplotprepared{\loadedtable}{d2}
\boxplotprepared{\loadedtable}{d3}
\boxplotprepared{\loadedtable}{e1}
\end{axis}
\end{tikzpicture}
\end{document}
对于小于 10 的行数,此方法可以正常工作,但一旦达到两位数,它就会截断数字并使用第 1 行,而不是 10、11、12 等。问题就在这里
\newcommand{\boxplotprepared}[2]{
\computerowindex{#1}{#2}
\expandafter\boxplotpreparedNum\expandafter#1\xindex
}
如果我理解正确,\expandafter
会导致首先\xinput
评估数字12
(例如),因此\boxplotpreparedNum
将1
其作为第二个参数,而第二个数字会丢失,因为它在环境中浮动axis
。不过这些\expandafter
命令似乎是必要的。如果我删除其中任何一个,就会出现错误,如果我同时删除两个,就会出现无意义的输出。我认为使用\let
或\edef
定义\xinput
会使它们变得不必要,但我不知道为什么它们不会。
如果有一种方法可以在命令中使用括号括住参数\expandafter
,那将是最简单的解决方案,但我尝试过的任何组合都不起作用,所以我甚至不确定是否可行。
我怎样才能让它工作?
1. 请注意,我已经在 MWE 代码中直接定义了该表;据我所知,它与当前问题无关。
答案1
事实证明,我对括号的思考是正确的。我没有意识到这是{
一个标记,因此添加括号需要额外的一个\expandafter
:
\newcommand{\boxplotprepared}[2]{
\computerowindex{#1}{#2}
\expandafter\boxplotpreparedNum\expandafter#1\expandafter{\xindex}
}
完整 MWE:
\documentclass{article}
\usepackage{pgfplotstable}
\usepgfplotslibrary{statistics}
\makeatletter
\pgfplotsset{
boxplot prepared from table/.code={
\def\tikz@plot@handler{\pgfplotsplothandlerboxplotprepared}%
\pgfplotsset{
/pgfplots/boxplot prepared from table/.cd,
#1,
}
},
/pgfplots/boxplot prepared from table/.cd,
table/.code={\pgfplotstablecopy{#1}\to\boxplot@datatable},
row/.initial=0,
make style readable from table/.style={
#1/.code={
\pgfplotstablegetelem{\pgfkeysvalueof{/pgfplots/boxplot prepared from table/row}}{##1}\of\boxplot@datatable
\pgfplotsset{boxplot/#1/.expand once={\pgfplotsretval}}
}
},
make style readable from table=lower whisker,
make style readable from table=upper whisker,
make style readable from table=lower quartile,
make style readable from table=upper quartile,
make style readable from table=median,
make style readable from table=lower notch,
make style readable from table=upper notch,
make style readable from table=average
}
\makeatother
\newcommand{\computerowindex}[2]{
\def\xindex{-1}
\pgfplotstableforeachcolumnelement{x}\of#1\as\cell{%
\edef\cellname{#2}
\ifx\cell\cellname\let\xindex\pgfplotstablerow\fi
}
}
\newcommand{\boxplotprepared}[2]{
\computerowindex{#1}{#2}
\expandafter\boxplotpreparedNum\expandafter#1\expandafter{\xindex}
}
\newcommand{\boxplotpreparedNum}[2]{
\addplot[boxplot prepared from table={
table=#1,
row=#2,
average=mean,
lower whisker = min,
upper whisker = max,
lower quartile = fq,
upper quartile = tq,
median=median},
boxplot prepared]
coordinates {};
%
}
\begin{document}
\pgfplotstableread{
x min qu2 fq median tq max mean
a1 19.9 21.384 25.175 28.05 31.425 44.6 28.366
a2 22.4 24 26.975 29.4 31.65 45.6 29.509
a3 29.1 29.398 32.1 34.9 38.175 48.9 35.582
b1 33.5 34.494 41.3 46.15 54.725 108.1 49.749
b2 39.2 41.662 52.625 64.1 83.3 126.3 69.364
b3 42.7 45.092 66.2 80.05 102.8 213.2 88.251
c1 54.4 56.76 75.5 107.9 135.45 195.7 109.501
c2 54.7 59 96.8 123.45 152.725 331.2 132.139
c3 64.7 65.99 102.95 139 200.025 348.2 153.915
d1 74.4 86.818 136.9 176.25 221.925 503.4 189.913
d2 80.6 100.508 144.175 191.7 247.5 454.1 205.501
d3 73.3 110.804 174.15 227.5 294.7 632.3 247.584
e1 98.2 111.55 163.1 222.15 300.05 512.4 240.966
e2 110.9 112.768 181.125 236.4 325.975 719.3 266.793
}{\loadedtable}
\begin{tikzpicture}
\begin{axis}[
boxplot/draw direction=y,
boxplot/average={auto},
boxplot/every average/.style={/tikz/mark=*,mark size=1},
ymin=0,ymax=800]
\boxplotprepared{\loadedtable}{a1}
\boxplotprepared{\loadedtable}{a2}
\boxplotprepared{\loadedtable}{a3}
\boxplotprepared{\loadedtable}{b1}
\boxplotprepared{\loadedtable}{b2}
\boxplotprepared{\loadedtable}{b3}
\boxplotprepared{\loadedtable}{c1}
\boxplotprepared{\loadedtable}{c2}
\boxplotprepared{\loadedtable}{c3}
\boxplotprepared{\loadedtable}{d1}
\boxplotprepared{\loadedtable}{d2}
\boxplotprepared{\loadedtable}{d3}
\boxplotprepared{\loadedtable}{e1}
\end{axis}
\end{tikzpicture}
\end{document}
如果有人知道更简单(即更易读)的解决方案,或者可以发布更好的(更清晰或更准确)的解释来说明我的解决方案为何有效,请发布它,我会接受您的答案。