14

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.

TylerH
  • 20,799
  • 66
  • 75
  • 101
user31168
  • 165
  • 1
  • 5

3 Answers3

3

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.

G5W
  • 36,531
  • 10
  • 47
  • 80
  • this keeps throwing an error for me `Error in LO[ends(g, i)[1], 2] : no 'dimnames' attribute for array` – DrBwts May 27 '21 at 16:54
  • @DrBwts I just started a new R session and ran my code exactly as it appears above. I got no error. – G5W May 27 '21 at 17:19
  • it works for the example graph in your answer but when I read in a directed weighted graph it throws the above error – DrBwts May 27 '21 at 17:25
  • My best suggestion is 1. try to make a small example that has the problem. 2. Post a new question with a reference to this question. use `dput` on your _SMALL_ network, so that I can see what is going in, – G5W May 27 '21 at 17:44
3

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"))
2

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()
No More Hacks
  • 299
  • 4
  • 14