问题
I have a graph with many edges between two nodes. When I plot it, I get a warning I don't understand in this context.
This works fine:
library(igraph)
gg <- graph.empty(n=0, directed=TRUE)
gg <- gg + vertex("10501")
gg <- gg + edge("10501", "10501")
gg <- gg + edge("10501", "10501")
plot(gg)
But the same graph with one more edge gives a warning:
gg <- graph.empty(n=0, directed=TRUE)
gg <- gg + vertex("10501")
gg <- gg + edge("10501", "10501")
gg <- gg + edge("10501", "10501")
gg <- gg + edge("10501", "10501")
plot(gg)
I fail to see the reason. Why this warning?
回答1:
Searching the igraph
package source for the line giving the warning, it seems that the culprit function is autocurve.edges
in plot.common.R
:
autocurve.edges <- function(graph, start=0.5) {
cm <- count.multiple(graph)
el <- apply(get.edgelist(graph, names=FALSE), 1, paste, collapse=":")
ord <- order(el)
res <- numeric(length(ord))
p <- 1
while (p <= length(res)) {
m <- cm[ord[p]]
idx <- p:(p+m-1)
if (m==1) {
r <- 0
} else {
r <- seq(-start, start, length=m)
}
res[ord[idx]] <- r
p <- p + m
}
res
}
According to ?igraph.plotting
(and the package source) the autocurve.edges
function is the called by default to determine how to curve edges:
By default the vector specifying the curvatire is calculated via a call to the autocurve.edges function. This function makes sure that multiple edges are curved and are all visible. This parameter is ignored for loop edges.
From early in igraph.plot
, we can see that this function is called, being passed the whole graph:
curved <- params("edge", "curved")
if (is.function(curved)) { curved <- curved(graph) }
This is the source of the warnings on the problematic graph:
autocurve.edges(gg)
# [1] -0.5 -0.5 0.0
# Warning messages:
# 1: In res[ord[idx]] <- r :
# number of items to replace is not a multiple of replacement length
# 2: In res[ord[idx]] <- r :
# number of items to replace is not a multiple of replacement length
To delve into why we're seeing these issues, the very first thing this function does is call count.multiple
, which returns the number of times each edge is repeated. In the offending graph:
count.multiple(gg)
# [1] 1.5 1.5 1.5
Instead of returning c(3, 3, 3)
(since the looping edge is repeated 3 times), it's returning c(1.5, 1.5, 1.5)
. Though I don't see any mention of this in ?count.multiple
, this is happening because the count of an edge is divided by 2 if it is a loop (aka an edge from a node to itself), due to the following line in igraph_count_multiple
from the structural_properties.c
file in the igraph
package source:
/* for loop edges, divide the result by two */
if (to == from) VECTOR(*res)[i] /= 2;
The fact that the warnings are generated is due to a bug -- autocurve.edges
was expecting to get c(3, 3, 3)
but instead got c(1.5, 1.5, 1.5)
from count.multiple
due to the loop edges. I think autocurve.edges
could actually be reimplemented in pure R using something like:
autocurve.edges <- function(graph, start=0.5) {
el <- apply(get.edgelist(graph, names=FALSE), 1, paste, collapse=":")
ave(rep(NA, length(el)), el, FUN=function(x) {
if (length(x) == 1) {
return(0)
} else {
return(seq(-start, start, length=length(x)))
}
})
}
Further, I think the documentation of count.multiple
should be updated to mention its special handling of loop edges.
In the meantime, I think the solution in your case would be to manually specify your curvature parameter to avoid the warnings:
plot(gg, edge.curved=FALSE)
Update: Submitted as a pull request to the rigraph project and now merged into the dev branch of the R igraph project: https://github.com/igraph/rigraph/pull/80
来源:https://stackoverflow.com/questions/30556493/why-igraph-plot-warns-that-number-of-items-to-replace-is-not-a-multiple-of-repl