4  Graphing in R and Excel

Learning Objectives

By the end of this module you should be able to:

  1. Create publication-quality charts in R using ggplot2.
  2. Understand the grammar of graphics and why ggplot2 is structured the way it is.
  3. Choose an appropriate chart type for a given question.
  4. Make the same chart in both Excel and R and understand the tradeoffs.
  5. Export charts for use in reports and presentations.

4.1 Why a New Grammar?

You know how to make charts in Excel (Module 1). Why learn another way?

The short answer is that ggplot2 — R’s most popular visualization package — produces charts that are better than Excel’s by default, more flexible when you need to customize them, and reproducible because they are generated from code. The long answer is that ggplot2 is built on an idea called the grammar of graphics (from Leland Wilkinson’s 1999 book of the same name), which organizes charts in a way that, once you understand it, makes making new kinds of charts feel like building with LEGO instead of hunting through menus.

The grammar of graphics says that every chart is a combination of a few basic elements:

  • Data — the dataset being plotted.
  • Aesthetics — mappings from data columns to visual properties (x, y, color, size, shape).
  • Geometries — the shapes that appear on the page (points, lines, bars, boxes).
  • Statistics — transformations of the data done as part of plotting (binning for histograms, smoothing for trend lines).
  • Scales — how data values map to aesthetic values (linear vs log axes, color palettes).
  • Coordinate systems — Cartesian, polar, etc.
  • Faceting — splitting the chart into small multiples by a categorical variable.

Every ggplot2 chart is built by adding these layers together. Once you understand the grammar, you can construct any chart you can imagine.

4.2 Your First ggplot

ggplot2 is part of the tidyverse, so if you have loaded the tidyverse, it’s already available.

A basic scatter plot:

ggplot(yields, aes(x = acres, y = yield_bu_acre)) +
  geom_point()

Break it down:

  • ggplot(yields, ...) — start a new plot using the yields data frame.
  • aes(x = acres, y = yield_bu_acre) — the aesthetic mapping. The x position is mapped to the acres column, the y position to the yield_bu_acre column.
  • + geom_point() — add a point geometry. Each row in the data becomes one point.

Note the + — ggplot2 layers are added with +, not the pipe. A common beginner mistake is to use |> instead. Don’t.

4.3 The Main Geoms

A tour of the most important geom_ functions. In each case, you set the aesthetic mapping with aes() and the geom draws something based on those mappings.

geom_point() — Scatter Plots

For showing the relationship between two continuous variables.

ggplot(yields, aes(x = acres, y = yield_bu_acre)) +
  geom_point(alpha = 0.5)  # alpha = transparency, helps when points overlap

geom_line() — Line Charts

For showing how a value changes over a continuous variable (usually time).

annual_mean <- yields |>
  group_by(year) |>
  summarise(mean_yield = mean(yield_bu_acre, na.rm = TRUE))

ggplot(annual_mean, aes(x = year, y = mean_yield)) +
  geom_line() +
  geom_point()

Notice that we summarized first, then plotted. ggplot2 does not have a built-in “line connecting the means” geom; you compute the means and then plot them.

geom_col() and geom_bar() — Bar Charts

geom_col() plots bars with heights equal to values you give it. Use this when you have already computed the values.

region_means <- yields |>
  group_by(region) |>
  summarise(mean_yield = mean(yield_bu_acre, na.rm = TRUE))

ggplot(region_means, aes(x = region, y = mean_yield)) +
  geom_col()

geom_bar() counts rows automatically. Use it when you have un-summarized data and want bar heights to be counts.

ggplot(yields, aes(x = region)) + geom_bar()

These confuse new users constantly. Rule of thumb: if your data is already summarized, use geom_col; if you want ggplot to count things for you, use geom_bar.

geom_histogram() — Histograms

For showing the distribution of a single continuous variable.

ggplot(yields, aes(x = yield_bu_acre)) +
  geom_histogram(bins = 30)

The bins argument controls how many bins to use. ggplot will print a warning if you don’t set it, nudging you to think about bin width.

geom_boxplot() — Box Plots

For comparing distributions across categories.

ggplot(yields, aes(x = region, y = yield_bu_acre)) +
  geom_boxplot()

This shows, for each region, the median, quartiles, and outliers of yield — side by side.

geom_smooth() — Trend Lines

Adds a smoother to a scatter plot.

ggplot(yields, aes(x = acres, y = yield_bu_acre)) +
  geom_point(alpha = 0.3) +
  geom_smooth(method = "lm")  # lm = linear regression

Use method = "lm" for a straight line; omit for a flexible nonparametric smoother. Useful for visual inspection of trends, but don’t confuse a visual smoother for a rigorous model — that comes later.

4.4 Mapping vs Setting Aesthetics

A critical distinction. Consider these two:

# Mapping: color depends on region
ggplot(yields, aes(x = acres, y = yield_bu_acre, color = region)) +
  geom_point()

# Setting: all points are blue
ggplot(yields, aes(x = acres, y = yield_bu_acre)) +
  geom_point(color = "blue")

When you want an aesthetic to depend on the data (each region gets its own color), put it inside aes(). When you want to set it to a constant (all points blue), put it outside aes(). This trips people up. If you see colors that don’t look right, check whether your color argument is in the right place.

4.5 Labels, Titles, and Themes

A bare ggplot is functional but ugly. Polish it with labs() and a theme_:

ggplot(yields, aes(x = acres, y = yield_bu_acre, color = region)) +
  geom_point(alpha = 0.6) +
  labs(
    title = "Canola yield by field size",
    subtitle = "Saskatchewan, 2025",
    x = "Field size (acres)",
    y = "Yield (bu/acre)",
    color = "Region",
    caption = "Data: [TBD]"
  ) +
  theme_minimal()

theme_minimal() is a clean, publication-ready default. Other good ones: theme_classic(), theme_bw(). Avoid the default grey background for anything you will show in public.

4.6 Faceting

Often the most powerful thing you can do with ggplot is split the chart into small multiples:

ggplot(yields, aes(x = yield_bu_acre)) +
  geom_histogram(bins = 30) +
  facet_wrap(~ region)

This produces one histogram per region, in a grid. Much easier to read than a single chart with overlapping histograms or legends.

facet_grid(region ~ variety) makes a two-dimensional grid. Useful for comparing combinations.

4.7 Saving Plots

my_plot <- ggplot(yields, aes(x = region, y = yield_bu_acre)) +
  geom_boxplot()

ggsave("region_boxplot.png", plot = my_plot, width = 6, height = 4, dpi = 300)

Specify dimensions in inches and a DPI of 300 for print quality. PNG is fine for slides and web; PDF or SVG for publication.

4.8 Excel vs R for Charts

I want to be honest about this: Excel charts are fine for many purposes. They are easy to make, they look acceptable with default settings, and they are immediately editable by non-technical colleagues. If you are making a one-off chart for an internal meeting, Excel may be the right choice.

R (ggplot2) wins when you need:

  • The chart to be reproducible from a script.
  • The chart to update automatically as the underlying data changes.
  • Many similar charts (via faceting or loops).
  • Fine-grained control over appearance.
  • Statistical features (trend lines, confidence bands, quantile ribbons).

Most working analysts use both. In this course we will favor R because it builds the reproducibility muscle, which is harder to build than the Excel-chart muscle.

4.9 Test Bank Sample

  1. (Concept.) Explain the difference between aes() and setting an aesthetic outside aes().
  2. (ggplot.) Write ggplot2 code to produce a scatter plot of yield vs acres, colored by region, with a linear trend line added.
  3. (Choice.) You want to compare the distribution of yields across four varieties. Which geom would you use?
  4. (Polish.) Add appropriate titles, axis labels, and a theme to a plot.
  5. (Faceting.) Describe a situation where facet_wrap is more useful than adding color = to the aesthetic.

4.10 Practice Exercises

  1. Make a histogram of yields, faceted by region, and write a short interpretation.
  2. Reproduce one of your Module 1 Excel charts in ggplot2. Which do you prefer?
  3. Make a scatter plot with a linear smoother and one without. How do they differ?
  4. [TBD: chart critique exercise with an ugly default Excel chart.]