Feature discussion: Layers aware of each other in ggplot2?

A new feature?

Is it a good idea to add a new feature to ggplot2, so that each layer can be aware of the previous layers?

Can you imagine any interesting use cases if such a feature were implemented? What kind of figure would require this feature?

It seems that some users are interested in this feature, so I thought it might be nice to see if anyone is interested to discuss and share ideas on this forum.

Example

Notice in the example below:

  • The two geom_text_repel() layers are not aware of each other.
  • In other words, the red A and blue A are overplotted on top of each other. Same for B, G, I, and J.
library(ggrepel)
#> Loading required package: ggplot2
library(patchwork)

dat <- data.frame(x= 1:10, y= 1:10, text= LETTERS[1:10])

p1 <- ggplot(data= dat, aes(x= x, y= y, label= text)) +
  geom_point() +
  geom_text_repel(colour = 'blue', seed = 1) +
  labs(title = "one layer")

p2 <- p1 + geom_text_repel(colour = 'red', seed = 2) +
  labs(title = "two layers")

p1 + p2

Created on 2021-06-22 by the reprex package (v0.3.0)

Questions

I'd be interested to hear your thoughts on these questions:

  1. Is it technically feasible to make layers aware of each other? What are your ideas for implementation?
  2. Suppose it is technically feasible. What applications can you imagine, beyond repelling text labels? Is there some compelling use-case that is only possible if layers are aware of each other?

Ideas

Could you criticize these ideas? Do you have a better idea?

Idea 1

Each layer of a ggplot2 call writes some information to a temporary text file.

For example, when we call geom_text_repel(), a side effect is writing to a temporary text file two columns that contain the positions of the repelled text labels.

Then, when geom_text_repel() is called a second time, it will look to see if the temporary file exists. If so, then those coordinates are automatically added as new data points from which the second layer of text labels will be repelled. Finally, the second layer of text label coordinates are appended to the same temporary text file.

If we call geom_text_repel() a third time, then it reads the coordinates of the text labels from the first two layers, and repels text labels from all of those. And so on.

Idea 2

Each layer of a ggplot2 call adds new columns to the dataframe underlying the ggplot2 figure.

We might imagine adding columns called "_ggrepel_1_x" and "_ggrepel_1_y" for the first call, and then "_ggrepel_2_x" "_ggrepel_2_y" for the second call, etc.

Inside the geom_text_repel() code, we would look for columns that match these names and automatically add them to the list of data points that should repel text labels.

Related:

I guess this is already possible with using ggplot_add.
Following is an example that warns when multiple ggrepel layers are found.
In this case, I wrapped ggrepel::geom_text_repel by geom_text_repel2 so to add a class that dispatches ggplot_add method, and to add an item that makes easy to distinguish which layer is related to ggrepel.

library(ggrepel)
#> Loading required package: ggplot2
library(patchwork)

# Wrapper of ggrepel::geom_text_repel
geom_text_repel2 <- function(...) {
    layer <- ggrepel::geom_text_repel(...)
    layer$ggrepel <- TRUE
    class(layer) <- c("ggrepel", class(layer))
    return(layer)
}

ggplot_add.ggrepel <- function(object, plot, object_name) {
    if (any(do.call(c, lapply(plot$layer, function(x) x$ggrepel)))) {
        warning(
            "There is more than one ggrepel layers. ",
            "This may cause overlap of labels"
        )
    }
   # Optionally, one may modify `object` here.
    NextMethod("ggplot_add")
}

dat <- data.frame(x= 1:10, y= 1:10, text= LETTERS[1:10])

p1 <- ggplot(data= dat, aes(x= x, y= y, label= text)) +
    geom_point() +
    geom_text_repel2(colour = 'blue', seed = 1) +
    labs(title = "one layer")

p2 <- p1 + geom_text_repel2(colour = 'red', seed = 2) +
    labs(title = "two layers")
#> Warning in ggplot_add.ggrepel(object, p, objectname): There is more than one
#> ggrepel layers. This may cause overlap of labels.

p1 + p2

Created on 2021-06-22 by the reprex package (v2.0.0)

1 Like

@atusy This is fantastic! Thank you so much for sharing a complete example with code!

I didn't know about ggplot_add, and your example is very clear.

This topic was automatically closed after 45 days. New replies are no longer allowed.


If you have a query related to it or one of the replies, start a new topic and refer back with a link.