Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save a layered pdf in R (via Sweave?)

Tags:

r

pdf

latex

sweave

I've searched SO, Googled, read ?pdf, and come up dry as to the possibility of saving a plot as a pdf with layers that can be swtiched on and off in the pdf viewer margins. An example of what I'm talking about are the USGS quad topo-maps, which can be downloaded as pdfs with multiple layers, such as this (zipped pdf).

The following sentence in the pdf() help file sounds ominous, but I also wanted to check that I'm not misinterpreting it:

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

I used to be able to save layered pdf's in Illustrator, but no longer have this program at my disposal. Perhaps someone can think of a workaround from within R? The data I'm using to map are large, but here's a toy example:

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()

It looks like this (it's a png, but the above will give a pdf) enter image description here

I'd like to be able to have the red and blue boxes as layers with visibility that can be switched on and off from within the pdf viewer.

Many thanks!

Edit: found thread in R-help (re: @mnel), and it looks to not be possible. I will still leave this question open, in case someone has come up with a nifty R-tastic workaround.

Edit (Sept 5th, 2012): I tried doing this via Sweave, and achieved partial success using the workaround posted here. This method produces a single pdf with 'layers' that can be switched on and off using hyperlinked text below the images. It uses 'animation' trickery to do so. While it is still not my ultimate desired outcome, it has the advantage of not depending on particular pdf viewers. I will still wait to see if someone posts a way to do layers, aka OCGs in a Sweave document, which I could then automate.

Edit (Sept 13, 2012): I posted my progress so far as an answer, using the code mentioned above. I was able to get it working in a more complex real world situation with no alterations to the code with overlays of different administrative and statistical boundaries within the US. In this case, I just named the different map overlays layer-0.pdf, layer-1.pdf, etc, and it worked without error. I still hope something better pops up here eventually.

Thanks all for you comments

like image 582
tim riffe Avatar asked Sep 04 '12 18:09

tim riffe


2 Answers

I'm able to achieve this via 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

(This is just the png version for illustration but when I open the pdf in Illustrator, I can turn off the individual layers as needed).

enter image description here

like image 167
Maiasaura Avatar answered Nov 14 '22 11:11

Maiasaura


Looks like the (tex) animation answer is the best I can come up with now. The following .Rnw file will create a pdf with a figure in the middle, and 2 text hyperlinks below it, which toggle visibility of the red and blue boxes independently. I found the Tex code that makes this work here. I've not looked at @Aaron's ocgtools suggestion yet, but will get there. Thanks all for your suggestions!

\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}
like image 1
tim riffe Avatar answered Nov 14 '22 11:11

tim riffe