% !TeX root = RJwrapper.tex \title{The \pkg{gridSVG} Package} \author{by Paul Murrell and Simon Potter} \newcommand{\js}{JavaScript} \maketitle \abstract{ The \pkg{gridSVG} package can be used to generate a \pkg{grid}-based R plot in an SVG format, with the ability to add special effects to the plot. The special effects include animation, interactivity, and advanced graphical features, such as masks and filters. This article provides a basic introduction to important functions in the \pkg{gridSVG} package and discusses the advantages and disadvantages of \pkg{gridSVG} compared to similar R packages. } <>= options(continue=" ") @ \section{Introduction} The SVG graphics format \citep{Dengler:11:SVG} is a good format for including plots in web pages because it is a vector format (so it scales well) and because it offers features for animation and interactivity. SVG also integrates well with other important web technologies such as HTML and \js{}. It is possible to produce a static R plot in an SVG format with the built-in \code{svg()} function (from the \pkg{grDevices} package), but the \CRANpkg{gridSVG} package \citep{gridsvg} provides an alternative way to generate an SVG plot that allows for creating animated and interactive graphics. There are two types of graphics functions in R: functions based on the default \pkg{graphics} package and functions based on the \pkg{grid} graphics package. As the package name suggests, the \pkg{gridSVG} package only works with a plot that is drawn using the \pkg{grid} graphics package. This includes plots from several important graphics packages in R, such as \CRANpkg{lattice} \citep{pkg:lattice} and \CRANpkg{ggplot2} \citep{pkg:ggplot}, but \pkg{gridSVG} does not work with all plots that can be produced in R. This article demonstrates basic usage of the \pkg{gridSVG} package and outlines some of the ways that \pkg{gridSVG} can be used to produce graphical results that are not possible in standard R graphics. There is also a discussion of other packages that provide ways to generate dynamic and interactive graphics for the web and the strengths and weaknesses of \pkg{gridSVG} compared to those packages. \section{Basic usage} The following code draws a \pkg{lattice} multi-panel plot (see Figure \ref{fig:lattice}). <<>>= library(lattice) @ <>= dotplot(variety ~ yield | site, data = barley, groups = year, key = simpleKey(levels(barley$year), space = "right"), subset = as.numeric(site) < 4, layout = c(1, 3)) @ <>= print( <> ) @ \begin{figure} \begin{center} \fbox{\includegraphics[width=.6\textwidth]{murrell-potter-lattice}} \end{center} \caption{\label{fig:lattice}A \pkg{lattice} multi-panel plot drawn on the standard \code{pdf()} graphics device.} \end{figure} The \code{grid.export()} function in \pkg{gridSVG} converts the current (\pkg{grid}) scene on the active graphics device to an SVG format in an external file. <<>>= library(gridSVG) @ <>= grid.export("lattice.svg") @ <>= <> <> @ This SVG file can be viewed directly in a browser (see Figure \ref{fig:lattice-web}) or embedded within HTML as part of a larger web page. \begin{figure} \begin{center} \fbox{\includegraphics[width=.6\textwidth]{lattice-svg.png}} \end{center} \caption{\label{fig:lattice-web}The \pkg{lattice} plot from Figure \ref{fig:lattice} exported to an SVG file by \pkg{gridSVG} and viewed in Firefox. This demonstrates that a static R plot can be converted to an SVG format with \pkg{gridSVG} for use on the web.} \end{figure} This usage of \pkg{gridSVG}, to produce a static SVG version of an R plot for use on the web, offers no obvious benefit compared to the built-in \code{svg()} graphics device. However, the \pkg{gridSVG} package provides several other functions that can be used to enhance the SVG version of an R plot. \section{A simple example} In order to demonstrate, with code, some of the distinctive features of \pkg{gridSVG}, we introduce a simple \pkg{grid} scene that is inspired by the Monty Hall problem.\footnote{\url{http://en.wikipedia.org/wiki/Monty\_Hall\_problem}} <<>>= library(grid) @ The scene consists of three words, ``goat'', ``goat'', and ``car'', drawn in random order across the page, with an opaque rectangle drawn on top of each word. In relation to the Monty Hall problem, the three rectangles represent three ``doors'', behind which are hidden two goats and a car. A ``contestant'' must choose a door and then he or she gets the ``prize'' behind that door. However, after the contestant has chosen a door, a ``game show host'' opens one of the other doors to reveal a ``goat'' and the contestant gets the opportunity to change to the remaining unopened door or stick with the original choice. Should the contestant stick or switch?\footnote{An exercise for the reader is to determine which door conceals the car based on the R code and figures presented in this article.} The following code produces the scene and the result is shown in Figure \ref{fig:montyhall}. The main drawing code is wrapped up in a function so that we can reuse it later on. <>= text <- sample(c("goat", "goat", "car")) cols <- hcl(c(0, 120, 240), 80, 80) @ <>= # Fix the order of the text so I can rely on it in screenshots, etc text <- c("car", "goat", "goat") @ <>= MontyHall <- function() { grid.newpage() grid.text(text, 1:3/4, gp = gpar(cex = 2), name = "prizes") for (i in 1:3) { grid.rect(i/4 - .1, width=.2, height=.8, just = "left", gp = gpar(fill = cols[i]), name = paste0("door", i)) } } @ <>= MontyHall() @ \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{murrell-potter-montyhall} \end{center} \caption{\label{fig:montyhall}A diagram of the Monty Hall problem, drawn using \pkg{grid}. Hidden behind each rectangle is either the word ``goat'' or the word ``car'').} \end{figure} The code in the \code{MontyHall()} function makes use of the fact that \pkg{grid} functions allow names to be associated with the objects in a scene. In this case, the three rectangles in this scene have been given names---\code{"door1"}, \code{"door2"}, and \code{"door3"}---and the text has been given the name \code{"prizes"}. The \pkg{grid} function \code{grid.ls()} can be used to display the names of all objects in a scene. <>= grid.ls(fullNames = TRUE) @ <>= MontyHall() grid.ls(full = TRUE) @ These names will be used later to identify the rectangles so that we can modify them to generate special effects. \section{Hyperlinks} The \code{grid.hyperlink()} function from the \pkg{gridSVG} package can be used to add hyperlinks to parts of a \pkg{grid} scene. For example, the following code adds a link to each door so that clicking on a door (while viewing the SVG version of the scene in a browser) leads to a Google Image Search on either ``car'' or ``goat'' depending on what is behind the door. The first argument to \code{grid.hyperlink()} is the name of the \pkg{grid} object with which to associate the hyperlink. The \code{href} argument provides the actual link and the \code{show} argument specifies how to show the target of the link (\code{"new"} means open a new tab or window). <<>>= library(gridSVG) @ <>= links <- c("http://www.google.com/search?q=car&tbm=isch", "http://www.google.com/search?q=goat&tbm=isch") for (i in 1:3) { grid.hyperlink(paste0("door", i), href = links[match(text[i], c("car", "goat"))], show = "new") } @ After running this code, the scene is completely unchanged on a normal graphics device, but if we use \code{grid.export()} to convert the scene to SVG, we end up with an image that contains hyperlinks. Figure \ref{fig:hyper} shows the result, with the mouse hovering over the middle door; at the bottom-left of the browser window, we can see from the hyperlink that there is a goat behind this door. <>= grid.export("montyhall-hyper.svg") @ <>= gridsvg("montyhall-hyper.svg", width = 6, height = 3, prefix = "hyper-") <> <> dev.off() @ % profile paul-shutter includes "capture mouse" and "delay 3 secs" % sleep 3; shutter -p paul-shutter -a -e -o montyhall-hyper-svg.png \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{montyhall-hyper-svg.png} \end{center} \caption{\label{fig:hyper}The Monty Hall image, with a hyperlink on each door. The mouse is hovering over the middle door and the browser is showing the hyperlink target in the bottom-left of its window. If we click the mouse, we will navigate to a Google Image Search for the word ``goat''.} \end{figure} \section{Animation} The function \code{grid.animate()} from \pkg{gridSVG} allows us to animate the features of shapes in a \pkg{grid} scene. For example, the following code draws the Monty Hall scene again and then animates the width of the middle door so that it slides open (to reveal the word ``goat''). The first argument to \code{grid.animate()} is the name of the object to animate. Subsequent arguments specify which feature of the object to animate, in this case \code{width}, plus the values for the animation. The \code{duration} argument controls how long the animation will last. <>= MontyHall() goatDoor <- grep("goat", text)[1] grid.animate(paste0("door", goatDoor), width = c(.2, 0), duration = 2) @ <>= grid.export("montyhall-anim.svg") @ <>= gridsvg("montyhall-anim.svg", width = 6, height = 3, prefix = "anim-") <> dev.off() @ <>= # Version for screen cap (end with door half open) gridsvg("montyhall-anim-cap.svg", width = 6, height = 3) MontyHall() grid.animate(paste0("door", goatDoor), width = c(.2, .1), duration = 2) dev.off() @ Again, no change is visible on a normal R graphics device, but if we export to SVG and view the result in a browser, we see the animation (see Figure \ref{fig:anim}). % sleep 3; shutter -p paul-shutter -a -e -o montyhall-anim-svg.png \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{montyhall-anim-svg.png} \end{center} \caption{\label{fig:anim}The Monty Hall image, with the middle ``door'' animated so that it slides open (to reveal the word ``goat'').} \end{figure} \section{Advanced graphics features} The \pkg{gridSVG} package offers several graphics features that are not available in standard R graphics devices. These include non-rectangular clipping paths, masks, fill patterns and fill gradients, and filters \citep{svgadvancedtech}. This section demonstrates the use of a mask on the Monty Hall scene. A mask is a greyscale image that is used to affect the transparency (or alpha-channel) of another image: anywhere the mask is white, the masked image is fully visible; anywhere the mask is black, the masked image is invisible; and anywhere the mask is grey, the masked image is semitransparent. The following code uses standard \pkg{grid} functions to define a simple scene consisting of a white cross on top of a grey circle on a white background, which we will use as a mask (see Figure \ref{fig:mask}). Any \pkg{grid} scene can be used to create a mask; in this case, we use the \code{gTree()} function from \pkg{grid} to create a graphical object that is a collection of several other graphical objects. <>= circleMask <- gTree(children = gList(rectGrob(gp = gpar(col = NA, fill = "white")), circleGrob(x = goatDoor/4, r=.15, gp = gpar(col = NA, fill = "grey")), polylineGrob(c(0, 1, .5, .5), c(.5, .5, 0, 1), id = rep(1:2, each = 2), gp = gpar(lwd = 10, col = "white")))) @ <>= grid.draw(circleMask) grid.rect(gp = gpar(col = "grey")) @ The next code shows how this crossed circle on a white background can be used as a mask to affect the transparency of one of the rectangles in the Monty Hall scene. The functions \code{mask()} and \code{grid.mask()} are from \pkg{gridSVG}. The \code{mask()} function takes a \pkg{grid} object (as generated above) and turns it into a mask object. The \code{grid.mask()} function takes the name of a \pkg{grid} object to mask, plus the mask object produced by \code{mask()}. <>= MontyHall() grid.mask(paste0("door", goatDoor), mask(circleMask)) @ <>= grid.export("montyhall-masked.svg") @ <>= gridsvg("montyhall-masked.svg", width = 6, height = 3, prefix = "masked-") <> dev.off() @ The effect of the mask is shown in Figure \ref{fig:mask}). % shutter -p paul-shutter -a -e -o montyhall-masked-svg.png \begin{figure} \begin{center} \hfill \includegraphics[width=.45\textwidth]{murrell-potter-mask-fig} \hfill \includegraphics[width=.45\textwidth]{montyhall-masked-svg.png} \hspace*{\fill} \end{center} \caption{\label{fig:mask}Using a mask on an image. The picture on the left shows a white cross on top of a grey circle on a white background. This is used as a mask on the rectangles in the Monty Hall image on the right. The effect is to create a semitransparent window in the middle door (through which we can glimpse the word ``goat'').} \end{figure} \section{Interactivity} The \code{grid.garnish()} function in the \pkg{gridSVG} package opens up a broad range of possibilities for enhancing a \pkg{grid} scene, particularly for adding interactivity to the scene. A simple example is shown in the code below. Here we are adding tooltips to each of the doors in the Monty Hall scene so that hovering the mouse over a door produces a label that shows what is behind the door (see Figure \ref{fig:tooltip}). The first argument to \code{grid.garnish()} is the name of the object to modify. Subsequent arguments specify SVG attributes to add to the object; in this case, we add a \code{title} attribute, which results in a tooltip (in some browsers). <>= MontyHall() for (i in 1:3) { grid.garnish(paste0("door", i), title = text[i]) } @ <>= grid.export("montyhall-tooltip.svg") @ <>= gridsvg("montyhall-tooltip.svg", width = 6, height = 3, prefix = "tooltip-") <> dev.off() @ % sleep 3; shutter -p paul-shutter -a -e -o montyhall-tooltip-svg.png \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{montyhall-tooltip-svg.png} \end{center} \caption{\label{fig:tooltip}The Monty Hall image with tooltips added to each door. The mouse is hovering over the middle door, which results in a tooltip being displayed to show that there is a ``goat'' behind this door.} \end{figure} The \code{grid.garnish()} function can also be used to associate \js{} code with an object in the scene. The following code shows a simple example where clicking on one of the rectangles pops up an alert box showing what is behind that door (see Figure \ref{fig:alert}). The attribute in this example is \code{onclick}, which is used to define an action that occurs when the object is clicked with the mouse (in a browser). <>= MontyHall() for (i in 1:3) { grid.garnish(paste0("door", i), onclick = paste0("alert('", text[i], "')")) } @ <>= grid.export("montyhall-alert.svg") @ <>= gridsvg("montyhall-alert.svg", width = 6, height = 3, prefix = "alert-") <> dev.off() @ % sleep 3; shutter -p paul-shutter -a -e -o montyhall-alert-svg.png \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{montyhall-alert-svg.png} \end{center} \caption{\label{fig:alert}The Monty Hall image with interactivity. The mouse has just been clicked on the middle door, which has resulted in an alert box popping up to show that this door has a ``goat'' behind it.} \end{figure} For more complex interactions, it is possible to include \js{} code within the scene, using the \code{grid.script()} function, so that an event on an object within the scene can be associated with a \js{} function call to perform a more sophisticated action. The code below shows a simple example where clicking on one of the rectangles in the Monty Hall scene will call the \js{} function \code{open()} to ``open'' the door (by making the rectangle invisible; see Figure \ref{fig:js}). The \code{open()} function is defined in a separate file called \code{"MontyHall.js"} (shown in Figure \ref{fig:jscode}). <>= MontyHall() for (i in 1:3) { grid.garnish(paste0("door", i), onclick = "open(evt)") } grid.script(file = "MontyHall.js") @ <>= grid.export("montyhall-js.svg") @ <>= gridsvg("montyhall-js.svg", width = 6, height = 3, prefix = "js-") <> dev.off() @ % sleep 3; shutter -p paul-shutter -a -e -o montyhall-js-svg.png \begin{figure} \begin{center} \includegraphics[width=.45\textwidth]{montyhall-js-svg.png} \end{center} \caption{\label{fig:js}The Monty Hall image with more interactivity. The mouse has just been clicked on the middle door, which has resulted in the middle door becoming invisible, thereby revealing a ``goat'' behind the door.} \end{figure} \begin{figure} \begin{boxedminipage}{\textwidth} \VerbatimInput{MontyHall.js} \end{boxedminipage} \caption{\label{fig:jscode}The \js{} code used in Figure \ref{fig:js} that defines the \code{open()} function to ``open'' a door by making the rectangle invisible.} \end{figure} \section{A more complex demonstration} The previous section kept things very simple in order to explain the main features of \pkg{gridSVG}. In this section, we present a more complex example which involves adding interactivity to a \pkg{lattice} multi-panel plot. The following code generates the \pkg{lattice} plot from Figure \ref{fig:lattice}. <>= <> @ Because the \pkg{lattice} package is built on \pkg{grid}, and because the \pkg{lattice} package names all of the objects that it draws,\footnote{\url{http://lattice.r-forge.r-project.org/Vignettes/src/naming-scheme/namingScheme.pdf}} there are names for every object drawn in this plot. The following code uses the \pkg{grid} function \code{grid.grep()}\footnote{Introduced in R version 3.1.0.} to show some of the named objects in this plot (in this case, all objects that have a name that contains \code{"xyplot.points"}). These are the objects that represent the data symbols within the \pkg{lattice} plot. <>= grid.grep("xyplot.points", grep = TRUE, global = TRUE) @ <>= <> <> @ The following code uses \code{grid.garnish()} to add event handlers to the objects that represent the points in the plot, so that \js{} functions are called whenever the mouse moves over a point and whenever the mouse moves off the point again. <>= numPoints <- length(levels(barley$variety)) grid.garnish("xyplot.points", grep = TRUE, global = TRUE, group = FALSE, onmouseover = rep("highlight(evt)", numPoints), onmouseout = rep("unhighlight(evt)", numPoints), "pointer-events" = rep("all", numPoints)) @ This use of \code{grid.garnish()} differs from the previous simple examples because it has an effect on several \pkg{grid} objects, rather than just one. The \code{grep} and \code{global} arguments specify that the name, \code{"xyplot.points"}, should be treated as a regular expression and the garnish will affect all objects in the scene with a name that matches that pattern. Furthermore, each \pkg{grid} object that matches represents several data symbols, so the \code{group} argument is used to specify that the garnish should be applied to each individual data symbol. Because, for each object, the garnish is being applied to multiple data symbols, we must provide multiple values, which explains the use of \code{rep()} for the \code{onmouseover}, \code{onmouseout}, and \code{pointer-events} arguments. The \js{} code that defines the event handlers \code{hightlight()} and \code{unhighlight()} is shown in Figure \ref{fig:lattice-jscode}. A detailed explanation of this code is beyond the scope of this article, but it should be clear that these functions are relatively simple, just looping over the two groups in each panel, and over the three panels, to highlight (or unhighlight) all points that share the same index. \begin{figure} \begin{boxedminipage}{\textwidth} \VerbatimInput{lattice-brush.js} \end{boxedminipage} \caption{\label{fig:lattice-jscode}The \js{} code that defines the \code{highlight()} and \code{unhighlight()} functions to implement linked selection of points for the \pkg{lattice} plot in Figure \ref{fig:lattice-brush}.} \end{figure} This \js{} code is added to the plot using \code{grid.garnish()}, and then the whole scene is exported to SVG with \code{grid.export()}. <>= grid.script(file = "lattice-brush.js") grid.export("lattice-brush.svg") @ <>= <> <> <> @ A snapshot of the final result is shown in Figure \ref{fig:lattice-brush}, with the mouse over one point and all related points highlighted. % sleep 3; shutter -p paul-shutter -a -e -o lattice-brush-cap-svg.png \begin{figure} \begin{center} \includegraphics[width=.6\textwidth]{lattice-brush-cap-svg.png} \end{center} \caption{\label{fig:lattice-brush}The \pkg{lattice} plot from Figure \ref{fig:lattice} with interaction added. Moving the mouse over a point highlights the point and highlights every other ``related'' point in all panels of the plot.} \end{figure} \section{Limitations} The \pkg{gridSVG} package provides an opportunity to produce more sophisticated, more dynamic, and more interactive R plots compared to the standard R graphics devices. However, there are some strict limitations on what can be achieved with this package. First of all, the package only works for plots that are based on the \pkg{grid} graphics system. This includes some major graphics packages, such as \pkg{lattice} and \pkg{ggplot2}, but excludes a large amount of graphics functionality that is only available in the default \pkg{graphics} package or packages that build on \pkg{graphics}. Given a plot from a function that is not based on \pkg{grid}, the \pkg{gridSVG} package will only produce a blank SVG file. Another limitation is that \pkg{gridSVG} does not generate any \js{} code itself. This means that anything beyond the most basic interactivity will require the user to write \js{} code, which imposes a burden on the user in terms of both time and knowledge. Another point that has only briefly been acknowledged in the example R code so far is that the \pkg{gridSVG} functions that add special features to a \pkg{grid} scene (such as hyperlinks and animation) rely heavily on the ability to \emph{identify} specific components of a \pkg{grid} scene. The Monty Hall examples all rely on the fact that the rectangles that are drawn to represent doors each have a name---\code{"door1"}, \code{"door2"}, and \code{"door3"}---and the code that adds hyperlinks or animation identifies the rectangles by using these names. This means that \pkg{gridSVG} is dependent upon an appropriate naming scheme being used for any \pkg{grid} drawing \citep{RJournal_2012-2_Murrell}. This requirement is met by the \pkg{lattice} package and, to a lesser extent by the \pkg{ggplot2} package, but cannot be relied on in general. % Some of these are pretty detailed so really belong in the JSS version(?) % Although doesn't write any javascript for you, DOES provide nice hooks for % javacsript to address. % Cairo SVG not all bad! (e.g., faithful font rendering (as paths)) % plotmath becomes MathML ? % Anything with drawDetails() method or grid.draw() method will NOT % export. % Anything with makeContent() (post R 3.0) will need to be explicitly % forced before doing any hyperlinking or animating (otherwise the % hyperlinking and animating is destroyed by forcing). % Some things do NOT work (e.g., making clipping region BIGGER) \section{Alternative approaches} The \pkg{gridSVG} package provides one way to produce dynamic and interactive versions of R plots for use on the web, but there are several other packages that provide alternative routes to the same destination. This section discusses the differences between \pkg{gridSVG} and several other packages that have similar goals. % NOT 'canvas' cos static graphics only % NOT 'RIGHT' cos not a fan % NOT 'clickme' or 'ggvis' cos like 'rCharts' % NOT 'cranvas' or 'Acinonyx' cos not web % NOT 'polycharts' or 'vega' or 'D3' or 'kineticJS' cos do not start from R % NOT 'svgmaps' cos it builds on top of gridSVG!!! % NOT 'animint' cos it's a bit like 'rCharts' (?) The \CRANpkg{animation} package \citep{pkg:animation} provides a convenient front-end for producing animations in various formats (some of which are appropriate for use on the web), but the approach is frame-based (draw lots of separate images and then stitch them together to make an animation). The advantage of an SVG-based approach to animation is that the animation is declarative, which means that the animation can be described more succinctly and efficiently and the resulting animation will often appear smoother. On the other hand, the \pkg{animation} package will work with any R graphics output; it is not restricted to just \pkg{grid}-based output. The \pkg{SVGAnnotation} package \citep{pkg:svgannotation} performs a very similar role to \pkg{gridSVG}, by providing functions to export R plots to an SVG format with the possiblity of adding dynamic and interactive features. One major advantage of \pkg{SVGAnnotation} is that it will export R plots that are based the standard \pkg{graphics} package (as well as plots that are based on \pkg{grid}). \pkg{SVGAnnotation} also provides some higher-level functions that automatically generate \js{} code to implement specific sorts of more complex interactivity. For example, the \code{linkPlots()} function can be used to generate linked plots, where moving the mouse over a data symbol in one plot automatically highlights a corresponding point in another plot. The main disadvantage of \pkg{SVGAnnotation} is that it works with the SVG that is produced by the built-in \code{svg()} device, which is much less structured than the SVG that is generated by \pkg{gridSVG}. That is not a problem if the functions that \pkg{SVGAnnotation} provides do everything that we need, but it makes for much more work if we need to, for example, write our own \js{} code to work with the SVG that \pkg{SVGAnnotation} has generated. Another package that can export R graphics output to SVG is the \CRANpkg{RSVGTipsDevice} package \citep{pkg:rsvgtips}. This package creates a standard R graphics device, so it can export any R graphics output, but it is limited to adding tooltips and hyperlinks. This package also requires the tooltips or hyperlinks to be added at the time that the R graphics output is produced, rather than after-the-fact using names to refer to previously-drawn output. This makes it harder to associate tooltips or hyperlinks with output that is produced by someone else's code, such as a complex \pkg{lattice} plot. A number of packages, including \pkg{rCharts} and \CRANpkg{googleVis} \citep{pkg:rcharts,article:googlevis}, provide a quite different approach to producing dynamic and interactive plots for the web. These packages outsource the plot drawing to \js{} libraries such as NVD3, highcharts, and the Google Visualisation API \citep{nvd3js,highcharts,googlevis}. The difference here is that the plots produced are not R plots. The advantage is that very little R code is required to produce a nice result, provided the \js{} library can produce the style of plot and the sort of interactivity that we want. Another approach to interactivity that is implemented in several packages, notably \CRANpkg{shiny} \citep{pkg:shiny}, involves running R as a web server and producing new R graphics in response to user events in the browser. The difference here is that the user typically interacts with GUI widgets (buttons and menus) outside the graphic and each user event generates a completely new R graphic. With \pkg{gridSVG}, the user can interact directly with elements of the graphic itself and all of the changes to the graphic occur in the browser with no further need of R. In summary, using the \pkg{gridSVG} package is appropriate if we want to add advanced graphics features to a \pkg{grid}-based R plot, or if we want to add dynamic or interactive elements to a \pkg{grid}-based R plot, particularly if we want to produce a result that is not already provided by a high-level function in the \pkg{SVGAnnotation} package. An approach that holds some promise is to generate SVG content using \pkg{gridSVG} and then manipulate that content by adding \js{} code based on a sophisticated \js{} library such as d3 \citep{d3} and Snap.svg \citep{snap}. \section{Availability} The \pkg{gridSVG} package is available from CRAN. The code examples in this article are known to work for \pkg{gridSVG} versions 1.3 and 1.4 using Firefox 28.0 on Ubuntu 12.04. Support for SVG varies between browsers, for example Chrome 34.0 on Ubuntu 12.04 does not produce the tooltips in Figure \ref{fig:tooltip}. Several web sites provide summary tables of supported SVG features.\footnote{\url{http://caniuse.com/svg}\\\url{http://en.wikipedia.org/wiki/Comparison\_of\_layout\_engines\_\%28Scalable\_Vector\_Graphics\%29}} Differences between browser \js{} engines is another potential source of variation. Nevertheless, all major browsers now provide native support of at least basic SVG features, several mature and stable \js{} libraries are available to abstract away browser differences, and the situation is constantly improving. Online versions of the figures in this article are available from \url{http://www.stat.auckland.ac.nz/~paul/Reports/gridSVGrjV2/}. Further documentation and examples for \pkg{gridSVG} are available from \url{https://www.stat.auckland.ac.nz/~paul/R/gridSVG/}. \section{Acknowledgements} We would like to thank the anonymous reviewers for many helpful comments that lead to improvements in this article. \bibliography{murrell-potter} \address{Paul Murrell\\ The University of Auckland\\ Auckland\\ New Zealand} \email{paul@stat.auckland.ac.nz} \address{Simon Potter\\ The University of Auckland\\ Auckland\\ New Zealand} \email{simon@sjp.co.nz}