Anatomy of an R file
R is a language and environment for statistical computing and graphics, widely used among statisticians and data miners for data analysis.
File extensions: .r, .R
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside an R file
Comment
Single-line (#). R has no native block comment syntax.
Everything from a # to the end of the line is ignored by the parser. There is no /* ... */ equivalent: every line of a "block" comment needs its own #, which is why long-time R users eventually invent workarounds for multi-line notes. A common trick wraps prose in an if (FALSE) { ... } block: the body is parsed (so it must still be syntactically valid R) but never executed, letting you stash old code or scratch notes without deleting them. RStudio's "Insert Section" (# Section ---- ) is a lighter-weight convention for the same itch.
Library/package loading
Loads an installed package so its functions become available.
library(ggplot2) attaches an already-installed package to the search path so you can call ggplot() and friends without qualifying them. It throws an error if the package was never installed with install.packages("ggplot2") first: library() only attaches, it never fetches. require(ggplot2) behaves similarly but returns FALSE instead of erroring, which is occasionally used inside functions to conditionally handle a missing dependency. CRAN, the default package repository, currently hosts upwards of 20,000 packages, which is either R's greatest strength or the reason your dependency tree looks li
Variable assignment
Assigns values to names, conventionally with the <- arrow.
<- is the idiomatic assignment operator in R, though = also works at the top level. The arrow reads like data flowing into a name. x_vals <- 1:10 creates the integer sequence 1, 2, ..., 10 and binds it to x_vals. Vectors are the fundamental data type; even a single number is a length-one vector. data.frame(x = x_vals, y = y_vals) builds a table-like structure from named vectors of equal length, the workhorse container for tabular data before tidyverse alternatives like tibbles entered the picture. rnorm(10) draws 10 values from a standard normal distribution: handy for generating fake noise, o
Function definition
Creates a reusable block of code with function() { }.
Functions are ordinary values in R: calculate_stats <- function(df) { ... } assigns an anonymous function object to a name, the same way any other assignment would. The last evaluated expression in the body is returned implicitly, though an explicit return() call is common for clarity. Arguments can have default values (function(df, digits = 2)), and R's scoping is lexical: a function sees the environment where it was defined, not where it was called. This makes closures straightforward and is part of why functional-programming idioms feel native in R.
Control flow (conditional)
Executes code based on a condition (if, else).
if (nrow(df) > 5) { ... } else { ... } branches on a single logical value; the condition must evaluate to a length-one TRUE/FALSE (a vector condition triggers a warning or error depending on R version). Curly braces group the branch bodies, though single statements can omit them. R also has a vectorized cousin, ifelse(condition, yes, no), which applies element-wise across a whole vector instead of branching once: reaching for if when you meant ifelse is a classic way to silently process only the first element.
Control flow (loop)
Repeats code with for, while, or repeat.
for (col in names(df)) { ... } iterates directly over the elements of a vector or list (here, the column names of a data frame) rather than counting indices. while repeats as long as a condition holds, and repeat loops until an explicit break. Loops are the readable choice for side effects like printing, but R rewards vectorizing numeric work instead: functions like sapply(), vapply(), and Map() apply a function across a vector without an explicit loop, and usually run faster because they avoid growing an R-level object one iteration at a time.
Function call
Executes a user-defined or built-in function.
calculate_stats(data) invokes the function bound to that name, passing data as the argument df. R resolves the call by looking up calculate_stats in the current environment and walking outward through enclosing scopes if it is not found locally. print(stats_summary) is itself a function call: in fact, typing a bare value at the console implicitly calls print() on it via R's auto-printing mechanism. Almost everything in R, including control structures like if and for, is "just" a function call under the hood, which is a fun fact right up until you try to explain it to someone on their first day
Plotting command
Builds a graphic, often layer by layer with ggplot2.
ggplot(data, aes(x = x, y = y)) initializes a plot and maps data columns to visual properties (aesthetics), then + geom_point() and + geom_smooth(method = "lm") add layers (points and a fitted regression line) on top. This "grammar of graphics" approach composes complex figures from small, orthogonal pieces instead of one monolithic plotting call. Base R ships its own plotting system (plot(), hist(), barplot()) that predates ggplot2 and remains faster for quick, throwaway looks at data. ggplot2, part of the tidyverse, trades a steeper initial learning curve for far more consistent and customiz
Official R site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.