Based on this question Automatically curving an arc when it is overlapping with another one, I am trying to set the pos
attribute in a RGraphviz
plot.
Can someone show how to correctly use the pos
attribute or suggest a more robust workaround. thanks.
Example
To be consistent with the above linked question, the following example starts from a bnlearn
graph with nodes in a grid layout.
library(bnlearn)
library(Rgraphviz)
library(igraph)
# Create graph
adj <- matrix(0L, ncol = 9, nrow = 9, dimnames = list(LETTERS[1:9], LETTERS[1:9]))
adj[upper.tri(adj)] <- 1
e <- empty.graph(LETTERS[1:9])
amat(e) <- adj
g <- as.graphNEL(e)
# layout in grid
ig <- igraph.from.graphNEL(g)
lay <- layout.grid(ig)
lay <- setNames(data.frame(norm_coords(lay, -100, 100, -100, 100)), c("x", "y"))
The help page ?GraphvizAttributes
indicates that pos
should be set as
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.
And a bit further down, for neato
only attributes
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.
I cannot find the correct way to apply this argument.
Various things I've tried with no success
# 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) <- nodes(e)
pos <- lapply(split(lay, rownames(lay)), unlist)
z <- 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 <- do.call(paste, c(lay, sep=","))
pos <- paste(lay1, '!') # also tried with `pos = paste(lay)`
names(pos) <- nodes(e)
z <- agopen(g, "gg", nodeAttrs=list(pos=pos,
pin=setNames(rep(TRUE, length(nodes(e))), nodes(e))),
layoutType="neato")
I can get the expected outcome with this workaround, but it won't be robust.
# write out dot file
z <- agopen(g, "gg")
agwrite(z, "so.dot")
#positions
lay1 <- do.call(paste, c(lay, sep=","))
pos <- paste('pos = "', lay1, '!"')
#read in dot
rd <- readLines("so.dot")
id <- sapply(paste0("label=", nodes(e)) , grep, rd)
#add in positions
for(i in seq(id)) {
rd[id[i]] <- 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")
To give the expected outcome