\documentclass[a4paper]{article} %\VignetteIndexEntry{gridSVG} \newcommand{\grid}{{\tt grid}} \newcommand{\gridSVG}{{\tt gridSVG}} \newcommand{\lattice}{{\tt lattice}} \newcommand{\R}{{\tt R}} \setlength{\parindent}{0in} \setlength{\parskip}{.1in} \title{The gridSVG package} \author{Paul Murrell} \begin{document} \maketitle @ \section*{Introduction} This package is an experiment in writing a graphics device, purely in R code, for the grid graphics system. The specific device implemented is for the W3C SVG (Scalable Vector Graphics) format, but there is also some effort at a general device interface that would support other specific devices. \section*{User Interface} There are five functions of interest to the user: \begin{description} \item[{\tt grid.hyperlink}] takes a grid {\tt grob} and turns it into an object of class {\tt linked.grob}, with an associated {\tt href}. This allows the association of hyperlinks with elements of a grid graphic. See {\tt gridSVG/tests/testlink.R} for examples. \item[{\tt grid.animate}] allows the user to associate a duration (plus some other things) with certain aspects of a grid {\tt grob}. This allows a grid graphic element to be animated. See {\tt gridSVG/tests/testanimate.R} {\tt testpendulum.R} and {\tt testball.R} for examples. \item[{\tt grid.garnish}] allows the user to associate arbitrary SVG attributes with a grid {\tt grob}. This provides a way to associate with a grob things that have no corresponding grid concept, like an {\tt onclick} attribute. See {\tt gridSVG/tests/testattrib.R} for a simple example. \item[{\tt grid.script}] allows the user to create a grid {\tt grob} that contains an SVG script (e.g., some ECMAscript code). This provides a way to produce a complete SVG document (complete with scripts) entirely using R grid code (i.e., without having to hand edit the SVG file that \gridSVG{} creates. Again, see {\tt gridSVG/tests/testattrib.R} for a simple example. \item[{\tt gridToSVG()}] saves the current grid graphic to an SVG file. See the {\tt gridSVG/tests} directory for examples of what can be done. See the section ``Known Problems'' below for things that are not yet supported. \end{description} In addition to these functions, \gridSVG{} supports alpha-transparency by respecting the {\tt alpha} graphical parameter which can be specified in a \grid{} {\tt gpar} object. For example, the following code produces overlapping transparent circles\footnote{The {\tt pushViewport()} call is currently necessary to set some default values. It may be possible to remove this in future versions.}: <>= library(grid) library(gridSVG) <>= pushViewport(viewport(gp=gpar(col="black", fill=NA))) grid.circle(x=0.33, r=unit(2, "inches"), gp=gpar(alpha=0.3, fill="red")) grid.circle(x=0.67, r=unit(2, "inches"), gp=gpar(alpha=0.3, fill="green")) popViewport() gridToSVG() @ \section*{Internal Structure} There are nine {\tt .R} files in the {\tt gridSVG/R} directory, corresponding to the nine different things that gridSVG aims to provide: \begin{description} \item[dev.R] This contain (S4 methods) code defining a generic R-level graphics device interface. In other words, generic functions that may be called by a graphics system (such as grid), and that a graphics device (such as an SVG device) should provide methods for. \item[griddev.R] Code for running through the grid display list and calling generic device functions. \item[devsvg.R] Code implementing SVG methods for the generic device interface. \item[svg.R] A set of R-level functions for producing SVG output. Callable directly (see, e.g., {\tt gridSVG/tests/testsvg.R}), but mostly just called by code in {\tt devsvg.R}. \item[gridsvg.R] The function {\tt gridToSVG()}. \item[hyper.R] Code implementing the {\tt linked.grob} class -- i.e., an extension of the standard grid {\tt grob} that supports hyperlinks. Includes the function {\tt grid.hyperlink()}. \item[animate.R] Code implementing the {\tt animated.grob} class -- i.e., an extension of the standard grid {\tt grob} that supports animation. Includes the function {\tt grid.animate()}. \item[script.R] Code implementing the {\tt script} class -- i.e., an extension of the standard grid {\tt grob} that supports SVG scripts. Includes the function {\tt grid.script()}. \item[attrib.R] Code implementing the {\tt svg.grob} class -- i.e., an extension of the standard grid {\tt grob} that supports arbitrary SVG attributes. Includes the function {\tt grid.garnish()}. \end{description} \section*{Known Problems} This package is a partial implementation of several ideas. This section describes some of the known holes in and issues with the implementation. \subsection*{Overall Design} The package is ass-backwards in its design. Normal devices receive calls from grid to perform operations; gridSVG works off grid's display list so only has the information stored there to figure out what to do. This means that it has to replicate some of the work that grid does when grid draws (e.g., in order to enforce vp slots in grobs). If/when normal devices are implemented as R-level objects, so that grid includes a {\tt dev} argument in all its calls to devices, it may be possible to make gridSVG behave more like a normal device and this may lead to some simplifications. \subsection*{Sizing of and units in the SVG image} Software that tries to render SVG on a device has the same problem that \R{} graphics devices have when trying to render \grid{} output: Locations and sizes can be in a variety of units (cm, inches, percentages, ...) {\it some of which are physical units} with real-world meaning. The renderer has to figure out how big something like 1{\tt "} is in the native device units. This problem is worst on computer screens where it is not necessarily easy (or possible) to find out how many pixels there are in a physical inch on the screen. What \R{} does is try its best and it seems that SVG renderers must do the same\footnote{According to Section 7.1 Introduction of the W3C Scalable Vector Graphics (SVG) 1.0 Specification, ``a real number value that indicates the size in real world units, such as millimeters, of a "pixel"'' is ``highly desirable but not required''.}. gridSVG works off the grid display list. This means that the image must first be drawn on some other device (e.g., X11 or PostScript) then copied (via the {\tt gridSVG()} function) to an SVG format. It is not possible to use the SVG notion of transformations to mirror \grid{}'s viewport transformations because the SVG transformations work on ALL graphical elements, including text. In particular, any scaling transformations scale the size of text. Furthermore, \grid{} actions such as {\tt upViewport()} and {\tt downViewport()} are difficult to replicate as SVG transformations. So the copying of \grid{} output to SVG involves converting all locations and sizes to a single SVG coordinate system. There are two (serious) possibilities for this coordinate system: \begin{enumerate} \item specify everything (including the size of the SVG image) in pixels. In this case, what we do is work off the original device's concept of a pixel. The SVG image may be rendered quite a different size compared to the original if the size of pixels on the rendering device is different from the size of pixels on the original device. Things should be pretty consistent -- something that is supposed to be half the size of the image should be rendered half the size of the image -- though this will {\it not} be the case if the change in pixel size is different for x- and y-axes. An image drawn first in a screen window then copied to SVG and viewed {\it on the same screen} should hopefully be the same size. If the original device is a screen device, there is no guarantee that physical sizes will be respected; this will depend on how accurately the screen device can determine the physical size of its pixels. If the original device is a file device (e.g. PostScript) then physical sizes will be accurate on the original device, BUT the correspondence between ``pixels'' on the file device and pixels when the SVG is rendered on screen is very unlikely to be good (e.g., ``pixels'' on PostScript are $\frac{1}{72}${\tt "}, which is highly unlikely to correspond to pixel size on a modern screen). \item specify everything (including the size of the SVG image) in inches. In this case, there is no guarantee that the SVG image will end up the right physical size (it will depend on whether the rendering software can find out enough about pixels-to-inches, BUT everything should be in proportion (if the image is overall a little smaller than it should be, at least something that should be half the size of the image will be half the size of the image. The final rendered size of the image will totally depend on where it gets rendered\footnote{This is not to say that it should be riciculously off; it should be pretty close to the right physical size if it's not exactly the right size.}. This appears to have fewer problems; unfortunately it is {\bf totally killed} by the fact that the locations for drawing polylines MUST be in pixels! (technically, that should be ``user coordinates'', but since I have a single, flat coordinate system structure, it equates to pixels.) \end{enumerate} \subsection*{Plotting Symbols} Only {\tt pch=1} and {\tt pch=3} are currently supported. This is just a matter of filling in the other options. \subsection*{Mathematical Annotation} The use of things like {\tt grid.text(expression(x[i]))} is supported in the main R graphics engine. gridSVG bypasses that and so does not support mathematical annotation (and probably never will!). \subsection*{Time unit arithmetic} Animation is no longer achieved via ``time units'' so old problems with arithmetic on time units in previous versions of \gridSVG{} disappear (i.e., the user does not need to be as careful when doing animation; just specify some unit values and/or expressions and it should go.) Having said that, there is still only support for animating a small set of aspects of grid {\tt grob}s (basically the locations and sizes of {\tt grob}s. \subsection*{Acknowledgements} Many thanks to Nathan Whitehouse and colleagues who contributed ideas and code for including arbitrary SVG attributes and SVG scripts. \end{document}