title: Setting edge width in Rgraphviz
body: <p>Apparently, it is possible, although not well documented, to set the edge width in Rgraphviz. Here is one way to do it:</p>
  
  <pre><code>library(graph)
  library(Rgraphviz)
  nodes &lt;- c( LETTERS[1:3] )
  edgesL &lt;- list( A=c("B", "C"), B=c("A", "C"), C=c("B", "A" ) )
  graph &lt;- new( "graphNEL", nodes= nodes, edgemode="undirected", edgeL=edgesL )
  rag &lt;- agopen( graph, "" )
  rag@AgEdge[[1]]@lwd &lt;- 5
  plot(rag)
  </code></pre>
  
  <p>The slot "lwd" is explicitly defined in the AgEdge man page. Result:</p>
  
  <p><img src="https://i.stack.imgur.com/1U0UW.png" alt="enter image description here"></p>
  
  <p>So far, so good. However, I cannot access the AgEdge object with edge ID (i.e., "A~C"), only with a numeric index. How do I use the above approach to tell graphviz to change the lwd for the edge between A and C?</p>
  
  <p>The proper way to add values of the attributes would be through the edgeAttrs option to agopen(), however. Let's try with a documented attribute:</p>
  
  <pre><code>eAttrs &lt;- list( color=c( "A~C"="red" ) )
  rag &lt;- agopen( graph, "", edgeAttrs=eAttrs )
  plot(rag)
  </code></pre>
  
  <p>OK, the result is correct:</p>
  
  <p><img src="https://i.stack.imgur.com/ViQUs.png" alt="enter image description here"></p>
  
  <p>OK, how about lwd, then; but -- bummer:</p>
  
  <pre><code>&gt; eAttrs &lt;- list( lwd=c( "A~C"=5 ) )
  &gt; rag &lt;- agopen( graph, "", edgeAttrs=eAttrs )
  Error in buildEdgeList(graph, recipEdges, edgeAttrs, subGList, attrs$edge) : 
    no slot of name "name" for this object of class "pEdge"
  </code></pre>
  
  <p>Weirdly enough, when you look up the agopen function, you find the following snippet of code:</p>
  
  <pre><code>if (!is.null(edgeAttrs$lwd)) {
      for (i in seq(along = edgeAttrs$lwd)) {
          attr(attr(g, "AgEdge")[[i]], "lwd") &lt;- edgeAttrs$lwd[i]
      }
  }
  </code></pre>
  
  <p>This looks like in theory, edgeAttrs should be able to handle lwd. The documentation is not helpful, unfortunately: if you look up the manual page for "agopen", it tells you</p>
  
  <pre><code> For a description of ‘attrs’, ‘nodeAttrs’ and ‘edgeAttrs’, see the
   ‘Ragraph’ man page.
  </code></pre>
  
  <p>However, "edgeAttrs" are not mentioned in the Ragraph man page at all. I am confused and angry. And desperate. Desperate people study the source code. Apparently, <code>agopen()</code> throws an error, because <code>getDefaultAttrs()</code> doesn't know about the lwd slot. We can amend it, though:</p>
  
  <pre><code>eAttrs &lt;- list( lwd=list( "A~C"=5, "A~B"=1 ) )
  rag &lt;- agopen( graph, "", edgeAttrs=eAttrs, attrs= list(edge=list(lwd=2)) )
  plot(rag)
  </code></pre>
  
  <p>This at least doesn't produce an error message, but produces an incorrect graph:</p>
  
  <p><img src="https://i.stack.imgur.com/wmgix.png" alt="enter image description here"></p>
  
  <p>This is because this weird code snippet above uses <code>seq(along= .. )</code> to fill out the lwd information, completely ignoring the fact that this is a named list and we want to enter the information by edge names, not their order.</p>
  
  <p>So, my question. Is there a simple, documented way of displaying a graph with varying edge widths in R / Rgraphviz? (I need Rgraphviz because I want to draw the nodes with a custom function, other packages do not provide this functionality, I think). </p>
  
  <p>Or do I need to code my own crutches? Oh, I can do it, here is a function that sets an attribute for an edge between ID1 and ID2 (which can be vectors of the same length, providing value is also a vector of the same length):</p>
  
  <pre><code>setEdgeAttr &lt;- function( graph, attribute, value, ID1, ID2 ) {
  
    idfunc &lt;- function(x) paste0( sort(x), collapse="~" )
    all.ids &lt;- sapply( AgEdge(graph), 
      function(e) idfunc( c( attr(e, "head"), attr( e, "tail" ))))
  
    sel.ids &lt;- apply(cbind( ID1, ID2 ), 1, idfunc )
  
    if(!all(sel.ids %in% all.ids)) stop( "only existing edges, please" )
    sel &lt;- match( sel.ids, all.ids )
  
    for(i in 1:length(sel)) {
      attr( attr( graph, "AgEdge" )[[ sel[i] ]], attribute ) &lt;- value[i]
    }
  
    return(graph)
  }
  </code></pre>
  
  <p>Does it work? Oh, yes:</p>
  
  <pre><code>rag &lt;- agopen( graph, "" )
  rag &lt;- setEdgeAttr( rag, "lwd", c(5, 20), c("B", "B"), c( "A", "C" ) )
  plot(rag)
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/tpJGT.png" alt="enter image description here"></p>
  
  <p>I just can't believe there is no easier way.</p>