Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to extract labels shown by ggrepel #254

Open
jttoivon opened this issue Jan 28, 2024 · 3 comments
Open

How to extract labels shown by ggrepel #254

jttoivon opened this issue Jan 28, 2024 · 3 comments
Labels

Comments

@jttoivon
Copy link

Hi,

How can I extract a list of those labels that ggrepel shows in the result figure?
In the below example I create 500 points, and ggrepel shows label for 395 of these points only. However, when I
try to extract the list of these 395 labels, I get all 500 labels. Any idea what I am doing wrong?

library(tidyverse)
library(ggrepel)
library(grid)
dev.size()
create_data <- function(n=10) {
  x <- runif(n)
  y <- runif(n)
  label <- paste0("***",1:n,"***")
  df <- tibble(x=x, y=y, label=label)
  df
}
set.seed(123)
tmp <- create_data(n=500)
g <- tmp %>% ggplot(aes(x, y, label=label)) + geom_text_repel()
g
extract_labels <- function(g, width=9.8, height=7) {
  # Trying to imitate solution to this https://github.com/slowkow/ggrepel/issues/24
  grid.newpage()
  pushViewport(viewport(width = width, height = height))
  gg <- g %>% ggplotGrob() %>% grid.force()
  print(gg)
  xx <- gg %>% getGrob("textrepeltree", grep = TRUE)
  xx
}
res <- extract_labels(g)
n_distinct(res$data$label)   # all 500 are here
length(res$children)         # this is also 500

Here is an image of the output produced by the code:

image

@slowkow
Copy link
Owner

slowkow commented Jan 29, 2024

Sorry, but I don't know how to help.

My understanding is that ggrepel should only be creating a grob for labels that are being plotted, but it should not be creating grobs for unplotted labels. If that's not happening, then maybe the plot is not being rendered appropriately? I don't know.

If anyone eventually finds something that works, I'd appreciate if you share it here so everyone can learn.

@jttoivon
Copy link
Author

jttoivon commented Jan 29, 2024

Thanks for the reply!

I got it working! It seems that the main problem was incorrect units in the viewport() call. I assumed the units would be in inches, but that isn't the case. The second problem was that I was doing the plotting and extracting separately. But now in my fixed example the extracted data should correspond to what is plotted.

library(tidyverse)
library(ggrepel)
library(grid)
#dev.size()
create_data <- function(n=10) {
  x <- runif(n)
  y <- runif(n)
  label <- paste0("***",1:n,"***")
  df <- tibble(x=x, y=y, label=label)
  df
}
set.seed(123)
tmp <- create_data(n=500)
g <- tmp %>% ggplot(aes(x, y, label=label)) + geom_text_repel()
extract_labels <- function(g, width=9.8, height=7) {
  force(g)
  # Trying to imitate solution to this https://github.com/slowkow/ggrepel/issues/24
  grid.newpage()
  #vp <- viewport(width = width, height = height)  # Wrong units!!!
  vp <- viewport(width = unit(width, "in"), height = unit(height, "in"))
  pushViewport(vp)
  gg <- g %>% ggplotGrob() %>% grid.force()
  print(g, vp=vp)  # Make the plot appear
  repeltree <- gg %>% getGrob("textrepeltree", grep = TRUE)
  popViewport()
  repeltree
}
res <- extract_labels(g, 5, 5)
n_distinct(res$data$label)   # all 500 are here
length(res$children)         # now this prints 20!!!!

@slowkow
Copy link
Owner

slowkow commented Jan 30, 2024

This is great! Thank you so much for sharing 🙏

I think this might help others who are trying to use the outputs from ggrepel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants