rggplot2ggallyggpairs

ggpairs(): customising select facets different from the rest (e.g. unique themes)


I want to have more control over the customisation of individual facets of the ggpairs() plot below.

  1. The upper right factes that show the correlation coefficients:

1.1) These facets should have a white background and not share the panel grid lines

1.2) The text "Corr:" should be black and not grey

1.3) The text lines should be centred on their left or in the middle, but they appear shifted

  1. The lower scatter plots and diagonal density plots:

2.1) They should have normal lines as their x and y axis (left and lower border of each facet) but no lines on the top and right borders

This is the code I have produced thus far:

ggpairs(
  data = mydata,
  mapping = aes(color = de.novo, fill = de.novo), 
  columns = c("rmsd", "pLDDT (AF2)", "ipTM (AF2)", "iPAE (AF2)"),
  
  upper = list(
    continuous = wrap("cor", size = 5),
    {panel.grid.major = element_blank()} 
  ),
  
  lower = list(
    continuous = wrap("points", size = 0.2, alpha = 0.25) 
  ),
  
  diag = list(
    continuous = wrap("densityDiag", alpha = 0.5) 
  )
)+
  
  scale_fill_manual(values = c("#3E049CFF", "#C03A83FF", "#FCD225FF")) + 
  scale_color_manual(values = c("#3E049CFF", "#C03A83FF", "#FCD225FF")) +
  
  theme_bw() +
  theme(
    panel.grid.minor.x = element_blank(),
    panel.border       = element_blank(),
    
    axis.title.y = element_text(size = 29.5, vjust = 2.5),
    axis.title.x = element_text(size = 29.5, vjust = -0.1),
    
    axis.text.y.left = element_text(color = "black", size = 23),
    axis.text.x.bottom= element_text(color = "black", size = 23),
    
    axis.ticks.y.left = element_line(linewidth=1.6, color = "black", unit(4, "pt")), 
    axis.ticks.length.y.left = unit(0.18, "cm"),
    
    axis.ticks.x.bottom = element_line(linewidth=1.6, color = "black", unit(4, "pt")),
    axis.ticks.length.x.bottom = unit(0.18, "cm"),
    
    strip.text.x = element_text(
      size = 23, color = "black"),
    
    strip.text.y = element_text(
      size = 23, color = "black"),
    
    strip.background = element_rect(
      color="black", fill="white", size=1.5, linetype="solid"),
    
    plot.margin = margin(22,16,7,10, "points")
  )

print(ggplot)

producing this plot (please ignore truncated and crashing axis text):

Produced plot

I have found the following questions going in a similar direction for my problem 1.1), but I was unable adapting them to this case:

Change colors in ggpairs now that params is deprecated

ggpairs() correlation values without gridlines

GGally::ggpairs plot without gridlines when plotting correlation coefficient

R GGally::ggpairs, corrlation matrix plot, how to custom diag

These are questions similar to my problem 1.3), but the align_percent() and hjust solutions did not work:

Adjust group text aesthetics in ggpairs()

GGpairs, correlation values are not aligned

For Problem 2), I have tried specifying unique theme components in upper(), lower() and diag(). For instance:

upper( ... 
theme(panel.grid.minor.x = element_blank()...)

This would be the easiest solution, but it did not work.


Solution

  • Fixing 1.2 and 1.3 can be easily achieved by setting justify_labels = "none" for ggally_cor and by setting the text color via title_args=.

    However, fixing the other issues requires some more work. First, GGally provides an experimental add_to_ggmatrix function which in principle can be used to modify and customize the panels and which offers a location= argument to target specific panels. Unfortunately this does not seem to work with theme modifications (but perhaps I miss something). Additionally, after some experimenting it looks as if ggmatrix or ggpairs does not allow for interior axes (lines).

    Instead one option to achieve your desired result would be to fake the axes lines using a geom_h/vline and add_to_ggmatrix.

    Finally, as the same approach does not seem to work for theme modifications I manipulate the ggpairs object directly to get rid of the grid lines for the upper panels.

    Using a minimal reprex based on iris:

    library(ggplot2)
    library(GGally)
    #> Registered S3 method overwritten by 'GGally':
    #>   method from   
    #>   +.gg   ggplot2
    
    mydata <- iris
    
    names(mydata) <- c("rmsd", "pLDDT (AF2)", "ipTM (AF2)", "iPAE (AF2)", "de.novo")
    
    p <- ggpairs(
      data = mydata,
      mapping = aes(color = de.novo, fill = de.novo),
      columns = c("rmsd", "pLDDT (AF2)", "ipTM (AF2)", "iPAE (AF2)"),
      upper = list(
        continuous = wrap(
          "cor",
          justify_labels = "none",
          title_args = list(color = "black", size = 8 / .pt),
          group_args = list(size =  8 / .pt)
        )
      ),
      lower = list(
        continuous = wrap("points", size = 0.2, alpha = 0.25)
      ),
      diag = list(
        continuous = wrap("densityDiag", alpha = 0.5)
      )
    ) +
      scale_fill_manual(
        values = c("#3E049CFF", "#C03A83FF", "#FCD225FF"),
        aesthetics = c("color", "fill")
      ) +
      # Global theme modifications. Do not add theme_bw()!!
      theme(
        strip.text.x = element_text(
          size = 8, color = "black"
        ),
        strip.text.y = element_text(
          size = 8, color = "black"
        ),
        strip.background = element_rect(
          color = "black", fill = "white", linetype = "solid"
        )
      )
    
    # Fake axis lines using geom_h/vline
    locations <- c("lower", "diag")
    p <- Reduce(
      \(x, y) {
        add_to_ggmatrix(x,
          geom_hline(yintercept = -Inf, lwd = 1),
          location = y
        ) |>
          add_to_ggmatrix(geom_vline(xintercept = -Inf, lwd = 1),
            location = y
          )
      },
      locations,
      init = p
    )
    
    # Remove grid lines
    m <- matrix(seq(16), 4, 4, byrow = TRUE)
    p$plots <- Map(
      \(x, i) {
        # Set theme for all panels
        t <- theme_bw() +
          theme(
            panel.border = element_blank()
          )
    
        # Remove grid lines for upper panels
        if (i %in% m[upper.tri(m)]) {
          t <- t +
            theme(
              panel.grid = element_blank()
            )
        }
    
        x + t
      },
      p$plots,
      seq_along(p$plots)
    )
    
    p