graphics.off() df <- data.frame(time=as.numeric(time(Nile)), flow=as.numeric(Nile)) library(ggplot2) library(gridSVG) library(XML) thePlot <- ggplot(df, aes(x=time, y=flow)) + geom_line() botPlot <- thePlot + scale_y_continuous(breaks=c(600, 1200)) + theme(plot.background=element_rect(colour="transparent"), axis.title.y=element_text(colour="white", size=6), axis.title.x=element_blank()) # The basic plot layout doplot <- function() { pushViewport(viewport(y=1, height=.8, just="top", name="topvp")) print(thePlot, newpage=FALSE) upViewport() pushViewport(viewport(y=0, height=.2, just="bottom", name="bottomvp")) print(botPlot, newpage=FALSE) upViewport() } # Scale factor: W/w # The *plotRegion* in the top plot is this factor times the # plotRegion in the bottom plot scale <- 4 # SVG version plotWidth <- 7 pdf("normalplot.pdf", width=plotWidth, height=plotWidth) grid.newpage() doplot() grid.force() # Determine the width of the margins in the main plot # Use full vpPath here otherwise "grab" in gridToSVG() # will not work downViewport("bottomvp::layout::panel.3-4-3-4") plotRegionWidth <- convertWidth(unit(1, "npc"), "inches", valueOnly=TRUE) marginWidth <- plotWidth - plotRegionWidth # Add semitrasparent "thumb" rect upViewport(0) downViewport("bottomvp::layout::panel.3-4-3-4") rg <- rectGrob(x=0, width=1/scale, just="left", gp=gpar(col=rgb(0,0,1,.5), fill=rgb(0,0,1,.2)), name="thumb") # Thumb ONLY captures mouseDown events # MouseUp and mouseMove events are capture anywhere on the image # (see below) thumb <- garnishGrob(rg, onmousedown="thumbDown(evt)") grid.draw(thumb) upViewport(0) # MouseUp and mouseMove events are also captured anywhere on the image grid.set("background", garnishGrob(grid.get("background", grep=TRUE), onmouseup="mUp(evt)", onmousemove=paste("mMove(evt, ", scale, ")", sep="")), grep=TRUE) grid.script(filename="slider.js") gridToSVG("normalplot.svg") dev.off() # Wide version pdf("wideplot.pdf", width=plotRegionWidth*scale + marginWidth) doplot() gridToSVG("wideplot.svg") dev.off() # Read in both SVG files, extract the top plot region from # the wide version and use that to replace the plot region # in the main version normalSVG <- xmlParse("normalplot.svg") wideSVG <- xmlParse("wideplot.svg") normalPlotSVG <- getNodeSet(normalSVG, "//svg:g[@id='topvp::layout::panel.3-4-3-4.1']", c(svg="http://www.w3.org/2000/svg"))[[1]] widePlotSVG <- getNodeSet(wideSVG, "//svg:g[@id='topvp::layout::panel.3-4-3-4.1']/svg:g[@id='panel.3-4-3-4']", c(svg="http://www.w3.org/2000/svg"))[[1]] # To set clip attribute for axis viewport, # need the x, y, width, height from background rect for panel-3-3 # (which is first below panel-3-3) # BEFORE we replace that with the one from fancyWide.svg! panelBg <- getNodeSet(normalPlotSVG, ".//svg:rect", c(svg="http://www.w3.org/2000/svg"))[[1]] # Replace panel-3-3 in original plot with wide version removeChildren(normalPlotSVG, "g") addChildren(normalPlotSVG, widePlotSVG) # Do same thing for x-axis normalAxisSVG <- getNodeSet(normalSVG, "//svg:g[contains(@id, 'topvp::layout::axis-b.4-4-4-4')]", c(svg="http://www.w3.org/2000/svg"))[[1]] wideAxisSVG <- getNodeSet(wideSVG, "//svg:g[contains(@id, 'topvp::layout::axis-b.4-4-4-4')]/child::*", c(svg="http://www.w3.org/2000/svg"))[[1]] removeChildren(normalAxisSVG, "g") addChildren(normalAxisSVG, wideAxisSVG) # Set a clip region for the x-axis on the top plot axisClipRectAttrs <- xmlAttrs(panelBg)[c("x", "y", "width", "height")] axisClipRectAttrs["height"] <- axisClipRectAttrs["y"] axisClipRectAttrs["y"] <- 0 addChildren(normalAxisSVG, newXMLNode("clipPath", newXMLNode("rect", attrs=axisClipRectAttrs), attrs=c(id="axis-b.4-4-4-4-clip"))) addAttributes(normalAxisSVG, "clip-path"="url(#axis-b.4-4-4-4-clip)") # Set event handling for entire image addAttributes(getNodeSet(normalSVG, "/svg:svg", c(svg="http://www.w3.org/2000/svg"))[[1]], onmouseup="mUp(evt)", onmousemove=paste("mMove(evt, ", scale, ")", sep="")) saveXML(normalSVG, file="sliderplot-complete.svg")