title: Use the `pos` argument in Rgraphviz to fix node position
body: <p>Based on this question <a href="https://stackoverflow.com/questions/45721802/automatically-curving-an-arc-when-it-is-overlapping-with-another-one">Automatically curving an arc when it is overlapping with another one</a>, I am trying to set the <code>pos</code> attribute in a <code>RGraphviz</code> plot.</p>
  
  <p>Can someone show how to correctly use the <code>pos</code> attribute or suggest a more robust workaround. thanks.</p>
  
  <p><em>Example</em></p>
  
  <p>To be consistent with the above linked question, the following example starts from a <code>bnlearn</code> graph with nodes in a grid layout.</p>
  
  <pre><code>library(bnlearn)
  library(Rgraphviz)
  library(igraph)
  
  # Create graph
  adj &lt;- matrix(0L, ncol = 9, nrow = 9, dimnames = list(LETTERS[1:9], LETTERS[1:9]))
  adj[upper.tri(adj)] &lt;- 1
  e &lt;- empty.graph(LETTERS[1:9])
  amat(e) &lt;- adj
  g &lt;- as.graphNEL(e)
  
  # layout in grid
  ig &lt;- igraph.from.graphNEL(g)
  lay &lt;- layout.grid(ig)
  lay &lt;- setNames(data.frame(norm_coords(lay, -100, 100, -100, 100)), c("x", "y"))
  </code></pre>
  
  <p>The help page <code>?GraphvizAttributes</code> indicates that <code>pos</code> should be set as </p>
  
  <blockquote>
    <p>Position of the node (For neato layouts, this is the initial position of the node). Specified using the notion val,val where each val is a double.</p>
  </blockquote>
  
  <p>And a bit further down, for <code>neato</code> only attributes</p>
  
  <blockquote>
    <p>pin: If TRUE and node has a pos attribute on input, neato prevents the node from moving from the input position. The default for this attribute is FALSE.</p>
  </blockquote>
  
  <p>I cannot find the correct way to apply this argument.</p>
  
  <p>Various things I've tried with no success</p>
  
  <pre><code># Passed named list with `x` and `y` positions
  # To see the `pos` attribute has not been added you can use `AgNode(z)[[1]]`  
  rownames(lay) &lt;- nodes(e)
  pos &lt;- lapply(split(lay, rownames(lay)), unlist)
  z &lt;- agopen(g, "gg", nodeAttrs=list(pos=pos, 
                                      pin=setNames(rep(TRUE, length(nodes(e))), nodes(e))), 
                                      layoutType="neato")
  
  # Passed as a named character string with coordinates pasted together
  lay1 &lt;- do.call(paste, c(lay, sep=","))
  pos &lt;- paste(lay1, '!') # also tried with `pos = paste(lay)`
  names(pos) &lt;- nodes(e)
  z &lt;- agopen(g, "gg", nodeAttrs=list(pos=pos, 
                                      pin=setNames(rep(TRUE, length(nodes(e))), nodes(e))), 
                                      layoutType="neato")
  </code></pre>
  
  <hr>
  
  <p>I can get the expected outcome with this workaround, but it won't be robust.</p>
  
  <pre><code># write out dot file
  z &lt;- agopen(g, "gg")
  agwrite(z, "so.dot")
  
  #positions
  lay1 &lt;- do.call(paste, c(lay, sep=","))
  pos &lt;- paste('pos = "', lay1, '!"')
  
  #read in dot
  rd &lt;- readLines("so.dot")
  id &lt;- sapply(paste0("label=", nodes(e)) , grep, rd)
  
  #add in positions
  for(i in seq(id)) {  
    rd[id[i]] &lt;- gsub(names(id)[i], paste(names(id)[i], pos[i], sep="\n"), rd[id[i]])
    }
  
  # output and render
  cat(rd, file="so1.dot", sep="\n")
  system("neato so1.dot -n -Tpdf -o so.pdf")
  </code></pre>
  
  <p>To give the expected outcome</p>
  
  <p><a href="https://i.stack.imgur.com/OBjz8.png" rel="noreferrer"><img src="https://i.stack.imgur.com/OBjz8.png" alt="enter image description here"></a></p>