Objective. Students will construct a layered ggplot2 visualization in R using geom, aesthetic mapping, faceting, and a custom theme, and export it as a 300 dpi PNG file.
This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.
VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.
In 2005, statistician Leland Wilkinson published The Grammar of Graphics, a framework that describes every statistical chart as a combination of independent, composable layers. Hadley Wickham adapted this framework into the R package ggplot2, released as part of the tidyverse. Instead of memorizing dozens of separate chart functions, you learn one consistent grammar and combine its parts to build almost any visualization imaginable.
The framework has six core components:
| Component | What it does | Example ggplot2 function |
|-----------|-------------|-------------------------|
| Data | The data frame being visualized | `ggplot(data = mpg)` |
| Aesthetics | Mappings from data variables to visual properties | `aes(x = displ, y = hwy, color = class)` |
| Geometries | The geometric shapes that represent data | `geom_point()`, `geom_bar()`, `geom_line()` |
| Statistics | Statistical transformations applied before plotting | `stat_smooth()`, `stat_bin()` |
| Coordinates | The coordinate system | `coord_flip()`, `coord_polar()` |
| Themes | Non-data visual styling | `theme_minimal()`, `theme_bw()` |
Faceting—splitting one plot into small multiples by a categorical variable—is a seventh practical tool, handled by `facet_wrap()` or `facet_grid()`.
The key mental model is that you add layers with `+`. Start with the canvas, then pile on geometry, aesthetics, facets, labels, and a theme one at a time.
Step 1 – Canvas
```r
ggplot(data = mpg, aes(x = displ, y = hwy))
```
This creates a blank coordinate plane. No points appear yet because no geometry has been specified.
Step 2 – Add geometry
```r
ggplot(data = mpg, aes(x = displ, y = hwy)) +
geom_point()
```
Now dots appear: engine displacement (liters) on the x-axis, highway miles per gallon on the y-axis.
Step 3 – Add a color aesthetic
```r
ggplot(data = mpg, aes(x = displ, y = hwy, color = class)) +
geom_point()
```
Maping `color` to `class` inside `aes()` tells ggplot2 to assign a distinct color to each vehicle class automatically and generate a legend.
Step 4 – Add faceting
```r
ggplot(data = mpg, aes(x = displ, y = hwy, color = class)) +
geom_point() +
facet_wrap(~ drv)
```
`facet_wrap(~ drv)` splits the plot into one panel per drive-train type (front, rear, four-wheel). Each panel shares the same axes, making comparisons honest.
Step 5 – Apply a theme and add labels
```r
ggplot(data = mpg, aes(x = displ, y = hwy, color = class)) +
geom_point() +
facet_wrap(~ drv) +
theme_minimal() +
labs(
title = "Engine Size vs. Highway MPG by Drive Train",
x = "Engine Displacement (L)",
y = "Highway MPG",
color = "Vehicle Class"
)
```
`theme_minimal()` removes the default grey background. `labs()` replaces machine-readable column names with human-readable labels. These two steps are often what separate a draft chart from a professional deliverable.
Screen resolution (72–96 dpi) is fine for on-screen viewing but insufficient for print or formal reports. Publication and most employer standards require 300 dpi minimum. Use `ggsave()` immediately after running your plot:
```r
ggsave(
filename = "my_chart.png",
plot = last_plot(),
width = 8,
height = 5,
units = "in",
dpi = 300
)
```
`last_plot()` captures whatever ggplot2 drew most recently. You can also assign your plot to an object (e.g., `p <- ggplot(...)`) and pass `plot = p` directly.
A common source of confusion: aesthetics that belong inside `aes()` are data-driven; properties set outside `aes()` are fixed for every point.
Mixing these up produces errors or silent misgrouping, which is a frequent debugging task in the field.
Data science work must be reproducible. Write your code in an `.R` script (not the console) and include these practices:
1. Load all packages at the top with `library(tidyverse)`.
2. Set a relative file path when reading CSV data so the script runs on any machine that has the project folder.
3. Place `ggsave()` at the bottom of the script so export is automatic whenever the script is sourced.
4. Add brief comments (`#`) to explain non-obvious choices.
Data visualization work involves real datasets that may contain personally identifiable information (PII) or confidential business data. Before loading any provided CSV:
These habits align with data-handling expectations tested on CompTIA Data+ and practiced across all four credentials in this program.
All syntax and concepts in this lesson are covered in R for Data Science by Hadley Wickham, Chapters 3 and 28, freely available at r4ds.had.co.nz.
Answer each question, then check it. Nothing is recorded; this is your own practice.
A free tech program — complimentary, as our commitment to get America working. Help us build VoTechWorks. Tell us what works, what doesn’t, and what you want to learn.