Two Continuous Variables

When you have two continuous variables, you are often interested in whether they covary: does one tend to change as the other changes?

Scatterplots

Do: run the code below to explore the relationship between engine displacement (displ) and highway mileage (hwy).

See: as displacement increases, highway mileage tends to decrease: a negative relationship. The points are fairly spread out, so it doesn’t look like a perfectly straight line.

Predict: if you had to summarise this pattern with a single line or curve drawn through the cloud of points, do you think a straight line would fit well, or does the pattern look like it curves?

Explain: the relationship looks broadly linear and negative, though there’s a lot of scatter around any single line, especially at low displacement values where mileage varies a lot.

Adding a fitted trend

Do: run this to add a smoothed trend line to the plot.

See: a curved trend line appears, with a grey confidence band around it, summarising the general relationship.

Predict: the message printed above the plot says geom_smooth() using method = 'loess'. Another method we can pick is lm. What do you think method = "lm" would do differently?

Explain: "loess" showed to fit a flexible, locally-weighted curve that can bend to follow local patterns in the data. "lm" fits a single straight line (linear regression) through the whole dataset. Both are valid summaries of the same relationship: "lm" assumes the relationship is linear everywhere, while "loess" makes no such assumption.

Adding a third variable: vehicle class

So far we’ve only used two variables. Just like with a single continuous variable, we can map a third variable onto colour to see whether it helps explain the pattern.

Do: colour the points by class (vehicle class).

See: the points now form distinct coloured clusters, and some classes sit clearly above or below the general cloud of points.

Predict: 2-seater sports cars have large engines, which on their own would predict poor highway mileage. Do you think 2-seaters follow the overall downward trend as strongly as the other classes, or do they behave differently? To check properly, we can fit one straight trend line per class instead of eyeballing the cloud of points, by combining the colour grouping with geom_smooth(method = "lm", se = FALSE). What do you expect this to show for 2-seaters compared to, say, SUVs?

Explain: A separate straight-line fit is drawn for each vehicle class (with se = FALSE switching off the confidence bands to keep the plot readable). The 2-seater line sits noticeably higher and flatter than the lines for classes like suv or pickup. Because geom_smooth() inherits the colour = class mapping from ggplot(), it fits one straight line per group instead of a single overall line. This confirms that 2-seaters don’t lose as much mileage as their engine size alone would suggest: they’re much lighter than SUVs or pickups with similarly sized engines, so their trend sits above and is flatter than the rest. Colouring by class and fitting a trend per group together show that the overall downward relationship is real, but it isn’t uniform across vehicle classes.

Common mistake: forgetting to share the mapping

A common mistake when trying to fit a line per group is to map colour on the wrong layer, so it never reaches geom_smooth().

Do: run the following, which looks almost identical to the version above except for where colour = class is placed.

See: the points are still coloured by class, but now there’s only a single straight trend line fitted across all the data, rather than one line per class.

Explain: here, colour = class was supplied only to geom_point(), not to the shared aes() inside ggplot(). Each layer only uses the mappings it’s given directly, plus whatever was set in ggplot() itself. This means that it does not pick up mappings from other layers. Since geom_smooth() never receives colour = class, it has no reason to split the data into groups, so it falls back to fitting one overall trend line. To get a line per group, the mapping needs to live in ggplot() (or be repeated on geom_smooth() directly), not just on geom_point().

Practice exercise

Using mpg, build a scatterplot of cty (x-axis) against hwy (y-axis), colouring the points by drv (drive type), with one trend line fitted per group. Try this first with the default smoothing method, then with method = "lm". How do the two sets of trend lines differ, and why?

Think back to what each method assumes about the shape of the relationship: one bends to follow local patterns in the data, the other fits a single straight line.

ggplot(mpg, aes(x = cty, y = hwy, colour = drv)) +
  geom_point() +
  geom_smooth()

ggplot(mpg, aes(x = cty, y = hwy, colour = drv)) +
  geom_point() +
  geom_smooth(method = "lm")

With the default method ("loess"), each group gets a flexible curve that can bend to follow local patterns within that drive type. With method = "lm", each group instead gets a single straight line summarising its overall trend. Both give one fitted line per drv group, since colour = drv is inherited by geom_smooth() either way, the difference is only in how flexible each individual line is allowed to be.

Back to top