Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally modify ggplot theme based on presence of facets?

Tags:

r

ggplot2

I'm working on a custom ggplot2 theme and was thinking it could be nifty to automatically modify elements of the theme depending on certain characteristics of the the plot object. For instance, is there a way to specify that if the plot contains facets, add a border to each panel?

I guess the question is really, can I access the current gg object from within a custom theme() call and then conditionally apply certain theme elements? In my head I would define my theme function to be something like this:

theme_custom <- function() {
  if (plot$facet$params > 0) {
  theme_minimal() +
    theme(panel.border = element_rect(color = "gray 50", fill = NA))
  }
  else {
    theme_minimal()
    }
}

If this is possible, it would look like this in use:

library(ggplot2)

# plot with facets automatically adds panel borders
ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  facet_wrap(vars(cyl)) +
  theme_custom()

# plot without facets no panel border
ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  theme_custom() 

NOTE: This was originally posted on RStudio Community and did not receive an answer.

like image 526
mfherman Avatar asked Sep 28 '19 19:09

mfherman


People also ask

Which function can I use to modify the elements of a theme in Ggplot?

To modify individual elements, you need to use theme() to override the default setting for an element with an element function.

What are facets in Ggplot?

The facet approach partitions a plot into a matrix of panels. Each panel shows a different subset of the data. This R tutorial describes how to split a graph using ggplot2 package. There are two main functions for faceting : facet_grid()

What does Facet_wrap do in Ggplot?

facet_wrap() makes a long ribbon of panels (generated by any number of variables) and wraps it into 2d. This is useful if you have a single variable with many levels and want to arrange the plots in a more space efficient manner. You can control how the ribbon is wrapped into a grid with ncol , nrow , as.

What is the function of Facet_grid () in Ggplot ()?

facet_grid() forms a matrix of panels defined by row and column faceting variables. It is most useful when you have two discrete variables, and all combinations of the variables exist in the data.


1 Answers

I think Oliver was thinking in the correct direction.

I don't think the theme_custom function is the correct place to check the plot for conditional theming, because theme functions are mostly agnostic about the precise plot that they are added to.

Instead, I think the appropriate place to check the plot is when the theme is added to the plot. You could write a theme function like the following, which sets a different class to the output.

theme_custom <- function() {
  out <- theme_minimal()
  class(out) <- c("conditional_theme", class(out))
  out
}

Now everytime a theme is added to a plot, this is done through the ggplot_add.theme function, which we can rewrite for the conditional_theme class. In my opinion, the correct way to check if a plot is facetted, is to check the class of the plot$facet slot, which can be FacetGrid, FacetWrap etc when a proper facet is added and defaults to FacetNull when no facet is set.

ggplot_add.conditional_theme <- function(object, plot, object_name) {
  if (!inherits(plot$facet, "FacetNull")) {
    object <- object + theme(panel.border = element_rect(colour = "grey50", fill = NA))
  }
  plot$theme <- ggplot2:::add_theme(plot$theme, object, object_name)
  plot
}

And now the use cases should work as intended:

ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  facet_wrap(vars(cyl)) +
  theme_custom()

enter image description here

ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  theme_custom() 

enter image description here

The only downside is that you would literally have to add the theme to the plot every time and you can't use the theme_set(theme_custom()) to have this apply to any plot in the session.

like image 97
teunbrand Avatar answered Oct 20 '22 03:10

teunbrand