<- function(vec) {
rescale_01
if(!is.numeric(vec)) {
stop("Input vector is not numeric")
}
if(length(vec) <= 1) {
stop("Input vector length must have at least two elements")
}
<- range(vec, na.rm = TRUE)
range
return((vec - range[1]) / (range[2] - range[1]))
}
Cool Plots & Searching for Efficiency
Today we will…
- Review Lab 9
- Function Checks
- Creative Plots
- Additional Tools for Creativity / Clarity
- Lab 7 Peer Review
- Function Style
if()
Style
- Work Time
- Lab 8: Searching for Efficiency
Lab 9
Vectorized Function Checks
. . .
How would you transform these input checks so the rescale_01()
function is vectorized?
Function Checks for Data Frames
<- function(df, var) {
rescale_column
<- df |>
df ::mutate(across(.cols = {{ var }}, .fns = ~rescale_01(..x)
dplyr
)
)
return(df)
}
. . .
How would you check if the input df
was a data frame?
Function Checks for Data Frames – Columns
<- function(df, cols){
rescale_column
stopifnot(is.data.frame(df))
<- df |>
df ::mutate(across(.cols = {{ cols }}, .fns = ~rescale_01(.x)
dplyr
)
)
return(df)
}
. . .
How would you check if the input cols
were columns that existed in df
?
Take Advanced R in the Spring!
Plots from Lab 7
Stacked Bars with Color!
Notice how their facets have more informative titles?
More Stacked Bars with Color!
Notice how every year with measurements is displayed?
Combining Year and Trip
Faceting by Year!
A Line Plot with Colors!
Do you want your legend on the left?
Code
fish |>
group_by(year, section, trip) |>
summarize(missing_count = sum(is.na(weight)), .groups = "drop") |>
mutate(trip = case_when(
trip == 1 ~ "Trip 1",
trip == 2 ~ "Trip 2")) |>
ggplot(aes(x = year, y = missing_count, color = section)) +
geom_line(linewidth = 1) +
scale_color_brewer(palette = "Set2") +
labs(
title = "Number of Missing Weight Measurements of Trout Species (Blackfoot River)",
x = "",
subtitle = "Across Sections of River and Trip Number",
y = "",
color = "Section") +
facet_wrap(~ trip) +
theme_minimal() +
theme(legend.position = "top")
Could you remove your legend?
Code
plot <- fish |>
group_by(year, section, trip) |>
summarize(missing_count = sum(is.na(weight)), .groups = "drop") |>
mutate(trip = case_when(
trip == 1 ~ "Trip 1",
trip == 2 ~ "Trip 2")) |>
ggplot(aes(x = year, y = missing_count, color = section)) +
geom_line(linewidth = 1) +
scale_color_brewer(palette = "Set2") +
labs(
title = "Missing Fish Weights for Trout Species on the Blackfoot River",
x = "Year",
y = "",
color = "Section") +
facet_wrap(~ trip) +
theme_minimal()
annotate_text <- data.frame(year = c(1994, 1993),
missing_count = c(150, 40),
trip = factor(c("Trip 2", "Trip 2"),
levels = c("Trip 1","Trip 2"),
),
section = factor(c("Johnsrud", "ScottyBrown"),
levels = c("Johnsrud", "ScottyBrown"))
)
plot +
geom_text(data = annotate_text, label = c("Johnsrud", "ScottyBrown")) +
theme(legend.position = "none",
plot.title = element_text(size = 12),
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 12),
strip.text.x = element_text(size = 12)
)
Could you remove your legend?
Code
library(ggtext)
fish |>
group_by(year, section, trip) |>
summarize(missing_count = sum(is.na(weight)), .groups = "drop") |>
mutate(trip = case_when(
trip == 1 ~ "Trip 1",
trip == 2 ~ "Trip 2")) |>
ggplot(aes(x = year, y = missing_count, color = section)) +
geom_line(linewidth = 1) +
scale_color_brewer(palette = "Set2") +
labs(
title = str_c("Missing Fish Weights for the ",
"<span style = 'color:#66C2A5'>**Johnsrud**</span>",
" and <span style = 'color:#FC8D62'>**ScottyBrown**</span>",
" Sections of the Blackfoot River"),
x = "Year",
y = "",
color = "Section") +
facet_wrap(~ trip) +
theme_minimal() +
theme(plot.title = ggtext::element_markdown(size = 16),
legend.position = "none",
axis.text.x = element_text(size = 12),
axis.text.y = element_text(size = 12),
axis.title = element_text(size = 12),
strip.text.x = element_text(size = 12)
)
Other Cool Stuff People Have Done!
Lab 7 Peer Review
Function Formatting
- There should be a new line after the opening {
- The closing } should be on its own line
- The body of the function should be indented
- The code uses whitespace around all commas and arithmetic operators
- The code uses new lines (returns) to eliminate character wrapping
Good
<- function(x) {
rescale_01 if (!is.numeric(x)) {
stop("Input must be a numeric vector")
}
if (length(x) <= 1) {
stop("Length of the input vector is not greater than 1")
}
<- range(x, na.rm = TRUE)
get_range - get_range[1]) / (get_range[2] - get_range[1])
(x }
Not so good
<- function(x)
rescale_01
{if (!is.numeric(x)) {
stop("Input must be a numeric vector")
}
if (length(x) <= 1) {
stop("Length of the input vector is not greater than 1")
}
<- range(x, na.rm=TRUE)
get_range -get_range[1]) / (get_range[2]-get_range[1])} (x
if()
on a single line?
<- function(x) {
rescale_01
if(!is.numeric(x)) stop("Input vector must be numeric.")
if(length(x) <= 1) stop("Input vector requires more than one element.")
<- range(x, na.rm = TRUE)
range_1
- range_1[1]) / (range_1[2] - range_1[1])
(x }
This technically works because the stop()
is on the same line as if()
.
. . .
But what if you have multiple things that happen if the condition is met?
if()
on multiple lines
<- function(gift){
pluralize_gift
# Check if the word ends in a y
if(str_detect(gift, "y$")){
# Replace the y at the end with an ies
<- str_replace(gift,
gift pattern = "y",
replacement = "ies")
} # Check for a oo (goose)
else if(str_detect(gift,"oo")){
# Replace the oo with a ee
<- str_replace(gift,
gift pattern = "oo",
replacement = "ee")
} else{
# Add an s to the end of the gift
<- str_c(gift, replacement = "s")
gift
}
return(gift)
}
Lab 8: Searching for Efficiency
Revisit previous lab problems through the lens of efficiency
- Use functions from
map()
instead ofacross()
- Reduce separate pipelines into a single pipeline