spacer
Home News Links People Catalog
spacer
activepages
spacer
Wow. Thanks for the suggestion that we should dive into SVG for an example of a useful XML-based language. It took me over two hours to get our example from last night working, but then only fifteen minutes to change it from circles into a histogram. I'll go over these examples next time we are all together, but I will also bring some X3D-based ones as well so we can see how data can be presented in 3-D using an XSL Transform as well. First we start with our data which is encoded in an XML document. If you remember in class we just grabbed some data from the Many Eyes Repository (a public data repository you can contribute to as well) at http://manyeyes.alphaworks.ibm.com/manyeyes/datasets:

The XML Document

<?xml version="1.0" standalone="yes"?>
<pollen_count>
<town>
<name>Blackstone</name>
<value>76</value>
</town>
<town>
<name>Clarksville</name>
<value>102</value>
</town>
<town>
<name>Farmville</name>
<value>144</value>
</town>
<town>
<name>Richmond</name>
<value>53</value>
</town>
</pollen_count>

Then we started to create a XSL Tranform document that could take the data out of our pollen counts dataset and visualize it using SVG. I had to do a little research and found the resource at http://www.w3.org/People/maxf/papers/2002-07-SVGOpen/svgopen.html to be most helpful. Here is the resultant code for our example in class (explanation follows):

The XSLT Document

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" media-type="application/xml" indent="yes" />
<xsl:template match="/">
<svg xmlns:svg="http://www.w3.org/2000/svg" viewBox="0 0 {25*(count(pollen_count/town/value)+1)} 200">
<xsl:for-each select="pollen_count/town/value">
<g style="fill-opacity:0.7;">
<circle cx="{position()}cm" cy="2cm" r="{.}" style="fill:green; stroke:black; stroke-width:0.1cm" transform="translate(-50,0)" />
</g>
</xsl:for-each>
<xsl:for-each select="pollen_count/town/name">
<text transform="matrix(1 0 0 1 {40*position()-60} 80)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">
<xsl:value-of select="." />
</tspan>
</text>
</xsl:for-each>
</svg>
</xsl:template>
</xsl:stylesheet>

I solved the problem of writing XML from within an XML document by using the xsl:output tag you see above. I also found that SVG has a great viewBox attribute you can set within the svg element to define the dimensions of your visual canvas. I set the view dynamically by providing 25 pixels width for each data element in the input (which is held in our case in the path pollen_count/town/value within the XML document hierarchy). I then took advantage of the period (.) symbol, which in context of an xsl:for-each element refers to the element content for the path item that was selected. We can perform computations on the selected data when the element's content is numerical. And, we can call built-in positioning functions that are available within the SVG language (it became obvious we were going to need some type of computation to process more than one numerical value and have it appear in a position on the output graphic under our control. I looked up the proper syntax for an SVG text element and played with the parameters until I got what I wanted.

With the XML and XSL documents (you can grab the xml here and the xslt here), you can run the SAXON processor to generate the SVG output using a command similar to the lightning strike example from our primer:

java -mx512m -cp .:saxon9he.jar net.sf.saxon.Transform -s:VA_pollen.xml -xsl:svgc.xml -o:pollenc.svg

The Output SVG Document

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 125 200"
preserveAspectRatio="xMidYMid meet"
zoomAndPan="magnify"
version="1.0"
contentScriptType="text/ecmascript"
contentStyleType="text/css">
<g style="fill-opacity:0.7;">
<circle cx="1cm" cy="2cm" r="76" style="fill:green; stroke:black; stroke-width:0.1cm"
transform="translate(-50,0)"/>
</g>
<g style="fill-opacity:0.7;">
<circle cx="2cm" cy="2cm" r="102" style="fill:green; stroke:black; stroke-width:0.1cm"
transform="translate(-50,0)"/>
</g>
<g style="fill-opacity:0.7;">
<circle cx="3cm" cy="2cm" r="144" style="fill:green; stroke:black; stroke-width:0.1cm"
transform="translate(-50,0)"/>
</g>
<g style="fill-opacity:0.7;">
<circle cx="4cm" cy="2cm" r="53" style="fill:green; stroke:black; stroke-width:0.1cm"
transform="translate(-50,0)"/>
</g>
<text transform="matrix(1 0 0 1 -20 80)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Blackstone</tspan>
</text>
<text transform="matrix(1 0 0 1 20 80)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Clarksville</tspan>
</text>
<text transform="matrix(1 0 0 1 60 80)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Farmville</tspan>
</text>
<text transform="matrix(1 0 0 1 100 80)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Richmond</tspan>
</text>
</svg>

Sweet, huh? Take a look at the output by opening the result in a Firefox Web browser (or any other browser where the SVG viewer is built right in). You'll see that we get the automatic resizing feature when you resize the browser window - that's the power of scalable vector graphics (the scalable part). You'll also notice that using circles in this manner is not the best for demonstrating relative magnitude (but not too bad). So, I also created an XSL Transform for creating a bar chart

A Second XSL Tranform Example

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" media-type="application/xml" indent="yes" />
<xsl:template match="/">
<svg xmlns:svg="http://www.w3.org/2000/svg" viewBox="0 0 {10*(count(pollen_count/town/value)+1)} 200">
<xsl:for-each select="pollen_count/town/value">
<rect x="{10*position()}" y="{180- .}" width="10" height="{.}" fill="red" stroke="black"/>
</xsl:for-each>
<xsl:for-each select="pollen_count/town/name">
<text transform="matrix(1 0 0 1 {10*position()} {120+10*position()})">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">
<xsl:value-of select="." />
</tspan>
</text>
</xsl:for-each>
</svg>
</xsl:template>
</xsl:stylesheet>
If you change your svgc.xml file to contain this example instead, and then re-run your SAXON transform process, you get the following SVG output (take a look at it here):
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 50 200"
preserveAspectRatio="xMidYMid meet"
zoomAndPan="magnify"
version="1.0"
contentScriptType="text/ecmascript"
contentStyleType="text/css">
<rect x="10" y="104" width="10" height="76" fill="red" stroke="black"/>
<rect x="20" y="78" width="10" height="102" fill="red" stroke="black"/>
<rect x="30" y="36" width="10" height="144" fill="red" stroke="black"/>
<rect x="40" y="127" width="10" height="53" fill="red" stroke="black"/>
<text transform="matrix(1 0 0 1 10 130)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Blackstone</tspan>
</text>
<text transform="matrix(1 0 0 1 20 140)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Clarksville</tspan>
</text>
<text transform="matrix(1 0 0 1 30 150)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Farmville</tspan>
</text>
<text transform="matrix(1 0 0 1 40 160)">
<tspan x="0" y="0" font-family="'MyriadPro-Regular'" font-size="4">Richmond</tspan>
</text>
</svg>

 

Welcome to Class

File Size: 37 kb
Posted: Sun, May 30, 2009

Class Project Discussion

File Size: 24 kb
Posted: Fri, Jun 26, 2009