Use the `pos` argument in Rgraphviz to fix node position

一个人想着一个人 提交于 2019-12-10 02:09:34

问题


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

来源:https://stackoverflow.com/questions/45801817/use-the-pos-argument-in-rgraphviz-to-fix-node-position

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!