Preamble

Packages and Datasets

This lab will continue to use the ggplot2 package:

library(ggplot2)

We will also continue using data from The College Scorecard:

colleges = read.csv("https://nfriedrichsen.github.io/data/Colleges2019.csv")

In the previous lab, we focused on the basic grammar used by ggplot2: aesthetics, geometric elements, layers, and facets. We also saw several ways to modify the appearance of a graphic.

This lab will focus on gaining more precise control over those graphics.

There are several related ideas that will appear throughout this lab:

Component What does it control?
Mapping Which variables control visual properties such as position, color, fill, or shape
Scale How the values of a mapped variable are represented visually
Theme Non-data components of the graph, such as text, backgrounds, grid lines, and legend placement
Guide How the reader interprets a scale, usually through a legend or color bar
ggplot(colleges, aes(x = Cost, y = Net_Tuition,
                     color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c() + 
  theme_bw()

For example, if we use aes(color = Adm_Rate), we have mapped Adm_Rate to the color aesthetic. A function such as scale_color_viridis_c() controls the scale used to translate values of Adm_Rate into colors. The resulting color bar is a guide that allows the reader to interpret those colors. Changing the theme can modify the appearance of the graph without changing this mapping.

Another important distinction throughout this lab is between discrete and continuous variables. Different scales are appropriate for different types of variables, and recognizing this distinction will help you select appropriate scale functions and understand some common ggplot2 error messages.

What should I remember?

The goal of this lab is not to memorize every ggplot2 option. In particular, you do not need to memorize theme component names, palette names, individual scale functions, hexadecimal color codes, or all of the arguments available within the element_*() functions. These are things you can look up when you need them.

Instead, you should understand:

  • the difference between an aesthetic mapping and a scale
  • how discrete and continuous variables require different types of scales
  • the difference between the color and fill aesthetics
  • what themes and guides control
  • that individual layers can use their own data, mappings, and fixed appearance options.

In the next lab, we will focus more on answering this question: which graphical choices are effective for displaying different kinds of data and relationships? This lab will give us enough control over our graphics to make those choices.

\(~\)

Customizing Themes

In the previous lab, we saw that ggplot2 provides several pre-built themes. For example:

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

Some commonly used themes include:

These functions change the general appearance of a graphic. However, we can also modify individual components of a theme using the theme() function.

A useful distinction is that themes control the non-data components of a graphic. Changing a theme does not change which observations are displayed or how variables are mapped to aesthetics. Instead, themes control things such as text, backgrounds, grid lines, tick marks, and the placement of legends.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  ) +
  labs(title = "College Cost and Net Tuition")

The theme() function contains many possible arguments because there are many components of a graph that can be modified. Fortunately, most of these components are modified using only a few types of theme elements:

element_text()
element_line()
element_rect()
element_blank()

The appropriate function depends upon the type of graphical element being modified.

Text

Text components are modified using element_text(). This includes axis labels, axis tick labels, titles, and legend text.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  labs(title = "College Cost and Net Tuition") +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 5), #smol
    legend.text = element_text(angle = 45),
    legend.title = element_text(angle = 45, vjust=-.5)
  )

Some useful arguments within element_text() include:

element_text(
  size = 12,
  face = "bold",
  color = "blue",
  angle = 45, #rotate
  hjust = 0.5, #horizontal adjustment (can be neg)
  vjust = 0.5 #vertical adjustment (can be neg)
)

You generally will not use all of these at once. They simply provide different ways to control how text is displayed.

Theme components can also be modified together or individually. For example,

axis.text = element_text(size = 10)

modifies the text on both axes, while

axis.text.x = element_text(angle = 45)

modifies only the x-axis tick labels.

Lines

Line components are modified using element_line(). This includes grid lines, axes, and tick marks. Useful arguments include properties such as:

element_line(
  color = "gray",
  linewidth = 0.5,
  linetype = "dashed"
)

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  theme_bw() +
  theme(
    panel.grid.major = element_line(linewidth = 0.5, color="blue", linetype = "dashed"),
    panel.grid.minor = element_line(linewidth = 0.2),
    axis.ticks = element_line(linewidth = 0.8)
  )

You are most likely going to care about customizing colors, linewidths, and line types.

Here are options for line types. You can use either the integer value or the name like "dashed".

Integer String Appearance
0 "blank" No line is drawn
1 "solid" Solid line (default)
2 "dashed" Dashed line
3 "dotted" Dotted line
4 "dotdash" Alternating dots and dashes
5 "longdash" Long dashed line
6 "twodash" Alternating dash lengths

Rectangles and Backgrounds

Background regions and borders are generally modified using element_rect().

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  theme(
    panel.background = element_rect(fill = "white"),
    panel.border = element_rect(color = "black", fill = NA),
    legend.background = element_rect(fill = "white")
  )

For rectangular elements, fill controls the interior while color controls the border.

Removing Elements

Sometimes the desired customization is simply to remove something. element_blank() removes a theme component entirely.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  theme(
    panel.grid.minor = element_blank(),
    axis.ticks = element_blank()
  )

This is different from making an element white or transparent: the element is simply not drawn.

Many theme components follow a hierarchical naming structure. For example:

plot.title         # Main plot title
plot.subtitle      # Plot subtitle

axis.text          # Axis tick labels on both axes
axis.text.x        # X-axis tick labels
axis.text.y        # Y-axis tick labels

axis.title         # Axis titles on both axes
axis.title.x       # X-axis title
axis.title.y       # Y-axis title

axis.ticks         # Tick marks on both axes

panel.grid         # All grid lines
panel.grid.major   # Major grid lines
panel.grid.minor   # Minor grid lines

panel.background   # Background of the plotting panel
panel.border       # Border surrounding the plotting panel

legend.text        # Labels for individual legend entries
legend.title       # Legend title
legend.background  # Background of the legend

The more general option changes all of the components beneath it, while a more specific option can be used when only one component should change.

You are not expected to memorize all of the available theme components. Instead, you should understand the general structure of theme() and recognize the four major element functions. When you want to modify a particular part of a graph, you can look up the appropriate theme component.

Question 1

Begin with the following graph:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  labs(
    title = "College Cost and Net Tuition",
    subtitle = "Colleges in the 2019 College Scorecard",
    x = "Sticker Cost",
    y = "Net Tuition",
    color = "College Type"
  )

Apply a non-default theme of your choice and then experiment with the following theme customizations. Your final graph does not need to represent choices you would make for a polished visualization (it can be ugly); the goal is to practice modifying different theme elements. Only one final graph needs to be shown for this lab submission.

A. Move the legend to the bottom of the graph.

B. Make the title larger and bold.

C. Remove the minor grid lines.

D. Modify one line element using element_line().

E. Modify one rectangular element using element_rect().

F. Make one additional theme modification of your choice that has not already been requested.

Briefly identify the theme component and element_*() function you used for Parts D, E, and F.


Color Palettes

When a variable is mapped to the color or fill aesthetic, ggplot2 automatically chooses a set of colors to represent its values. However, we are not restricted to these default colors.

A color palette is a collection or sequence of colors designed to be used together. ggplot2 provides access to several families of pre-built palettes, and we can also construct our own.

For example, consider the default colors used to represent Region:

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

There are several ways that we can replace these default colors.

ColorBrewer Palettes

One commonly used collection of palettes comes from ColorBrewer. These palettes can be accessed in ggplot2 using functions such as scale_color_brewer().

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point() +
  scale_color_brewer(palette = "Set1") +
  labs(title = "Set1")

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Region)) +
  geom_point() +
  scale_color_brewer(palette = "Dark2") +
  labs(title = "Dark2")

The palette argument determines which collection of colors is used.

Some (but not all) available ColorBrewer palettes include: "Set1", "Set2", "Set3", "Dark2", "Paired", "Pastel1", "Pastel2", "Accent"

These are examples of qualitative palettes. Qualitative palettes use different colors to distinguish categories without implying that one category is larger or smaller than another.

We can see the available “qualitative” (designed for categorical) ColorBrewer palettes using:

RColorBrewer::display.brewer.all(type = "qual")

ColorBrewer also contains palettes designed for quantitative values. For example,

RColorBrewer::display.brewer.all(type = "seq")

displays sequential palettes, while

RColorBrewer::display.brewer.all(type = "div")

displays diverging palettes.

Sequential palettes progress from one end of a color scale to another. Diverging palettes have two different ends with a contrasting color near the center.

For now, the important point is simply that different types of palettes exist. We will discuss more about choosing an effective palette for a particular purpose in the next lab.

Question 2

Modify the graph we have been looking at and explore the different qualitative ColorBrewer palette options. Make a list of your favorite ones so far. Are there palettes that make the different regions easier or more difficult to distinguish?

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

\(~\)

Viridis Palettes

Another commonly used family of color palettes that deserves special attention is viridis.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c(option = "viridis") +
  labs(title = "Viridis")

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c(option = "plasma") +
  labs(title = "Plasma")

Several palettes are available within this family:

"viridis", "magma", "inferno", "plasma", "cividis", "mako", "rocket", "turbo"

The palette is selected using the option argument:

scale_color_viridis_c(option = "magma")

The direction of the palette can also be reversed using direction = -1:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c() +
  labs(title = "Default Direction")

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c(direction = -1) +
  labs(title = "Reversed Direction")

Question 3

For the plot below, experiment with the viridis color palettes and see which ones work best for this graph. Also try out if direction=-1 gives you a better graph. Salary10yr_median is the median salary of graduates 10 years after graduating. What does this plot tell you about the relationship between these 3 variables?

ggplot(data = colleges, aes(x = Avg_Fac_Salary, color = Debt_median, y=Salary10yr_median)) + geom_point()

\(~\)

Creating Color Gradients

We can also construct a continuous color palette directly.

The scale_color_gradient() function creates a gradient between two colors:

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

Here, smaller values of Adm_Rate are represented closer to purple and larger values closer to yellow.

A gradient can also contain a specified middle color using scale_color_gradient2:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_gradient2(
    low = "blue",
    mid = "white",
    high = "red",
    midpoint = 0.5
  )

The midpoint argument determines which numerical value receives the middle color. This creates a diverging gradient centered at the specified value.

\(~\)

Choosing Colors Manually

For categorical variables, we can also specify the exact color assigned to each category.

For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  scale_color_manual(
    values = c(
      "Public" = "purple",
      "Private" = "orange"
    )
  )

Using a named vector makes the correspondence between categories and colors explicit:

"Public" = "purple"
"Private" = "orange"

rather than relying upon the order in which the categories happen to appear.

Colors can be specified using many standard color names. You can see the named colors recognized by R using:

# run this in your own console
colors()

R also understands hexadecimal color codes, which can be used when there is a particular color shade/hue/brightness combination you want.

"#440154"
"#21918C"
"#FDE725"

\(~\)

Scales

Throughout the previous section, we used several functions to change how colors were displayed:

scale_color_brewer()
scale_color_viridis_c()
scale_color_gradient()
scale_color_gradient2()
scale_color_manual()

Although we introduced these functions as ways to choose color palettes, they are all examples of scales.

A scale controls how the values of a variable are translated into the visual properties of a graph. For example, suppose we map Adm_Rate to color:

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

The aesthetic mapping color = Adm_Rate tells ggplot2 which variable should control color. The color scale determines how the values of that variable are represented by colors.

For example, both of the following graphs have exactly the same aesthetic mappings:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_gradient(low = "white", high = "red")

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Adm_Rate)) +
  geom_point() +
  scale_color_viridis_c(option = "magma")

The data and mappings have not changed. Only the scale used to display the color aesthetic has changed.

\(~\)

Scale Functions

Scale functions generally follow a common naming structure:

scale_[aesthetic]_[type]()

The first part tells ggplot2 which aesthetic is being controlled. For example:

scale_color_...
scale_fill_...
scale_x_...
scale_y_...

The remainder of the function name describes the type of scale being used.

For example:

scale_color_gradient()
scale_color_manual()

scale_fill_gradient()
scale_fill_manual()

scale_x_continuous()
scale_y_continuous()

This naming system means that once you understand how scales work, you do not need to memorize every possible scale function individually.

\(~\)

Discrete and Continuous Scales

An important distinction is whether the variable mapped to an aesthetic is discrete or continuous.

A discrete variable consists of separate categories. For example, Type and Region are discrete variables.

A continuous variable is numerical and can take values along a numerical scale. For example, Adm_Rate, Cost, and Net_Tuition are continuous variables.

For the math savvy: Please don’t yell at me about discrete also having different meaning for quantitative variables. I didn’t invent the system!

Different scale functions are designed for these different types of variables.

For example, the following graph maps the categorical variable Type to color:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition, color = Type)) +
  geom_point() +
  scale_color_brewer(palette = "Dark2")

In contrast, the following graph maps the quantitative variable Adm_Rate to color:

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

Some scale functions make this distinction explicit in their names. In the viridis family, for example:

scale_color_viridis_d()  # discrete
scale_color_viridis_c()  # continuous

The _d version is used when colors represent categories, while the _c version is used when colors represent values along a continuous numerical scale.

For example:

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

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

Other scale functions are designed specifically for one type of variable even if _d or _c does not appear in the function name. For example, scale_color_gradient() represents continuous values using a gradient, while scale_color_manual() allows us to assign values to individual categories.

Question 4

Consider the following code:

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

A. Run the code. Read the error message and explain why scale_color_viridis_c() cannot be used here.

B. Modify the scale function so that the graph works correctly.

C. The ColorBrewer palettes we encountered earlier can also be used with discrete or continuous variables. Investigate the difference between scale_color_brewer() and scale_color_distiller(). Which function would be appropriate for Type? Recreate the graph using that function and a ColorBrewer palette of your choice.


Color versus Fill

The color aesthetic is not synonymous with every color that appears on a graph.

In ggplot2, color generally controls the color of points and lines or the outline of a shape, while fill controls the color of its interior.

For example:

ggplot(data = colleges,
       mapping = aes(x = Type, fill = Type)) +
  geom_bar() +
  labs(title = "Fill")

ggplot(data = colleges,
       mapping = aes(x = Type, color = Type)) +
  geom_bar() +
  labs(title = "Color")

Because color and fill are different aesthetics, they also have different scale functions.

For example:

scale_color_brewer()
scale_fill_brewer()

scale_color_viridis_c()
scale_fill_viridis_c()

scale_color_manual()
scale_fill_manual()

The scale function needs to correspond to the aesthetic that was actually mapped.

For example:

ggplot(data = colleges,
       mapping = aes(x = Type, fill = Type)) +
  geom_bar() +
  scale_fill_brewer(palette = "Set2")

Here Type is mapped to fill, so we use scale_fill_brewer() rather than scale_color_brewer().


Position Scales

Scales are not limited to color. The x- and y-axes of a graph are also controlled by scales.

For example:

ggplot(data = colleges,
       mapping = aes(x = Enrollment, y = Net_Tuition)) +
  geom_point()

Since Enrollment is quantitative, its x-axis is controlled by a continuous position scale. We can explicitly modify this scale using:

scale_x_continuous()

Similarly, a continuous variable on the y-axis can be modified using:

scale_y_continuous()

One useful application is changing the transformation used to display an axis.

For example, college enrollment is highly skewed because a relatively small number of institutions have extremely large enrollments:

ggplot(data = colleges,
       mapping = aes(x = Enrollment, y = Net_Tuition)) +
  geom_point() +
  labs(title = "Original Scale")

ggplot(data = colleges,
       mapping = aes(x = Enrollment, y = Net_Tuition)) +
  geom_point() +
  scale_x_continuous(transform = "log2") +
  labs(title = "Log2 Scale")

Both graphs contain the same observations. The second graph changes the scale used to display their positions on the x-axis.

Other transformations are available. For example:

scale_x_continuous(transform = "log10")
scale_x_continuous(transform = "sqrt")
scale_x_continuous(transform = "reverse")

Similar transformations can be applied to the y-axis using scale_y_continuous().

A transformation changes how values are positioned along an axis; it does not remove or alter the original observations in the data.

Question 5

Transforming a scale is not only useful for changing the appearance of a graph. Sometimes a transformation can reveal a relationship between variables that is difficult to see on their original scales. This can be particularly useful when we are interested in fitting a linear relationship between variables.

Consider the following graph:

ggplot(data = colleges,
       mapping = aes(x = Enrollment, y = Cost, color = Type)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE)

The lines show the fitted linear relationship between Enrollment and Cost separately for public and private colleges.

A. Examine the graph and the two fitted lines. Does a linear relationship appear to describe the relationship between Enrollment and Cost particularly well on the original scale? Explain briefly.

B. Modify the x-axis using

scale_x_continuous(transform = "log2")

How does transforming Enrollment change the appearance of the relationship?

C. Based on the transformed graph, does either college type seem to have a roughly linear relationship with log2(Enrollment)? Describe what you see.


Guides and Legends

When an aesthetic represents a variable, the reader needs some way to determine what the different colors, shapes, or other visual properties mean. These references are called guides.

Guides are closely connected to the aesthetic mappings and scales we have already discussed. The mapping in aes() determines which variable controls an aesthetic, the scale determines how the values are displayed, and the guide explains that scale to the reader.

For categorical color mappings, the guide will usually appear as a legend:

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

For continuous color mappings, the guide commonly appears as a color bar:

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

Modifying Guides

When modifying a guide, we generally refer to it using the name of the aesthetic that created it. In other words, look back at the argument used inside aes().

For example, if we map

aes(color = Adm_Rate)

then the corresponding guide is associated with color. We can change its title using:

labs(color = "Admissions Rate")

Similarly, a guide created by fill = Type would be modified using fill, while a guide created by shape = Type would be modified using shape.

For example:

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

Notice that we use color = "Admissions Rate" rather than Adm_Rate = "Admissions Rate". Here, color refers to the aesthetic, while "Admissions Rate" is the new title we want displayed for its guide.

Multiple Guides

A graph can have multiple guides when multiple aesthetics are mapped to variables. For example:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition,
                     color = Region, shape = Type)) +
  geom_point() + scale_color_brewer(palette="Accent")

Here, color represents Region while shape represents Type. ggplot2 therefore provides a guide explaining each mapping.

Each guide can be modified using the corresponding aesthetic name:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition,
                     color = Region, shape = Type)) +
  geom_point() + scale_color_brewer(palette="Accent") +
  labs(
    color = "College Region",
    shape = "College Type"
  )

This produces two separate guides, and with many categories they can take up quite a bit of space. There are additional options for controlling the size and arrangement of guides, but we will not worry about those details here. The reality is that we should probably find a different way to visualize this many categories.

Moving and Removing Guides

As we saw earlier, the position of the guides can be changed using theme():

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

Guides can also be removed when they are not needed:

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

Removing a guide does not remove the aesthetic mapping. It only removes the reference that explains the mapping to the reader.


More Control over Individual Layers

In the previous lab, we saw that data and aesthetic mappings placed in ggplot() are inherited by subsequent layers:

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

However, individual layers can supply their own data, aesthetic mappings, and appearance options.

For example, we can display every college in the background but add a second layer containing only Iowa colleges:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point(alpha = 0.2) +
  geom_point(
    data = subset(colleges, State == "IA"),
    color = "red",
    size = 3
  )

Both layers inherit x = Cost and y = Net_Tuition from ggplot(). However, the second layer replaces the inherited data with the subset of Iowa colleges.

The second layer could also add its own aesthetic mapping:

ggplot(data = colleges,
       mapping = aes(x = Cost, y = Net_Tuition)) +
  geom_point(alpha = 0.2) +
  geom_point(
    data = subset(colleges, State == "IA"),
    mapping = aes(color = Type),
    size = 3
  )

Now only the Iowa colleges are colored according to Type.

Notice that the individual layer has three things we can control separately:

The order of the layers also matters. Layers added later are drawn over layers added earlier. This is why the highlighted Iowa colleges appear on top of the faint background points.

Question 6

Modify the previous graph as follows:

  • In the background layer, map Type to shape and adjust alpha so shapes are visible but not dominating the Iowa data.
  • Apply a non-default discrete color palette to the existing Type color mapping for the Iowa colleges.
  • Give the axes and guides readable labels and apply a non-default theme.
  • Give the graph a descriptive title.

Your graph should look roughly like the following (different colors and shapes are OK):

\(~\)