plot(), points(), lines()Creates plots and adds points/lines
axis(), box()Adds custom axes and borders
text(), mtext()Adds labels in the plot or margins
hist()Makes histograms
boxplot()Compares distributions
barplot(), pie()Bar charts and pie charts
abline(), legend()Reference lines and legends
Base R — Histogram
A histogram, with color
Dataset: life_exp
hist() plots the distribution of a numeric column. col and border set the fill and outline.
hist(life_exp$Average_Life_Expectancy, main = "Histogram of Average Life Expectancy", xlab = "Average Life Expectancy", col = "lightblue", border = "grey")
Histogram, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a histogram of Average_Life_Expectancy with color — in base R. Compare what the AI gives you to the example above.
Base R — Histogram
Adding mean and median lines
Dataset: life_exp
abline() draws a reference line over an existing plot. legend() labels what each color means. Remember na.rm = TRUE — this column has missing values.
hist(life_exp$Average_Life_Expectancy, col = "lightblue", border = "black") abline(v = mean_le, col = "blue", lwd = 2) abline(v = median_le, col = "red", lwd = 2) legend("topleft", legend = c("Mean", "Median"), col = c("blue", "red"), lwd = 2)
Histogram + Lines, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — the same histogram with mean and median reference lines and a legend — in base R. Compare what the AI gives you to the example above.
Base R — Boxplot
Comparing distributions by group
Dataset: life_exp
boxplot() with formula syntax (numeric ~ category) compares a distribution across groups. col takes one color per box.
boxplot(Average_Life_Expectancy ~ Gender, data = life_exp, main = "Boxplot of Life Expectancy by Gender", xlab = "Gender", ylab = "Average Life Expectancy", col = c("lightblue", "lightgreen"))
Boxplot, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a boxplot of Average_Life_Expectancy by Gender, with one color per box — in base R. Compare what the AI gives you to the example above.
Base R — Scatter Plot
Points colored by category
Dataset: life_exp
pch sets the point shape (19 is a solid filled circle). ifelse() assigns a color conditionally, one value per row.
plot(life_exp$Year, life_exp$Average_Life_Expectancy, xlab = "Year", ylab = "Average Life Expectancy", main = "Life Expectancy Over Time by Gender", pch = 19, col = ifelse(life_exp$Gender == "Male", "blue", "red"))
Scatter Plot, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a scatter plot of Average_Life_Expectancy over Year, points colored by Gender — in base R. Compare what the AI gives you to the example above.
Base R — Line Plot
Two lines, a legend, and an annotation
Dataset: life_exp
subset() splits the data by group. lines() adds a second line to the same plot. range() sets axis limits wide enough for both. text() and abline() add the annotation.
plot(male_data$Year, male_data$Average_Life_Expectancy, type = "l", col = "blue", lwd = 2, xlim = range(life_exp$Year), ylim = range(life_exp$Average_Life_Expectancy, na.rm = TRUE)) lines(female_data$Year, female_data$Average_Life_Expectancy, col = "red", lwd = 2) legend("bottomright", legend = c("Male", "Female"), col = c("blue", "red"), lwd = 2) abline(v = 1918, col = "black", lty = 3) text(1918, 75, "End of World War I")
Line Plot, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — two life expectancy lines by Gender over Year, with a legend and a labeled reference line at 1918 — in base R. Compare what the AI gives you to the example above.
Base R — Bar Chart
Counting records by category
Dataset: air
table() counts how many rows fall into each category. barplot() turns those counts into bars.
type_counts <- table(air$Type_Name)
barplot(type_counts, main = "Number of Readings by Type", xlab = "Type", ylab = "Count", col = "steelblue")
Bar Chart, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a vertical bar chart counting air readings by Type_Name — in base R. Compare what the AI gives you to the example above.
Base R — Bar Chart
Same chart, horizontal
Dataset: air
horiz = TRUE flips the bars sideways — useful when category labels are long. las = 1 keeps axis labels horizontal for readability.
barplot(type_counts, main = "Number of Readings by Type", xlab = "Count", horiz = TRUE, col = "steelblue", las = 1)
Horizontal Bar Chart, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — the same bar chart of air readings by Type_Name, oriented horizontally — in base R. Compare what the AI gives you to the example above.
Base R — Pie Chart
Showing a share of the whole
Dataset: ev
table() counts each category again; pie() turns those counts into wedges sized by proportion.
pie(ev_type_counts, main = "Share of Vehicles by Type", col = c("cornflowerblue", "coral"))
Pie Chart, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a pie chart showing the share of ev by `Electric Vehicle Type` — in base R. Compare what the AI gives you to the example above.
Before You Continue
The choice AI can't make
AI can generate a working plot() call in one pass. It will not tell you whether a line chart, bar chart, or boxplot is the right choice for what you're trying to show — that depends on the shape of your data and the question you're asking.
ggplot2
Key Components
ggplot(data, aes())The base canvas and variable mapping
geom_point()Adds points — a scatterplot layer
geom_smooth()Adds a fitted trend line
geom_bar(), geom_boxplot()Bar charts and boxplots as layers
geom_histogram()Histograms as a layer
facet_wrap()Splits into panels by a category
labs(), theme_minimal()Labels and a clean, minimal look
Layers stack with +, in order.
ggplot2 — Points & Trend
A scatterplot with a fitted line
Dataset: ev
geom_point() adds the points; geom_smooth(method = "lm") adds a straight-line fit through them.
Write your own AI prompt to reproduce this chart — a scatterplot of Electric_Range over Model_Year with a linear trend line — with ggplot2. Compare what the AI gives you to the example above.
ggplot2 — Grouping
Coloring both layers by category
Dataset: ev
Mapping color inside the base aes() applies it to every layer that follows — both the points and the trend line. se = FALSE removes the shaded confidence band.
Write your own AI prompt to reproduce this chart — coloring both layers by category — with ggplot2. Compare what the AI gives you to the example above.
ggplot2 — Bar Chart
Counting records with geom_bar()
Dataset: air
geom_bar() counts rows per category automatically — no need to build the table yourself first, unlike base R's barplot().
ggplot(data = air, aes(x = Type_Name)) + geom_bar(fill = "steelblue") + labs(title = "Number of Readings by Type", x = "Type", y = "Count")
Bar Chart, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a bar chart counting air readings by Type_Name — with ggplot2. Compare what the AI gives you to the example above.
ggplot2 — Boxplot
Comparing distributions with geom_boxplot()
Dataset: life_exp
Unlike base R's formula syntax, ggplot2 maps the category to x and the numeric column to y directly in aes().
ggplot(data = life_exp, aes(x = Gender, y = Average_Life_Expectancy)) + geom_boxplot(fill = "lightgreen") + labs(title = "Life Expectancy by Gender", x = "Gender", y = "Average Life Expectancy")
Boxplot, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a boxplot of Average_Life_Expectancy by Gender — with ggplot2. Compare what the AI gives you to the example above.
ggplot2 — Histogram
Distributions with geom_histogram()
Dataset: life_exp
binwidth controls how wide each bar is — try changing it and notice how the shape of the distribution appears to change.
ggplot(data = life_exp, aes(x = Average_Life_Expectancy)) + geom_histogram(binwidth = 5, fill = "lightblue", color = "black") + labs(title = "Distribution of Life Expectancy", x = "Average Life Expectancy", y = "Count")
Histogram, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — a histogram of Average_Life_Expectancy with binwidth 5 — with ggplot2. Compare what the AI gives you to the example above.
Console OutputError in `geom_point()`:
! Problem while computing aesthetics.
Caused by error:
! object 'Electric_Rang' not found
Electric_Rang doesn't exist — the real column is Electric_Range
Prompt an AI to diagnose it, then verify against the actual column names in ev before trusting the fix
ggplot2 — Polished
Faceting, labels, and a theme together
Dataset: ev
facet_wrap() splits into panels by a category. labs() sets the title and axis labels. theme_minimal() strips the default gray background and gridlines.
ggplot(data = ev, aes(x = Model_Year, y = Electric_Range, color = `Electric Vehicle Type`)) + geom_point(alpha = .5) + geom_smooth(method = "lm", se = FALSE) + facet_wrap(~range_group) + labs(title = "Electric range by model year", x = "Model Year", y = "Electric Range (mi)") + theme_minimal()
Polished Plot, Prompted
Now prompt it
Now Prompt It
Write your own AI prompt to reproduce this chart — the faceted, labeled, and themed version of the electric range chart — with ggplot2. Compare what the AI gives you to the example above.
Before We Wrap
More layers isn't the goal
AI makes it easy to keep adding layers — a color mapping, a facet, a theme — without stopping to check whether each one adds clarity or just complexity. Before accepting a plot, ask whether a reader unfamiliar with the data could state its main point in one sentence.
Suggested Reading
Go deeper
1. Wickham, Hadley. 2010. "A Layered Grammar of Graphics." Journal of Computational and Graphical Statistics 19, no. 1: 3–28.
2. Healy, Kieran. 2018. Data Visualization: A Practical Introduction. Princeton University Press.
Wickham for the logic behind ggplot2; Healy for visualization design and practice more broadly.
Group Hackathon
Data Manipulation & Visualization — Your Own Dataset
Import your own dataset.
Part 1 — Manipulation (base R + dplyr)
Index/subset rows and columns
Filter — a single condition, then combined (&/|)
Rename a column; create a new variable
Convert a column's type (e.g., to factor)
Missing values: count them, then compare a summary stat with vs. without them
Part 2 — Visualization (base R + ggplot2)
Histogram, bar chart (vertical & horizontal), pie chart, boxplot, scatterplot — your own style
Export your charts to .pdf and .jpg
Work time: 15 minutes. Presentation: 3 minutes per group. On PowerPoint, show your code and output for each task — not a live run. Every group member must complete at least one task themselves.
Live Share
Show us what you got
Volunteers walk us through the plot, the code, and how the prompt compared once they tried it.
Recap
Two engines, one habit
hist(), boxplot(), barplot(), pie(), plot() — one function, many arguments, in base R
abline(), legend(), text() — layering reference lines, legends, and annotations
ggplot2 — a base mapping, one or more geoms, then optional layers for grouping, facets, labels, and themes
Carry This Forward
Code first, understanding first — and before trusting any plot, ask what a reader unfamiliar with the data would actually take from it.