In Rgraphviz, how can I assign nodes and edges to particular layers, and plot only a selected layer or layers?
After perusing and searching the Rgraphviz documentation, I think I've figured out how to assign nodes and edges to particular layers -- but I still can't figure out how to plot only a selected layer.
This "How to use layers" item on the graphviz wiki implies that there should be a "layerselect" graph attribute that can be used to plot only a specified layer. However, the list of allowed graph attributes in Rgraphviz does not include "layerselect." The "layers" graph attribute says "Only those components belonging to the current layer appear," but I can find no information on how to set (or even query) the "current layer."
I tried to do it anyway, but wasn't successful. Here's a reproducible example of my attempt:
require('Rgraphviz')
params <- LETTERS[1:5] #nodes A, B, C, D, E
edgelist <- vector('list', #set up edges
length=length(params))
names(edgelist) <- params
edgelist[['B']] <- c('E','A') #add edges from B to E and from B to A
edgelist[['A']] <- 'C' #add edge from A to C
edgelist[['D']] <- 'E' #add edge from D to E
graph.nel <- new('graphNEL', #construct graphNEL object
nodes=params,
edgeL=edgelist,
edgemode='directed')
#I want there to be two layers:
#"redlayer", containing nodes A, B, C, E and the edges between them;
#"blacklayer", containing node D and the edge from D to E.
#Assign the colors and layers of the edges
eAttr <- list(color=c('B~A'='red',
'A~C'='red',
'B~E'='red',
'D~E'='black'),
layer=c('B~A'='redlayer',
'A~C'='redlayer',
'B~E'='redlayer',
'D~E'='blacklayer')
)
#Assign the colors and layers of the nodes
nAttr <- list(color=c(B='red',
A='red',
C='red',
E='red',
D='black'),
layer=c(B='redlayer',
A='redlayer',
C='redlayer',
E='redlayer',
D='blacklayer'))
#Now plot
plot(graph.nel,
attrs=list(graph=list(layers='redlayer:blacklayer', #Define the two layers
layersep=':', #Explicitly define the layer separation character
layerselect='redlayer')), #Attempt to select only the 'redlayer' for plotting
edgeAttrs=eAttr, #specify edge attributes
nodeAttrs=nAttr #specify node attributes
)
The result of the above code is the following plot:
However, I expected that only the nodes and edges colored red (i.e. those assigned to the layer named 'redlayer') would appear!
I've also tried
plot(graph.nel,
attrs=list(graph=list(layers='redlayer'), #Attempt to select only the 'redlayer' for plotting
edgeAttrs=eAttr, #specify edge attributes
nodeAttrs=nAttr #specify node attributes
)
but it results in exactly the same plot -- that is, both layers are still being plotted.
Is there any way to plot only the layer named 'redlayer' in this example?
Related
I have a very large bipartite network model that I created from 5 million lines of a dataset. I decompose my network model because I can not draw a graph of this size. Now all I need is to plot the decompose graphics one by one. There is no problem with that. But I want to draw the graph with a shape according to the attributes of each node. For example, I want a square for the "A" attributes on my graph G, and a triangle for the "B" attributes. In addition to this I want to add vertex labels by attributes. Here is my codes to plot first component of graph after creating bipartite G and its work:
components <- decompose(G)
plot(components[[1]])
I tried something like this to adding labels and changing vertex shapes according to graph attributes but it didn't work:
plot(components[[1]], vertex.label= V(G)$attributes,
vertex.shape=c("square", "triangle"))
Does anyone can help me, I'm stuck. Thank you so much!
the components function returns a list of vertices which make up a component. So you need to traverse the list, create a subgraph and plot. As for plotting attributes you need to provide a reproducible example for us to help.
library(igraph)
set.seed(8675309)
g <- sample_gnp(200, p = 0.01)
V(g)$name <- paste0("Node", 1:vcount(g))
V(g)$shape <- sample(c("circle","square"), vcount(g), replace = T)
clu <- components(g)
grps <- groups(clu)
lapply(grps, function(x) plot(induced_subgraph(g, x)))
I'm trying to use igraph::cluster_walktrap in R to look for communities inside of a graph, however I noticed a weird behaviour (or at least, a behaviour I am not able to explain).
Suppose you are given an undirected graph by defining a list of its edges. Say
a,b
c,d
e,f
...
Then, if I define another graph by swapping randomly selected vertices in the edge list definition:
a,b
d,c
e,f
...
I expect the two graphs to be isomorphic and the difference between the two graph to be empty. This is exactly what happens in R in my toy example. Following this line of reasoning, calling cluster_walktrap on the two graphs (using set.seed appropriately) should yield the same result since the two graphs are the same. This is not happening and the only explanation I can give is that the starting point of each random walk is not the same for the two graphs. Why is this?
You can follow my reasoning in the toy example below. I don't understand why the last two objects are not identical.
require(igraph)
# Number of vertices
verteces <- 50
# Swap randomly some elements in the edges definition
set.seed(20)
row_swapped <- sample(1:verteces,25,replace=F)
m_values <- sample(letters, verteces*2, replace=T) #1:100
# Build edge lists
m1 <- matrix(m_values, verteces, 2)
m1
a <- m1
colS <- seq(round(ncol(m1)*0.3))
m1[row_swapped, 2:1] <- m1[row_swapped, 1:2]
m1
b <- m1
# Define the two graphs
ag <- igraph::graph_from_edgelist(a, directed = F)
bg <- igraph::graph_from_edgelist(b, directed = F)
# Another way of building an isomorphic graph for testing
#bg <- permute(ag, sample(vcount(ag)))
# Should be empty: ok
difference(ag, bg)
# Should be TRUE: ok
isomorphic(ag,bg)
# I expect it to be TRUE but it isn't...
identical(ag, bg)
# Vertices
V(ag)
ag
V(bg)
bg
# Calculate community
set.seed(100)
ac1 <- cluster_walktrap(ag)
set.seed(100)
bc1 <- cluster_walktrap(bg)
# I expect all to be TRUE, however
# merges is different
# membership is different
# names are different
identical(ac1$merges, bc1$merges)
identical(ac1$modularity, bc1$modularity)
identical(ac1$membership, bc1$membership)
identical(ac1$names, bc1$names)
identical(ac1$vcount, bc1$vcount)
identical(ac1$algorithm, bc1$algorithm)
The results are not different. You have two things going on which is making your graphs not identical but isoporphic. I emphasize identical because it has a very strict definition.
1) identical(ag, bg) is not identical because the vertices and edges are not in the same order between the two graphs. Exactly, the same nodes and edges exist but they are not in the exact same place or orientation. For, example if I shuffle the rows of a and make a new graph...
a1 <- a[sample(1:nrow(a)), ]
a1g <- igraph::graph_from_edgelist(a1, directed = F)
identical(ag, a1g)
#[1] FALSE
2) This goes for edges as well. An edge is stored as node1, node2 and a flag if the edge is directed or not. so when you swap rows the representation at the "byte level" (I use this term loosely) is different even though the relationship is the same. Edge 44 represents the same relationship but is stored based on how it was constructed.
E(ag)[44]
# + 1/50 edge from 6318240 (vertex names):
# [1] q--d
E(bg)[44]
# + 1/50 edge from 38042e0 (vertex names):
# [1] d--q
So onto your cluster_walktrap, first, the function returns the index of the vertices, not the name which can be misleading. Which means the reason the objects aren't identical is because ag and bg have different ordering of nodes in the object.
If I reorder the membership by node name the two become identical.
identical(membership(bc1)[order(names(membership(bc1)))], membership(ac1)[order(names(membership(ac1)))])
#[1] TRUE
# Erdos
par(mfrow=c(1,2))
g <- erdos.renyi.game(100, 1/100)
V(g)$size<-seq(0.05,5,0.05)
betweenness(g)
# Draw nodes and save positions
locs <- layout.fruchterman.reingold(g)
plot(g,
layout=locs,
vertex.label=NA,
main="Original",
vertex.color=degree(g))
g
vertex.color=degree(g)
did not work. Could anyone tell me how to color the vertices by "degree"?
Red (high value) to blue (low value) would be perfect.
Thanks!
A solution I found is to create a new color vector with the grey color R provides us with colors()[]. If you check colors()[] in your terminal, you can see the full list of colors that are readable by the plot.igraph() function.
You first charge your data (graph, etc.) :
edgelist <- read.csv(...)
graph <- make_graph_from_data(edgelist)
Then you create a vector of colors that corresponds to the length of your vertices list :
length(V(g)) # with a length of X vertices :
colors <- c(paste0(rep("grey",X),seq(X,1)))
Finally, you plot it with the attribute vertex.color :
plot(g,vertex.color=colors[degree(graph)])
However, one can only use this little trick for graph with less than 100 values in degree(graph)...
Let g be an igraph object. For example, g <- make_graph(~A-C-B, C-D, E-D-F). And let us set up a vertex attribute called level
V(g)[c("A", "B")]$level <- 1
V(g)[c("C")]$level <- 2
V(g)[c("D")]$level <- 3
V(g)[c("E", "F")]$level <- 4
Are there any tools in igraph to build a layout for g such that it respects level in a meaning that a vertex with less level is always placed to the left and vertices with same level have the same (or close) abscissa.
So, for the given graph I'd like to see a picture like this:
Since a layout in igraph is just a matrix of {x,y} coordinates, you can set the x-coordinates equal to your levels.
g <- make_graph(~A-C-B, C-D, E-D-F)
V(g)$level <- c(1,2,1,3,4,4)
l <- matrix(c(V(g)$level,1,2,3,2,3,1),nrow=length(V(g)$level),ncol=2)
plot(g, layout=l)
I just did the y-axis by hand, but you can construct it as you see fit.
Using Sugiyama layout
Sugiyama layout works by adding layers. There are a lot of options with the layout, but, basically, it tries to create a hierarchical representation of the graph.
l <- layout_with_sugiyama(g, layers = -V(g)$level)$layout
#note the "-", this ensures that the smaller level values get small x coordinates
plot(g,layout=l[,c(2,1)])
Dear Stackoverflow community,
I am currently using R to compile an affiliation network where nodes are companies/umbrella organisations and ties are defined as "member of". At the moment, my list is still small and I can create edges as follow, based on the position of the nodes (I use igraph):
g <- igraph::add_edges(g, c(1,51,
1,52,
1,53,
1,54))
However, I am adding new nodes and the final network will include at least 500 organisations. This means that the position of a node can change everytime I add a new one. Since I cannot redo the edges everytime I add a new node, is there a way I can add edges knowing the names of the nodes?
The names of the nodes are treated as an attribute, I tried to use the same command as above including names - as opposed to positions - but it did not work:
g <- igraph::add_edges(g, c(V(g)$name=="Company1", V(g)$name == "Umbrella2"))
Any suggestion on how I could create edges by specifying the names and not the position?
I believe you're looking for as.numeric(V(g)["Company1"]).
I would strongly advice against building your network structure in an R-script, though. Even for a small network, I would have inputed my data in an excel-file, create an R-script that reads the data as an edge-list and creates an igraph from it. That way, you can add your companies and organisations as you go with greater oversight of what data has actually gone in to your network, which I guess is what you're looking for in the first place. Doing that here would be out of bounds for the question though.
As for the adding-nodes-by-name, I wrote this example for you which I hope is pedagogical.
library(igraph)
# Make an empty Bipartite graph
g <- make_bipartite_graph(0, NULL, directed=TRUE)
g <- delete_vertices(g, 1)
# Create vertices of two different types: companies and umbrellas
g <- add_vertices(g, 5, color = "red", type=TRUE, name=paste("Company", 1:5, sep="_"))
g <- add_vertices(g, 2, color = "blue", type=FALSE, name=paste("Umbrella", 1:2, sep="_"))
# In a bipartate graph edges may only appear BETWEEN verticies of different types. Companies
# can belong to umbrellas, but not to each other.
# Look at the types:
ifelse(V(g)$type, 'Company', 'Umbrella') # true for companies, false for umbrellas
# Lets add some edges one by one. This is what I believe you're asking for in the question:
g <- add_edges(g, c(as.numeric(V(g)["Company_1"]), as.numeric(V(g)["Umbrella_1"])))
g <- add_edges(g, c(as.numeric(V(g)["Company_1"]), as.numeric(V(g)["Umbrella_2"])))
g <- add_edges(g, c(as.numeric(V(g)["Company_2"]), as.numeric(V(g)["Umbrella_1"])))
g <- add_edges(g, c(as.numeric(V(g)["Company_3"]), as.numeric(V(g)["Umbrella_1"])))
g <- add_edges(g, c(as.numeric(V(g)["Company_4"]), as.numeric(V(g)["Umbrella_2"])))
g <- add_edges(g, c(as.numeric(V(g)["Company_5"]), as.numeric(V(g)["Umbrella_2"])))
# Note that "Company_1" belongs to two umbrella organisations, as I assume your companies can:
plot(g)