Search code examples
rggplot2scatter-plotggallyggpairs

Add text to a ggpairs() scatterplot?


dumb but maddening question: How can I add text labels to my scatterplot points in a ggpairs(...) plot? ggpairs(...) is from the GGally library. The normal geom_text(...) function doesn't seem to be an option, as it take x,y arguments and ggpairs creates an NxN matrix of differently-styled plots.

Not showing data, but imagine I have a column called "ID" with id's of each point that's displayed in the scatterplots.

Happy to add data if it helps, but not sure it's necessary. And maybe the answer is simply that it isn't possible to add text labels to ggpairs(...)?

library(ggplot2)
library(GGally)

ggpairs(hwWrld[, c(2,6,4)], method = "pearson")

enter image description here

Note: Adding labels is for my personal reference. So no need to tell me it would look like an absolute mess. It will. I'm just looking to identify my outliers.

Thanks!


Solution

  • It is most certainly possible. Looking at the documentation for ?GGally::ggpairs there are three arguments, upper, lower and diag, which from the details of the documentations are

    Upper and lower are lists that may contain the variables 'continuous', 'combo', 'discrete' and 'na'. Each element of thhe list may be a function or a string

    ... (more description)

    If a function is supplied as an option to upper, lower, or diag, it should implement the function api of function(data, mapping, ...){#make ggplot2 plot}. If a specific function needs its parameters set, wrap(fn, param1 = val1, param2 = val2) the function with its parameters.

    Thus a way to "make a label" would be to overwrite the default value of a plot. For example if we wanted to write "hello world" in the upper triangle we could do something like:

    library(ggplot2)
    library(GGally)
    #' Plot continuous upper function, by adding text to the standard plot
    #' text is placed straight in the middle, over anything already residing there!
    continuous_upper_plot <- function(data, mapping, text, ...){
      p <- ggally_cor(data, mapping, ...)
      if(!is.data.frame(text))
        text <- data.frame(text = text)
      lims <- layer_scales(p)
      p + geom_label(data = text, aes(x = mean(lims$x$range$range), 
                                      y = mean(lims$y$range$range), 
                                      label = text), 
                     inherit.aes = FALSE) 
    }
    ggpairs(iris, upper = list(continuous = wrap(continuous_upper_plot, 
                                                         text = 'hello world')))
    

    with the end result being: enter image description here

    There are 3 things to note here:

    1. I've decided to add the text in the function itself. If your text is part of your existing data, simply using the mapping (aes) argument when calling the function will suffice. And this is likely also better, as you are looking to add text to specific points.
    2. If you have any additional arguments to a function (outside data and mapping) you will need to use wrap to add these to the call.
    3. The function documentation specifically says that arguments should be data, mapping rather than the standard for ggplot2 which is mapping, data. As such for any of the ggplot functions a small wrapper switching their positions will be necessary to overwrite the default arguments for ggpairs.