在读取输入数据时对其进行过滤

在读取输入数据时对其进行过滤

制作 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}

相关内容