Dan Chaltiel
Dan Chaltiel

Reputation: 8523

subsetting a ggplot2 by color after its creation

I have a collection of ggplots that I want to explore. The creation of these ggplots is complicated, and it would be hard for me to change the way they are made.

My goal is to subset a plot to show only one color group, like it is done using plotly::ggplotly() (HTML plots).

I expect it should be similar to the way we subset a plot to the x dimension using xlim(), but for the color dimension.
However, it seems that it does not seem to work the same way.

Here is a reproducible example with expected output:

library(tidyverse)
p = ggplot(mtcars, aes(mpg, wt, color=factor(cyl))) +
  geom_point()
#initial plot
p

#subset on x
p + lims(x=c(15,20)) #same as xlim(15, 20)
#> Warning: Removed 19 rows containing missing values (geom_point).

#subset on color (fail)
p + lims(color="6")

#expected output (without data manipulation)
ggplot(mtcars %>% filter(cyl==6), 
       aes(mpg, wt, color=factor(cyl))) +
  geom_point()

Created on 2022-01-30 by the reprex package (v2.0.1)

As you can see, instead of subsetting on color, it only removed the color attribute.

Note that, with the x dimension there was a warning about removing values, whereas there was not with the color dimension.

Is there a way to subset the plot after its creation?

Upvotes: 1

Views: 394

Answers (2)

Dan Chaltiel
Dan Chaltiel

Reputation: 8523

Using @Allan's answer and some other, I could make a one-liner out of my problem:

library(tidyverse)
p = ggplot(mtcars, aes(mpg, wt, color=factor(cyl))) +
  geom_point()
p %+% filter(p$data, cyl==6)

Created on 2022-01-30 by the reprex package (v2.0.1)

Upvotes: 1

Allan Cameron
Allan Cameron

Reputation: 174348

Each ggplot object has a member called data, which is a data frame you can filter, so you could create a little function that filters based on existing variables:

filter_ggplot <- function(p, predicate) {
  predicate <- match.call()$predicate
  backup    <- p$data
  p$data    <- p$data[with(backup, eval(predicate)),]
  print(p)
  p$data    <- backup
  invisible(p)
}

This allows:

p

p %>% filter_ggplot(cyl == 6)

p %>% filter_ggplot(cyl == 4)

Created on 2022-01-30 by the reprex package (v2.0.1)

Upvotes: 3

Related Questions