如何在 R 中保存分层的 PDF 文件(通过 Sweave)?

11

我在Stack Overflow搜索,谷歌搜索,并阅读了?pdf文档,但是没有找到将绘图保存为pdf并在pdf查看器边缘上切换打开和关闭的层的可能性。我所说的一个例子是可以下载多个层的pdf文件,例如美国地质调查局的四角拓扑地图,如this(压缩的pdf文件)。

pdf()帮助文件中的以下句子听起来很不祥,但我也想确认一下是否我误解了它:

 The R graphics model does not distinguish graphics objects at the level 
 of the driver interface.

我曾经可以在Illustrator中保存分层的PDF文件,但现在无法使用这个程序。也许有人能想到一个从R内部解决的方法吗?我用来绘制地图的数据很大,但这里有一个玩具示例:

pdf("2objects.pdf")
plot(NULL, type = "n",xlim = c(0,1),ylim = c(0,1))
rect(0,.7,.7,0,border = "blue",lwd=2)
rect(.3,1,1,.3,border = "red",lty=2,lwd=2)
dev.off()

看起来是这样的(它是一个png,但上面的内容将给出一个pdf) enter image description here 我希望能够将红色和蓝色框作为图层,并在pdf查看器中可以切换其可见性。
非常感谢!
编辑:找到R-help中的线程(关于@mnel),似乎不可能。 我仍然会保留这个问题,以防有人想出了一个巧妙的R解决方法。
编辑(2012年9月5日):我尝试使用Sweave来实现这一点,并通过here发布的解决方法部分成功。该方法生成一个单独的PDF文件,其中包含可以使用图像下方的超链接文本打开和关闭的“层”。它使用“动画”技巧来实现。虽然它仍不是我最终想要的结果,但它具有不依赖于特定PDF查看器的优点。我仍然会等待看看是否有人发布了在Sweave文档中执行层,即OCG的方法,然后我就可以自动化。

编辑(2012年9月13日):我将我的进展作为答案发布,使用上述代码。我能够在更复杂的现实情况下将其工作,而不需要对叠加的不同行政和统计边界进行任何修改。在这种情况下,我只是将不同的地图覆盖命名为layer-0.pdflayer-1.pdf等,它可以正常工作。我仍然希望这里最终会出现更好的东西。

感谢您的评论


1
如果您使用tikzDevice并且可以配置tikzpgf以提供带有图层的pdf,则可能能够使其正常工作。不幸的是,该软件包已存档,但它确实可以生成美丽的图形(至少在我两年前使用它时是这样的)。 - mnel
谢谢@mnel,我现在正在尝试使用Sweave,如果有什么结果我会发布的。 - tim riffe
我想知道ImageMagick是否能够将两个单独的PDF文件制作成分层PDF文件? - Aaron left Stack Overflow
在 ImageMagick 帮助论坛中搜索了一下,但没有找到相关提及。看起来它应该能够做到这点。 - tim riffe
1
这是一个来自tex SE网站的问题,它使用ocgtools包并提供了一些示例代码:http://tex.stackexchange.com/q/65096/2823 - Aaron left Stack Overflow
2个回答

2
看起来现在我能想到的最好的答案是使用 (tex) animation。以下的.Rnw文件将创建一个pdf,其中包含一个图形和2个文本超链接,可以独立地切换红色和蓝色框的可见性。我找到了使其工作的Tex代码here。我还没有看过@Aaron的ocgtools建议,但会去看一下。感谢大家的建议!
\documentclass{article}
%----------------------------------------------------------------%\
\usepackage[OT1]{fontenc}
\usepackage{Sweave}
\usepackage{animate}
\usepackage{hyperref}
\usepackage[margin=0.4in]{geometry}
%----------------------------------------------------------------%

\makeatletter
% command to create a toggle link
\newcommand{\ShowHideLayer}[3]{%
  % #1: anim No. (zero-based),
  % #2: layer No. (zero-based),
  % #3: link text
  \leavevmode%
  \pdfstartlink user {
    /Subtype /Link
    /Border [\@pdfborder]%
    /A <<
      /S/JavaScript
      /JS (
        \if at anim@useocg%
          if(a#1.fr[#2].state==true){
            a#1.fr[#2].state=false;
          }else{
            a#1.fr[#2].state=true;
          }
        \else
          if (a#1.fr[#2].display==display.visible){
            a#1.fr[#2].display=display.hidden;
          }else{
            a#1.fr[#2].display=display.visible;
          }
          this.dirty=false;
        \fi
      )
    >>
  }#3%
  \pdfendlink%
}

% command to create a link to show/hide all layers
\newcommand{\ShowHideAll}[2]{%
  % #1: anim No. (zero-based),
  % #2: link text
  \leavevmode%
  \pdfstartlink user {
    /Subtype /Link
    /Border [\@pdfborder]%
    /A <<
      /S/JavaScript
      /JS (
        var countvisible=0;
        for(var i in a#1.fr){
          \if at anim@useocg
            if(a#1.fr[i].state==true){countvisible++;}
          \else
            if (a#1.fr[i].display==display.visible){countvisible++;}
          \fi
        }
        if(countvisible){
          for(var i in a#1.fr){
            \if at anim@useocg
              a#1.fr[i].state=false;
            \else
              a#1.fr[i].display=display.hidden;
              this.dirty=false;
            \fi
          }
        }
        else{
          for(var i in a#1.fr){
            \if at anim@useocg
              a#1.fr[i].state=true;
            \else
              a#1.fr[i].display=display.visible;
              this.dirty=false;
            \fi
          }
        }
      )
    >>
  }#2%
  \pdfendlink%
}
\makeatother

\begin{document}

% heres the R-making of the plots, saved to working directory,
% which should be the folder containing this .Rnw file
% 3 versions of the same plot, one for each layer
<<echo = FALSE, hide = TRUE>>=
pdf("layer-0.pdf")
plot(NULL, type = "n", xlim = c(0, 1), ylim = c(0, 1), xlab = "", ylab = "")
dev.off()

pdf("layer-1.pdf")
plot(NULL, type = "n", xlim = c(0, 1), ylim = c(0, 1), axes = FALSE, xlab = "", ylab = "")
rect(0, .7, .7, 0, border = "blue", lwd = 2)
dev.off()

pdf("layer-2.pdf")
plot(NULL, type = "n", xlim = c(0, 1), ylim = c(0, 1), axes = FALSE, xlab = "", ylab = "")
rect(.3, 1, 1, .3, border = "red", lty = 2, lwd = 2)
dev.off()
@

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{center}
  %animated layer-set No. 0
  %                                          v-- frame rate ignored
  \animategraphics[width=1\linewidth,step]{1}{layer-}{0}{2}

  \ShowHideLayer{0}{1}{toggle red box}\\
  \ShowHideLayer{0}{2}{toggle blue box}\\
\end{center}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}

1
我可以通过ggplot实现这一点。
library(ggplot2)
df <- data.frame(x = c(1,10), y = c(20,40), class = 1:2)
layered_plot <- ggplot(df, aes(xmin = x, xmax = x + 1, ymin = y, ymax = y + 2, fill = class)) +
geom_rect() + 
opts(legend.position = "none") 
# Now save this as pdf
ggsave(layered_plot, file="p1.pdf")

enter image description here

这只是用于说明的 png 版本,但当我在Illustrator中打开 pdf 时,可以根据需要关闭各个图层。

enter image description here


这可能是Illustrator的一个功能吗?导入PDF时,似乎Illustrator会将所有矢量元素分解为单个对象。我希望有一个解决方案,可以为一个框创建一个图层,为另一个框创建一个图层,同时避开Illustrator。谢谢! - tim riffe
不确定这是否是Illustrator的问题。但是,如果您只需要关闭一个或两个元素,那么这很好用。您还可以通过拖动框选并点击组合来快速分组元素(例如坐标轴)。这将有助于减少项目数量。 - Maiasaura
保存文件时加上.svg扩展名怎么样?这将保留图层(同样)但也可以绕过Illustrator(如果您有另一个免费的程序可以打开)。 - Maiasaura
我相信在r-help线程中已经讨论过这个问题,并且它还没有被实现。 - mnel
我曾看到过 @mnel 的评论,这就是为什么我现在转而寻求一个 LaTeX/Sweave 解决方案。例如,LaTeX 有一个 'ocgtools' 包,但语法到目前为止都有点超出我的理解范围。我能够通过使用 LaTeX 的 'animation' 包并结合 Sweave 获得类似但不够优秀的结果。 - tim riffe
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接