rggplot2directed-acyclic-graphsggraph

Is there a way to plot directed entry/exit points to a network node using R package ggraph (or similar)?


Use case: I'm trying to plot an archaeological "Harris Matrix" in R using the excellent ggraph package. A Harris Matrix is a directed graph of relationships modeling the chronological relationship between stratigraphic contexts.

I can get pretty close using igraph's Sugiyama layout, and geom_edge_elbow for right-angled edges (see reprex below for code):-

Output using ggraph of matrix relations

BUT: in an orthodox-styled Harris Matrix, edges for the entry and exit of a node lie above or below the node (not behind/or on top of it), depending on whether they are incoming (before) or outgoing (after), in order to separate more clearly the chronological flow being represented. The result should look a bit like this:-

more canonical Harris Matrix

Can this be done using ggraph? I can't find any options within either geom_edge_elbow or geom_node_label to do so. If not, are there other ways in R to plot such diagrams, ideally with static export and interactive (e.g. Shiny) options?

(NB: Question cross-posted to a ggraph issue on github).


library(tidyverse)
library(igraph)
library(ggraph)

context_entities = data.frame(
  name=c("100","101","102","103","104","105")
)
matrix_relationships <- data.frame(
  to=   c("100","101","102","101","103","103"),
  from= c("101","102","103","103","104","105"),
  rel=  c("before","before","before","before","before","before")
)
#create graph and depth map
harris_matrix_graph <- igraph::graph_from_data_frame(matrix_relationships, directed = T,
                                                    vertices=context_entities)
# igraph origin of layout
harris_matrix_graph_layout <- harris_matrix_graph |>
  igraph::layout_with_sugiyama()

harris_matrix_graph %>% ggraph::ggraph(layout="sugiyama") +
  ggraph::geom_edge_elbow() +
  ggraph::geom_node_label(aes(label=name))

Solution

  • Each "annotate" draws a "Z" shaped elbow. Or best said, a ┏┚ shape.

    library(igraph)
    library(ggraph)
    library(ggplot2)
    
    context_entities = data.frame(
      name=c("100","101","102","103","104","105")
    )
    matrix_relationships <- data.frame(
      to=   c("100","101","102","101","103","103"),
      from= c("101","102","103","103","104","105"),
      rel=  c("before","before","before","before","before","before")
    )
    #create graph and depth map
    harris_matrix_graph <- igraph::graph_from_data_frame(matrix_relationships, directed = T,
                                                         vertices=context_entities)
    # igraph origin of layout
    harris_matrix_graph_layout <- harris_matrix_graph |> layout_with_sugiyama()
    
    edges <- as_edgelist(harris_matrix_graph, names = F)
    layout <- harris_matrix_graph_layout$layout
    
    p <- ggraph::ggraph(harris_matrix_graph, layout="sugiyama") 
    for (i in seq_len(NROW(edges))) {
      p <- p + annotate("segment", x    = layout[edges[i,1], 1], y    = layout[edges[i,1], 2], 
                                   xend = layout[edges[i,1], 1], yend = (layout[edges[i,1], 2] + layout[edges[i,2], 2])/2)
      p <- p + annotate("segment", x    = layout[edges[i,1], 1], y    = (layout[edges[i,1], 2] + layout[edges[i,2], 2])/2, 
                                   xend = layout[edges[i,2], 1], yend = (layout[edges[i,1], 2] + layout[edges[i,2], 2])/2)
      p <- p + annotate("segment", x    = layout[edges[i,2], 1], y    = (layout[edges[i,1], 2] + layout[edges[i,2], 2])/2, 
                                   xend = layout[edges[i,2], 1], yend = layout[edges[i,2], 2])
    }
    p <- p +  ggraph::geom_node_label(aes(label=name)) 
    p
    

    Created on 2024-10-07 with reprex v2.1.1