ggplot2This 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.
\(~\)
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")
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.\(~\)
ggplot2 creates graphicsThe 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:
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.
\(~\)
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.
\(~\)
The fundamental principles of creating effective data visualizations are quite simple. In short, an effective visualization should:
It’s helpful to understand these principles with a few examples of effective and ineffective visuals.
Consider survey data on the popularity of different internet browsers over time:
Which graph is more effective? Why?
\(~\)
Consider the heights of men and women in the NHANES sample:
Which graph is more effective? Why?
\(~\)
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:
\(~\)
ggplot2The ggplot framework is unique because graphics are
grammatically defined. Two of the most important pieces
are:
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.
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.
\(~\)
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.
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.
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?
\(~\)
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.
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.
\(~\)
Create a scatterplot showing the relationship between
Cost and Net_Tuition.
Region to the color aesthetic."Great Lakes",
"Far West", and "Plains" regions.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.
\(~\)
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?
\(~\)
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:
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.
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.
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 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")
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 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.
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?
\(~\)
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.
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?
\(~\)
Create a graphic using the colleges data that displays
the relationship between Cost, Net_Tuition,
andType
Your finished graphic should:
There are multiple reasonable solutions to this question.
\(~\)
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.
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:
Budget and OpeningWeekend.Genre or
LeadStudio.There are several reasonable ways to construct this graph.