Search code examples
rggplot2ggpubr

How to add a border around a chart created via ggarrange and increase space between combined charts


I am trying to draw Numa Nodes CPU and memory usage.

my chart

There are 4 numa nodes in my example with CPU and memory usage charts in each.

The problem is - in every Node there could be many CPU values (1 bar for each core, 20 cores in my example) and only one memory value, so I had to use different width of charts (CPU charts are wider than memory's). Because of that annotation text (NUMA XX) does not look like it was the middle of chart now. I can't really say which Node's memory bar is that.

I think I need to split numa nodes from each other using border or background color so CPU and memory of each Numa node were together. Also I think I need to decrease space between CPU and memory inside numa node and increase space between numa nodes. How to do that?

My code:

library(dplyr)

library(ggplot2)

library(ggpubr)

library(tidyr)

memory_df <- structure(list(NumaNode = c("00", "00", "01", "01", "02", "02", "03", "03"),
                         CounterName = c("TotalMemory", "UsedMemory", "TotalMemory", 
                                      "UsedMemory", "TotalMemory", "UsedMemory", "TotalMemory", "UsedMemory"),
                    Value = c(48, 45.55, 48, 46.38, 48, 46.54, 48, 47.39)),
                    row.names = c(NA, -8L),
                    class = c("tbl_df", "tbl", "data.frame"))

memory_y_scale <-  memory_df %>% filter(CounterName=='TotalMemory') %>% select (Value) %>% max() + 6

cpu_df <- structure(list(NumaNode = c("00", "00", "00", "00", "00", "00", 
                                      "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", 
                                      "00", "00", "00", "01", "01", "01", "01", "01", "01", "01", "01", 
                                      "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", 
                                      "01"), Counter = c("00", "01", "10", "11", "12", "13", "14", 
                                                         "15", "16", "17", "18", "19", "02", "03", "04", "05", "06", "07", 
                                                         "08", "09", "00", "01", "10", "11", "12", "13", "14", "15", "16", 
                                                         "17", "18", "19", "02", "03", "04", "05", "06", "07", "08", "09"
                                      ), Value = c(10.79, 5.85, 9.55, 9.71, 9.77, 4.73, 4.62, 10.92, 
                                                   3.55, 10.3, 1.38, 6.28, 5.42, 4.45, 10.09, 3.42, 10.14, 4.34, 
                                                   9.48, 4.17, 5.2, 3.85, 10.17, 8.49, 10.36, 8.06, 10.01, 8.42, 
                                                   9.12, 7.6, 1.98, 2.41, 4.72, 3.19, 4.74, 3.66, 4.28, 9.83, 5.78, 
                                                   10.18)), row.names = c(NA, -40L), class = c("tbl_df", "tbl", 
                                                                                               "data.frame"))



# plot function =======================================================================

plot_numa = function(num){
  
  # memory plot =====================
  
  memory_filtered_df = memory_df %>% filter(str_detect(NumaNode, num))
  
  memory_plot  <-  memory_filtered_df %>%
    filter(str_detect(CounterName, "Memory")) %>%
    pivot_wider(names_from = CounterName, values_from = Value) %>%
    ggplot(aes(x = "") ) +
    geom_col(aes(y = TotalMemory), fill = "white", color = "black") +
    geom_col(aes(y = UsedMemory), fill = "#00FF66FF", color = "black") +
    geom_text(aes(label = paste(TotalMemory, "GB"), y = TotalMemory + 5 ), color = "black") +
    geom_text(aes(
      label = paste(UsedMemory, "GB"),
      y = ifelse((TotalMemory-UsedMemory > 10), UsedMemory + 5, UsedMemory - 4)),
      color = "black") +
    theme_bw() +
    ylim(0, memory_y_scale) +
    labs(x = "Memory", y = "")
  
  # cpu plot =====================
  
  cpu_filtered_df <-  cpu_df %>% filter(str_detect(NumaNode, num))
  
  if (nrow (cpu_filtered_df) == 0 )    {
    cpu_filtered_df <- cpu_df %>% filter(str_detect(NumaNode, "00"))
  }
  
  cpu_plot <-  cpu_filtered_df %>%
    ggplot(aes(x = Counter)) +
    geom_col(aes(y = 100), fill = "white", color = "white", alpha = 0) +
    geom_col(aes(y = Value), fill = "#00AFBB", color = "black") +
    theme_bw() +
    labs(x = "CPU, % Processor Time", y = "") 
  
  
  ggpubr::ggarrange(cpu_plot, memory_plot, ncol = 2, widths = c(4,1)) %>% 
    ggpubr::annotate_figure(top = paste("        NUMA",num))
  
}

numa_numbers <- unique(memory_df$NumaNode)

ggpubr::ggarrange(plotlist = map(.x = numa_numbers, .f = ~plot_numa(num = .x)))

Here is example of borders I want. I am unhappy with it because 4 tiles too close to each other and borders are overlayed.

example of result


Solution

  • Please find below some code, for the spacing part, using plot.margin inside theme(). I also changed a bit line 76, widths: ggpubr::ggarrange(cpu_plot, memory_plot, ncol = 2, widths = c(2,1)) %>% .

    library(ggpubr)
    library(tidyverse)
    
    memory_df <- structure(list(NumaNode = c("00", "00", "01", "01", "02", "02", "03", "03"),
                                CounterName = c("TotalMemory", "UsedMemory", "TotalMemory", 
                                                "UsedMemory", "TotalMemory", "UsedMemory", "TotalMemory", "UsedMemory"),
                                Value = c(48, 45.55, 48, 46.38, 48, 46.54, 48, 47.39)),
                           row.names = c(NA, -8L),
                           class = c("tbl_df", "tbl", "data.frame"))
    
    memory_y_scale <-  memory_df %>% filter(CounterName=='TotalMemory') %>% select (Value) %>% max() + 6
    
    cpu_df <- structure(list(NumaNode = c("00", "00", "00", "00", "00", "00", 
                                          "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", 
                                          "00", "00", "00", "01", "01", "01", "01", "01", "01", "01", "01", 
                                          "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", "01", 
                                          "01"), Counter = c("00", "01", "10", "11", "12", "13", "14", 
                                                             "15", "16", "17", "18", "19", "02", "03", "04", "05", "06", "07", 
                                                             "08", "09", "00", "01", "10", "11", "12", "13", "14", "15", "16", 
                                                             "17", "18", "19", "02", "03", "04", "05", "06", "07", "08", "09"
                                          ), Value = c(10.79, 5.85, 9.55, 9.71, 9.77, 4.73, 4.62, 10.92, 
                                                       3.55, 10.3, 1.38, 6.28, 5.42, 4.45, 10.09, 3.42, 10.14, 4.34, 
                                                       9.48, 4.17, 5.2, 3.85, 10.17, 8.49, 10.36, 8.06, 10.01, 8.42, 
                                                       9.12, 7.6, 1.98, 2.41, 4.72, 3.19, 4.74, 3.66, 4.28, 9.83, 5.78, 
                                                       10.18)), row.names = c(NA, -40L), class = c("tbl_df", "tbl", 
                                                                                                   "data.frame"))
    
    
    
    # plot function =======================================================================
    
    plot_numa = function(num){
      
      # memory plot =====================
      
      memory_filtered_df = memory_df %>% filter(str_detect(NumaNode, num))
      
      memory_plot  <-  memory_filtered_df %>%
        filter(str_detect(CounterName, "Memory")) %>%
        pivot_wider(names_from = CounterName, values_from = Value) %>%
        ggplot(aes(x = "") ) +
        geom_col(aes(y = TotalMemory), fill = "white", color = "black") +
        geom_col(aes(y = UsedMemory), fill = "#00FF66FF", color = "black") +
        geom_text(aes(label = paste(TotalMemory, "GB"), y = TotalMemory + 5 ), color = "black") +
        geom_text(aes(
          label = paste(UsedMemory, "GB"),
          y = ifelse((TotalMemory-UsedMemory > 10), UsedMemory + 5, UsedMemory - 4)),
          color = "black") +
        theme_bw() +
        ylim(0, memory_y_scale) +
        labs(x = "Memory", y = "") +
        theme(plot.margin = unit(c(0.01,2,2,0.01), "cm"))
      
      # cpu plot =====================
      
      cpu_filtered_df <-  cpu_df %>% filter(str_detect(NumaNode, num))
      
      if (nrow (cpu_filtered_df) == 0 )    {
        cpu_filtered_df <- cpu_df %>% filter(str_detect(NumaNode, "00"))
      }
      
      cpu_plot <-  cpu_filtered_df %>%
        ggplot(aes(x = Counter)) +
        geom_col(aes(y = 100), fill = "white", color = "white", alpha = 0) +
        geom_col(aes(y = Value), fill = "#00AFBB", color = "black") +
        theme_bw() +
        labs(x = "CPU, % Processor Time", y = "") +
        theme(plot.margin = unit(c(0.01,0.01,2,0), "cm"))
      
      
      ggpubr::ggarrange(cpu_plot, memory_plot, ncol = 2, widths = c(2,1)) %>% 
        ggpubr::annotate_figure(top = paste("        NUMA",num))
      
    }
    
    numa_numbers <- unique(memory_df$NumaNode)
    
    ggpubr::ggarrange(plotlist = map(.x = numa_numbers, .f = ~plot_numa(num = .x)))
    

    And the output: enter image description here