Twenty-Five Things You Didn't Know You Could Do with R
This blog post contains code samples for my keynote at Cascadia R Conference 2025. In addition, I've added resources for those interested in learning more. I'll also post the recording of my talk when it is available.
Slides
Access Data Automagically
Pull in Data Directly from Google Sheets
Sample Code
library(googlesheets4)
survey_data <-
read_sheet(YOURSHEETURLHERE)
Resources
I talk about how to use {googlesheets4} in Chapter 11 of my book R for the Rest of Us: A Statistics-Free Introduction.
Pull in Data Directly from Qualtrics
Sample Code
library(qualtRics)
survey_data <-
fetch_survey(surveyID = "YOURSURVEYIDHERE")
library(tidycensus)
get_acs(
state = "OR",
geography = "place",
geometry = TRUE,
variables = "B01003_001"
)
Resources
Great places to learn more are the tidycensus docs and Kyle Walker's book about analyzing US census data
Work with APIs to Access Data
Sample Code
This code doesn't work (you won't have an API key to make it work), but should give you a sense of how {httr2} works.
library(httr2)
fathom_api_key <- Sys.getenv("FATHOM_API_KEY")
request("https://api.usefathom.com/v1/aggregations") |>
req_url_query(
entity = "pageview",
aggregates = "visits,uniques,pageviews",
sort_by = "visits:desc"
) |>
req_headers(
Authorization = str_glue("Bearer {fathom_api_key}")
) |>
req_perform()
Resources
Check out {httr2} package docs and this presentation about getting data out of Web APIs by Ted Laderas
Scrape Data
library(rvest)
library(tidyverse)
read_html("https://en.wikipedia.org/wiki/List_of_FIFA_World_Cup_finals") |>
html_elements("table") |>
pluck(4) |>
html_table() |>
select(-Ref.)
Sample Code
Resources
Efficiently Make Beautiful Data Viz
Make Your Own Theme
Sample Code
Here is the full code for my theme:
theme_dk <- function(base_family = "Inter Tight", base_size = 14) {
theme_dk <-
ggplot2::theme_minimal(
base_size = base_size,
base_family = base_family
) +
ggplot2::theme(
panel.grid.minor = ggplot2::element_blank(),
panel.grid.major = ggplot2::element_line(
color = "grey90",
linewidth = 0.5,
linetype = "dashed"
),
axis.ticks = ggplot2::element_blank(),
axis.text = ggplot2::element_text(
color = "grey50",
size = ggplot2::rel(0.8)
),
axis.title = ggplot2::element_blank(),
plot.title.position = "plot",
plot.title = ggplot2::element_text(
face = "bold",
size = ggplot2::rel(1.5)
),
plot.subtitle = ggplot2::element_text(
color = "grey40",
size = ggplot2::rel(1.1)
),
plot.caption = ggplot2::element_text(
color = "grey50",
margin = ggplot2::margin(t = 20)
),
plot.margin = ggplot2::margin(10, 10, 10, 10),
strip.text = ggplot2::element_text(
color = "grey40",
size = ggplot2::rel(0.9)
),
panel.spacing = ggplot2::unit(2, "lines")
)
theme_dk
}
Resources
Check out the Customize Your Theme lesson video from my Going Deeper with R course.
Transcript
Click on the transcript to go to that point in the video. Please note that transcripts are auto generated and may contain minor inaccuracies.
I also talk about it in Chapter 3 of my book R for the Rest of Us: A Statistics-Free Introduction.
Use Your Theme Everywhere
Sample Code
---
title: "Penguins Report"
---
```{r}
theme_dk <- function(base_family = "Inter Tight", base_size = 14) {}
```
```{r}
theme_set(theme_dk())
```
```{r}
penguins_bar_chart
```
Resources
Learn more about modifying themes in theme() function documentation
Make Your Text Consistent with Your Theme
Sample Code
---
title: "Penguins Report"
---
```{r}
theme_dk <- function()
```
```{r}
theme_set(theme_dk())
update_geom_defaults(geom = "text", aes(family = "IBM Plex Mono"))
```
```{r}
penguins_bar_chart +
geom_text(
aes(label = avg_bill_length_formatted),
vjust = 1.5,
color = "white",
size = 4
)
```
library(tidycensus)
median_income_by_county <-
get_acs(
geography = "county",
variables = c(median_income = "B19013_001"),
geometry = TRUE
)
Resources
Chapter 4 of my book covers making maps with ggplot, and you can learn more in the Mapping with R course
Do Geospatial Analysis
Sample Code
library(sf)
library(tidyverse)
library(mapgl)
portland_libraries <- read_sf("https://raw.githubusercontent.com/rfortherestofus/twenty-five-things/refs/heads/main/data/portland_libraries.geojson")
portland_libraries_one_mile_buffer <-
portland_libraries |>
st_buffer(1609.34)
pps_elementary_schools <-
read_sf("https://raw.githubusercontent.com/rfortherestofus/twenty-five-things/refs/heads/main/data/pps_elementary_schools.geojson
pps_elementary_schools_near_libraries <-
pps_elementary_schools |>
st_join(portland_libraries_one_mile_buffer) |>
mutate(has_nearby_library = case_when(
is.na(library) ~ "Not within one mile of library",
.default = "Within one mile of library"
)) |>
select(school, has_nearby_library)
maplibre(bounds = portland_libraries_one_mile_buffer) |>
add_fill_layer(
source = portland_libraries_one_mile_buffer,
fill_color = "#7570b3",
fill_opacity = 0.5,
tooltip = "library",
id = "portland_libraries"
) |>
add_circle_layer(
source = pps_elementary_schools_near_libraries,
circle_color = match_expr(
"has_nearby_library",
values = c(
"Within one mile of library",
"Not within one mile of library"
),
stops = c(
"#1b9e77",
"#d95f02"
)
),
tooltip = "school",
id = "schools"
) |>
add_categorical_legend(
values = c(
"Within one mile of library",
"Not within one mile of library"
),
legend_title = NULL,
colors = c("#1b9e77", "#d95f02"),
circular_patches = TRUE
)
Resources
Chapter 7 of Kyle Walker's book covers spatial analysis with US census data
Check out documentation on st_join(), st_filter(), st_combine() and more functions used for geospatial analysis
Make Interactive Maps
Sample Code
maplibre(bounds = pps_elementary_schools_near_libraries) |>
add_fill_layer(
source = portland_libraries_one_mile_buffer,
fill_color = "#7570b3",
fill_opacity = 0.5,
tooltip = "library",
id = "portland_libraries"
) |>
add_circle_layer(
source = pps_elementary_schools_near_libraries,
circle_color = match_expr(
"has_nearby_library",
values = c(
"Within one mile of library",
"Not within one mile of library"
),
stops = c(
"#1b9e77",
"#d95f02"
)
),
tooltip = "school",
id = "schools"
) |>
add_categorical_legend(
values = c(
"Within one mile of library",
"Not within one mile of library"
),
legend_title = NULL,
colors = c(
"#1b9e77",
"#d95f02"
),
circular_patches = TRUE
)
Resources
Check out {mapgl} package docs
Report in New Ways with Quarto
Make Many Different Outputs with Quarto
Resources
Keep Your Quarto Outputs on Brand
Sample Code
meta:
name: R for the Rest of Us
link: https://rfortherestofus.com
color:
foreground: "#404e6b"
primary: "#6cabdd"
typography:
fonts:
- family: Inter
source: google
- family: IBM Plex Mono
source: google
base: Inter
headings: Inter
monospace: IBM Plex Mono
Resources
Check out brand.yml documentation.
Watch my recent video interview with Garrick Aden-Buie, covering consistent branding with brand.yml:
Publish Your Quarto Documents Online
Resources
In this Going Deeper with R course video, I teach how to publish your documents using Netlify. Check it out:
Transcript
Click on the transcript to go to that point in the video. Please note that transcripts are auto generated and may contain minor inaccuracies.
Make PDFs with Typst
Sample Code
The best place to see sample code is in this repo, which accompanies my 2024 posit::conf talk (see below).
Resources
My posit::conf(2024) talk covered how to use typst.
Automate all the Things
Email Your Reports Directly from R
Sample Code
library(tidyverse)
library(quarto)
library(gmailr)
rendered_report <- str_glue("covid-business-relief-contact-log-{today()}.html")
quarto_render(
input = "report.qmd",
output_file = rendered_report
)
gm_auth_configure()
gm_auth(email = TRUE, cache = ".secret")
email_report <-
gm_mime() |>
gm_to("Joe Schmoe <[email protected]>") |>
gm_from("David Keyes <[email protected]>") |>
gm_subject("COVID Business Relief Contact Log") |>
gm_text_body("See attached") |>
gm_attach_file(rendered_report)
gm_send_message(email_report)
Resources
Check out the {gmailr} package docs
Another alternative for sending emails directly from R is the {blastula} package
Run Your Code Without Lifting a Finger
Sample Code
name: Render Report and Send It
on:
schedule:
- cron: '00 14 * * 1-5'
jobs:
build:
runs-on: ubuntu-latest
container: rocker/geospatial
env:
GMAILR_APP: ${{ secrets.GMAILR_APP }}
GMAILR_EMAIL: ${{ secrets.GMAILR_EMAIL }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install dependencies
run: |
install.packages("remotes")
remotes::install_cran("quarto")
remotes::install_cran("gmailr")
ETC
shell: Rscript {0}
- name: Render + Send
run: |-
Rscript render_gmail.R
Resources
I demonstrate GitHub Actions in this blog post and video tutorial
Albert Rapp has also written a blog post about automation with GitHub actions
Use R to Work With Files Created in R
Sample Code
library(fs)
library(zip)
library(tidyverse)
library(googledrive)
county_pages <- dir_ls("outputs/pages/county/")
measure_pages <- dir_ls("outputs/pages/measure/")
all_pages_zip <-
zip(
zipfile = str_glue("outputs/zip/obtn-files-{today()}.zip"),
files = c(county_pages, measure_pages)
)
drive_upload(all_pages_zip)
Resources
See documentation for the {fs}, {zip} and {googledrive} packages.
We also have a blog post on working with {fs}.
Use AI to Write Better Code
Create Custom Instructions
Sample Code
My custom instructions are: "Please answer the following R question. When I program, I always like to use the tidyverse. Please don't ever give me base R solutions. Please also always use the native pipe (|>) not the tidyverse pipe (|>)."
Use AI Directly in your Code Editor
Resources
In the Using AI with R course, I teach how to use AI in both RStudio and Positron.
Using AI in RStudio:
Transcript
Click on the transcript to go to that point in the video. Please note that transcripts are auto generated and may contain minor inaccuracies.
Using AI in Positron:
Transcript
Click on the transcript to go to that point in the video. Please note that transcripts are auto generated and may contain minor inaccuracies.
Show AI Your Data
Resources
Simon Couch shows how the {gander} package can make tedious coding tasks faster and more efficient in a recent R for the Rest of Us podcast interview.
Use AI for Data Analysis
Translate Text
Sample Code
library(tidyverse)
library(mall)
survey_spanish <-
read_csv("https://raw.githubusercontent.com/rfortherestofus/twenty-five-things/refs/heads/main/data/survey_spanish.csv")
survey_translated <-
survey_spanish |>
llm_translate(spanish, language = "English", pred_name = "english")
survey_translated_summary <-
survey_translated |>
llm_summarize(english, max_words = 5, pred_name = "summary")
library(ellmer)
identify_themes <- function(text) {
chat <- chat_openai(
system_prompt = "You are a sociologist,
looking for the top three themes in the responses to a survey.
Each response is separated by \n"
)
chat$chat(text)
}
survey_translated_combined <-
survey_translated |>
pull(english) |>
paste(collapse = "\n")
survey_translated_combined |>
identify_themes()
Resources
I show how to use {ellmer} in my Using AI with R course:
Check out the {ellmer} package docs
Join the Community
I wrote a blog post a long time ago about how the R community became so welcoming.
Learn More about R for the Rest of Us
If you're interested in learning more R, check out our courses. And if you'd like to hire us to help you communicate more effectively and efficiently, check out our consulting services.
Sign up for the newsletter
Get blog posts like this delivered straight to your inbox.
You need to be signed-in to comment on this post. Login.