ggraph icon indicating copy to clipboard operation
ggraph copied to clipboard

Remove isolated nodes from dynamic layout in ggraph plot

Open lianntucker opened this issue 3 years ago • 1 comments

I want to plot friendships that persist over multiple waves, and keep the nodes in the same coordinates for each plot. I'm able to use ggraph and graphlayouts' dynamic layout to keep the nodes in the same positions over four waves, but I want to remove the nodes over time that lose their ties. This is an example of what I have done so far:

library(dplyr)
library(magrittr)
library(ggplot2)
library(igraph)
library(tidygraph)
library(ggraph)
library(viridis)
library(gridExtra)

set.seed(1234)

gtest <- erdos.renyi.game(100, 0.03, type = "gnp", directed = TRUE,
                 loops = FALSE) %>%
         set_vertex_attr("label", value = 1:100)

g_nodes <- get.data.frame(gtest, what = "vertices") %>%
           mutate(sex = sample(0:1, n(), replace = TRUE),
                  sex = as.character(sex))

g_edges1 <- get.edgelist(gtest) %>% as.data.frame()
g_edges2 <- sample_n(g_edges1, 130, replace = FALSE)
g_edges3 <- sample_n(g_edges2, 70, replace = FALSE)
g_edges4 <- sample_n(g_edges3, 20, replace = FALSE)


g1 <- graph_from_data_frame(d=g_edges1, vertices = g_nodes, directed = TRUE)
g2 <- graph_from_data_frame(d=g_edges2, vertices = g_nodes, directed = TRUE)
g3 <- graph_from_data_frame(d=g_edges3, vertices = g_nodes, directed = TRUE)
g4 <- graph_from_data_frame(d=g_edges4, vertices = g_nodes, directed = TRUE)

gList <- list(g1, g2, g3, g4)

xy <- graphlayouts::layout_as_dynamic(gList,alpha = 0.2)
pList <- vector("list",length(gList))

for(i in 1:length(gList)){
  pList[[i]] <- ggraph(gList[[i]],layout="manual",x=xy[[i]][,1],y=xy[[i]][,2])+
    geom_edge_link(color = "black", alpha = 0.7,
                   arrow = arrow(type = "closed",
                                 angle = 25,
                                 length = unit(1.5, 'mm')), 
                   end_cap = circle(1, 'mm'), 
                   width = 0.5, show.legend = FALSE) +   
    geom_node_point(aes(color = factor(sex)), size = 3) +
    scale_color_hue(l=40) +
    theme_graph()+
    theme(legend.position = "none")
}
Reduce("+",pList)+
  plot_annotation(title="Friendship network",theme = theme(title = element_text(family="Arial Narrow",face = "bold",size=16)))

Which gives me this plot:

net

This is what I want, except for plots 2-4 I want to delete the nodes with no edges. I've tried also deleting the isolates from the individual graph functions such as:

g1 <- graph_from_data_frame(d=g_edges1, vertices = g_nodes, directed = TRUE) 

g2 <- graph_from_data_frame(d=g_edges2, vertices = g_nodes, directed = TRUE) %>%
      delete.vertices(., which(degree(.)==0))

g3 <- graph_from_data_frame(d=g_edges3, vertices = g_nodes, directed = TRUE) %>%
      delete.vertices(., which(degree(.)==0))

g4 <- graph_from_data_frame(d=g_edges4, vertices = g_nodes, directed = TRUE) %>%
      delete.vertices(., which(degree(.)==0))

But then I get this error when I try to run the plot:

Error in data.frame(..., check.names = FALSE) : 
  arguments imply differing number of rows: 100, 98

Any ideas on how I can remove the isolates within the plot itself?

lianntucker avatar Mar 29 '21 16:03 lianntucker

change the code within the for loop to

rem_nodes <- which(degree(gList[[i]])==0)
ggraph(delete.vertices(gList[[i]],rem_nodes),
layout="manual",x=xy[[i]][-rem_nodes,1],y=xy[[i]][-rem_nodes,2])+
  geom_edge_link(color = "black", alpha = 0.7,
                 arrow = arrow(type = "closed",
                               angle = 25,
                               length = unit(1.5, 'mm')), 
                 end_cap = circle(1, 'mm'), 
                 width = 0.5, show.legend = FALSE) +   
  geom_node_point(aes(color = factor(sex)), size = 3) +
  scale_color_hue(l=40) +
  theme_graph()+
  theme(legend.position = "none")

schochastics avatar May 03 '22 19:05 schochastics

Alternatively use filter = !node_is_isolated() inside the aes() function for geom_node_point()

thomasp85 avatar Jan 08 '24 14:01 thomasp85