我在写作中使用了相当多的箱线图,并pgfplots
出于多种原因选择它作为我的绘图解决方案(其中之一是拥有在tex
文件本身中构建绘图的数据的好处)。
自从pgfplots 1.8+
我第一次开始使用它们,但由于我通常使用它R
来分析我的数据,而且由于我觉得这是一个相对常见的设置,所以我想知道人们是如何做到的,看看我们是否可以找到一个共同的最佳方法。
总结:如果您使用R
和pgfplots
,您如何制作箱线图?
答案1
这是我最近开始使用的,因为我或多或少了解了如何使用 的新箱线图界面pgfplots
。虽然我知道它不是特别漂亮(怎么可能漂亮?我绝不是程序员R
……),但它确实能完成工作。但看看其他人想出了什么会很有趣。
编辑:自从写这个答案以来,我使用的函数已经扩展了很多,现在可以接受更多选项,并允许输出完全指定的tikzpicture
环境。待办事项清单上还有一件事,就是让它接受箱线图列表,并将其打印为组图集。但恕我直言,这是当前版本。旧版本可以在答案编辑历史中看到。
此版本还利用了outid
R boxplot 对象中的自定义条目,其中包含异常值的 ID。如果未设置该条目,该函数仍将起作用(并分配数字作为占位符)。
pgfbp <- function (bp, figure.opts=c(), axis.opts=c(), plot.opts=c(), standalone=TRUE, tab='\t', caption=c(), label=c(), use.defaults=TRUE, caption.alt=c(), legends=FALSE) {
indent <- function (tab, n) { return(paste(rep(tab, n), collapse='')) }
if (!is.list(plot.opts)) {
plot.opts <- list(plot.opts)
}
if (standalone) {
axis.default <- c(
'boxplot/draw direction=y',
paste('xtick={', paste(1:ncol(bp$stats), collapse=', '), '}', sep=''),
paste('xticklabels={', paste(bp$names, collapse=', '), '}', sep='')
)
if (use.defaults) {
axis.opts <- append(axis.opts, axis.default, 0)
}
message('\\begin{figure}', appendLF=FALSE)
if (length(label)) {
message(' % fig:', label)
} else {
message('')
}
t <- indent(tab, 1)
message(t, '\\centering')
message(t, '\\begin{tikzpicture}', appendLF=FALSE)
if (length(figure.opts)) {
message('[')
t <- indent(tab, 3)
for (opt in figure.opts) {
message(t, opt, ',')
}
t <- indent(tab, 2)
message(t, ']')
} else {
message('')
}
message(t, '\\begin{axis}', appendLF=FALSE)
if (length(axis.opts)) {
message('[')
t <- indent(tab, 4)
for (opt in axis.opts) {
message(t, opt, ',')
}
t <- indent(tab, 3)
message(t, ']')
} else {
message('')
}
} else {
t <- indent(tab, 0)
}
for (c in 1:ncol(bp$stats)) {
options <- plot.opts[[((c - 1) %% length(plot.opts)) + 1]]
# Boxplot name
message(t, '% ', bp$names[c], '')
# Boxplot command
message(t, '\\addplot+[')
# Options for each boxplot
tt <- indent(tab, 1)
# Boxplot prepared quantities
message(t, tt, 'boxplot prepared={%')
tt <- indent(tab, 2)
message(t, tt, 'lower whisker = ', bp$stats[1,c], ',')
message(t, tt, 'lower quartile = ', bp$stats[2,c], ',')
message(t, tt, 'median = ', bp$stats[3,c], ',')
message(t, tt, 'upper quartile = ', bp$stats[4,c], ',')
message(t, tt, 'upper whisker = ', bp$stats[5,c], ',')
message(t, tt, 'sample size = ', bp$n[c], ',')
tt <- indent(tab, 1)
message(t, tt, '},')
for (opt in options) {
message(t, tt, opt, ',')
}
# Outliers
out <- bp$out[bp$group==c]
if (length(out) == 0) {
message(t, '] coordinates {};')
} else {
message(t, '] table[y index=0, meta=id, row sep=\\\\] {')
tt <- indent(tab, 1)
message(t, tt, 'x id \\\\')
for (o in 1:length(out)) {
id <- if (!is.null(bp$outid)) { bp$outid[o] } else { o }
message(t, tt, out[o], ' ', id, ' \\\\')
}
message(t, '};')
}
if (legends) {
message(t, '\\addlegendentry{', bp$names[c], '}')
}
}
if (standalone) {
t <- indent(tab, 2)
message(t, '\\end{axis}')
t <- indent(tab, 1)
message(t, '\\end{tikzpicture}')
if (length(caption)) {
message(t, '\\caption', appendLF=FALSE)
if (length(caption.alt)) {
message('[', caption.alt, ']', appendLF=FALSE)
}
message('{', caption, '}', appendLF=FALSE)
}
if (length(label)) {
message(t, '\\label{fig:', label, '}', appendLF=FALSE)
}
message('\\end{figure}')
}
}
在 中R
,您可以保存箱线图对象并将其作为参数传递给pgfbp
:
boxplot(response ~ group, data=data) -> bp
pgfbp(bp)
并将输出复制到您的tex
文件中。
标记异常值
至于meta
列,我将其包含在此功能中的原因是,有时(特别是向我的主管展示初始图时)标记异常值很有用,以便能够识别单个参与者的异常趋势。我使用 pgfplots 样式来执行此操作:
\pgfplotsset{
label outliers/.style={
mark size=0,
nodes near coords,
every node near coord/.style={
font=\tiny,
anchor=center
},
point meta=explicit symbolic,
},
}
但我仍然需要找到一个好的解决方案来从数据中提取每个异常值的标签(我有一个从以前的版本中拼凑起来的解决方案,但我认为这对于这个问题来说有点太具体了)。上面的版本使用数字作为占位符,但如果不使用它们,它们很容易被删除。
答案2
您无需pgfplots
在文本文件中直接插入 R 代码块并获取该块(文本、表格或图形)的结果,而只需输入 PDF 文件中的 R 代码即可。
源文件必须具有扩展名.Rnw
(R noweb),R 可以使用 Sweave 函数(或)将其转换为您通常编译的knitr
格式。如果您使用编辑器,只需单击一下即可完成所有步骤。.tex
rstudio
% File example.Rnw
% compile with:
% R CMD Sweave example.Rnw
% pdflatex example.tex
\documentclass{article}
\begin{document}
\SweaveOpts{concordance=TRUE}
\begin{figure}[h!]
\centering
<<echo=F,fig=T>>=
a <- c(1,23,42,13,33,56,23,45,87)
boxplot(a, col="cyan")
@
\caption{This is R boxplot in a \LaTeX\ file}
\end{figure}
\end{document}
编辑
使用针织品除了 Sweave,您还可以在块选项中包含 R tikz 设备(请参阅这里例如)并使用与文档其余部分相同的字体,甚至在 R 图表中包含 LaTeX 公式,这样看起来就像真正的 LaTeX 图表。我很少担心这个问题,因为我喜欢在图形和正文中使用不同的字体,但在同一文档中使用 R 和 pgfplots 图表可能是一个好主意。