Skip to content

Instantly share code, notes, and snippets.

@James-Ansley
Last active October 3, 2024 01:00
Show Gist options
  • Save James-Ansley/7fa33bd17696141ad1e0026e16f4e473 to your computer and use it in GitHub Desktop.
Save James-Ansley/7fa33bd17696141ad1e0026e16f4e473 to your computer and use it in GitHub Desktop.
A simple density plot generator

A function to generate simple density plots.

Example

Single density plots can be generated:

(
  density_plot(
      test_1_data,
      x = "grade",
      title = "Density of Grades",
      limits = c(0, 100)
  )
  + labs(x = "Grade (/100)")
)

image

Or plots can be wrapped by proviging a group_on argument:

(
  density_plot(
      test_1_data,
      x = "grade",
      title = "Density of Grades By Stream",
      group_on = "stream",
      limits = c(0, 100)
  )
  + labs(x = "Grade (/100)")
)

image

library(tidyverse)
#' Returns a beautiful density plot
#'
#' @param data A data frame
#' @param x The x-axis variable as a string
#' @param group_on (optional) The variable to facet-wrap on as a string
#' @param title (optional) The title, if given will append "(n=<n>)"
#' @param limits (optional) a numeric vector of length 2 specifying the min and max values
#' @returns A ggplot2 plot
density_plot <- function(
data,
x,
title = NULL,
group_on = NULL,
limits = NULL
) {
plot <- ggplot(data, aes(x = !!as.name(x)))
if (!is.null(group_on)) {
data <- data |> group_by(!!as.name(group_on))
}
summary <- (
data
|> summarise(
mean = mean(!!as.name(x)),
median = median(!!as.name(x)),
n = n()
)
)
if (!is.null(group_on)) {
plot <- plot + facet_wrap(
~ get(group_on),
dir = "v",
labeller = as_labeller(~ paste0(
.x,
" (n=",
(summary |> filter(!!as.name(group_on) == .x) |> pull(n)),
")"
))
)
}
if (!is.null(title)) {
total <- summary |> pull(n) |> sum()
plot <- plot + labs(title = paste0(title, " (n=", total, ")"))
}
return(
plot
+ geom_density(alpha = 0.25, fill = "salmon")
+ theme(plot.title = element_text(face = "bold"))
+ scale_x_continuous(expand = expansion(add = 1.05), limits = limits)
+ scale_colour_manual(
name = "Summary", values = c(mean = "red", median = "blue")
)
+ scale_linetype_manual(
name = "Summary", values = c(mean = "solid", median = "longdash")
)
+ geom_vline(
aes(xintercept = mean, color = "mean", linetype = "mean"),
data = summary
)
+ geom_vline(
aes(xintercept = median, color = "median", linetype = "median"),
data = summary
)
+ labs(color = "Summary", linetype = "Summary")
)
}
#' Returns a beautiful 2x2 density plot grid
#'
#' @param data A data frame
#' @param x The x-axis variable as a string
#' @param group_on A character vector of exactly two variables to use as the
#' rows and columns of the grid in that order
#' @param x_limits A numeric vector of length 2 specifying the min and max values for the x-axis
#' @param title The title — The number of observations will be appended "(n=<n>)"
#' @param scales (optional) scales used in facet wrap (if group_on is provided)
#' @returns A ggplot2 plot
density_grid <- function(
data,
x,
group_on,
x_limits,
title,
scales = "fixed"
) {
data <- data |> group_by(!!as.name(group_on[1]), !!as.name(group_on[2]))
summary <- (
data
|> summarise(
mean = mean(!!as.name(x)),
median = median(!!as.name(x)),
n = n(),
.groups = "keep"
)
)
total <- summary |> pull(n) |> sum()
label_x_position = x_limits[1] + 0.1 * (x_limits[2] - x_limits[1])
max_y <- (
data
|> reframe(density = max(density(!!as.name(x))$y))
|> pull(density)
|> max()
)
return(
ggplot(data, aes(x = !!as.name(x)))
+ geom_density(alpha = 0.25, fill = "salmon")
+ facet_grid(
rows = vars(!!as.name(group_on[1])),
cols = vars(!!as.name(group_on[2]))
)
+ geom_text(
data = summary,
aes(x = label_x_position, y = max_y * 0.975, label = paste0("n=", n)),
inherit.aes = FALSE,
parse = FALSE
)
+ theme(plot.title = element_text(face = "bold"))
+ scale_x_continuous(expand = expansion(add = 1.05), limits = x_limits)
+ scale_colour_manual(
name = "Summary",
values = c(mean = "red", median = "blue")
)
+ scale_linetype_manual(
name = "Summary",
values = c(mean = "solid", median = "longdash")
)
+ geom_vline(
aes(xintercept = mean, color = "mean", linetype = "mean"),
data = summary
)
+ geom_vline(
aes(xintercept = median, color = "median", linetype = "median"),
data = summary
)
+ labs(
title = paste0(title, " (n=", total, ")"),
color = "Summary",
linetype = "Summary"
)
+ theme(panel.spacing.x = unit(0.75, "lines"))
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment