suppressPackageStartupMessages(library(dplyr))
<- starwars[, c("name", "species", "height")]
sw_a <- starwars[, c("name", "homeworld")] sw_b
tl;dr
Some people look at an R script and see code. But I feel something.
A philosophy
Have you experienced the Aesthetics Wiki?
It’s missing R-related entries for some reason, which definitely fit the aesthetic philosophy of having:
perspectives on beauty and the human condition and a political, economic, or social statement
Tell me you don’t look at an R script and get an immediate vibe.
I want to suggest two obvious aesthetics for submission to the wiki—Basecore and Tidywave—and to introduce the definitely-soon-to-be-mainstreamed V4 Punk1.
The addendum
Basecore
Overview
- History: emerged as Base Academic in 1993, mainstreamed as Base Core from 2000 to date.
- Visuals:
[
(square-bracket selector),$
(dollar selector),~
(formula-form tilde). - Media: Writing R Extensions, the R-help mailing list, that textfile with a Y2K warning that came bundled with R v1.0.
- Fashion: cardigans, a wired mouse with a ball in it, the old-school IDE you get when you click ‘R.app’ instead of ‘RStudio.app’.
- Palette: grey.
- Nearest aesthetic: Chaotic Academia, which ‘acknowledges the pretentiousness of classic academia, subtly mocking it at times’.
Sample
Classic stuff. Typical base-R code uses a lot of intermediate assignment to create temporary objects for further manipulation. Many actions make use of square bracket notation to indicate some action over rows and columns of a data.frame. Data.frame columns have to be called within the context of the data.frame they belong to, using dollar or square-bracket notation. The tilde is used for formula notation (‘this given that’).
Set up demo data
<- sw_a[sw_a$species == "Human", names(sw_a) != "species"]
x <- merge(x, sw_b, by = "name")
x $height <- x$height / 100
x$homeworld <- ifelse(
x!x$homeworld %in% c("Tatooine", "Naboo"),
"Other",
$homeworld
x
)<- aggregate(x, height ~ homeworld, mean, na.rm = TRUE)
x <- x[order(-x$height), ]
x x
homeworld height
3 Tatooine 1.792500
2 Other 1.776471
1 Naboo 1.772000
Tidywave
Overview
- History: humble academic origins in 2008, later popularised with the creation of the {tidyverse} in 2016.
- Visuals:
%>%
({magrittr} pipe),.
(data placeholder),~
(lambda function). - Media: R for Data Science, conflict warnings in the console when you do
library(tidyverse)
, that one gif of Hadley tapping merrily on an invisible keyboard (‘just typing R code!’). - Fashion: RStudio, hex stickers, rapid deprecation.
- Palette: Posit blue, yellow, and grey.
- Nearest aesthetic: Corporate Memphis because I’ve literally seen it in Posit marketing.
Sample
The script reads from left-to-right and top-to-bottom, recipe style, using pipes: ‘take dataset, then do a thing, then do a thing’, etc. Each function is verb that indicates its action. Non-standard evaluation is rampant. A tilde replaces the tedious typing of function(). A titchy inconspicuous .
acts as a data placeholder on the right-hand side of a pipe.
%>%
sw_a filter(species == "Human") %>%
select(-species) %>%
left_join(sw_b, by = "name") %>%
mutate(
height = height / 100,
homeworld = if_else(
!homeworld %in% c("Tatooine", "Naboo"),
"Other",
homeworld
)%>%
) summarise(
height = mean(height, na.rm = TRUE),
.by = homeworld
%>%
) arrange(desc(height))
# A tibble: 3 × 2
homeworld height
<chr> <dbl>
1 Tatooine 1.79
2 Other 1.78
3 Naboo 1.77
V4 Punk
Overview
- History: incremental emergence following R version 4.0 in 2020, boosted greatly in 2022 with the release of the base pipe. The future of R.
- Visuals:
|>
(base pipe),_
(data placeholder),\()
(lambda function). - Media: meme blogs, cheeky Fosstodon posts.
- Fashion: hubris, evil moustaches, troll-face emojis.
- Palette: rainbow?
- Nearest aesthetic: Vacation Dadcore, so you can ‘escape to a simpler time without sacrificing any of the fun’.
Sample
Hear me out: what if tidyverse, but made entirely of base R functions2? This is now possible with the base pipe and by using obscure functions that help you avoid square brackets3. It’s also sketchy as heck; just see the help files for subset()
(‘unanticipated consequences’) and transform()
(‘you deserve whatever you get!’). The death of Basecore and Tidywave, for sure.
|>
sw_a subset(
== "Human",
species select = -species
|>
) merge(sw_b, by = "name") |>
transform(
height = height / 100,
homeworld = ifelse(
!homeworld %in% c("Tatooine", "Naboo"),
"Other",
homeworld
)|>
) aggregate(
~ homeworld,
height mean(x, na.rm = TRUE)
\(x) |>
) sort_by(~ height, decreasing = TRUE) # hot off the v4.4 press
homeworld height
3 Tatooine 1.792500
2 Other 1.776471
1 Naboo 1.772000
Can’t wait to see this roll out into production code.
Environment
Session info
Last rendered: 2024-05-09 09:04:29 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
other attached packages:
[1] dplyr_1.1.4
loaded via a namespace (and not attached):
[1] digest_0.6.35 utf8_1.2.4 R6_2.5.1 fastmap_1.1.1
[5] tidyselect_1.2.1 xfun_0.43 magrittr_2.0.3 glue_1.7.0
[9] tibble_3.2.1 knitr_1.46 pkgconfig_2.0.3 htmltools_0.5.8.1
[13] rmarkdown_2.26 generics_0.1.3 lifecycle_1.0.4 cli_3.6.2
[17] fansi_1.0.6 vctrs_0.6.5 withr_3.0.0 compiler_4.4.0
[21] rstudioapi_0.16.0 tools_4.4.0 pillar_1.9.0 evaluate_0.23
[25] yaml_2.3.8 rlang_1.1.3 jsonlite_1.8.8
Footnotes
These suffixes are meaningful: core ‘implies a system, a set of rules’, wave ‘a significant shift within a genre’ and punk ‘reject[s] social norms’.↩︎
I called this ‘The Modern Base Aesthetic’ in my talk, ‘Base Slaps!’, at the NHS-R conference 2023. But now I realise the aesthetics run deeper.↩︎
If you truly want something that looks like {dplyr} code but depends only on base R, then check out the {poorman} package.↩︎