I would like to go one step further with this question ( Find total of second variable related to the distance of route from get.shortest.paths() ). How does one get the matrix of distances between nodes, when the 'shortest' path is found using the newcost variable?
(My experience with igraph is very limited).
df2 = rbind(c(234,235,21.6,75),
c(234,326,11.0,35),
c(235,241,14.5,78),
c(326,241,8.2,98),
c(241,245,15.3,75),
c(234,245,38.46,65))
df2 = as.data.frame(df2)
names(df2) = c("start_id","end_id","newcost","distance")
require(igraph)
g2 <- graph.data.frame(df2, directed=FALSE)
tmp2 = shortest.paths(g2,weights=E(g2)$newcost)
tmp2 #this gives the matrix of newcost-weighted shortest distances
Where I could use help is how to find all paths, say using optimal.path <- get.shortest.paths
, and using sum(E(g2, path = optimal.path)$distance)
to create the matrix of distances
what I would really like is an edgelist of distances for all node pairs, like:
startid endid shortestdist
234 235 75
234 245 208
What is tricky about this problem is that newcost is used to find the shortest paths, but what I want is the sum of another variable - the distance variable on each shortest path between node pairs.
Ok, first let me make it clear that I am not an igraph
user myself. Nevertheless I thought the question was interesting so I thought I'd take a look. And I too could find no easy solution to the problem you are having. I ended up making some helper functions to make the process possible. There is a good chance that i've re-coded the functionality inside igraph
already but I could not find it.
Let me first define get.shortest.paths.for.all
which will not just return the shortest path lengths for a given attribute, but will also return the shortest path themselves for all vertices in the graph. Here's that code
get.shortest.paths.for.all<-function(graph, attr) {
paths<-lapply(1:(vcount(graph)-1), function(i) {
get.all.shortest.paths(
graph,
weights=get.edge.attribute(g2,attr),
from = V(graph)[i],
to = V(graph)[(i+1):vcount(graph)]
)$res
})
unsplit(paths, rep.int(seq_along(paths), sapply(paths, length)))
}
Now let me define get.path.dist.matrix
will takes a graph and a list of paths (like the one returned by get.shortest.paths.for.all
) and will calculate the distance for a given attribute between each of those paths
get.path.dist.matrix<-function(graph, path, attr) {
dd<-get.adjacency(graph, attr=attr)
uniqs <- numeric(0)
if (is.list(path)) {
starts<-sapply(path, head, 1)
ends<-sapply(path, tail, 1)
uniqs <- unique(sort(c(starts,ends)))
} else {
uniqs <- c(head(path,1), tail(path,1))
}
m<-matrix(0, nrow=length(uniqs), ncol=length(uniqs),
dimnames=list(V(graph)$name[uniqs],V(graph)$name[uniqs]))
for(pp in path) {
m[pp[1], pp[length(pp)]]<-sum(dd[embed(pp,2)])
}
m+t(m)
}
Using your sample data, I use them like this
paths <- get.shortest.paths.for.all(g2, "newcost")
get.path.dist.matrix(g2, paths,"distance")
# 234 235 326 241 245
# 234 0 75 35 133 208
# 235 75 0 176 78 153
# 326 35 176 0 98 173
# 241 133 78 98 0 75
# 245 208 153 173 75 0
Which seems reasonable and distinct from shortest.paths(g2,weights=E(g2)$distance)
. To try to test my functions, I see that
all(tmp2==get.path.dist.matrix(g2, paths,"newcost"))
So feel free to try these out and let me know if you see any problems or possible improvements.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.