- Carpentries: ggplot2
- R Graph GalleryBrowse chart types with copy-paste code
- ggsci color palettesJournal-style color schemes for ggplot2
- ColorBrewerPick sequential and diverging color palettes
- ggplot2 point shapesReference for shape numbers
library(ggplot2)
gap <- read.csv("rawdata/gapminder.csv")
R has built-in plotting functions. They're quick but limited.
plot(x = gap$year, gap$lifeExp)
plot(x = gap$year, gap$lifeExp,
xlab = "Year", ylab = "Life Expectancy (yrs)")
hist(gap$lifeExp)
# Saving base R plots is awkward
jpeg("plots/lifeExp_histogram.jpg")
hist(gap$lifeExp, breaks = 30)
dev.off()
ggplot2 builds plots in layers. Every plot starts with data and aesthetics, then adds geoms (geometric objects).
# Start with data — empty canvas
ggplot(gap)
# Add aesthetics (x/y variables)
ggplot(gap, aes(x = gdpPercap, y = lifeExp))
# Add a geom layer — now you have points
ggplot(gap, aes(x = gdpPercap, y = lifeExp)) +
geom_point()
# Boxplot
ggplot(gap, aes(x = lifeExp, y = continent)) +
geom_boxplot()
Use str(gap) to explore the data. Find another variable to plot. Try year vs. lifeExp. Notice the problem with boxplot — fix it with group = year or as.factor(year).
Grouping by Year — Two Fixes
# Fix 1: tell ggplot to group by year
ggplot(gap, aes(x = year, y = lifeExp, group = year)) +
geom_boxplot()
# Fix 2: coerce year to a factor
gap %>%
mutate(year = as.factor(year)) %>%
ggplot(aes(x = year, y = lifeExp)) +
geom_boxplot()
# Set a fixed color
ggplot(gap, aes(x = gdpPercap, y = lifeExp)) +
geom_point(color = "blue", alpha = 0.5)
# Map color to a variable (inside aes)
ggplot(gap, aes(x = gdpPercap, y = lifeExp, color = continent)) +
geom_point(alpha = 0.5)
# ggsci palette (install.packages("ggsci") first)
library(ggsci)
ggplot(gap, aes(x = year, y = lifeExp, group = country, color = continent)) +
geom_line() +
scale_color_aaas()
# Manual colors (use ColorBrewer to pick)
ggplot(gap, aes(x = year, y = lifeExp, group = country, color = continent)) +
geom_line() +
scale_color_manual(values = c("#4a1486", "#6a51a3", "#807dba", "#9e9ac8", "#bcbddc"))
# Shapes and size
ggplot(gap, aes(x = gdpPercap, y = lifeExp, color = continent, shape = continent)) +
geom_point(alpha = 0.5, size = 2) +
scale_color_nejm()
# Layer boxplot + jitter
ggplot(gap, aes(x = lifeExp, y = continent)) +
geom_boxplot(outlier.alpha = 0) +
geom_jitter(alpha = 0.5, height = 0.3, aes(color = year))
# Labels and themes
ggplot(gap, aes(x = lifeExp, y = continent)) +
geom_boxplot(outlier.alpha = 0) +
geom_jitter(alpha = 0.5, height = 0.3, aes(color = year)) +
labs(x = "Life Expectancy (yrs)", y = "Continent", title = "LifeExp by Continent") +
theme_classic()
Pick any plot and test theme_bw(), theme_minimal(), theme_classic(), theme_light(). Pick your favorite.
Tweaking ggplot2 details (axis breaks, legend position, margins) is tedious to look up. Ask AI instead — describe exactly what you want.
The Finished Plot with AI Customizations
Plot1 <- ggplot(gap, aes(x = lifeExp, y = continent)) +
geom_boxplot(outlier.alpha = 0) +
geom_jitter(alpha = 0.5, height = 0.3, aes(color = year)) +
scale_x_continuous(breaks = seq(30, 90, by = 10), limits = c(30, 90)) +
theme(axis.title.y = element_text(angle = 0, vjust = 0.5)) +
labs(x = "Life Expectancy (yrs)", y = "Continent", title = "LifeExp by Continent") +
theme_classic()
Plot1
ggsave(Plot1, file = "plots/lifeByContinent.png", width = 5, height = 5, units = "in")
ggsave(Plot1, file = "plots/lifeByContinent.pdf", width = 5, height = 5, units = "in")
# Facet wrap — one panel per continent
ggplot(gap, aes(x = gdpPercap, y = lifeExp, color = continent)) +
geom_point() +
scale_x_log10() +
scale_color_nejm() +
theme_bw() +
facet_wrap(~ continent)
# Use AI to fix the legend position in faceted plots
ggplot(gap, aes(x = gdpPercap, y = lifeExp, color = continent)) +
geom_point() +
scale_x_log10() +
scale_color_nejm() +
theme_bw() +
facet_wrap(~ continent) +
theme(
legend.position = c(1, 0),
legend.justification = c("right", "bottom"),
plot.margin = unit(c(5.5, 5.5, 5.5, 5.5), "mm")
)
# Highlight a specific country with a second geom layer
dataUS <- gap %>% filter(country == "United States")
plot2 <- ggplot(gap, aes(x = gdpPercap, y = lifeExp, color = continent)) +
geom_point() +
scale_x_log10() +
facet_wrap(~ continent) +
geom_point(data = dataUS, aes(x = gdpPercap, y = lifeExp), color = "black")
ggsave(plot2, file = "plots/LifeGdpFacet.png", width = 5, height = 5, units = "in")
install.packages("patchwork")
library(patchwork)
multipanel <- Plot1 + plot2
ggsave(multipanel,
file = "plots/combo.png",
width = 8, height = 5, units = "in")
ggsave(multipanel,
file = "plots/combo.pdf",
width = 8, height = 5, units = "in")
At this point, AI is faster than documentation for tweaking plots. Describe what you want in plain English.
Axis labels and tick marks · Legend position and appearance · Font sizes and families · Color palette changes · Adding text or annotation labels · Adjusting margins · Changing background or gridlines. Describe what you see vs. what you want — AI will figure out the right theme() arguments.