# Plot weight by cylinders, with weight by gear inside
# Using {ggpattern} by @coolbutuseless
# https://coolbutuseless.github.io/package/ggpattern/
# Load packages
library(dplyr)
library(purrr)
library(tidyr)
library(ggplot2)
library(ggpattern)
# Prepare mean wt per cyl with filenames for gear-wt plots
<- mtcars %>% group_by(cyl) %>% summarise(mean_wt = mean(wt))
cyl_weights
# See the pixel dimensions of the bars
# This will depend on the size of your plot; I just used the default 7 x 7
<- ggplot(cyl_weights, aes(as.character(cyl), mean_wt)) +
dummy_plot geom_col_pattern(pattern = "placeholder", pattern_type = "dummy") +
labs(
title = "Weight by gears by weight by cylinders",
caption = "Thanks to {ggpattern} by @coolbutuseless",
x = "Cylinders", y = "Weight"
+
) theme_grey(base_size = 15)
# Save the dummy plot
ggsave("~/Desktop/dummy_plot.png", dummy_plot) # defaults to 7 x 7 output
tl;dr
The {ggpattern} package lets you add pattern fills to your {ggplot2} plot… so I did the inevitable.
Yo dawg
Followers of this blog might remember the unveiling of cloud_pie()
, the greatest new visualisation technique of the 21st Century.
Luckily, R-package machine mikefc of @coolbutuseless has released {ggpattern}, which lets you image- or pattern-fill the bars of your {ggplot2} plot. Most usefully with pictures of kittens or Bill Murray.
This has opened the door to yet another ground-breaking viz. The secret yet obvious real purpose of {ggpattern} is to put plots inside your plots.1
Voilà.
It may be too much to take in; let me explain. The main plot is of car weight by the number of cylinders from the mtcars dataset.
But lo, each bar is itself a plot of weight by gears for the number of cylinders on the x-axis of the main plot. The most efficient plot of all time?
Please clean your blown mind from the ceilling before you leave, thank you.
The secret
Expand for the full, hacky, non-reproducible code used to create this masterpiece.
[](resources/dummy_plot.png]{fig-alt=“Subplot of weight by gears for 4 cylinders.” width=“100%”}
# Plot of mean weight by gear for each cyl
<- mtcars %>%
sub_plots group_by(cyl) %>% nest() %>% ungroup() %>% # listcol by cyl
mutate(
data_mean = map(data, ~group_by(., gear) %>% summarise(mean_wt = mean(wt))),
plot = map( # listcol of plots for each cyl
data_mean,~ggplot(., aes(as.character(gear), mean_wt)) +
labs(title = "Weight by gears", x = "Gears", y = "Weight") +
geom_col() +
theme_grey(base_size = 60) # trial and error until it looked okay
),filename = paste0(cyl, "_cyl.png") # unique filename based on cyl value
%>%
) arrange(cyl) %>% # in order of cy number
mutate( # pixel values manually added from looking at the dummy plot output!
width = 141 * 0.084666667, # conversion from pixels to mm given 300 dpi
height = c(261, 357, 458) * 0.084666667
%>%
) select(filename, plot, height, width)
# Save the sub-plots as separate files wth provided dimensions
# These will be read into the main plot
pwalk(sub_plots, ggsave, path = "~/Desktop/")
# Plot weight by cylinders, with weight by gear inside
<- cyl_weights %>%
main_plot mutate( # add filepaths for where to find the saved subplots
filename = case_when(
== 4 ~ "~/Desktop/4_cyl.png",
cyl == 6 ~ "~/Desktop/6_cyl.png",
cyl == 8 ~ "~/Desktop/8_cyl.png",
cyl
)%>%
) ggplot(aes(as.character(cyl), mean_wt)) +
geom_col_pattern(
aes(pattern_filename = I(filename)),
pattern = "image",
pattern_type = "squish"
+
) labs(
title = "Weight by gears by weight by cylinders",
caption = "Thanks to {ggpattern} by @coolbutuseless",
x = "Cylinders", y = "Weight"
+
) theme_grey(base_size = 15)
# Save plot
ggsave("~/Desktop/ggpattern_plot.png", main_plot) # default 7 x 7 output
In short, you can use arguments pattern = "placeholder"
and pattern_type = "dummy"
to geom_col_pattern()
to produce a plot containing pixel dimensions for each bar.
From there, you can create plots that match those dimensions. Then you can recreate your plot but this time use argument pattern = "image"
and provide the filepaths as an aes()
thetic.
Bless you, @coolbutuseless.
Environment
Session info
Last rendered: 2024-07-14 20:13:50 BST
R version 4.4.0 (2024-04-24)
Platform: aarch64-apple-darwin20
Running under: macOS Ventura 13.2.1
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.0
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: Europe/London
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] htmlwidgets_1.6.4 compiler_4.4.0 fastmap_1.2.0 cli_3.6.3.9000
[5] tools_4.4.0 htmltools_0.5.8.1 rstudioapi_0.16.0 yaml_2.3.8
[9] rmarkdown_2.26 knitr_1.46 jsonlite_1.8.8 xfun_0.43
[13] digest_0.6.35 rlang_1.1.4.9000 evaluate_0.23
Footnotes
It can’t be chartjunk if it’s simply more charts, he said, after posting a tweet about it on April 1st.↩︎