Elements of Data Science
SDS 322E

H. Sherry Zhang
Department of Statistics and Data Sciences
University of Texas at Austin

Get the repository for today:
library(usethis)
create_from_github("SDS322E-26FALL/0303-viz2", fork = FALSE)

Learning objectives

Expand your ggplot2 skills:

  • Construct a ggplot with multiple geometries
  • Understand when to use an aesthetic, such as color, inside or outside aes()
  • New geometries for text and label: geom_text(), geom_label()

Combining multiple geometries

gapminder |> 
  ggplot(aes(x = year, y = lifeExp, group = country)) +
  geom_line()

What if I want to highlight some points in the map? Say two points: 2007 for USA and Australia?

Combining multiple geometries - a naive try

What if we just add geom_point() to the above code?

gapminder |> 
  ggplot(aes(x = year, y = lifeExp, group = country)) +
  geom_line() + 
  geom_point()

We only want to highlight two points, not all the points

Combining multiple geometries - keep building

Separate dataset for each layer:

  • geom_line() - data: gapminder
  • geom_point() - data: only 2007 USA and Australia in the gapminder data
gapminder_2007 <- gapminder |> 
  filter(year == 2007,
         country %in% c("United States", 
                        "Australia")
         )
gapminder_2007
# A tibble: 2 × 6
  country continent  year lifeExp    pop gdpPercap
  <fct>   <fct>     <int>   <dbl>  <int>     <dbl>
1 Austra… Oceania    2007    81.2 2.04e7    34435.
2 United… Americas   2007    78.2 3.01e8    42952.
ggplot() +
  geom_line(data = gapminder, 
            aes(x = year, y = lifeExp, group = country)) +
  geom_point(data = gapminder_2007, 
             aes(x = year, y = lifeExp))

We still can’t really see the two points ….

Combining multiple geometries - make it better

Make the two points bigger and a more distinguish color

ggplot() +
  geom_line(data = gapminder, 
            aes(x = year, y = lifeExp, group = country)) +
  geom_point(data = gapminder_2007, 
             aes(x = year, y = lifeExp), color = "red", size = 3)

Much better :)

All the followings are equivalent

gapminder_2007 <- gapminder |> 
  filter(year == 2007, country %in% c("United States", "Australia"))

ggplot() +
  geom_line(data = gapminder, aes(x = year, y = lifeExp, group = country)) +
  geom_point(data = gapminder_2007, aes(x = year, y = lifeExp), color = "red", size = 3)


gapminder |>
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line(aes(group = country)) +
  geom_point(data = gapminder_2007, color = "red", size = 3)


gapminder |>
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line(aes(group = country)) +
  geom_point(data = gapminder |> filter(year == 2007, country %in% c("United States", "Australia")),
             color = "red", size = 3)

These are NOT equivalent to the above

This gives an error:

ggplot(aes(x = year, y = lifeExp, 
           group = country)) +
  geom_line(data = gapminder) +
  geom_point(data = gapminder_2007, 
             color = "red", size = 3)

Error in fortify(): ! data must be a <data.frame>, or an object coercible by fortify(), or a valid <data.frame>-like object coercible by as.data.frame(), not a object. ℹ Did you accidentally pass aes() to the data argument?

Because at ggplot(aes(...)), the code doesn’t know what year and lifeExp it refers to - there is no data yet.

Can you spot it here?

gapminder |>
  ggplot(aes(x = year, y = lifeExp)) +
  geom_point(data = gapminder_2007, 
             color = "red", size = 3) + 
  geom_line(aes(group = country)) 

The point layer is now plotted first and the line layer is plotted on top of it, hence the points are hidden behind the lines.

Have you notice this?

We’ve been using color = "red" rather than aes(color = "red") throughout this example. This is NOT an error!

ggplot(aes(x = year, y = lifeExp, group = country)) +
  geom_line(data = gapminder) +
  geom_point(data = gapminder_2007, color = "red", size = 3)
  • color = "red" is a constant value to be applied to all points, hence you want to specify it inside the geom_xxx(), but outside aes(...).

  • aes(...) is used to map a variable in the data to a visual property, not a fixed value.

  • These rules apply to other aesthetics such as size, shape, linetype, etc.

What would happen …

… if we do aes(color = "red")?

gapminder |> 
  ggplot(aes(x = year, y = lifeExp, group = country)) +
  geom_line() +
  geom_point(data = gapminder_2007, aes(color = "red"), size = 3)

This looks okay, but….

What would happen …

… if we do aes(color = "blue")?

gapminder |>
  ggplot(aes(x = year, y = lifeExp)) +
  geom_line(aes(group = country)) +
  geom_point(data = gapminder_2007, aes(color = "blue"), size = 3)

It colors the points in red but says “blue” in the legend - this is misleading!

It happens that the first color in the default color palette used by ggplot2 is red, so the previous example is misleading but looks okay.

Your time (1/2)

usethis::create_from_github("SDS322E-26FALL/0303-viz2", fork = FALSE)

With the gapminder data,

  1. plot lifeExp vs gdpPercap with points
  2. use geom_smooth() to add a smooth line to indicate the trend
  3. check the method argument of geom_smooth() - what is the default method?
  4. if you change the order of geom_point() and geom_smooth(), what happens and why?

Solution

# 1) 
gapminder |> 
  ggplot(aes(x = lifeExp, y = gdpPercap)) + 
  geom_point()
# 2)
gapminder |>
  ggplot(aes(x = lifeExp, y = gdpPercap)) +
  geom_point() +
  geom_smooth()
  1. For method = NULL the smoothing method is chosen based on the size of the largest group (across all panels). stats::loess() is used for less than 1,000 observations; otherwise mgcv::gam() is used with formula = y ~ s(x, bs = “cs”) with method = “REML”.

  2. The smooth line will be behind the points and this is because ggplot2 draws the layers in the order they are specified in the code - the later layers are drawn on top of the earlier layers.

Now you’ve had the basics to make some plots with ggplot2, let’s think about how to display the data to tell a story.

  • Unless you’re instructed to make a xxx plot, you will need to decide which geom to use based on the type of data you have and the insights you want to communicate.

  • In a project, it is often not straightforward to know the exact plot you want and you tweak it until you’re satisfied. (We will see what this means) trails and errors….

Is this a good plot?

aka what does it tell you?

ggplot(gapminder, aes(x = year, y = lifeExp, group = country)) + 
  geom_line()

I can see a general increasing trend for most countries, with two drops at around 1977 and 1992. Is it good enough?

Maybe adding some colors to reveal country/ continent information will help.

I want to add some colors to reveal country/ continent information

ggplot(gapminder, 
       aes(x = year, y = lifeExp, group = country)) + 
  geom_line(aes(color = country))

Ooops… this is bad (and should be avoided) because there are too many countries and the color mapping doesn’t allow you to read which color corresponds to which country.

Tip: When a categorical variable has too many levels, it is not a good idea to map it to color.

We need to think about how to reduce the number of levels and here we can use continent:

ggplot(gapminder, 
       aes(x = year, y = lifeExp, group = country)) + 
  geom_line(aes(color = continent))

Now we can see Europe and Oceania have higher life expectancy among all countries, while Africa has the lowest, along with some Asian countries.

Maybe we want to add a label/ text to the countries with the lowest life expectancy:

This will be the exercise for today.

Is it a good idea to facet the plot by continent?

ggplot(gapminder, 
       aes(x = year, y = lifeExp, group = country)) + 
  geom_line(aes(color = continent))  + 
  facet_wrap(vars(continent)) + 
  scale_x_continuous(breaks = seq(1950, 2010, by = 25)) + 
  theme(legend.position = "bottom")

Your time (2/2)

Combine the dplyr verbs you’ve learnt with your ggplot2 skill to label the country of the lowest point

Hint: 1) The point has the smallest lifeExp in our data, 2) the geometry to use is geom_label(), it takes a new aesthetic, label

(Bonus) You can try to label the lowest green point.