![当数据中有 NaN 行时,箱线图为空](https://linux22.com/image/339194/%E5%BD%93%E6%95%B0%E6%8D%AE%E4%B8%AD%E6%9C%89%20NaN%20%E8%A1%8C%E6%97%B6%EF%BC%8C%E7%AE%B1%E7%BA%BF%E5%9B%BE%E4%B8%BA%E7%A9%BA.png)
我已经有一个相当复杂的设置,其中我读取文件中的箱线图数据、这些文件的名称列表以及用于绘制每个文件的箱线图的循环。然而,这个文件的其中一行没有数据,用一行全是 NaN 来表示。我需要一种不产生错误的方式来应对这种情况(我使用 externalize 来生成这些图,任何错误的图都会产生致命错误)。
这是一个不那么简单的例子:
% !TEX program = lualatex
% !TeX encoding = UTF-8
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepgfplotslibrary{statistics}
\usetikzlibrary{pgfplots.groupplots}
\usepackage{pgffor}
\usepackage{filecontents}
\begin{filecontents}{dataA.txt}
row min Q1 median Q3 max
A 8e-4 2e-1 3e-2 4e-3 6e0
B 2e-4 1e-1 2e-1 3e-1 9e-1
C 1e-3 5e-1 3e0 4e0 5e0
D 1e-2 1e0 2e0 3e0 4e0
E 2e-10 8e-2 3e-1 4e-1 1e0
F 8e-12 3e-1 6e-1 1e0 2e0
\end{filecontents}
\begin{filecontents}{dataB.txt}
row min Q1 median Q3 max
A NaN NaN NaN NaN NaN
B 2e-4 1e-1 2e-1 3e-1 9e-1
C 1e-3 5e-1 3e0 4e0 5e0
D 1e-2 1e0 2e0 3e0 4e0
E 2e-10 8e-2 3e-1 4e-1 1e0
F 8e-12 3e-1 6e-1 1e0 2e0
\end{filecontents}
\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
}
\makeatother
\newcommand{\BoxPlot}[1]{ % \BoxPlot{\file}
\begin{tikzpicture}
\begin{semilogyaxis}[
boxplot/draw direction=y,
width=0.7\textwidth,
xmin=0,xmax=7,
xtick={1,2,3,4,5,6},
xticklabels={A,B,C,D,E,F}]
\pgfplotsforeachungrouped \i in {0,1,2,3,4,5} {
\edef\temp{
\noexpand\addplot+ [
boxplot prepared from table={
table=\noexpand#1,
row=\i,
lower whisker=min,
upper whisker=max,
lower quartile=Q1,
upper quartile=Q3,
median=median
}, boxplot prepared
]
coordinates {};
}
\temp
}
\end{semilogyaxis}
\end{tikzpicture}
}
\begin{document}
\newcommand*{\ListOfFiles}{%
dataA,
dataB%
}
\foreach \x in \ListOfFiles {
\pgfplotstableread{\x.txt}{\DATA}
\begin{figure}[htpb]
\centering
\BoxPlot{\DATA}
\caption{Here is \x}
\end{figure}
}
\end{document}
理想情况下,遇到 NaN 行时根本不会绘制任何图。但生成没有任何错误的图才是最重要的。
答案1
我找到了一个解决方法(但仍然欢迎更清洁的解决方案):
设置值的限度ymax
(例如1e2
),并将更高的数字作为箱线图的数据(例如2e2
)。这样,箱线图就简单地绘制在显示范围之外:
% !TEX program = lualatex
% !TeX encoding = UTF-8
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepgfplotslibrary{statistics}
\usetikzlibrary{pgfplots.groupplots}
\usepackage{pgffor}
\usepackage{filecontents}
\begin{filecontents}{dataA.txt}
row min Q1 median Q3 max
A 8e-4 2e-1 3e-2 4e-3 6e0
B 2e-4 1e-1 2e-1 3e-1 9e-1
C 1e-3 5e-1 3e0 4e0 5e0
D 1e-2 1e0 2e0 3e0 4e0
E 2e-10 8e-2 3e-1 4e-1 1e0
F 8e-12 3e-1 6e-1 1e0 2e0
\end{filecontents}
\begin{filecontents}{dataB.txt}
row min Q1 median Q3 max
A 200 200 200 200 200
B 2e-4 1e-1 2e-1 3e-1 9e-1
C 1e-3 5e-1 3e0 4e0 5e0
D 1e-2 1e0 2e0 3e0 4e0
E 2e-10 8e-2 3e-1 4e-1 1e0
F 8e-12 3e-1 6e-1 1e0 2e0
\end{filecontents}
\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
}
\makeatother
\newcommand{\BoxPlot}[1]{ % \BoxPlot{\file}
\begin{tikzpicture}
\begin{semilogyaxis}[
boxplot/draw direction=y,
width=0.7\textwidth,
xmin=0,xmax=7,
ymin=1e-11,ymax=1e2,
xtick={1,2,3,4,5,6},
xticklabels={A,B,C,D,E,F}]
\pgfplotsforeachungrouped \i in {0,1,2,3,4,5} {
\edef\temp{
\noexpand\addplot+ [
boxplot prepared from table={
table=\noexpand#1,
row=\i,
lower whisker=min,
upper whisker=max,
lower quartile=Q1,
upper quartile=Q3,
median=median
}, boxplot prepared
]
coordinates {};
}
\temp
}
\end{semilogyaxis}
\end{tikzpicture}
}
\begin{document}
\newcommand*{\ListOfFiles}{%
dataA,
dataB%
}
\foreach \x in \ListOfFiles {
\pgfplotstableread{\x.txt}{\DATA}
\begin{figure}[htpb]
\centering
\BoxPlot{\DATA}
\caption{Here is \x}
\end{figure}
}
\end{document}