This package implements some graph layout algorithms that are not
available in igraph
.
A detailed introductory tutorial for graphlayouts and ggraph can be found here.
The package implements the following algorithms:
# dev version
::install_github("schochastics/graphlayouts")
remotes
#CRAN
install.packages("graphlayouts")
This example is a bit of a special case since it exploits some weird issues in igraph.
library(igraph)
library(ggraph)
library(graphlayouts)
set.seed(666)
<- sample_pa(1000,1,1,directed = F)
pa
ggraph(pa,layout = "nicely")+
geom_edge_link0(width=0.2,colour="grey")+
geom_node_point(col="black",size=0.3)+
theme_graph()
ggraph(pa,layout="stress")+
geom_edge_link0(width=0.2,colour="grey")+
geom_node_point(col="black",size=0.3)+
theme_graph()
Stress majorization also works for networks with several components. It relies on a bin packing algorithm to efficiently put the components in a rectangle, rather than a circle.
set.seed(666)
<- disjoint_union(
g sample_pa(10,directed = F),
sample_pa(20,directed = F),
sample_pa(30,directed = F),
sample_pa(40,directed = F),
sample_pa(50,directed = F),
sample_pa(60,directed = F),
sample_pa(80,directed = F)
)
ggraph(g,layout = "nicely") +
geom_edge_link0() +
geom_node_point() +
theme_graph()
ggraph(g, layout = "stress",bbox = 40) +
geom_edge_link0() +
geom_node_point() +
theme_graph()
Backbone layouts are helpful for drawing hairballs.
set.seed(665)
#create network with a group structure
<- sample_islands(9,40,0.4,15)
g <- simplify(g)
g V(g)$grp <- as.character(rep(1:9,each=40))
ggraph(g,layout = "stress")+
geom_edge_link0(colour=rgb(0,0,0,0.5),width=0.1)+
geom_node_point(aes(col=grp))+
scale_color_brewer(palette = "Set1")+
theme_graph()+
theme(legend.position = "none")
The backbone layout helps to uncover potential group structures based on edge embeddedness and puts more emphasis on this structure in the layout.
<- layout_as_backbone(g,keep=0.4)
bb E(g)$col <- F
E(g)$col[bb$backbone] <- T
ggraph(g,layout="manual",x=bb$xy[,1],y=bb$xy[,2])+
geom_edge_link0(aes(col=col),width=0.1)+
geom_node_point(aes(col=grp))+
scale_color_brewer(palette = "Set1")+
scale_edge_color_manual(values=c(rgb(0,0,0,0.3),rgb(0,0,0,1)))+
theme_graph()+
theme(legend.position = "none")
The function layout_with_focus()
creates a radial layout
around a focal node. All nodes with the same distance from the focal
node are on the same circle.
library(igraphdata)
library(patchwork)
data("karate")
<- ggraph(karate,layout = "focus",focus = 1) +
p1 draw_circle(use = "focus",max.circle = 3)+
geom_edge_link0(edge_color="black",edge_width=0.3)+
geom_node_point(aes(fill=as.factor(Faction)),size=2,shape=21)+
scale_fill_manual(values=c("#8B2323", "#EEAD0E"))+
theme_graph()+
theme(legend.position = "none")+
coord_fixed()+
labs(title= "Focus on Mr. Hi")
<- ggraph(karate,layout = "focus",focus = 34) +
p2 draw_circle(use = "focus",max.circle = 4)+
geom_edge_link0(edge_color="black",edge_width=0.3)+
geom_node_point(aes(fill=as.factor(Faction)),size=2,shape=21)+
scale_fill_manual(values=c("#8B2323", "#EEAD0E"))+
theme_graph()+
theme(legend.position = "none")+
coord_fixed()+
labs(title= "Focus on John A.")
+p2 p1
The function layout_with_centrality
creates a radial
layout around the node with the highest centrality value. The further
outside a node is, the more peripheral it is.
library(igraphdata)
library(patchwork)
data("karate")
<- betweenness(karate)
bc <- ggraph(karate,layout = "centrality", centrality = bc, tseq = seq(0,1,0.15)) +
p1 draw_circle(use = "cent") +
annotate_circle(bc,format="",pos="bottom") +
geom_edge_link0(edge_color="black",edge_width=0.3)+
geom_node_point(aes(fill=as.factor(Faction)),size=2,shape=21)+
scale_fill_manual(values=c("#8B2323", "#EEAD0E"))+
theme_graph()+
theme(legend.position = "none")+
coord_fixed()+
labs(title="betweenness centrality")
<- closeness(karate)
cc <- ggraph(karate,layout = "centrality", centrality = cc, tseq = seq(0,1,0.2)) +
p2 draw_circle(use = "cent") +
annotate_circle(cc,format="scientific",pos="bottom") +
geom_edge_link0(edge_color="black",edge_width=0.3)+
geom_node_point(aes(fill=as.factor(Faction)),size=2,shape=21)+
scale_fill_manual(values=c("#8B2323", "#EEAD0E"))+
theme_graph()+
theme(legend.position = "none")+
coord_fixed()+
labs(title="closeness centrality")
+p2 p1
graphlayouts
implements two algorithms for visualizing
large networks (<100k nodes). layout_with_pmds()
is
similar to layout_with_mds()
but performs the
multidimensional scaling only with a small number of pivot nodes.
Usually, 50-100 are enough to obtain similar results to the full
MDS.
layout_with_sparse_stress()
performs stress majorization
only with a small number of pivots (~50-100). The runtime performance is
inferior to pivotMDS but the quality is far superior.
A comparison of runtimes and layout quality can be found in the wiki
tl;dr: both layout algorithms appear to be faster than
the fastest igraph algorithm layout_with_drl()
.
Below are two examples of layouts generated for large graphs using
layout_with_sparse_stress()
A retweet network with 18k nodes and 61k edges
A co-citation network with 12k nodes and 68k edges
layout_as_dynamic()
allows you to visualize snapshots of
longitudinal network data. Nodes are anchored with a reference layout
and only moved slightly in each wave depending on deleted/added edges.
In this way, it is easy to track down specific nodes throughout time.
Use patchwork
to put the individual plots next to each
other.
library(patchwork)
#gList is a list of longitudinal networks.
<- layout_as_dynamic(gList,alpha = 0.2)
xy <- vector("list",length(gList))
pList
for(i in 1:length(gList)){
<- ggraph(gList[[i]],layout="manual",x=xy[[i]][,1],y=xy[[i]][,2])+
pList[[i]] geom_edge_link0(edge_width=0.6,edge_colour="grey66")+
geom_node_point(shape=21,aes(fill=smoking),size=3)+
geom_node_text(aes(label=1:50),repel = T)+
scale_fill_manual(values=c("forestgreen","grey25","firebrick"),guide=ifelse(i!=2,FALSE,"legend"))+
theme_graph()+
theme(legend.position="bottom")+
labs(title=paste0("Wave ",i))
}Reduce("+",pList)+
plot_annotation(title="Friendship network",theme = theme(title = element_text(family="Arial Narrow",face = "bold",size=16)))
The functions layout_mirror()
and
layout_rotate()
can be used to manipulate an existing
layout