I am using igraph in R for network analysis. I want to display an edge attribute on each line in the plot. An example is below
df <- data.frame(a = c(0,1,2,3,4),b = c(3,4,5,6,7))
nod <- data.frame(node = c(0:7),wt = c(1:8))
pg <- graph_from_data_frame(d = df, vertices = nod,directed = F)
plot(pg)
I want the value of the "wt" feature to show up between each node on the line, or preferably, in a little gap where the line breaks.
Is it possible to make this happen?
Use the parameter edge.label to assign labels of the edges, I used - probably wrong - nod$wt. Of course, you could assign other labels.
You could use the following code:
# load the package
library(igraph)
# your code
df <- data.frame(a = c(0,1,2,3,4),b = c(3,4,5,6,7))
nod <- data.frame(node = c(0:7),wt = c(1:8))
pg <- graph_from_data_frame(d = df, vertices = nod,directed = F)
# plot function with edge.label added
plot(pg, edge.label = nod$wt)
Please, let me know whether this is what you want.
Related
I have the following network graph:
library(tidyverse)
library(igraph)
set.seed(123)
n=15
data = tibble(d = paste(1:n))
relations = tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
)
graph = graph_from_data_frame(relations, directed=T, vertices = data)
V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")
plot(graph, layout=layout.circle, edge.arrow.size = 0.2)
I learned how to remove all the "edges" in this graph:
g <- graph-E(graph)
plot(g)
Now, I am trying to do this same thing, but using a "loop" instead:
for (i in 1:15)
for (j in 1:15) {
graph <- graph - edge(paste0(i, "|", j))
}
But I think the problem is that the above code is trying to delete "edges" that exist, and this code does not have the ability to "skip" (override) an instance when it is commanded to delete a non-existing edge:
Error in delete_edges(e1, unlist(e2, recursive = FALSE)) :
At iterators.c:1828 : Cannot create iterator, invalid edge id, Invalid vertex id
Is there a way to instruct this "loop" to "skip" every instances where two edges do not have a connection and to continue until the loop is done?
Thank you!
I don't know why you want to run a for loop, but please find below a possible solution using the as_edgelist() function from the igraph library.
Reprex
Your data
library(igraph)
library(dplyr)
set.seed(123)
n=15
data = tibble(d = paste(1:n))
relations = tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
)
graph = graph_from_data_frame(relations, directed=T, vertices = data)
V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")
plot(graph, layout=layout.circle, edge.arrow.size = 0.2)
Suggested code
edgelist <- as_edgelist(graph, names = TRUE)
for (i in 1:15) {
graph <- graph - edge(paste0(edgelist[i,1], "|", edgelist[i,2]))
}
plot(graph)
Created on 2022-02-24 by the reprex package (v2.0.1)
I generated a random network by using 620 nodes and 2102 edges. I want to visualize it by using plot.But, 1. not sure how to make the plot nicer (make nodes more separated at least)? 2.adjust the node size based on 'degree'.
my codes are:
set.seed(42)
Network_random <- erdos.renyi.game(620,2102,type='gnm')
plot(Network_random, vertex.col="degree", main="Network Random",layout=layout_nicely,margin=-0.25)
my current plot is as below:
What about this?
set.seed(42)
Network_random <- erdos.renyi.game(620, 2102, type = "gnm") %>%
set_vertex_attr(name = "size", value = pmax(degree(.), 5)) %>%
plot(vertex.label = NA, vertex.color = degree(.), main = "Network Random", margin = -0.25)
I am trying to produce a Sankey diagram with the help of this page:
https://www.r-graph-gallery.com/321-introduction-to-interactive-sankey-diagram-2.html
Now, I modified the data a bit, and was wondering if I can right and left-sink the nodes, i.e. that the top-nodes are always to the left (aligned) and the last nodes always to the right. It appears that networkd3 only has the sinkright option.
Using the following code:
library(networkD3)
library(dplyr)
# A connection data frame is a list of flows with intensity for each flow
links <- data.frame(
source=c("group_A", "group_B", "group_C", "group_C"),
target=c("group_D", "group_C", "group_F", "group_G"),
value=c(3, 4, 3, 1)
)
# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(
name=c(as.character(links$source),
as.character(links$target)) %>% unique()
)
# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
# Make the Network
p <- sankeyNetwork(Links = links, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name",
fontSize=20)
p
Gives me this output:
Sankey Plot
It looks already promising, but I would like to move group_A to the left side (while keeping the right side aligned). Is this possible?
It appears this seems to be not possible with networkD3 out of the box. However, I found out that plotly offers a x position option, which worked in the end:
fig <- plot_ly(
type = "sankey",
arrangement = "snap",
node = list(
label = nodes$name,
x = c(0.1, 0.1, 0.5, 0.7, 0.7, 0.7),
pad = 10), # 10 Pixel
link = list(
source = links$IDsource,
target = links$IDtarget,
value = links$value))
fig <- fig %>% layout(title = "Sankey with manually positioned node")
fig
# example data
library(igraph)
links <- cbind.data.frame(from = rep("A", 6),
to = LETTERS[1:6],
weight = rep((1:3), each =2))
nodes <- nodes <- cbind.data.frame(id = LETTERS[1:6],
feature = rep((1:3), each =2))
net <- graph_from_data_frame(d = links, vertices = nodes, directed = T)
V(net)$color <- V(net)$feature
plot(net, vertex.size=30, edge.arrow.size = 0)
This is what I get:
What I want is to cluster the same colored nodes together, something similar as shown in the figure below. How can I do it?
Maybe the option mark.groups in plot could help
plot(net,mark.groups = split(V(net)$name,V(net)$color))
which gives
I created the following two graphs using igraph:
t1terms <- c("fire",
"people",
"residents",
"victims",
"affected",
"please",
"can",
"london",
"support",
"survivors")
t1labels <- as.vector(t1terms)
g<-graph.full(n=10, directed = FALSE, loops = FALSE) %>%
set_vertex_attr("label", value = t1labels)
t2terms <- c("fire",
"victims",
"says",
"people",
"cladding",
"police",
"may",
"will",
"dead",
"theresa")
t2labels <- as.vector(t2terms)
g1<-graph.full(n=10, directed = FALSE, loops = FALSE) %>%
set_vertex_attr("label", value = t2labels)
I can't figure out how to merge the two graphs without duplicating common nodes. I really appreciate some help. I tried 'graph.union', but it didn't work.
Thank you,
Chamil
Use igraph's built-in conventions and make the vertex labels into each's name:
V(g)$name <- V(g)$label
V(g1)$name <- V(g1)$label
Grab the attributes and edge list of each graph and rbind() them together, creating a combination attribute data.frame and combination edge list data.frame while ensuring that you're only keeping unique() vertices:
attrs <- rbind(as_data_frame(g, "vertices"), as_data_frame(g1, "vertices")) %>% unique()
el <- rbind(as_data_frame(g), as_data_frame(g1))
Use attrs and el to make your new graph:
new_g <- graph_from_data_frame(el, directed = FALSE, vertices = attrs)
You can get the union by turning each graph into an edgelist, joining the edgelists and the making that into a graph.
EL = matrix(get.vertex.attribute(g, "label")[get.edgelist(g)], ncol=2)
EL1 = matrix(get.vertex.attribute(g1, "label")[get.edgelist(g1)], ncol=2)
ELU = rbind(EL, EL1)
ELU = ELU[!duplicated(ELU),]
GU = graph_from_edgelist(ELU, directed=FALSE)
## To check the result
par(mfrow=c(1,3))
plot(g)
plot(g1)
plot(GU)