ggplot2

Misc

  • Packages

    • {ggreveal} - Reveal a ggplot Incrementally (e.g. groups, facets)
    • {thematic} - Enables automatic styling of R plots in Shiny, R Markdown, and RStudio
    • {hrbrthemes} - hrbrmstr’s collection of themes
    • {{brand_yml}} - Create reports, apps, dashboards, plots and more that match your company’s brand guidelines with a single _brand.yml file
      • For Quarto dashboards, websites, reports, etc.
      • For Python shiny, seaborn, matplotlib, etc.
      • For R shiny, ggplot2, plot, RMarkdown
    • {ggblanket} - Similar ggplot ui but with simpler structure. Stuff that would require multiple geoms are replaced with one geom and basic arguments. Compatible with popular ggplot extensions
  • Resources

  • Don’t use stat calculating geoms and set axis limits with scale_y_continuous

    • See examples of the behavior in this thread
  • Defaults for any {ggplot2} geom using the default_aes field (i.e. GeomBlah$default_aes )

  • Basic Function

    viz_monthly <- 
      function(df, y_var, threshhold = NULL) {
    
        ggplot(df,
               aes(x = .data[["day"]],
                   y = .data[[y_var]])) +
          geom_line() +
          geom_hline(yintercept = threshhold, 
                     color = "red", 
                     linetype = 2) +
          scale_x_continuous(breaks = seq(1, 29, by = 7)) +
          theme_minimal()
    
    }
    • I’ve written a couple basic ones in the wild without tidyeval, but uses conditionals for theming: Fun1, Fun2
  • Storing geom settings in a dataframe (source)

    df <- data.frame(x = seq(from = 1, to = 20, by = 1),
                     y = rnorm(20, mean = 50, sd = 4),
                     limits = "c(0,30)")
    
    ggplot(data = df, aes(x = x, y = y)) +
      geom_line() +
      scale_y_continuous(limits= eval(parse(text=df$limits)))
  • FIltering Data in Geoms (source)

    mtcars |> 
      rownames_to_column() |> 
      ggplot(aes(mpg, hp)) +
      geom_point() +
      geom_label(
        aes(label = rowname),
        data = ~slice_max(.x,
                          hp,
                          n = 2),
        nudge_x = 3
      )
  • Dynamic Axis Limits (source)

    ggplot(...) +
      ... +
      scale_x_continuous(
        breaks = seq(2021, 2023, 1),
        limits = c(min(df$year) - .1, max(df$year) + .1),
        position = "top",
        labels = c("Baseline", "2022", "2023")
      )

Themes

  • Docs

  • Theme Elements Cheatsheet (source)

  • Use the same font family to all geom_text elements

    update_geom_defaults(
      geom = "text",
      aes(family = "Open Sans")
    )
    • geom_text is not impacted by theme settings, so setting this option keeps you from having to manually add the font family to each instance.
  • Setting color defaults (source)

    # Discrete with a list
    options(ggplot2.discrete.colour = list_of_colors)
    
    # Continuous with a function
    options(
      ggplot2.continuous.colour = \(...){
        scico::scale_color_scico(
          palette = "batlow", 
          ...
        )
      }
    )
    
    # Ordinal with a function
    options(
      ggplot2.ordinal.colour = \(...){
        scale_color_viridis_d(
          option = "G", 
          direction = -1, 
          ...
        )
      }
    )
    • If you have a particular set of palettes you like to use for projects, these options can be put into a R file and loaded via source e.g. source(here::here("_defaults.R"))
  • Basic Syntax

    theme_psc <- function() {
      theme_void(base_family = "Open Sans") +
        theme()
    }
  • Transparent Background

    p +
      theme(
        panel.background = element_rect(fill='transparent'), #transparent panel bg
        plot.background = element_rect(fill='transparent', color=NA), #transparent plot bg
        panel.grid.major = element_blank(), #remove major gridlines
        panel.grid.minor = element_blank(), #remove minor gridlines
        legend.background = element_rect(fill='transparent'), #transparent legend bg
        legend.box.background = element_rect(fill='transparent') #transparent legend panel
      )
    ggsave('myplot.png', p, bg='transparent')
  • theme_notebook

    theme_notebook <- function(...) {
      theme_minimal() %+replace%
        theme(
          panel.background = element_rect(fill='#FFFDF9FF'),
          panel.grid.minor = element_blank(),
          plot.background = element_rect(fill='#FFFDF9FF', color=NA),
          legend.background = element_rect(fill='#FFFDF9FF'),
          legend.box.background = element_rect(fill='#FFFDF9FF'),
          ...
        )
    }
  • Cedric Sherer (article)

    theme_set(theme_minimal(base_size = 15, base_family = "Anybody"))
    theme_update(
      axis.title.x = element_text(margin = margin(12, 0, 0, 0), color = "grey30"),
      axis.title.y = element_text(margin = margin(0, 12, 0, 0), color = "grey30"),
      panel.grid.minor = element_blank(),
      panel.border = element_rect(color = "grey45", fill = NA, linewidth = 1.5),
      panel.spacing = unit(.9, "lines"),
      strip.text = element_text(size = rel(1)),
      plot.title = element_text(size = rel(1.4), face = "bold", hjust = .5),
      plot.title.position = "plot"
    )
  • Eric Bickel

    ggplot2::theme_set(
      theme_bw(base_size = 12) +
        theme(
              plot.title = element_text(face = 'bold', hjust = 0),
              text = element_text(colour = '#4e5c65'),
              panel.background = element_rect('#ffffff'),
              strip.background = element_rect('#ffffff', colour = 'white'),
              plot.background = element_rect('#ffffff'),
              panel.border = element_rect(colour = '#ffffff'),
              panel.grid.major.x = element_blank(),
              panel.grid.major.y = element_blank(),
              panel.grid.minor.y = element_blank(),
              legend.background = element_rect('#ffffff'),
              legend.title = element_blank(),
              legend.position = 'right',
              legend.direction = 'vertical',
              legend.key = element_blank(),
              strip.text = element_text(face = 'bold', size = 10),
              axis.text = element_text(face = 'bold', size = 9),
              axis.title = element_blank(),
              axis.ticks = element_blank()
        )

Bespoke

  • Comparison Plot (source)
    • Example

      Code

      library(tidyverse)
      library(scales)
      
      comparison_plot <- 
        function(
          df,
          highlight_town,
          value_type,
          highlight_color
        ) {
      
          plot <- 
            df |>
              ggplot(
                aes(
                  x = value,
                  y = 1
                )
              ) +
              # Light gray lines for all towns
              geom_point(
                shape = 124,
                color = "gray80"
              ) +
              # Line for town to highlight
              geom_point(
                data = df |> filter(location == highlight_town),
                shape = 124,
                color = highlight_color,
                size = 10
              )
      
          if (value_type == "percent") {
              final_plot <- plot +
                scale_x_continuous(
                  labels = percent_format(accuracy = 1)
                )
          }
      
          if (value_type == "number") {
            final_plot <- plot +
              scale_x_continuous(
                labels = comma_format(accuracy = 1)
              )
          }
        }
      
      comparison_plot(
        df = single_family_homes,
        highlight_town = "Hartford",
        value_type = "percent",
        highlight_color = psc_blue
      ) +
        theme_whatever()
      
      
      big_number_plot <- 
        function(value, 
                 text,
                 value_color
        ) {
          ggplot() +
            # Add value
            geom_text(
              aes(
                x = 1,
                y = 1,
                label = value
              ),
              color = value_color,
              fontface = "bold",
              size = 20,
              hjust = 0
            ) +
            # Add text
            geom_text(
              aes(
                x = 1,
                y = 2,
                label = str_to_upper(text)
              ),
              color = "gray70",
              size = 7,
              hjust = 0
            )
      }
      
      big_number_plot(
        value = "19%",
        text = "Single-Family Homes as\nPercent of All Homes",
        value_color = psc_blue
      ) +
        theme_whatever() # should start with theme_void