44

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

enter image description here

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.