rtidyverseigraphggraph

ggraph/igraph show uncorrece label and hierarchical structure


ggraph/igraph, the result in below plot isn't correct :

1)The amount of DE is 4.5, but the sub circles are 8.8 and 9 (the correct amount should be "DE cat_a 3.0, DE cat_b 1.5")

  1. there is no sub circle for UK/US

How to fix it ? Thanks!

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

base <- data.frame(from =c('US','US','UK','UK','DE','DE'),
                   to = c('cat_a','cat_b','cat_a','cat_b','cat_a','cat_b'),
                   sales=c(1,3,5,4,3,1.5))

vetic <- base %>% gather(key='type', value ='dim',c(1:2)) %>% 
  group_by(dim) %>% summarise(sales = sum(sales)) 

mdf <- graph_from_data_frame(base,directed = TRUE,vertices = vetic)


ggraph(mdf, layout = 'circlepack', weight=sales) + 
  geom_node_circle(aes(fill = depth)) +
    geom_node_text(size=10,aes(label= paste0(name,'\n',sales)))+
  theme_void()+scale_fill_distiller(palette = "RdPu") 

enter image description here


Solution

  • The problem lies with how you are creating your graph. It seems you want to show the amount of cat_a and cat_b within each country, but you are creating the graph as though cat_a and cat_b are each a single node. If you want a cat_a and a cat_b node inside each country, then you need to specify them as distinct nodes.

    For example, we can do:

    library(ggraph)
    library(igraph)
    library(tidyverse)
    library(viridis)
    
    base <- data.frame(from =c('US','US','UK','UK','DE','DE'),
                       to = c('cat_a','cat_b','cat_a','cat_b','cat_a','cat_b'),
                       sales=c(1,3,5,4,3,1.5))
    
    base_fixed <- base %>% mutate(to = paste(from, to)) 
    

    Which gives the following data frame:

    base_fixed
    #>   from       to sales
    #> 1   US US cat_a   1.0
    #> 2   US US cat_b   3.0
    #> 3   UK UK cat_a   5.0
    #> 4   UK UK cat_b   4.0
    #> 5   DE DE cat_a   3.0
    #> 6   DE DE cat_b   1.5
    

    Similarly, the vertices should have a label and value for each of the resulting 9 nodes (3 country nodes, plus two "cat" nodes within each):

    vertices <- base_fixed %>%
      group_by(from) %>%
      summarize(sales = sum(sales)) %>%
      rbind(base_fixed %>% select(-1) %>% rename(from = to))
    
    vertices
    #> # A tibble: 9 x 2
    #>   from     sales
    #>   <chr>    <dbl>
    #> 1 DE         4.5
    #> 2 UK         9  
    #> 3 US         4  
    #> 4 US cat_a   1  
    #> 5 US cat_b   3  
    #> 6 UK cat_a   5  
    #> 7 UK cat_b   4  
    #> 8 DE cat_a   3  
    #> 9 DE cat_b   1.5
    

    The graph could then be drawn as follows:

    graph_from_data_frame(base_fixed, vertices = vertices) %>%
      ggraph(layout = 'circlepack', weight = sales) + 
      geom_node_circle(aes(fill = depth)) +
      geom_node_text(size = 5, 
                     aes(label = ifelse(depth == 0, '',
                          paste0(substr(name, 4, 20), '\n', sales)))) +
      geom_node_label(size = 6, aes(label = ifelse(depth == 1, NA,
                       substr(name, 1, 2)))) +
      theme_void() +
      scale_fill_distiller(palette = "RdPu", guide = 'none') +
      coord_equal()
    

    enter image description here

    Created on 2023-05-15 with reprex v2.0.2