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)
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
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")
(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).
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}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With