| name | r-style-guide |
| description | R style guide covering naming conventions, spacing, layout, and function design best practices. Use when writing R code. |
R Style Guide & Function Writing Best Practices
Consistent naming, spacing, structure, and function design for R code
Function Writing Best Practices
Structure and Style
rescale01 <- function(x) {
rng <- range(x, na.rm = TRUE, finite = TRUE)
(x - rng[1]) / (rng[2] - rng[1])
}
map_dbl()
map_chr()
map_lgl()
Naming and Arguments
calculate_mean_score <- function(data, score_col) {
}
my_function <- function(.data, ...) {
}
Style Guide Essentials
Object Names
- Use snake_case for all names
- Variable names = nouns, function names = verbs
- Avoid dots except for S3 methods
day_one
calculate_mean
user_data
DayOne
calculate.mean
userData
Spacing and Layout
x[, 1]
mean(x, na.rm = TRUE)
if (condition) {
action()
}
data |>
filter(year >= 2020) |>
group_by(category) |>
summarise(
mean_value = mean(value),
count = n()
)
Assignment
x <- 5
x = 5
Indentation and Line Length
- Use 2 spaces for indentation (never tabs)
- Keep lines under 80 characters when possible
- For long function calls, put each argument on its own line
do_something_complicated(
data = my_data,
arg_one = value_one,
arg_two = value_two,
arg_three = value_three
)
result <- data |>
filter(year >= 2020) |>
mutate(
new_var = old_var * 2,
another_var = str_to_lower(text_var)
) |>
summarise(
mean_value = mean(value),
.by = category
)
Comments
running_avg <- zoo::rollmean(values, k = 5)
x <- x + 1
File Organization
library(dplyr)
library(ggplot2)
source("R/helpers.R")
MAX_ITERATIONS <- 1000
DEFAULT_THRESHOLD <- 0.05
process_data <- function(data) {
}
main <- function() {
data <- read_csv("data/input.csv")
result <- process_data(data)
write_csv(result, "data/output.csv")
}
Function Design Guidelines
Single Responsibility
read_and_validate <- function(path) {
data <- read_csv(path)
validate_columns(data)
data
}
validate_columns <- function(data) {
required <- c("id", "value", "date")
missing <- setdiff(required, names(data))
if (length(missing) > 0) {
stop("Missing columns: ", paste(missing, collapse = ", "))
}
}
do_everything path output_path ...
Return Values
calculate_metrics <- function(data) {
metrics <- list(
mean = mean(data$value),
sd = sd(data$value),
n = nrow(data)
)
return(metrics)
}
square <- function(x) {
x^2
}
process <- function(x) {
if (is.null(x)) return(NULL)
result
Error Handling
Prefer cli::cli_abort() over stop() for user-facing errors. Structure messages as a problem statement followed by context bullets.
validate_input <- function(x, threshold = 0) {
if (!is.numeric(x)) {
cli::cli_abort(c(
"{.arg x} must be numeric.",
x = "You supplied {.cls {class(x)}}.",
i = "Convert with {.fn as.numeric} first."
))
}
if (any(x < threshold)) {
cli::cli_abort(c(
"{.arg x} must be >= {threshold}.",
x = "{sum(x < threshold)} value{?s} below threshold.",
i = "Set {.arg threshold} to adjust the lower bound."
))
clicli_abort
x
i
stop typeofx call.
Inline markup tokens:
{.arg x} — argument name (backtick-formatted)
{.fn foo} — function name
{.cls {class(x)}} — class name
{.val {value}} — literal value
{?s} — pluralisation (value{?s} → "value" or "values")
Default Arguments
summarise_data <- function(data, na.rm = TRUE, digits = 2) {
}
filter_data <- function(data, min_value = NULL, max_value = NULL) {
if (!is.null(min_value)) {
data <- filter(data, value >= min_value)
}
if (!is.null(max_value)) {
data <- filter(data, value <= max_value)
}
data
}
Tidyverse API Conventions
Data-First Argument
my_transform <- function(data, var, threshold = 0.5) {
data |>
filter({{ var }} > threshold)
}
data |> my_transform(value, threshold = 0.8)
Prefixed Non-Standard Arguments
group_summary <- function(.data, ..., .by = NULL) {
.data |>
summarise(..., .by = {{ .by }})
}
Consistent Return Types
my_function <- function(data) {
result <- data |>
filter(!is.na(value))
tibble::as_tibble(result)
}
Common Style Mistakes
Avoid These Patterns
x<-1+2
x <- 1 + 2
if ((x > 0)) {}
if (x > 0) {}
if (x == T) {}
if (x == TRUE) {}
x <- 1; y <- 2
x <- 1
y <- 2
attach(mtcars)
meanmpg
detachmtcars
meanmtcarsmpg
withmtcars meanmpg
mtcars pullmpg mean