Abstract
This article discusses the importance of providing structure and labelling within SVG code, particularly when the SVG code is generated indirectly by a high-level system and when the SVG code describes a complex image such as a statistical plot. We argue that this is a desirable goal, but that many high-level systems that generate SVG do not provide sufficient structure and labelling. An example of a system, based on R, that does provide structure and labelling, is described to demonstrate that the goal is acheivable and we highlight the crucial features of this system that we see as important factors in achieving this goal.
SVG is a language for describing images. It is both a vector graphics language, meaning images are described as a series of shapes rather than a raster matrix, and it is a markup language, meaning that components of the image are described using elements consisting of tags and attributes. For example, Figure 1, “Code for a simple image” shows SVG code for a simple image that consists of two rectangles (<rect> elements) and two circles (<circle> elements; see Figure 2, “A simple image”).
Figure 1. A simple image, described using SVG, that consists of two rectangles and two circles.
<?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="250" height="150"> <g transform="translate(25, 25)"> <rect x="0" y="0" width="100" height="100" stroke="black" fill="white"/> <rect x="100" y="0" width="100" height="100" stroke="black" fill="white"/> <circle cx="50" cy="50" r="30"/> <circle cx="150" cy="50" r="30"/> </g> </svg>
Two important features of the code in
Figure 1, “Code for a simple image”
are the structure of the code
and the labelling of the code.
An example of the structure in this code
is demonstrated by the way that elements are nested within
each other (the
<rect>
and
<circle>
elements are nested within a
<g>
element)
and an example of the labelling in this code
is the way that every component of the image
is a named element (either a
<rect>
or a
<circle>)
and every piece of information about each component,
such as location or colour, is a named attribute
(e.g., fill="white"
) .
This structure and labelling within an SVG image is important because it makes it possible to identify each component of the image, either by where the component is within the structure of the document or by the type of element used to represent the component or the attributes associated with the component.
This report will briefly demonstrate why this structure and labelling is useful in SVG images and then discuss how difficult it is to generate good structure and labelling for complex SVG images, such as statistical plots. We will demonstrate that good structure and labelling is possible using the R language for statistical computing and graphics and attempt to summarise the important features that are necessary to provide structure and labelling for complex images.
One advantage of using markup like SVG for
images is that style information
can be specified separately from the description of the
image content. For example, the code in
Figure 3, “Code for a simple image with CSS” modifies the simple image
in Figure 2, “A simple image”
by adding CSS styling code within a
<style>
element. Additional class
attributes
have also been added to the two
<rect>
elements. This CSS code
changes the fill colour to grey for both circles
and changes the fill colour to black for the rectangle
on the left of the image (see Figure 4, “A simple image with CSS”).
The CSS code works by associating properties,
such as fill: black
,
with specific elements within the image and it
identifies specific elements within the image via
selectors.
For example, the selector circle
specifies all
<circle>
elements within the image.
The selector rect.left
specifies any
<rect>
elements that have the attribute class="left"
.
In other words, the CSS code relies on labelling within the SVG
to be able to associate styling information with specific
components of the image.
Figure 3. A simple image, described using SVG, that consists of two rectangles and two circles, with styling controlled via CSS.
<?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="250" height="150"> <style type="text/css"> circle { fill: #DDDDDD } rect.left { fill: black } </style> <g transform="translate(25, 25)"> <rect x="0" y="0" width="100" height="100" stroke="black" fill="white" class="left"/> <rect x="100" y="0" width="100" height="100" stroke="black" fill="white" class="right"/> <circle cx="50" cy="50" r="30"/> <circle cx="150" cy="50" r="30"/> </g> </svg>
Figure 4. A simple image, described using SVG, that consists of two rectangles and two circles, with styling controlled via CSS.
Another advantage of using markup is that interactive behaviour
can be attached to components of the image.
For example, the code in
Figure 5, “Code for a simple image with javascript”
extends the original image by adding javascript code
within a
<script>
element. Additional
id
and on-click
attributes
have also been added to the second
<rect>
element.
Now if we click on the rectangle on the right of the image
its fill is changed to black
(see Figure 6, “A simple image with javascript”).
The javascript code works by identifying a
specific component of the image, using the getElementById()
function, and then changing that element's fill colour.
In this case, the javascript code targets the unique element
with the attribute id="rect-2"
.
Again, the javascript code relies on labelling within the SVG code
to be able to identify which element to change.
Figure 5. A simple image, described using SVG, that consists of two rectangles and two circles, with interaction added via javascript.
<?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="250" height="150"> <style type="text/css"> circle { fill: #DDDDDD } rect.left { fill: black } </style> <script type="application/ecmascript"> changeBG = function() { r = document.getElementById("rect-2"); r.setAttribute("fill", "black"); } </script> <g transform="translate(25, 25)"> <rect x="0" y="0" width="100" height="100" stroke="black" fill="white" class="left"/> <rect x="100" y="0" width="100" height="100" stroke="black" fill="white" class="right" id="rect-2" onclick="changeBG()"/> <circle cx="50" cy="50" r="30"/> <circle cx="150" cy="50" r="30"/> </g> </svg>
Figure 6. A simple image, described using SVG, that consists of two rectangles and two circles, with interaction added via javascript; when the right rectangle is clicked, it turns black.
A third advantage of using markup is that the image can be programmatically processed to add, remove, or modify components of the image. For example, the code in Figure 7, “Code for transforming a simple image” uses XSLT to transform the original SVG image so that we extract just the circle on the left of the image and the rectangle on the right of the image (see Figure 8, “A transformed image”).
This XSLT code works by copying specific components of the SVG image
and it identifies specific components using XPath expressions.
For example, the XPath expression svg:svg/svg:g/svg:circle[1]
identifies the first
<circle>
element that is a child of a
<g>
element, which in turn is a child of the top-level
<svg>
element.
The XPath expression //svg:rect[@class='right']
identifies any rectangle element that has the attribute
class="right"
.
Yet again, the XSLT code relies on the structure and labelling of the SVG
code to identify which components of the image to process.
Figure 7. Code to process the simple image to extract just the left circle and the right rectangle.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg" version='1.0'> <xsl:template match="/"> <svg xmlns="http://www.w3.org/2000/svg" width="250" height="150"> <g transform="translate(25, 25)"> <xsl:copy-of select="//svg:rect[@class='right']"/> <xsl:copy-of select="svg:svg/svg:g/svg:circle[1]"/> </g> </svg> </xsl:template> </xsl:stylesheet>
Figure 8. A transformation of the simple image so that only the left circle and the right rectangle remain.
All three of these cases - the application of CSS styling,
the attachment of javascript functions, and the processing via XSLT -
are very dependent on being able to identify specific components
of the image.
To some extent, we get landmarks or signposts within a document -
element names, attributes, and nesting of elements -
simply because we are using a markup language. For example, the SVG
language definition requires
that the outermost element must be an
<svg>
element and it dictates that
<rect>
elements have attributes x
and y
whereas
<circle>
elements have attributes cx
and cy
.
However, there is a still a lot of freedom and variation within the
markup language definition so that a very wide range of
images is possible. The problem that then arises is how to ensure that
it is still
possible to identify every separate component of the image,
even when images become large and complex.
One way to provide structure and labelling for an SVG image is to manually generate the SVG code (as in Figure 1, “Code for a simple image”). However, this method rapidly becomes impractical. For example, the statistical plot in Figure 9, “A complex image” requires over 450 lines of SVG code and the positioning of the text, lines, and data symbols within the image is not something that would be simple to do by hand.
In order to generate a complex SVG image it becomes necessary to use a higher-level system that automates the generation of SVG code. The example used in Figure 9, “A complex image” was generated with R using the code shown in Figure 10, “R code for a complex image” (code to load the data not shown). This is clearly a lot easier than writing the SVG by hand, but what does the SVG that R generates look like? Is the SVG code generated by R nicely structured and labelled?
Figure 10. R code to generate a statistical plot
ggplot(elec, aes(x=volume, y=price, colour=source)) + geom_point() + facet_wrap(~ year, nrow=1)
Figure 11, “SVG code generated by R” shows some fragments from the SVG code for Figure 9, “A complex image”. This is enough to show the sort of problem that automatically generated SVG can suffer from. There is no obvious way to associate these SVG elements with specific components of the SVG image in Figure 9, “A complex image”. So the price of not having to generate SVG code manually is that the automatically generated SVG code does not have useful structure or labelling.
<rect x="0" y="0" width="576" height="288" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/> <rect x="0" y="0" width="576" height="288" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/> <path style="fill:none;stroke-width:1.062992;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0 288 L 576 288 L 576 0 L 0 0 Z M 0 288 "/> <g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> <use xlink:href="#glyph0-0" x="86.457031" y="69.999023"/> <use xlink:href="#glyph0-1" x="91.791016" y="69.999023"/> <use xlink:href="#glyph0-1" x="97.125" y="69.999023"/> <use xlink:href="#glyph0-2" x="102.458984" y="69.999023"/> </g>
This example is a particularly clear demonstration of unstructured SVG generation. Appendix B, Other Software for Generating SVG presents some other examples of SVG generation from several other software systems: two javascript libraries, gRaphael and Highcharts; the plot2svg extension package for Matlab; and the gnumeric spreadsheet software. These are not all as bad as this example, but they all fall short in some way of the ideal of fully structured and labelled SVG.
The SVG code produced by R in Figure 11, “SVG code generated by R”
is actually only one way to generate SVG from R.
That example used the Cairo-based graphics device in R,
which is available through the svg()
function
from the grDevices package.
An alternative way to generate SVG from R is via the
gridSVG package. This section demonstrates that
this alternative approach can be used to generate SVG that is both
structured and labelled.
The starting point for generating SVG from R using the gridSVG package, is to produce an image using the grid package. For example, the code in Figure 12, “grid code for a simple image” draws an image similar to the very simple SVG image in Figure 2, “A simple image” (see Figure 13, “A simple grid image”). Important points about this code are that the rectangles and circles are drawn within a grid viewport, which defines a sub-region on the page, there is a single function call to produce the two rectangles and a single function call to produce the two circles, and the rectangles and the circles (and the viewport) are explicitly named.
Figure 12. grid code to generate a simple image
pushViewport(viewport(width=.8, height=.8, name="margin")) grid.rect(x=0:1/2, width=1/2, just="left", name="rect") grid.circle(x=c(1, 3)/4, r=1/4, gp=gpar(fill="black"), name="circ") popViewport()
A structured and labelled SVG version of the image can then be generated
using the gridToSVG()
function from the
gridSVG package. The code in Figure 14, “gridSVG code”
shows the simple call
required and Figure 15, “SVG code from gridSVG”
shows the SVG code that is produced.
One important feature of this SVG code is the fact that the
<rect>
and
<circle>
elements are nested within a
<g>
element that represents the grid
viewport in the original image.
The
<rect>
elements are further nested
within another
<g>
element, reflecting the fact that they were both generated
by a single call to the function grid.rect()
, and the
<circle>
elements are similarly nested.
Finally, all elements have id
attributes
based on the names that were specified in the grid
code.
Figure 15. SVG code generated from R using the gridSVG package
<g id="margin.1"> <g id="rect.1"> <rect id="rect.1.1" x="14.4" y="7.2" width="57.6" height="57.6"/> <rect id="rect.1.2" x="72" y="7.2" width="57.6" height="57.6"/> </g> <g id="circ.1"> <circle id="circ.1.1" cx="43.2" cy="36" r="14.4" fill="rgb(0,0,0)" fill-opacity="1"/> <circle id="circ.1.2" cx="100.8" cy="36" r="14.4" fill="rgb(0,0,0)" fill-opacity="1"/> </g> </g>
In summary, using grid, it is possible to generate an image with structure and labelling and then gridSVG produces SVG code that retains that structure and labelling.
One simple thing that we have demonstrated so far is that structure and labelling can be manually specified with grid, much like it can be manually specified with SVG, but what we are more interested in is the ability to generate a complex image, such as a statistical plot, that has useful structure and labelling. This is where the lattice package comes in.
The lattice package uses grid to render sophisticated and complex statistical plots. For example, the code in Figure 16, “R code for a complex image” is all that is required to generate the plot in Figure 17, “A complex grid image”.
This image actually contains a great deal of structure and labelling.
The grid.ls()
function can be used to show the names
of all grid objects within an image and
Figure 18, “Labelling in a lattice plot” shows part of the list for the plot
in Figure 17, “A complex grid image”. This shows that every component
of the plot, right down to the tick marks on the left side
of the panel in row 1, column 1 (plot_01.ticks.left.panel.1.1
),
has a detailed label.
Figure 18. A listing of the grid objects in a statistical plot produced by lattice
grid.ls()
[1] "plot_01.background" [2] "plot_01.xlab" [3] "plot_01.ylab" [4] "plot_01.ticks.top.panel.1.1" [5] "plot_01.ticks.left.panel.1.1" [6] "plot_01.ticklabels.left.panel.1.1" [7] "plot_01.ticks.bottom.panel.1.1" [8] "plot_01.ticklabels.bottom.panel.1.1" [9] "plot_01.xyplot.points.group.1.panel.1.1" [10] "plot_01.xyplot.points.group.2.panel.1.1" [11] "plot_01.xyplot.points.group.3.panel.1.1" [12] "plot_01.xyplot.points.group.4.panel.1.1"
If this image is exported to SVG (with code similar to
Figure 14, “gridSVG code”), the structure and labelling is
preserved. Figure 19, “SVG code from lattice” shows a fragment of the SVG
from Figure 17, “A complex grid image”.
This fragment shows the SVG code representing the tick marks
on the left side of the panel in row 1, column 1.
There is structure demonstrated
by the nesting of elements (in particular, the top-most
<g>
element represents the grid viewport
that the ticks are drawn within) and there is labelling demonstrated by
the id
attributes of the
<g> and
<polyline>
elements.
<g id="plot_01.toplevel.vp::plot_01.strip.1.1.off.vp.1"> <g id="plot_01.ticks.top.panel.1.1.1"> <polyline id="plot_01.ticks.top.panel.1.1.1.1" points="59.98,245.81 59.98,251.48"/> <polyline id="plot_01.ticks.top.panel.1.1.1.2" points="97.59,245.81 97.59,251.48"/> <polyline id="plot_01.ticks.top.panel.1.1.1.3" points="135.21,245.81 135.21,251.48"/> </g> </g>
We have demonstrated that it is possible to produce a complex statistical plot with a small amount of code, but still generate highly structured and labelled SVG. This makes it possible to apply styling, add interactivity, or post-process the SVG image, but a major stumbling block remains: how does a person, particularly someone other than the creator of the original plot, discover the structure and labelling of the SVG code?
Simply viewing a displayed image of the SVG (like Figure 17, “A complex grid image”) gives no clues to the SVG structure or labelling. We can see the structure and labelling in the raw SVG code, but relating individual SVG elements to the appropriate component of the displayed image may not always be straightforward, especially in complex images where the SVG code runs to hundreds of lines (there are over 550 lines of SVG code for Figure 17, “A complex grid image”).
Web browsers like Firefox provide powerful tools for manually "inspecting"
SVG images, so that it is possible to select a displayed component
with the mouse and see the corresponding SVG code. The
grid and gridDebug packages in R
provide similar functionality, for example, the
grid.ls()
function mentioned previously.
These tools are helpful for
interactively exploring the structure and labelling in a single image,
but they do not support
programmatically modifying an SVG image when, for example, we perform
a large batch processing of many SVG images, or we wish to modify
many features within a single SVG image (e.g., add tooltips
to regions within a map). In that case, it is necessary to
understand the algorithm used to produce the structure and labelling
so that we can accurately predict the location and id
values for elements within the SVG code.
This leads to a need for proper documentation of the algorithm that is used for structuring and labelling the SVG images. Even better, we could use an API that provides functions to assist with generating the location and labels for components of an image.
In the case of generating SVG from R, there is an added complication
because the lattice package first generates a structure
and labelling for an image and then the gridSVG package
translates that structure and labelling to SVG.
It is therefore necessary to document both the
lattice
naming scheme and the
gridSVG translation process.
In terms of an API, lattice provides
two functions, trellis.vpname()
and
trellis.grobname()
, that assist with the generation
of labels for specific components of a plot. For example, the following
code shows the programmatic way to generate the grob name for
the ticks on the left side of the plot in Figure 17, “A complex grid image”.
ticks <- trellis.grobname("ticks.left", "panel", column=1, row=1) ticks
[1] "plot_01.ticks.left.panel.1.1"
The gridSVG package provides functions for use in
R and javascript that support look-up of the SVG id
value that are generated from the original grid names.
For example, the following code generates the SVG id
for the ticks on the left side of the plot in Figure 17, “A complex grid image”.
mappings <- readMappingsJS("lattice-plot.svg.mappings.js") gridSVGMappings(mappings) getSVGMappings(ticks, "grob")
[1] "plot_01.ticks.left.panel.1.1.1"
This section briefly describes an example that demonstrates the usefulness of being able to work with structured and labelled SVG.
The code below draws a simple grid image consisting
of a spiral, drawn as multiple line segments with ever-decreasing
line widths (see Figure 20, “A zoomable grid spiral”).
This image is designed so that more detail is revealed if the image
is enlarged. Enlarging the image is made possible by including the
javascript code from the file SVGPan-spiral.js
, which is
a small modification of the
SVGPan
javascript library. With this javascript included in the SVG file,
the mouse wheel can be used to zoom into and out of the image.
The important point about this example is that an SVG image that was
created by one author
using R has been combined with a javascript library that was created
by another independent author. This was possible because the SVG
image from R contains a viewport called "viewport"
,
which is translated to an SVG
<g>
element with an id="viewport.1"
and the javascript
library determines what part of the image to zoom based on a
specific id
.
In other words, by having control of the labelling of the SVG
that is generated by R, we were able to link to the javascript
library very easily.
This basic idea lies behind a real world application that provides zoomable choropleth maps of New Zealand (see Languages in Aotearoa New Zealand published by the Royal Society of New Zealand).
SVG is a markup language that enables images to be described using structure and labelling so that every individual component of the image is uniquely identifiable.
If images are generated with structure and labelling they become useful resources from which further images may be produced, for example by independently specifying the styling of the image with CSS, by adding interactivity to the image with javascript, or by processing the image to extract, modify, and recombine the image with XSLT.
Software systems that generate complex SVG images from a high-level description often do not provide structure or labelling in the SVG code that they produce, but it is possible to generate complex SVG images with structure and labelling from R using the grid, lattice, and gridSVG packages. The important features of the solution that these R packages provide are:
A low-level system that enables an image to be described with structure and labelling.
A high-level system that produces complex images in a structured way and employs a naming scheme that automatically generates labels for every component of an image.
Documentation of the structure and naming scheme.
Tools for interactively exploring the structure and labelling in an image.
An API for generating labels and locations for individual components of an image.
We have shown that it is desirable to have structure and labelling in an SVG image and that it is possible to generate such an image from a high-level system that produces complex statistical plots. This section discusses the implications for other software.
The first point is that this is something that other software could do better. For example, javascript libraries, such as gRaphael and Highcharts, could provide more structure and labelling for the images that they generate.
The second point is that the benefits of structure and labelling are not exclusive to SVG. It would also be useful if software that generates HTML for web pages, such as DocBook converters and software that transforms simpler document markup to HTML (e.g., asciidoc and markdown), generated structure and labelling so that the resulting web page could be worked with and further developed by other authors.
An important subtlety is that the structure and labelling generated by a high-level system should not just be designed for the high-level system's own use; the ultimate goal is to produce a document that does not limit what other people can do with the document.
Most of the code in this report is R code that uses packages that are available from CRAN (see version information below). The exception is version 1.1-0 of the gridSVG package, which was only available from github at the time of writing. This should appear on CRAN in the near future.
sessionInfo()
R Under development (unstable) (2013-03-31 r62459) Platform: x86_64-unknown-linux-gnu (64-bit) locale: [1] LC_CTYPE=en_NZ.UTF-8 LC_NUMERIC=C [3] LC_TIME=en_NZ.UTF-8 LC_COLLATE=en_NZ.UTF-8 [5] LC_MONETARY=en_NZ.UTF-8 LC_MESSAGES=en_NZ.UTF-8 [7] LC_PAPER=C LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_NZ.UTF-8 LC_IDENTIFICATION=C attached base packages: [1] grid stats graphics grDevices utils datasets methods [8] base other attached packages: [1] lattice_0.20-14 gridSVG_1.1-0 RJSONIO_1.0-1 XML_3.95-0.2 [5] ggplot2_0.9.3 XDynDocs_0.3-1 Sxslt_0.91-1 loaded via a namespace (and not attached): [1] codetools_0.2-8 colorspace_1.2-1 dichromat_2.0-0 digest_0.6.3 [5] gtable_0.1.1-1 labeling_0.1 MASS_7.3-26 munsell_0.4 [9] plyr_1.8 proto_0.3-10 RColorBrewer_1.0-5 reshape2_1.2.2 [13] scales_0.2.3 stringr_0.6.2
The software packages used in Appendix B, Other Software for Generating SVG were: Gnumeric Spreadsheet 1.10.17, plot2svg dated 10 Apr 2005 (Updated 17 Sep 2012), Highcharts 2.0, gRaphael 0.5.1.
This appendix briefly considers the SVG generated by several high-level systems for drawing statistical plots and comments on the presence or absence of structure and labelling in the SVG code.
The plot2svg package for Matlab allows a Matlab plot to be exported in an SVG format (also adding access to advanced SVG features such as filters). Basic usage involves a single command, as shown in Figure B.1, “Matlab code for a complex image” (see Figure B.2, “An image generated by plot2svg” for the output).
Figure B.3, “SVG code generated by plot2svg” shows a fragment of the SVG
code generated by plot2svg.
The SVG code does include id
attributes
on some elements,
but they are very uninformative, serving only an internal use for
plot2svg. The structure or nesting of elements does provide
a grouping of the data symbols
(<circle>
elements) together within a
<g>
element, but again the labelling renders this structure
uninformative. Overall, there is little assistance within the
SVG code for working with the image any further.
<g id="ID000000"> <clipPath id="ID000001"> <rect x="68.250" y="29.531" width="406.875" height="320.906"/> </clipPath> </g> <g id="ID000002" clip-path="url(#ID000001)"> <g id="ID000003" clip-path="url(#ID000001)"> <g> <circle cx="451.721" cy="265.415" r="3.000" fill="none" stroke="#0000ff" stroke-width="0.5pt"/> </g> <g> <circle cx="449.794" cy="262.857" r="3.000" fill="none" stroke="#0000ff" stroke-width="0.5pt"/> </g> </g> </g>
The Gnumeric spreadsheet software can produce statistical charts and it is possible to export these charts in an SVG format (see Figure B.4, “An image generated by Gnumeric”).
Figure B.5, “SVG code generated by Gnumeric” shows a fragment of the SVG code generated by Gnumeric. This shows relatively efficient SVG code because various shapes have been defined at the start of the document and then the <use> elements just repeatedly reuse those shapes. However, there is neither nesting of elements to provide structure nor labelling of elements to assist with selection of specific components of the plot.
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> <use xlink:href="#glyph0-2" x="11.679688" y="114.441406"/> <use xlink:href="#glyph0-0" x="16.769531" y="114.441406"/> </g> <use xlink:href="#surface16639" transform="matrix(1,0,0,1,28.13876,107.337157)"/> <use xlink:href="#surface16639" transform="matrix(1,0,0,1,27.270721,91.839662)"/> <use xlink:href="#surface16639" transform="matrix(1,0,0,1,36.471936,81.367268)"/>
The gRaphael javascript library allows statistical charts to be produced with relatively little javascript code. Figure B.6, “gRaphael javascript code” shows the javascript code required to produce the plot in Figure B.7, “An image generated by gRaphael”.
Figure B.6. gRaphael javascript code for producing a statistical plot
<script><![CDATA[ var paper = Raphael(10, 10, 640, 480); paper.dotchart(0, 0, 620, 460, [76, 70, 67, 71, 69], [0, 1, 2, 3, 4], [100, 120, 140, 160, 500], { max: 10, axisylabels: ['Mexico', 'Argentina', 'Cuba', 'Canada', 'United States of America'], heat: true, axis: '0 0 1 1'}); ]]></script>
Figure B.8, “SVG code generated by gRaphael” shows a fragment of the SVG code that gRaphael generates. Again, there is neither structure nor labelling to identify significant components within the plot.
Figure B.8. SVG code generated by gRaphael
<text style="text-anchor: middle; font: 11px 'Fontin Sans',Fontin-Sans,sans-serif;" x="157" y="325" text-anchor="middle" font="11px 'Fontin Sans', Fontin-Sans, sans-serif" stroke="none" fill="#000000"/> <text style="text-anchor: middle; font: 11px 'Fontin Sans',Fontin-Sans,sans-serif;" x="197.8" y="325" text-anchor="middle" font="11px 'Fontin Sans', Fontin-Sans, sans-serif" stroke="none" fill="#000000"/> <text style="text-anchor: middle; font: 11px 'Fontin Sans',Fontin-Sans,sans-serif;" x="238.60000000000002" y="325" text-anchor="middle" font="11px 'Fontin Sans', Fontin-Sans, sans-serif" stroke="none" fill="#000000"/> <path style="" fill="none" stroke="#000000" d="M157,313.5L463,313.5M157.5,313L157.5,318M177.9,313L177.9,318M198.3,313L198.3,318M218.70000000000002,313L218.70000000000002,318M239.10000000000002,313L239.10000000000002,318M259.5,313L259.5,318M279.9,313L279.9,318M300.29999999999995,313L300.29999999999995,318M320.69999999999993,313L320.69999999999993,318M341.0999999999999,313L341.0999999999999,318M361.4999999999999,313L361.4999999999999,318M381.89999999999986,313L381.89999999999986,318M402.29999999999984,313L402.29999999999984,318M422.6999999999998,313L422.6999999999998,318M443.0999999999998,313L443.0999999999998,318M463.4999999999998,313L463.4999999999998,318"/> <circle cx="463" cy="303" r="4.47213595499958" fill="#90bf2f" stroke="none" style="fill-opacity: 1;" fill-opacity="1"/> <circle cx="259" cy="266.5" r="4.898979485566357" fill="#9fbf2f" stroke="none" style="fill-opacity: 1;" fill-opacity="1"/> <circle cx="157" cy="230" r="5.291502622129181" fill="#acbf2f" stroke="none" style="fill-opacity: 1;" fill-opacity="1"/>
Highcharts is another javascript library for producing statistical plots (free for personal use). Figure B.9, “Highcharts javascript code” shows the javascript required to produce the plot in Figure B.10, “An image generated by highcharts”.
Figure B.9. Highcharts javascript code for producing a statistical plot
<script><![CDATA[ $(document).ready(function() { var chart1 = new Highcharts.Chart({ chart: { renderTo: 'container', type: 'bar' }, title: { text: 'Fruit Consumption' }, xAxis: { categories: ['Apples', 'Bananas', 'Oranges'] }, yAxis: { title: { text: 'Fruit eaten' } }, series: [{ name: 'Jane', data: [1, 0, 4] }, { name: 'John', data: [5, 7, 3] }] }); }); ]]></script>
Figure B.11, “SVG code generated by highcharts” shows
a fragment of the SVG code generated by Highcharts, which shows that
there is some structure and labelling within
the SVG code that Highcharts generates.
There is a clear correspondence between the conceptual components
used in the original javascript code, with axis labelling information
collected together within
<g>
elements that have a useful class
attribute.
This does allow for some further processing of an SVG image that
is generated by Highcharts. For example, it is possible to
style the plot using CSS to affect all axis labelling.
However, the labelling is insufficient to be able to reliably
distinguish the axis labelling for the x-axis from the labelling for
the y-axis. Similar structure and labelling makes it possible to
style all of the rectangles in the plot, but there is
insufficient labelling to reliably address specific rectangles
or to reliably distinguish one series of rectangles from another.
Although Highcharts produces by far the most structure and labelling
in its SVG code, out of the high-level systems considered in this section,
there is still plenty of room for Highcharts to provide more
assistance for further processing of Highcharts plots.
<g class="highcharts-axis-labels"> <text text-anchor="end" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;width:457px;color:#666;line-height:14px;fill:#666;" y="92.43333333333334" x="53"> <tspan x="53">Apples</tspan> </text> <text text-anchor="end" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;width:457px;color:#666;line-height:14px;fill:#666;" y="185.10000000000002" x="53"> <tspan x="53">Bananas</tspan> </text> <text text-anchor="end" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;width:457px;color:#666;line-height:14px;fill:#666;" y="277.7666666666667" x="53"> <tspan x="53">Oranges</tspan> </text> </g> <g class="highcharts-axis-labels"> <text text-anchor="middle" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;color:#666;line-height:14px;fill:#666;" y="332" x="61"> <tspan x="61">0</tspan> </text> <text text-anchor="middle" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;color:#666;line-height:14px;fill:#666;" y="332" x="124.6"> <tspan x="124.6">0.5</tspan> </text> <text text-anchor="middle" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;color:#666;line-height:14px;fill:#666;" y="332" x="188.2"> <tspan x="188.2">1</tspan> </text> </g>
[XML] 2012. “ XML : Tools for parsing and generating XML within R and S-Plus. ”. R package version 3.9-4.
[latticeNaming] 2011. “ A Naming Scheme for Lattice Grobs ”. http://lattice.r-forge.r-project.org/Vignettes/src/naming-scheme/namingScheme.pdf.
[svgpan] 2013. “ svgpan : A JavaScript library to zoom, drag and pan SVG images ”. http://code.google.com/p/svgpan/.
dynDoc("labels.xml", "HTML", force = TRUE, xslParams = c(html.stylesheet = "http://stattech.wordpress.fos.auckland.ac.nz/wp-content/themes/twentyeleven/style.css customStyle.css", base.dir = "HTML", generate.toc = "article toc")) Wed Apr 10 10:22:12 2013