Mark.groups in Igraph Error: unknown vertex.names selected - r

I am trying to create a network plot in igraph where
communities are marked by a color overlay as created by mark.groups
nodes are colored by a node attribute: deu
nodes are shaped a node attribute: topic_type
For this, I created an igraph object
And now, I try the following code:
set.seed(2)
plot(graph_deu,
mark.groups=list(c(33,1,34,2,36,53,54,56,42,43,55,57,18), c(35,48,50,27), c(38,45,46,47,49,28,25)),
mark.col=c("lemonchiffon", "slategray1", "thistle1"),
mark.border = NA,
edge.width =E(graph_deu)$weight,
vertex.size = deu_deg,
vertex.color = deu,
vertex.shape = topic_type,
vertex.label = node_labels,
vertex.label.cex=1.5
)
And I get the error:
Fehler in simple_vs_index(x, ii, na_ok) : Unknown vertex selected.
This seems to be igraph not finding the vertices as specified in mark.groups, but I have actually no idea why it would not find these vertices, as they are all correctly numbered.
Then, to avoid mark.groups, I tried another option - I directly plot the community object (mod2), however, in this case, nodes get colored according to community and not according to attribute deu:
plot(mod2, graph_deu,
edge.width =E(graph_deu)$weight,
vertex.size = deu_deg,
vertex.color = deu,
vertex.shape = topic_type,
vertex.label = node_labels,
vertex.label.cex=1.5)
This produces a network where vertices are colored by community, not by deu-attribute. What I would like it to look: I would like the communities to be circled by the semi-transparent overlay, but the nodes should be individually colored by deu-attribute.
Your help will be very appreciated. this is my first post on stackoverflow so if I should provide more pieces of code to reproduce I am happy to share it, I hope though that my igraph object is enough for the problem at hand.

Your graph has only 24 nodes, but you are referring to nodes using number higher than that, e.g. 36,53,54. If you use a number, igraph assumes that is the number of the node, so these number don't make sense for this graph. What you mean is the nodes with the names "36","53","54". The names are strings, not numbers. What you need to do is find the node numbers that correspond to these names. I show one way to do that below. Also, your plot statement refers to a number of variables that you did not provide so I commented them out here.
graph_deu = upgrade_graph(graph_deu)
plot(graph_deu)
Group1 = as.numeric(V(graph_deu)[as.character(c(33,1,34,2,36,53,54,56,42,43,55,57,18))])
Group2 = as.numeric(V(graph_deu)[as.character(c(35,48,50,27))])
Group3 = as.numeric(V(graph_deu)[as.character(c(38,45,46,47,49,28,25))])
set.seed(2)
plot(graph_deu,
mark.groups=list(Group1, Group2, Group3),
mark.col=c("lemonchiffon", "slategray1", "thistle1"),
mark.border = NA,
edge.width =E(graph_deu)$weight,
# vertex.size = deu_deg,
# vertex.color = deu,
# vertex.shape = topic_type,
# vertex.label = node_labels,
vertex.label.cex=1.5
)

Related

igraph error in R with vertex.size : longer object length is not a multiple of shorter object length

I am using the package igraph in Rto be able to plot a network. However, once I pass the command vertex.size in the graph function, it does 2 things. 1) it removes a few of the edges and directed arrows from the network and 2) it gives me an error:
In layout[, 2] + label.dist * sin(-label.degree) * (vertex.size + :
longer object length is not a multiple of shorter object length
Here is some reproducible data that shows the errors:
Setting up the data
stack.edges <- data.frame(from = c("XTD-PRI", "XTD-PRI", "EVS-16", "EVS-16", "EVS-16", "J-4", "J-4", "Sigma", "Sigma", "T-1"),
to = c("XTD-PRI", "E-6", "T-5", "XCP-8", "A-1", "P-1", "M-3", "Sigma", "MST-8", "EVS-16"))
stack.vtx <- data.frame(ID = c("XTD-PRI", "XTD-PRI", "EVS-16", "EVS-16", "EVS-16", "J-4", "J-4", "Sigma", "Sigma", "T-1"), Freq = c(1, 2, 2, 2, 1, 2, 2, 2, 2, 1),
color = c("#F0027F", "#F0027F", "#7FC97F", "#7FC97F", "#7FC97F", "#F0027F", "#F0027F", "#FDC086", "#FDC086", "#7FC97F"))
Graphing the network
library(igraph)
stack_graph <- graph_from_data_frame(stack.edges, directed = TRUE)
plot(stack_graph,
layout = layout_in_circle(stack_graph),
edge.width = 1.5,
edge.arrow.size = 0.3,
vertex.shape = "circle",
vertex.color = stack.vtx$color,
vertex.label.color = "black")
#vertex.size = stack.vtx$Freq)
Now, compare the above graph by removing the '#' in front of the vertex.size parameter. To note, passing ex) vertex.size = 10 will work.
My objective: to graph the vertices by the size of the stack.vtx$Freq vector, so 7 of the circles (vertices) should be twice as large as the other 3 circles (vertices).
During my research for this error, I have found the following:
This error occurs when performing a function on vectors when they are not the same length. However, this is not the case here, as both vectors (stack.edges & stack.vtx) are both the same length (ex source: Why do I get "warning longer object length is not a multiple of shorter object length"?).
The command rescale_vertex_igraph by the package netdiffuseR. According to the documentation: "This function rescales a vertex size before passing it to plot.igraph." I tried vertex.size = rescale_vertex_igraph(stack.vtx$Freq, adjust = 200). This does resize the size of the vertices, but not proportional (instead of the 7 vertices being 2x's as large as the other 3 vertices, they look like they are 4x's as large and I still get the same error.
Following the advice on this post: igraph edges disappear when specifying vertex size I have also tried to rescale the stack.vtx$Freq values by 'playing' around with them and passing values such as: vertex.size = stack.vtx$Freq/2); vertex.size = stack.vtx$Freq * 3.14 but none of these options work and remove edges altogether and does not resize it the way I would like.
Any help on resizing my vertices based on the stack.vtx$Freq vector would be greatly appreciated!
If you look at the collection of vertices:
verts <- c(stack.edges$from, stack.edges$to)
unique(verts)
[1] "XTD-PRI" "EVS-16" "J-4" "Sigma" "T-1" "E-6" "T-5" "XCP-8" "A-1" "P-1" "M-3" "MST-8"
There are 12 unique vertices defined. The frequency column in stack.vtx is only 10 elements long. In fact only 5 of the 12 vertices are mentioned in stack.vtx data.frame and with conflicting values for some of the duplicate vetices.
One can use:
vertex_attr(stack_graph)
to obtain the list of vertices in the proper order and use this as a guide to create the vector of vertex.size. Also check to ensure the coloring is correct.
I don't know why "vertex.color" did not generate the same error. Maybe just a quirk or color is handled slightly differently.

How to retain the general shape of a network in igraph?

I currently have a network graph in igraph with which I am running simulations to see how the frequency of traits change over time like so:
g <- erdos.renyi.game(1000, 1/1000)
V(g)$nice <- sample(c(0, 1), vcount(g), replace = TRUE, prob = c(0.1, 0.9)
Following this I have a working code that modifies the the network across several "turns". The problem arises when I graph the network. I initially graph the network at t = 0 and once more at t = 20 or so to compare the two and see how they have changed. However, the location of the nodes have changed from the initial to the final. Is there a way that I can retain the location of the nodes in the actual graph? (i.e. so that node 4 will remain at some coordinate (a, b) despite changes in the network)
You can repeat the same layout by using the layout argument to plot. First, you create a layout using one of the many layout_ arguments, then just call plot specifying the layout. If you plot again with the same layout, the nodes will be in the same place.
LO_FR = layout_with_fr(g)
plot(g, layout=LO_FR, vertex.size=4, vertex.label=NA,
main="layout_with_fr")
LO_N = layout_nicely(g)
plot(g, layout=LO_N, vertex.size=4, vertex.label=NA,
main="layout_nicely")
Type help(package=igraph) and then scroll down to the functions whose names start with layout_. Try several and pick one that you like.

cluster walktrap returns three communities, but when plotting they are all on top of each other, with no visible clustering

I've been following documentation tutorials and even lecture tutorials step by step. But for some reason the output of my plot is like this:
The output doesn't make any sense to me. There clearly is no structure, or communities in this current plot, as you can see that the bigger circles are all overlapping. Shouldn't this, in this case, return only a single community? Additionally the modularity of my network is ~0.02 which would again, suggest there is no community structure. But why does it return 3 communities?
this is my code: (exactly same as in documentation, with different dataset)
m <- data.matrix(df)
g <- graph_from_adjacency_matrix(m, mode = "undirected")
#el <- get.edgelist(g)
wc <- cluster_walktrap(g)
modularity(wc)
membership(wc)
plot(wc,g)
my data set looks is a 500x500 adjacency matrix in the form of a csv, with a 1-500 column and index names corresponding to a person.
I tried understanding the community class and using different types of variables for the plot, e.g. membership(wc)[2] etc. My thought is that the coloring is simply wrong, but nothing Ive tried so far seems to fix the issue.
You can have inter-community connections. You're working with a graph of 500 nodes and they can have multiple connections. There will be a large number of connections between nodes of different communities, but if you conduct a random walk you're most likely to traverse connections between nodes of the same community.
If you separate the communities in the plot (using #G5W's code (igraph) Grouped layout based on attribute) you can see the different groups.
set.seed(4321)
g <- sample_gnp(500, .25)
plot(g, vertex.label = '', vertex.size = 5)
wc <- cluster_walktrap(g)
V(g)$community <- membership(wc)
E(g)$weight = 1
g_grouped = g
for(i in unique(V(g)$community)){
groupV = which(V(g)$community == i)
g_grouped = add_edges(g_grouped, combn(groupV, 2), attr=list(weight = 2))
}
l <- layout_nicely(g_grouped)
plot( wc,g, layout = l, vertex.label = '', vertex.size = 5, edge.width = .1)
Red edges are intercommunity connections and black edges are intracommunity edges

Plot two igraph networks using the same coordinates and same placement in the plot frame

I am trying to plot a network that changes in time. The network starts with a certain number of nodes and edges and each time step some of the nodes and edges are removed.
I want to be able to plot the network so that the nodes are in the same place in each. However when I try this. sometimes the nodes shift position in the plot frame even if the relation to each other is the same.
I am making the network change into a gif so even small changes are annoying. I think the change may occur when a large fraction of the nodes are removed but I am not sure.
The code below illustrates this using an ER graph.
library(igraph); library(dplyr)
#generate random graph
set.seed(500)
RandomGraph <- sample_gnm(1000, 2500)
#name nodes
V(RandomGraph)$name <- paste0("Node", 1:1000)
#Get the coordinates of the Nodes
Coords <- layout_with_fr(RandomGraph) %>%
as_tibble %>%
bind_cols(data_frame(names = names(V(RandomGraph))))
#Delete random vertices
deletevertex <-sample( V(RandomGraph)$name, 400)
RandomGraph2 <-delete.vertices(RandomGraph, deletevertex)
#get the coordinates of the remaining Nodes
NetCoords <- data_frame(names = names(V(RandomGraph2))) %>%
left_join(Coords, by= "names")
#plot both graphs
RandomGraph%>%
plot(.,vertex.size=.8, edge.arrow.size=.4, vertex.label = NA, layout = as.matrix(Coords[,1:2]))
RandomGraph2%>%
plot(.,vertex.size=.8, edge.arrow.size=.4, vertex.label = NA, layout = as.matrix(NetCoords[,2:3]))
#They nodes have the same relationship to each other but are not laid out in the same position in the frame
As you can see the plots have placed nodes in the same place relative to each other but not relative to the frame.
How can I have the plot position fixed.
plot.igraph rescales each axis by default (from -1 to +1 on both x and y).
You just need to turn that off: rescale = F and then explicitly set appropriate xlim and ylim values.
For your example code..
RandomGraph%>%
plot(.,vertex.size=.8, edge.arrow.size=.4, vertex.label = NA, layout = as.matrix(Coords[,1:2]),rescale=F,xlim=c(-25,30),ylim=c(-20,35))
RandomGraph2%>%
plot(.,vertex.size=.8, edge.arrow.size=.4, vertex.label = NA, layout = as.matrix(NetCoords[,2:3]),rescale=F,xlim=c(-25,30),ylim=c(-20,35))
The problem is that
identical(range(Coords[1]), range(NetCoords[2]))
# [1] FALSE
Since igraph normalizes the coordinates on a range between -1 and 1 before plotting, this leads to slightly different coordinates for NetCoords compared to Coords. I'd just calculate the normalized coordinates for all nodes beforehand:
coords_rescaled <- sapply(Coords[-3], function(x) -1+((x-min(x))*2)/diff(range(x)))
rownames(coords_rescaled) <- Coords$names
And then assign the normalized coordinates (or the required subset) and set rescale=FALSE (as #jul) already suggested:
par(mfrow=c(1,2), mar=c(1,.5,1,.5))
RandomGraph%>%
plot(.,edge.arrow.size=.4, layout = coords_rescaled, rescale=F);box()
RandomGraph2%>%
plot(.,edge.arrow.size=.4, layout = coords_rescaled[NetCoords$names, ], rescale=F);box()

Setting subgraph attributes in Rgraphviz

I'm trying to set a fill color in Rgraphviz for a subgraph. In the documentation, it is implied that you can set subgraph attributes where you set whether or not the subgraph is a cluster, like so:
subGList = list()
subGList[[1]] = list(graph=sg.iip, attrs=c(fillcolor="lightgreen", style = "filled",
shape = "rectangle"), cluster = TRUE)
Unfortunately, setting attributes in this manner doesn't seem to have any effect on the plot.
Because my subgraphs contain 20-30 nodes (where the full graph has 250 nodes), it's not really reasonable to code it with the nodewise method where you have to use each node name and set it to the color.
edit My current workaround is to do:
vc <- as.list(rep("lightgreen", length(subgraphNames)))
names(vc) <- subgraphNames
plot(fG.iip.NEL, 'neato', subGList=subGList, nodeAttrs = list(fillcolor=vc))

Resources