This lab focuses on data visualization and how to create high quality graphics using the ggplot2 package. In this lab we will use cleaned data, with subsequent labs covering how to manipulate data prior to graphing. Much of this will be extremely familiar from your STA209 class, but we will get into more fine control and the nuts-and-bolts of how ggplot2 is actually working.

NOTE: More material will be added to this lab on Wednesday.

\(~\)

Preamble

Packages and Datasets

This lab will use the ggplot2 package:

# install.packages("ggplot2")
library(ggplot2)

It will also use data from The College Scorecard:

colleges <- read.csv("https://nfriedrichsen.github.io/data/Colleges2019.csv")
  • Description: The colleges data set contains attributes and outcomes for all primarily undergraduate institutions in the United States with at least 400 full-time students for the year 2019.

\(~\)

How ggplot2 creates graphics

The ggplot2 package builds graphics in a structured manner using layers. Layers are sequentially added to a graph, with each serving a particular purpose, such as:

  1. Displaying raw data
  2. Displaying a statistical summary
  3. Adding metadata (ie: annotations, context, references, etc.)

Consider the following examples:

## Example #1.1 - nothing (just a base layer)
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition))

## Example #1.2 - add a layer displaying raw data
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point()

## Example #1.3 - add another layer (smoother)
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point() +
  geom_smooth()

## Example #1.4 - add another layer (reference text)
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point() +
  geom_smooth() + 
  annotate("text", x = 20000, y = 40000, label = "Data from 2019")

Note: A high-quality graphic doesn’t require any particular number of layers. In fact, more layers can sometimes detract from the clarity of a data visualization.

\(~\)

More on the base layer

The mapping and data arguments provided in the base layer are carried forward to all subsequent layers. This is often desirable, but we can also specify or change aesthetics within an individual layer.

Consider the difference between the following two graphs:

## Color is mapped to Region
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point()

## Every point is set to red
ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point(color = "red")

In the first graph, color = Region appears inside aes(). This tells ggplot2 that color should represent information contained in the variable Region.

In the second graph, color = "red" appears outside aes(). This does not represent another variable. Instead, it simply instructs ggplot2 to draw every point in red.

Aesthetics can also be specified locally within individual layers:

## Example #2.1
ggplot(data = colleges) +
  geom_point(mapping = aes(x = Cost, y = Net_Tuition)) 

## Example #2.2
ggplot(data = colleges) +
  geom_point(mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point(mapping = aes(x = Cost, y = Enrollment), color = "red")

Local specification is useful when different layers of a graph need to display different variables or use different aesthetics.

\(~\)

Creating Effective Visualizations

The fundamental principles of creating effective data visualizations are quite simple. In short, an effective visualization should:

  1. Clearly convey a particular message
  2. Let the data speak for itself with minimal distortion
  3. Avoid “sales tactics” and unnecessary frills

It’s helpful to understand these principles with a few examples of effective and ineffective visuals.

Example #1

Consider survey data on the popularity of different internet browsers over time:

Which graph is more effective? Why?

\(~\)

Example #2

Consider the heights of men and women in the NHANES sample:

Which graph is more effective? Why?

\(~\)

Lab

ggplot graphics are an expansive topic, and not everything can be self-contained in this lab. Throughout the lab, I encourage you to reference the following resources if you need to figure out the proper function or syntax for a particular task:

\(~\)

The Grammar of ggplot2

The ggplot framework is unique because graphics are grammatically defined. Two of the most important pieces are:

  • Aesthetics (or “aes”) - mappings of variables to visual properties such as position, color, or size.
  • Geometric elements (or “geoms”) - what you actually see in the plot, such as points, lines, bars, or curves.

For example:

ggplot(data = colleges, mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point()

Here, Cost, Net_Tuition, and Region are mapped to the aesthetics x, y, and color. The points themselves are created using geom_point().

Different geoms can display the same variables in different ways, and different types of variables naturally lend themselves to different geoms.

Question #1

Consider the graph below:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  geom_smooth()

A. Which variables are mapped to the x, y, and color aesthetics?

B. What geometric elements are being displayed?

C. What happens if you move color = Type from the ggplot() function into geom_point()? Run the modified code and briefly describe the difference.

\(~\)

Mapping versus Setting Aesthetics

Remember that placing an aesthetic inside aes() maps a variable to that aesthetic:

ggplot(colleges, aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point()

In contrast, specifying something like color = "red" outside aes() simply changes the appearance of the geom:

ggplot(colleges, aes(x = Cost, y = Net_Tuition)) +
  geom_point(color = "red")

This distinction applies to other visual properties as well.

Question #2

Create two scatterplots showing the relationship between Enrollment and Cost.

A. In the first graph, map the variable Type to the color aesthetic.

B. In the second graph, make every point purple.

Make sure you understand why color = Type and color = "purple" need to appear in different locations in your code.

Question #3

Begin with a scatterplot displaying the relationship between Adm_Rate and Net_Tuition.

A. Add a smoother to the graph. What does the graph suggest about the relationship between admissions rate and net tuition?

B. Modify the graph so that Type controls the color of the points, but does not control the color of the smoother.

C. Now modify the graph so that Type controls the color of both the points and the smoother. Does considering college type change your understanding of the relationship between admissions rate and net tuition? Explain briefly.

D. Compare your code for Parts B and C. What changed about where color = Type was specified?

\(~\)

Facets

Adding more aesthetics is one way to display additional variables, but graphs can quickly become difficult to interpret when too many things are displayed at once.

Facets allow us to break the data into separate plots according to one or more categorical variables.

  • facet_wrap() displays separate panels according to one categorical variable.
  • facet_grid() displays panels corresponding to combinations of two categorical variables.

Consider the following examples:

reduced_colleges = subset(
  colleges,
  Region %in% c("Great Lakes", "Far West", "Plains")
)

## facet_wrap
ggplot(data = reduced_colleges, aes(x = Cost)) +
  geom_density() +
  facet_wrap(~Region, nrow = 1)

## facet_grid
ggplot(data = reduced_colleges, aes(x = Cost)) +
  geom_density() +
  facet_grid(Type ~ Region)

The facet_wrap() function wraps a series of plots according to a fixed number of rows or columns, while facet_grid() constructs a grid based upon combinations of the variables supplied to it.

Question #4

Create a histogram of Enrollment and facet the graph according to the variable Type.

Then modify your graph so that the histograms are also colored according to Type.

Briefly compare what the color aesthetic and faceting are doing. What information is being represented redundantly?

Compare the distributions of enrollment for the different types of colleges.

\(~\)

Question #5

Create a scatterplot showing the relationship between Cost and Net_Tuition.

  • Map Region to the color aesthetic.
  • Display only colleges from the "Great Lakes", "Far West", and "Plains" regions.
  • Use facets to display the three regions in separate panels.
  • Add a smoother to each panel.

Describe the relationship between Cost and Net_Tuition. Does the relationship appear similar across the three regions, or are there differences worth noting?

You may use subset() to restrict the data before constructing your graph.

\(~\)

Required Practice

Question #6

Create a graphic that displays the relationship between Adm_Rate, Net_Tuition, and Type.

  • Part A: Create one graphic displaying all three variables. You should decide how each variable is represented. Briefly describe how each of the three variables is represented in your graph.

  • Part B: Create a second graphic displaying the same three variables, but change how at least one of the variables is represented. For example, a variable represented using color in Part A could instead be represented using facets in Part B.

Briefly describe what you changed between the two graphics. Does either representation make anything about the relationship between the variables easier or harder to see?

\(~\)

New Material for Wednesday

Scales and Guides

So far, we have used aesthetics to determine which variables control properties such as position and color. Scales determine how values of those variables are translated into what actually appears on the graph.

For example:

## Default scales
ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point()

## Put Cost on the log2 scale
ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_x_continuous(transform = "log2")

Scales can also control how colors are displayed:

## Gradient from purple to yellow
ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_gradient(low = "purple", high = "yellow")

## Viridis color scale
ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_continuous(type = "viridis")

The names of scale functions generally indicate both the aesthetic being modified and the type of scale being used.

There are two useful distinctions to keep in mind:

  1. Scale functions differ depending upon the type of variable being displayed. For example, Adm_Rate is quantitative, so a continuous color scale is appropriate. A categorical variable requires a discrete color scale.

  2. The color aesthetic is not synonymous with every use of color on a graph. Some geoms use fill to control the color of their interior. In that situation, you would modify the fill scale rather than the color scale.

A guide is something that helps the reader interpret one of these mappings. Legends and color bars are common examples of guides.

Question #7

Create a scatterplot showing Enrollment on the x-axis and Net_Tuition on the y-axis.

A. Map Adm_Rate to color.

B. Put Enrollment on the natural-log scale.

C. Change the color scale to a continuous viridis scale.

D. Add the argument direction = -1 to the scale_color_continuous layer.

Briefly describe what each of the two scale changes accomplishes. What does the direction = -1 argument do?

\(~\)

Themes

Themes are pre-built style templates used to tailor a graphic’s appearance.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point() +
  theme_bw()

Some commonly used pre-built themes include:

  • theme_bw()
  • theme_linedraw()
  • theme_light()
  • theme_dark()
  • theme_minimal()
  • theme_classic()
  • theme_void()

You can compare them below:

Themes can be further customized using theme(). For example, a graph’s legend can be removed using:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point() +
  theme_bw() +
  theme(legend.position = "none")

Question #8

The code below creates a line graph depicting, via a smoothed moving average, the approval of former presidents Jimmy Carter, Ronald Reagan, and Barack Obama.

## Data processing
approval <- read.csv("https://gist.githubusercontent.com/elliottmorris/8775a074deffbfc5a9be098e754a5167/raw/6de8de053f9f5cb3506281ea622be0e059a4a920/pres_approval_data.csv")

approval$Week = as.numeric(
  difftime(
    as.Date(approval$End.Date, "%m/%d/%y"),
    as.Date(approval$Inaug.Date, "%m/%d/%y"),
    units = "weeks"
  )
)

approval2 = subset(
  approval,
  President %in% c("Reagan", "Carter", "Obama")
)

## Creating the graph
ggplot(data = approval2,
       mapping = aes(x = Week, y = Approving, color = President)) +
  geom_smooth(method = "loess", span = 0.6, se = FALSE)

Modify the graph to try a few different non-default themes. Briefly discuss which theme you feel is most effective for this graph and include the graph using your preferred theme.

\(~\)

Labels and Annotations

Labels and annotations provide context or draw the viewer’s attention toward particular aspects of a graphic.

Labels corresponding to aesthetics such as x, y, and color can be controlled using labs():

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  labs(
    x = "Sticker Cost",
    y = "Price Paid",
    color = "Admissions Rate"
  )

The same function can also be used to add titles and other information to a graph.

Annotations are added to a graphic as another layer using annotate():

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() + 
  annotate(
    geom = "rect",
    xmin = 65000,
    xmax = 77000,
    ymin = 20000,
    ymax = 52000,
    color = "red",
    alpha = 0.2
  )

The example above draws a rectangle around a particular region of the scatterplot. The argument alpha = 0.2 makes the rectangle partially transparent.

Question #9

Use the subset() function to create a data frame containing only colleges located in the state of Iowa. Using these data, create a box plot of admissions rates, rename the x-axis label to “Admissions Rate”, and add a text annotation above the outlier saying “Grinnell”. Finally add a title to the graph. (Hint: an example of text annote is given in example 1.4 in the preamble)

How do we know this dot corresponds to Grinnell?

\(~\)

Statistical Layers

Sometimes we would like a graph to display a statistical summary, such as a mean or error bar, rather than only the raw observations.

We could calculate these quantities separately and then create a graph, but ggplot2 also provides statistical layers that perform these calculations for us.

For example:

ggplot(data = colleges[1:30,],
       mapping = aes(x = Net_Tuition, y = Type)) +
  geom_point() + 
  stat_summary(fun = mean,
    geom = "point",
    color = "red",
    size = 3
  ) +
  stat_summary(
    fun.data = mean_se,
    geom = "errorbar",
    color = "red"
  )

The graph displays the original observations as points, then adds statistical layers showing the mean and one standard error above and below the mean for private and public colleges.

Notice that the first use of stat_summary() uses the fun argument because mean() returns a single value. The second uses fun.data because mean_se() returns the information needed to construct the interval.

Question #10

Using the subset containing only colleges located in Iowa, create side-by-side boxplots comparing Net_Tuition for public and private colleges.

Use stat_summary() to add the mean and median Net_Tuition for each type of college to the boxplots. Modify the appearance of these points using color and shape so that the mean and median can be distinguished from one another and from the boxplot itself. Add a purple X where Grinnell should appear.

Where does the median point appear relative to the boxplot? Why should it appear in this location? Compare the mean and median for public and private colleges. What do these values, along with the boxplots, suggest about the distributions? What have we learned about Grinnell?

\(~\)

Required Practice

Question #11

Create a graphic using the colleges data that displays the relationship between Cost, Net_Tuition, andType

Your finished graphic should:

  1. Display the individual colleges.
  2. Use color to represent one of the variables.
  3. Use a non-default color scale.
  4. Use a non-default theme.
  5. Replace at least two default labels with more readable labels.
  6. Use either a scale transformation or facets in a way that you think helps display the data.

There are multiple reasonable solutions to this question.

\(~\)

Question #12

Construct a new graph (or modify your graph from question 11) that investigates the relationship between Cost, Net_Tuition, and Type for Iowa colleges compared to colleges in all other states.

Display all colleges in the background, and then use an additional layer to highlight the Iowa colleges. Briefly describe anything you observe about Iowa colleges compared with the overall data.

Question #13

The code below loads a data set containing Hollywood films released between 2007 and 2011 and creates a smaller data set containing the four largest studios and three most common genres.

movies = read.csv("https://nfriedrichsen.github.io/data/HollywoodMovies.csv")

movies_subset = subset(
  movies,
  LeadStudio %in% c("Warner Bros", "Fox", "Paramount", "Universal") &
    Genre %in% c("Action", "Comedy", "Drama"),
  select = c(
    "Movie", "LeadStudio", "Story", "Genre", "Budget",
    "TheatersOpenWeek", "Year", "OpeningWeekend"
  )
)

Create a graphic that shows the relationship between OpeningWeekend and the explanatory variables Budget, Genre, and LeadStudio.

Your graph should:

  1. Use an appropriate geom for displaying the relationship between Budget and OpeningWeekend.
  2. Use the color aesthetic to display either Genre or LeadStudio.
  3. Use facets to display the other categorical variable.
  4. Use a non-default theme.
  5. Change the labels of the variables so that they are more readable.
  6. Use a non-default color scale.

There are several reasonable ways to construct this graph.