Visualizing distributions 1

Author

Claus O. Wilke

Introduction

In this worksheet, we will discuss how to display distributions of data values using histograms and density plots.

First we need to load the required R packages. Please wait a moment until the live R session is fully set up and all packages are loaded.

Next we set up the data.

We will be working with the titanic dataset which contains information about passengers on the Titanic, including their age, sex, the class in which they traveled on the ship, and whether they survived or not:

Histograms

We start by drawing a histogram of the passenger ages (column age in the dataset titanic). We can do this in ggplot with the geom geom_histogram(). Try this for yourself.

Solution
ggplot(titanic, aes(age)) +
  geom_histogram()

If you don’t specify how many bins you want or how wide you want them to be, geom_histogram() will make an automatic choice, but it will also give you a warning that the automatic choice is probably not good. Make a better choice by setting the binwidth and center parameters. Try the values 5 and 2.5, respectively.

Hint
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = ___, center = ___)
Solution
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = 5, center = 2.5)

Try a few more different binwidths, e.g. 1 or 10. What are good values for center that go with these choices?

Density plots

Density plots are a good alternative to histograms. We can create them with geom_density(). Try this out by drawing a density plot of the passenger ages (column age in the dataset titanic). Also, by default geom_density() does not draw a filled area under the density line. We can change this by setting an explicit fill color, e.g. “cornsilk”.

Hint
ggplot(titanic, aes(age)) +
  geom_density(___)
Solution
ggplot(titanic, aes(age)) +
  geom_density(fill = "cornsilk")

Just like for histograms, there are options to modify how much detail a density plot shows. A small binwidth in a histogram corresponds to a low bandwidth (bw) in a density plot and similarly a large binwidth corresponds to a high bandwidth. In addition, you can change the kernel, e.g. kernel = "rectangular" or kernel = "triangular". Try this out by using a bandwidth of 1 and a triangular kernel.

Hint
ggplot(titanic, aes(age)) +
  geom_density(fill = "cornsilk", bw = ___, kernel = ___)
Solution
ggplot(titanic, aes(age)) +
  geom_density(fill = "cornsilk", bw = 1, kernel = "triangular")

Try a few more different bandwidth and kernel choices, e.g. 0.1 or 10, or rectangular or gaussian kernels. How does the density plot depend on these choices?

Small multiples (facets)

We can also draw separate histograms for passengers meeting different criteria, for example for passengers traveling in the different classes. Whenever we draw multiple plot panels containing the same type of plot but for different subsets of the data, we speak of “small multiples”. In ggplot, we generate small multiples with the function facet_wrap(). The function facet_wrap() takes as its argument a list of data columns to subdivide the data by. This list is provided as an R formula. It’s Ok if you don’t know what an R formula is. Simply think of it as the name of the column with a tilde (~) in front. For example, ~class means draw a separate panel for each class, ~survived means draw a separate panel for each survival status, and ~class + survived means draw a separate panel for each combination of class and survival status.

As an example, the following code generates small multiple histograms by class:

Now use the same principle to draw small multiple histograms by survival status.

Hint
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(___)
Solution
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived)

Now make a plot that breaks down the data by both survival status and class.

Hint
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(___)
Solution
ggplot(titanic, aes(age)) +
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived + class)

Finally, do the same but drawing density plots rather than histograms.

Hint
ggplot(titanic, aes(age)) +
  ___ +
  facet_wrap(~survived + class)
Solution
ggplot(titanic, aes(age)) +
  geom_density(fill = "cornsilk", bw = 2) +
  facet_wrap(~survived + class)

otice the difference between this plot and the corresponding histogram plot. Histograms show absolute counts whereas the density plots are normalized so that the area under the curve is 1. As a consequence, the density plot does not provide an accurate representation of the number of passengers in each grouping. This can be changed. See next section.

Manipulating stats

You may have noticed that neither geom_histogram() nor geom_density() require you to define an aesthetic mapping for the y variable. This is because under the hood, a statistical transformation (called a “stat”) calculates the histogram or density from the raw data and then sets the appropriate y mapping.

Sometimes it can be useful to access or modify this mapping directly. We tell ggplot that we want to map a value calculated by a stat, rather than one that is in the original data, by writing after_stat(...) inside the aes() function. So, for example, the default y mapping for geom_density() is y = after_stat(density). An alternative mapping, y = after_stat(count) scales densities by the number of points in each grouping, thus producing something more similar to a histogram. You can see the difference between these two choices in the following two examples:

The same options of after_stat(count) and after_stat(density) exist for geom_histogram() as well. Try this by making histograms that use the calculated density for the y value.

Hint
ggplot(titanic, aes(age, y = ___)) + 
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived + class)
Solution
ggplot(titanic, aes(age, y = after_stat(density))) + 
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived + class)

Now, instead, try mapping the calculated counts onto the fill aesthetic.

Hint
ggplot(titanic, aes(age, fill = ___)) + 
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived + class)
Solution
ggplot(titanic, aes(age, fill = after_stat(count))) + 
  geom_histogram(binwidth = 5, center = 2.5) +
  facet_wrap(~survived + class)

Finally, we can make our own combination of geoms and stats, by setting the stat argument of a geom, e.g. stat = "density" to use the density stat. To try this out, draw a density plot using geom_point(), and also map the calculated density values onto the point color.

Hint
ggplot(titanic, aes(age, color = ___)) +
  geom_point(stat = "density") +
  facet_wrap(~survived + class)
Solution
ggplot(titanic, aes(age, color = after_stat(density))) +
  geom_point(stat = "density") +
  facet_wrap(~survived + class)