Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to separate edge label from edge in igraph?

I would like to move the position of the edge label so that it is not on top of it. Here is a little example:

 g <- graph.empty(n=3) 
 g <- graph(c(1,2,3,2,1,3), directed=T)
 E(g)$weight <- c(3,2,5) 
 plot(g, edge.label = E(g)$weight)

In my example, the labels are on the edges and I want them to move perpendicular to the edge a little bit.

like image 842
user31168 Avatar asked Apr 14 '14 01:04

user31168


3 Answers

Sorry to be the guy that says "How about using library(x)?"

My code using ggraph?

library(igraph)
library(ggraph)

g <- graph.empty(n=3) 
g <- graph(c(1,2,3,2,1,3), directed=T)
E(g)$weight <- c(3,2,5) 

#your plot
plot(g, edge.label = E(g)$weight)


#using ggraph
ggraph(graph = g) +
  geom_node_circle(size = 1, mapping = aes(r =0.03), fill="goldenrod") +
  geom_edge_link(mapping = aes (label = weight),
                 arrow = arrow(type = "closed", angle = 15), 
                 end_cap = circle(8, 'mm'), , 
                 start_cap = circle(8, 'mm'), 
                 colour="grey",
                 label_dodge  = unit(5, "mm"),
                 angle_calc = "along") +
  geom_node_text(mapping = aes(label = "2")) +
  theme_graph()
like image 138
No More Hacks Avatar answered Nov 18 '22 22:11

No More Hacks


igraph plotting has parameters edge.label.x and edge.label.y for placing the edge labels, but these must be specified in the coordinates used for making the plot. To get the right coordinates, you need to take control of the layout yourself. @GaborCsardi suggested something like this in his comment, but implementing this is complicated enough that I think it deserves a full answer.

## Setup - your example graph
library(igraph)
g <- graph.empty(n=3) 
g <- graph(c(1,2,3,2,1,3), directed=T)
E(g)$weight <- c(3,2,5) 

Now, instead of just plotting, we capture the layout of the vertices so that we can use it. I set the random seed for reproducibility.

set.seed(1234)
LO = layout_nicely(g)

The layout gives x-y coordinates for the vertices that we can use for plotting. We want to use those positions to compute where we will write the edge labels. We will start by just computing the centers of the edges and then adjusting the positions perpendicular to the edges. One fine point: if an edge is nearly horizontal, the slope of the perpendicular is nearly infinite, so the calculation of the perpendicular displacement may cause problems. We will test for this and sidestep that problem.

## Start with the centers of the edges (on line)
ELx = rep(0, ecount(g))
ELy = rep(0, ecount(g))
for(i in 1:ecount(g)) {
    ELx[i] = (LO[ends(g,i)[1],1] + LO[ends(g,i)[2],1])/2
    ELy[i] = (LO[ends(g,i)[1],2] + LO[ends(g,i)[2],2])/2 }

## Adjust perpendicular to line
d = 0.03
for(i in 1:ecount(g)) {
    if(abs(LO[ends(g,i)[1],2] - LO[ends(g,i)[2],2]) < 0.1) {
        ## This avoids problems with horizontal edges
        ELy[i] = ELy[i] + shift 
    } else {
        S = (LO[ends(g,i)[2],1] - LO[ends(g,i)[1],1]) / 
            (LO[ends(g,i)[1],2] - LO[ends(g,i)[2],2])
        shift = d / sqrt(1 + S^2)
        ELx[i] = ELx[i] + shift
        ELy[i] = ELy[i] + S*shift
    }
}

Now we can plot and specify a better position for the edge labels. By default, plotting of igraph objects rescales the layout to the range [-1,1] for both the x and y axes. If that happens, the values in the layout no longer correspond to positions on the graph. So we will use rescale=FALSE. But igraph still wants to plot in the range [-1,1], so we also have to set xlim and ylim.

plot(g, layout=LO, edge.label = E(g)$weight,
    rescale=FALSE, xlim=range(LO[,1]), ylim=range(LO[,2]), 
    edge.label.x=ELx, edge.label.y=ELy)

Graph with shifted edge labels

The adjustment distance d = 0.03 is somewhat arbitrary. I picked it to make this graph look nice. If you have a more complicated graph, you might want to adjust that distance.

like image 21
G5W Avatar answered Nov 18 '22 22:11

G5W


You can move the edge labels vertically by adding return characters. You can move them horizontally by adding spaces. For example,

plot(g, edge.label = c(" 3","2\n","5\n"))
like image 25
Dave Hunter Avatar answered Nov 18 '22 21:11

Dave Hunter