制作 pgf 图时,有一件事相当繁琐,那就是准备 pgf 的原始数据。具体来说,就是缩小数据集以避免内存上限。
在 R 中生成一些虚拟数据:
nPoints <- 10^6
df <- data.frame(seq(nPoints), cumsum(runif(nPoints, 0, 1)))
fwrite(x=df, file="data.dat", sep=" ", col.names=F)
直接绘图data.dat
导致我的机器出现容量超出错误:
TeX capacity exceeded, sorry [pool size=6177416].
我认为可以通过以下方式直接过滤输入数据,
\documentclass[preview]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
\begin{tikzpicture}
\begin{axis}[]
\addplot+[only marks] table [
x index={0},
y expr={ifthenelse(mod(\coordindex, 10000) == 0, \thisrowno{1}, NaN)},
unbounded coords=jump,
] {data.dat};
\end{axis}
\end{tikzpicture}
\end{document}
但是,这只是加载整个数据文件,然后显示指定的点,而不是仅加载指定的点。该pgfplotstable
包提供的\pgfplotstabletypeset[every nth row={integer}[shift]{options}]
功能看起来很有用。但是,不清楚应该怎么options
做才能从读取的数据中删除行,以及排版是在读取数据期间还是之后进行。
是否可以只读取文件中选定的行?pgfplotstable
如果可以,如何操作?
答案1
排序答案:凯撒的归凯撒。LaTeX 不是用来管理大量数据的。即使你可以在 LaTeX 端减少数据,但因为你使用的是 R,所以数据减少应该在 R 端进行。这样不仅可以更快,而且更容易。
较长的答案:另一方面,R 也可以绘制大量数据(如果这有时有用则是另一个问题……)。使用knitr
,所有 R 微积分都在编译主文档时完成,但不会使 TeX 引擎过载。并且只有在数据发生变化时才会更新图表(除非您使用CACHE=FALSE
)。
缺点可能是(也可能不是)R 图表默认没有 LaTeX 样式(其他字体、轴上的不同刻度等),但使用 tikzDevice(knitr 的 `dev='tikz' 选项)是真正的 LateX 图表。缺点是 R 也受到 LaTeX 限制,因此您可以选择使用 R 样式表示数千个点,还是使用 LaTeX 样式仅表示最多几千个点。
两页的示例:
MWE.Rnw(用Rstudio编译):
\documentclass[twocolumn]{article}
\usepackage{geometry,parskip}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
<<echo=F>>=
set.seed(4)
library(data.table)
df <- data.frame(A=1:50, B=cumsum(runif(50, 0, 1)))
fwrite(x=df, file="data.dat", sep=" ", col.names=F)
@
If instead of tikz plots: \bigskip\bigskip
\begin{tikzpicture}
\begin{axis}[]
\addplot+[only marks] table [
x expr=\thisrowno{0},
y expr=\thisrowno{1}
] {data.dat};
\end{axis}
\end{tikzpicture}
You can live with raw R plots ...
<<echo=F>>=
plot(df$A,df$B,xlab="",ylab="",col="blue", pch=19,cex=2)
# ,axes=FALSE, ylim=c(-2,32),xlim=c(-2,52))
@
\newpage
.. and R-tunned tikz plots ...
<<Rplot2,echo=F,dev='tikz'>>=
plot(df$A,df$B,xlab="",ylab="",col="blue",
pch=19,cex=2,axes=FALSE,
ylim=c(-2,32),xlim=c(-2,52)
)
axis(1, tcl=0.75, cex.axis=2.5)
axis(2, las=1, tcl=0.75, line = 0, cex.axis=2.5,labels=seq(10,30,10), at=seq(10,30,10))
axis(3, tcl=0.75, labels = FALSE)
axis(4, tcl=0.75, labels = FALSE)
box()
@
\newpage
Then you can choose plot 15000 points without tikz:
<<echo=F>>=
df2 <- data.frame(A=jitter(rep(1:50,300),10), B=jitter(rep(1:30,500),10))
fwrite(x=df2, file="data2.dat", sep=" ", col.names=F)
@
<<Rplot3b,echo=F>>=
# This plot does not work with tikz
plot(df2$A~df2$B,xlab="",ylab="",col="blue",cex=.1)
@
Or some more reasonable, like {\em only} 2/3 of points, with tikz:
<<Rplot3,echo=F,dev="tikz">>=
df3 <- df2[sample(nrow(df2), 10000), ]
plot(df3$A~df3$B,xlab="",ylab="",col="blue",cex=.1)
@
\newpage
Or only the 0.2\,\%, by random sampling:
<<>>=
df3 <- df2[sample(nrow(df2), 500), ]
@
<<Rplot4,echo=F,dev="tikz">>=
plot(df3$A~df3$B,xlab="",ylab="",col="blue",cex=.5)
@
Or by sistematic sampling:
<<>>=
df3 <- df2[c(TRUE,rep(FALSE,50)), ]
@
<<Rplot5,echo=F,dev="tikz">>=
plot(df3$A~df3$B,xlab="",ylab="",col="blue",cex=.5)
@
\end{document}