Introduction

The design of svgR is influenced by three considerations:

The first is easy to satisfy, just replicate the svg interface in R. The second and third give rise to the structural variations/enhancements described in this document.

Attribute Combining

Combo Attributes is short for combined attributes.

Vectors are natural to the R language. A single assignment statement to assign multiple values is second nature to the R programmer. For example, consider specifying the center of a circle. The typical R programmer is likely to use a single vector assignment such as cxy=c(400,100), instead of a pair of assignments cx=400, cy=100.

Since svgR is designed to be easy to use for R programmers, svgR supports using combined SVG attributes. That means, that although SVG requires cx cy to be specified seperately, svgR allows them to be specified jointly as a single vector.

Consider the following:

The R script to generate a red circle:

Consider the following

svgR(
  wh=c(600,100),
  circle(cxy=c(100,50), r=30, fill='red')
)

We can visualize the call structure of the above code as

Anatomy of an svgR Function Call svgR wh=c(600,100) circle cxy=c(100,50) r=30 fill=red The root node represents the function svgR The light yellow nodes represent named parameters, which in svgR lingo are called attributes. The blue node represents a call to the circle function, which in svgR lingo is called an element. This element is a shape element, and tells svgR that a circle is wanted. Elements are only available for use within the scope of the svgR call.

Generated SVG markup

The above call will generate the following SVG markup:

## <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" id="root" width="600" height="100">
##   <circle r="30" fill="red" cx="100" cy="50"/>
## </svg>

This SVG markup looks like

Resulting SVG Markup Tree svg id=root width=600 height=100 circle r=30 fill=red cx=100 cy=50 The svgR automatically generates an SVG root node and gives it an id of ‘root’. The wh attribute is split into 2 SVG attributes width, and height, which specify width and height of the display region The svgR circle element creates the SVG circle element. The cxy attribute is split into 2 SVG attributes cx, cy which specify the center of the circle.
We should note that instead of cxy and wh, we can also use cx, cy, width, and height
directly in svgR, its just a little more typing. In the tree to left, light yellow is used to indicate attributes.

Handling Lists

Another feature of svgR is that an unnamed argument that is a list, can be “promoted”, providing a convenient way to do iteration. We illustrate this with another slightly more complex example

Using lapply for muliple circles.

colors<-c('red','yellow','green')
WH<-c(900,100)
svgR(
  wh=WH,
  lapply(1:3, function(i)
    circle(cxy=c(i*100,50), r=50, fill= colors[i])
  )
)

The svgR Call Structure

Noting that lapply returns a list, we see that the structure of this call is essentially:

An svgR Function Call using lapply svgR wh=c(900,100) list circle circle circle cxy=c(100,50) r=50 fill=red cxy=c(200,50) r=50 fill=yellow cxy=c(300,50) r=50 fill=green The svgR function has two arguments (child nodes): a wh attribute and a list, The list is the return value of the lapply. The list contains three elements, the circle nodes, resulting from the circle function calls.

Next: Promotion of the list elements

What happens next is that svgR promotes the children of the list to become arguments of the root.

List Promotion svgR wh=c(900,100) circle circle circle cxy=c(100,50) r=50 fill=red cxy=c(200,50) r=50 fill=yellow cxy=c(300,50) r=50 fill=green The three circle elements in the list are promoted up to become arguments to the svgR call. List promotion occurs whenever an argument is unnamed and a list. In that case, the elements of the list argument are then moved one level up in the call tree. This process is performed recursively, so that the resulting arguments will either be named or non-lists. This behaviour is similar to the usual R unlist, except that names lists are not unlisted (since named arguments are attributes.) This behaviour is one of the features that give svgR it power of expressibilty.

The Resulting SVG tree

Finally, svgR generates an SVG tree, as shown below

The Generated SVG svg id=root width=900 height=100 circle r=50 fill=red cx=100 cy=50 circle r=50 fill=yellow cx=200 cy=50 circle r=50 fill=green cx=300 cy=50 Again, the svgR attributes that consist of vectors are split into seperate svg attributes. Also, light yellow denotes attributes, blue denotes shape elements, green denotes container elements,

Anonymous Elements

Traditionally, Patterns, Gradients, Masks and Filters are defined inside a defs element and when used, are referenced by an xlink. However, tracing/unraveling the reference can be painful and frustrating, particullary when it is only needed once.

In svgR, we introduce the notion of anonymous Patterns, Gradients, Masks and Filters. This can be thought of as analogous to the use of anonymous functions, namely define where used. Since svgR creates SVG markup, to implement these anonymous elements, behind the scenes svgR relocate those elements while providing identifiers.

In the subsequent sections we provide details the svgR anonymous patters, Gradients, Masks and Filters.

The Structural Analysis for an Anonymous Pattern

Example (Fill Pattern)

Consider the following mask

WH<-c(900,100)
svgR( wh=WH,
  circle( cxy=c(50,50), r=50, 
    fill=pattern( xy=c(0,0), wh=c(20,20), patternUnits='userSpaceOnUse',
      polygon( points=c(c(0,0), c(20,0), c(10,20) ), fill='red' )
    )
  )
)

Call Structure (Fill=Pattern)

The call tree looks like

Anatomy of an svgR Function Call svgR wh=c(900,100) circle cxy=c(50,50) r=50 fill= pattern xy=c(0,0) wh=c(20,20) patternUnits=userS polygon points=c(0,0,20,0, fill=red

Generated SVG (Fill=Pattern)

The generated SVG tree, is

The Generated SVG svg id=root width=900 height=100 pattern patternUnits=userS width=20 height=20 x=0 y=0 id=genid3 polygon points=0 0 20 0 10 fill=red circle r=50 fill=url(#genid3) cx=50 cy=50

The Structural Analysis for an Anonymous Gradient

Example (Fill Gradient)

Consider the following mask

WH<-c(900,100)
svgR( wh=WH,
  circle( cxy=c(50,50), r=50, 
    fill=radialGradient( colors=c('yellow','blue') )
  )
)

Call Structure (Fill=Gradient)

The call tree looks like

Anatomy of an svgR Function Call svgR wh=c(900,100) circle cxy=c(50,50) r=50 fill= radialGradient colors=c(yellow,bl

Generated SVG (Fill=Gradient)

The generated SVG tree, is

The Generated SVG svg id=root width=900 height=100 radialGradient id=genid5 stop offset=0% stop-color=yellow stop offset=100% stop-color=blue circle r=50 fill=url(#genid5) cx=50 cy=50

The Structural Analysis for an Anonymous Mask

Example (Masking)

Consider the following mask

WH<-c(800,100)
svgR( wh=WH,
  text(xy=c(20,70),'Masking Example!',font.size=50),
  circle(cxy=c(50,50), r=50, fill='red', 
    mask=mask(
      rect( xy=c(0,0), wh=WH, fill='#AAAAAA' ),
      rect( cxy=c(50,50), wh=c(60,80), fill='black' )
    )
  )
)
Masking Example!

Call Structure (Masking)

The call tree looks like

Anatomy of an svgR Function Call svgR wh=c(800,100) text circle xy=c(20,70) font.size=50 cxy=c(50,50) r=50 fill=red mask= mask rect rect xy=c(0,0) wh=c(800,100) fill=#AAAAAA cxy=c(50,50) wh=c(60,80) fill=black

Generated SVG (Masking)

The generated SVG tree, is

The Generated SVG svg id=root width=800 height=100 text font-size=50 x=20 y=70 mask id=genid7 rect fill=#AAAAAA width=800 height=100 x=0 y=0 rect fill=black width=60 height=80 x=20 y=10 circle r=50 fill=red mask=url(#genid7) cx=50 cy=50

Structural Analysis of an Anonymous Filter

A short example

WH=c(800, 120) # window rect
svgR( wh=WH,
  text( 'svgR', xy=c(50,70), font.size=50,  fill="lightblue", stroke="darkblue",
    filter = filter( xy=c(-10,-10), wh=c(200,60),
              feBlend( x=-10, width=200, 
                in1="SourceGraphic", 
                in2=feGaussianBlur( stdDeviation=3, in1=feOffset( dxy=c(3,3), in1="SourceAlpha") )
              )
      )   
  )
)
svgR

Call Structure (Filter)

The call tree looks like

Anatomy of an svgR Function Call svgR wh=c(800,120) text xy=c(50,70) font.size=50 fill=lightblue stroke=darkblue filter= filter xy=c(-10,-10) wh=c(200,60) feBlend x=-10 width=200 in1=SourceGraphic in2= feGaussianBlur stdDeviation=3 in1= feOffset dxy=c(3,3) in1=SourceAlpha

Generated SVG (Filter)

The generated SVG tree, is

The Generated SVG svg id=root width=800 height=120 filter width=200 height=60 x=-10 y=-10 id=genid13 feOffset in=SourceAlpha dx=3 dy=3 result=genid11 feGaussianBlur stdDeviation=3 in=genid11 result=genid12 feBlend x=-10 width=200 in=SourceGraphic in2=genid12 text font-size=50 fill=lightblue stroke=darkblue filter=url(#genid1 x=50 y=70

todo: clippath, marker