R: R ggplot2
Last updated: 2026-08-26
In the previous lesson, we covered basic R plotting—fast but ugly. In this lesson, we’ll dive into R’s true “secret weapon”—ggplot2. Designed by Hadley Wickham, its “Grammar of Graphics” syntax makes plotting as easy as “building with blocks,” produces publication-quality visuals by default, and is used in 90% of R academic papers.
After completing this lesson, you’ll be able to create 5 core types of charts using ggplot2 and understand the core concept of “layering.”
1. What You'll Learn
- ggplot2 core: Grammar of Graphics syntax
- The "ggplot() + aes() + geom_xxx()" trio
- 5 basic geoms:point / line / bar / histogram / boxplot
- Aesthetic mapping aes(x, y, color, size, shape)
- labs() tag + theme_minimal() theme
- Key Differences Between ggplot2 and Basic R
2. A Story of Data Visualization
(1) Pain Point: Basic R is too ugly
Bob used basic R to create a chart showing sales trends in four cities:
plot(1:4, sales, type = "b")
The manager glanced at it and asked, "Can this image be included in the report?"
(2) The ggplot2 Solution
library(ggplot2)
ggplot(sales_df, aes(x = quarter, y = sales, color = city, group = city)) +
geom_line(linewidth = 1) +
geom_point(size = 3) +
labs(title = "Q1-Q4 Sales Trends", x = "Quarter", y = "Sales") +
theme_minimal()
4 lines of code + default publication-quality visuals. That’s the power of ggplot2.
3. Core Concepts of "Grammar of Graphics"
(1) What is the Grammar of Graphics?
graph TB
A[ggplot2 Charts] --> B[Data Data<br/>data]
A --> C[Aesthetic Mapping Aesthetics<br/>aes]
A --> D[Geometric Objects Geometries<br/>geom_xxx]
A --> E[Statistical Transformations Statistics<br/>stat_xxx]
A --> F[Coordinate System Coordinate<br/>coord_xxx]
A --> G[Sub-section Facet<br/>facet_xxx]
A --> H[Topic Theme<br/>theme_xxx]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
style F fill:#ffe1e1
style G fill:#e1ffe1
style H fill:#ffe1d4
In a nutshell: ggplot2 breaks down a plot into 7 layers, each of which is independent and replaceable.
(2) The Three Pillars of ggplot2
| Function | Purpose | Example |
|---|---|---|
ggplot() |
Initialization (Specified Data) | ggplot(df) |
aes() |
Aesthetic Mapping (Variables → Visuals) | aes(x, y, color) |
geom_xxx() |
Geometric Objects (Layers) | geom_point() |
Minimal Example:
library(ggplot2)
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point()
4. The First ggplot2 Plot
(1) 5-Step Drawing Process
library(ggplot2)
# 1. Prepare data
df <- data.frame(
x = 1:10,
y = (1:10) ^ 2
)
# 2. Initialization(Data)
p <- ggplot(df, aes(x = x, y = y))
# 3. Add a Layer
p <- p + geom_point()
# 4. Add a tag
p <- p + labs(title = "Quadratic Curve", x = "X", y = "Y")
# 5. Add a topic
p <- p + theme_minimal()
# 6. Print
print(p)
Or use + to do it all in one go:
ggplot(df, aes(x = x, y = y)) +
geom_point() +
labs(title = "Quadratic Curve", x = "X", y = "Y") +
theme_minimal()
+ to chain layers, similar to how |> is used to chain data operations.
(2) Output to a file
# Save as PNG
ggsave("myplot.png", width = 8, height = 6, dpi = 300)
# Save as PDF(For a thesis)
ggsave("myplot.pdf", width = 8, height = 6)
# Custom Size
ggsave("myplot.png", width = 10, height = 8, units = "cm", dpi = 300)
5. Aesthetic Mapping aes()
(1) Common Mappings
| Mapping | Function | Example |
|---|---|---|
x, y |
X / Y coordinates | aes(x = age, y = height) |
color / colour |
color (outer) | aes(color = gender) |
fill |
Fill Color (Bar/Area) | aes(fill = region) |
size |
Font Size | aes(size = amount) |
shape |
Dot Shape | aes(shape = category) |
alpha |
Transparency | aes(alpha = weight) |
linetype |
Linear | aes(linetype = type) |
(2) Practical Application: 3-D Mappings
# Color + Size + Shape 3 dimensions
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl), size = hp)) +
geom_point(alpha = 0.7) +
labs(title = "Vehicle Weight vs Fuel Consumption", color = "Number of cylinders", size = "Horsepower")
(3) ⚠️ Inside vs. Outside of aes()
# aes() Inside:Map to a variable(Each dot is a different color)
ggplot(df, aes(x, y, color = group)) + geom_point()
# → Different group Display different colors
# aes() Outside:Fixed value(All dots are the same color)
ggplot(df, aes(x, y)) + geom_point(color = "red")
# → All the dots are red
color = "red" inside aes() will be interpreted as the "red column" (if the data contains a red column). Fixed colors must be placed outside aes().
6. 5 Basic Geoms
(1) geom_point() Scatter Plot
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
geom_point(size = 3) +
labs(title = "Vehicle Weight vs Fuel Consumption", x = "Weight", y = "Fuel Consumption")
(2) geom_line() Line Chart
df <- data.frame(
x = 1:10,
y = c(2, 4, 3, 5, 4, 6, 5, 7, 6, 8),
group = "A"
)
ggplot(df, aes(x = x, y = y)) +
geom_line(color = "blue", linewidth = 1) +
geom_point(color = "blue", size = 3)
(3) geom_bar() Bar Chart
# Data
df <- data.frame(
city = c("Beijing", "Shanghai", "Guangzhou", "Shenzhen"),
sales = c(4800, 7000, 3900, 4500)
)
# Bar Chart
ggplot(df, aes(x = city, y = sales, fill = city)) +
geom_bar(stat = "identity") + # identity = Use y values
labs(title = "Total Sales by City", x = "City", y = "Sales") +
theme_minimal()
geom_bar(stat = "identity") uses the y-values from the data; geom_bar() counts by default.
(4) geom_histogram() Histogram
# 1000 A random number from a normal distribution
data <- data.frame(x = rnorm(1000, mean = 100, sd = 15))
ggplot(data, aes(x = x)) +
geom_histogram(bins = 30, fill = "skyblue", color = "white") +
labs(title = "Normal Distribution", x = "Value", y = "Frequency")
(5) geom_boxplot() Box Plot
# 4 Class Test Scores
scores <- data.frame(
class = rep(c("1Cls", "2Cls", "3Cls", "4Cls"), each = 10),
score = c(rnorm(10, 80, 8), rnorm(10, 75, 10),
rnorm(10, 85, 7), rnorm(10, 70, 12))
)
ggplot(scores, aes(x = class, y = score, fill = class)) +
geom_boxplot() +
labs(title = "4 Class Grade Distribution", x = "Class", y = "Fractions")
7. Tags and Topics
(1) labs() tag
ggplot(df, aes(x, y)) +
geom_point() +
labs(
title = "Main Title",
subtitle = "Subtitle",
caption = "Data Sources:xxx",
x = "X Axis",
y = "Y Axis",
color = "Color Mapping",
fill = "Fill Mapping"
)
(2) Theme theme_xxx()
| Theme | Style |
|---|---|
theme_minimal() |
Minimalist (Most Common) |
theme_bw() |
Black and White |
theme_classic() |
Classics (Academic) |
theme_void() |
Blank |
theme_light() |
Light |
theme_dark() |
Dark |
# Comparison 4 Topics
p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
(p + theme_minimal()) # Default Recommendation
(p + theme_bw())
(p + theme_classic())
(p + theme_void())
(3) Fine-Tuning the Theme
p + theme(
plot.title = element_text(size = 16, face = "bold"),
axis.text = element_text(size = 10),
legend.position = "bottom" # Legend Location
)
8. Colors and Mappings
(1) Discrete Colors
# 1. Built-in Color Palette
p + scale_color_brewer(palette = "Set1") # Classic
p + scale_color_brewer(palette = "Dark2") # Dark
p + scale_color_brewer(palette = "Pastel1") # Light-colored
# 2. Specify manually
p + scale_color_manual(values = c("red", "blue", "green"))
# 3. rainbow
p + scale_color_manual(values = rainbow(4))
(2) Continuous Color
# Gradient(For continuous variables)
p + scale_color_gradient(low = "blue", high = "red")
p + scale_color_viridis_c() # viridis(Recommendations)
p + scale_color_distiller(palette = "RdYlBu")
9. Complete Example: Multi-Image Sales in 4 Cities
Below is an example of a complete workflow that ties together all the concepts covered in this lesson.
▶ Example: 4 Cities, 5 Photos Collection
# ============================================
# 4 City Sales 5 Image Gallery
# Features:Use ggplot2 to create 5 publication-quality charts
# ============================================
library(ggplot2)
library(dplyr)
library(tidyr)
# 1. Prepare data
sales_wide <- tibble(
city = c("Beijing", "Shanghai", "Guangzhou", "Shenzhen"),
Q1 = c(1000, 1500, 800, 1200),
Q2 = c(1200, 1800, 900, 1400),
Q3 = c(1100, 1700, 1000, 1300),
Q4 = c(1500, 2000, 1200, 1600)
)
sales_long <- sales_wide |>
pivot_longer(cols = -city, names_to = "quarter", values_to = "sales")
cat("=== Sales Data ===\n")
print(sales_long)
# 2. Plot 1:Linear Trend(By City)
p1 <- ggplot(sales_long, aes(x = quarter, y = sales, color = city, group = city)) +
geom_line(linewidth = 1) +
geom_point(size = 3) +
labs(title = "Q1-Q4 Sales Trends", x = "Quarter", y = "Sales", color = "City") +
scale_color_brewer(palette = "Set1") +
theme_minimal()
print(p1)
# 3. Plot 2:Total Sales Bar Chart
total_sales <- sales_wide |>
mutate(total = Q1 + Q2 + Q3 + Q4) |>
select(city, total)
p2 <- ggplot(total_sales, aes(x = reorder(city, total), y = total, fill = city)) +
geom_bar(stat = "identity") +
coord_flip() + # Sideways
labs(title = "Total Sales by City", x = "City", y = "Total Sales") +
theme_minimal() +
theme(legend.position = "none")
print(p2)
# 4. Plot 3:Pie Chart of Percentage Distributions(geom_bar + coord_polar)
p3 <- ggplot(total_sales, aes(x = "", y = total, fill = city)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") + # Polar Coordinates(Pie Chart)
labs(title = "Share of Sales") +
theme_void() +
scale_fill_brewer(palette = "Set2")
print(p3)
# 5. Plot 4:Histogram(All Sales Data)
p4 <- ggplot(sales_long, aes(x = sales, fill = city)) +
geom_histogram(bins = 10, alpha = 0.7, position = "identity") +
labs(title = "Sales Distribution", x = "Sales", y = "Frequency") +
scale_fill_brewer(palette = "Set1") +
theme_minimal()
print(p4)
# 6. Plot 5:Box-and-Whisker Plot(By City)
p5 <- ggplot(sales_long, aes(x = city, y = sales, fill = city)) +
geom_boxplot() +
labs(title = "Sales Distribution by City", x = "City", y = "Sales") +
theme_minimal() +
theme(legend.position = "none")
print(p5)
# 7. Save All Images
ggsave("01_trend.png", p1, width = 8, height = 6, dpi = 300)
ggsave("02_total.png", p2, width = 8, height = 6, dpi = 300)
ggsave("03_pie.png", p3, width = 8, height = 6, dpi = 300)
ggsave("04_hist.png", p4, width = 8, height = 6, dpi = 300)
ggsave("05_box.png", p5, width = 8, height = 6, dpi = 300)
cat("\n=== 5 The image has been saved ===\n")
cat(" 01_trend.png - Linear Trend\n")
cat(" 02_total.png - Bar Chart Comparison\n")
cat(" 03_pie.png - Pie Chart of Percentage Distributions\n")
cat(" 04_hist.png - Histogram\n")
cat(" 05_box.png - Urban Box Lines\n")
Expected output: 5 publication-quality charts (the default "theme_minimal" is already attractive enough).
❓ FAQ
aes() is a variable mapping (e.g., color = group where each group has a different color); outside aes() is a fixed value (e.g., color = "red" where everything is red). Placing "red" inside aes() will be treated as a column name.geom_bar() and geom_col()?geom_bar(stat = "identity") uses a y value; geom_col() is its syntactic sugar (more concise). geom_bar() counts by default (no y required).geom_text() / geom_label():ggplot(df, aes(x, y)) + geom_point() +
geom_text(aes(label = name), vjust = -0.5) # Add labels above the data points
theme(legend.position = "none").ggsave("plot.png", dpi = 300, width = 8, height = 6), 300 dpi is the standard for printing.📖 Summary
- ggplot2 is based on the Grammar of Graphics and breaks down plots into 7 layers (data, aesthetics, geometry, statistics, coordinates, facets, and themes)
- The Three Pillars:
ggplot()(Data) +aes()(Mapping) +geom_xxx()(Layers) - 5 basic geom types: point / line / bar / histogram / boxplot
Aesthetic Mapping:
colorfillsizeshapealphalinetype aes()Inside = variable mapping;aes()Outside = fixed value- Use
theme_minimal(),theme_bw(), etc., for themes; usescale_color_brewer(palette = "Set1")for color palettes ggsave()Save image (dpi = 300, printing standard)- ggplot2 offers publication-quality visuals by default—it’s used in all professional R reports and papers
📝 Exercises
-
Basic Exercise: Create a data frame (10 rows, 2 columns of x and y values), use
ggplot + geom_point + labs + theme_minimalto plot a scatter plot, and verify the difference betweencolor = "red"(inside) andcolor = "red"(outside) inaes(). -
Basic Exercise: Create a scatter plot using the
mtcarsdataset (wtvsmpg), color the points according tocyl(color = factor(cyl)), and add a title and theme usinglabs(). -
Basic Exercise: Create a data frame (5 cities + sales figures), use
geom_col()to plot a bar chart, sort the data usingreorder(city, sales), and verify the sorting results. -
Advanced Exercise: Simulate the scores for Class 4 with 30 students, use
geom_boxplot()to plot a score distribution chart for Class 4, and addfill = classfor fill color andtheme_minimal()for a theme. -
Challenge: Use
mtcarsto create 6 figures (combining thepar(mfrow)style with ggplot2): ① Scatter plot of wt vs. mpg ② Histogram of wt distribution ③ Box plot of mpg ④ wt vs. mpg by cylinder ⑤ Color-mapped scatter plot ⑥ Complete theme customization. Save the 6 plots as a PDF.