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



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:

R
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

R
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?

100%
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:

R
library(ggplot2)
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()


4. The First ggplot2 Plot

(1) 5-Step Drawing Process

R
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:

R
ggplot(df, aes(x = x, y = y)) +
  geom_point() +
  labs(title = "Quadratic Curve", x = "X", y = "Y") +
  theme_minimal()
💡 Tip: In ggplot2, use + to chain layers, similar to how |> is used to chain data operations.

(2) Output to a file

R
# 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

R
# 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()

R
# 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
💡 Tip: 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

R
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

R
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

R
# 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()
⚠️ Note: geom_bar(stat = "identity") uses the y-values from the data; geom_bar() counts by default.

(4) geom_histogram() Histogram

R
# 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

R
# 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

R
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
R
# 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

R
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

R
# 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

R
# 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

R 📖 Display only
# ============================================
# 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")
61 logic lines (exceeds 40-line limit, display only)

Expected output: 5 publication-quality charts (the default "theme_minimal" is already attractive enough).


❓ FAQ

Q Should I use ggplot2 or basic R?
A Use ggplot2 for publications, papers, and reports (publication-quality visuals + consistent style); use basic R for a quick look at data (one-line plotting). This tutorial focuses primarily on ggplot2.
Q What’s the difference between inside and outside of aes()?
A Inside 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.
Q What is the difference between geom_bar() and geom_col()?
A geom_bar(stat = "identity") uses a y value; geom_col() is its syntactic sugar (more concise). geom_bar() counts by default (no y required).
Q How do I add comments?
A Use geom_text() / geom_label():
R
ggplot(df, aes(x, y)) + geom_point() +
  geom_text(aes(label = name), vjust = -0.5)  # Add labels above the data points
Q How do I remove the legend?
A theme(legend.position = "none").
Q How do I save high-resolution images?
A ggsave("plot.png", dpi = 300, width = 8, height = 6), 300 dpi is the standard for printing.

📖 Summary


📝 Exercises

  1. Basic Exercise: Create a data frame (10 rows, 2 columns of x and y values), use ggplot + geom_point + labs + theme_minimal to plot a scatter plot, and verify the difference between color = "red" (inside) and color = "red" (outside) in aes().

  2. Basic Exercise: Create a scatter plot using the mtcars dataset (wt vs mpg), color the points according to cyl (color = factor(cyl)), and add a title and theme using labs().

  3. Basic Exercise: Create a data frame (5 cities + sales figures), use geom_col() to plot a bar chart, sort the data using reorder(city, sales), and verify the sorting results.

  4. Advanced Exercise: Simulate the scores for Class 4 with 30 students, use geom_boxplot() to plot a score distribution chart for Class 4, and add fill = class for fill color and theme_minimal() for a theme.

  5. Challenge: Use mtcars to create 6 figures (combining the par(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.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏