Session 3: Data Visualizion
Visuals tell the story behind the data analysis and lead the reader through it. It is
therefore of crucial importance to select appropriate visuals. They depend on the audience
and the need:
• Visuals for exploratory analysis - large number of imperfect graphs that allow
the analyst to understand data better. Usually quick and dirty and few of them (if
any) are presented to the interested audience.
• Visuals for communication - few graphs that contain key points and fact, are
well-thought and executed, suitably colored and clearly presented for the benet of
the interested audience.
Key results need to be shown in clear, concise and appealing way so that they can support
organizational decision-making. Dierent visualization solutions from simple graphs to
complex BI tools and online dashboards exist and here we will focus on R basic
visualization capabilities. For a more thorough treatment, the reader may consult Chang
(2018).
The rst pass at visuals should take a few points under consideration:
• Small is beautiful - minimalist visuals should get rid of superuous parts but
retain necessary ones
• Appropriate for data - visual should be suitable for the data it visualizes
• Compressed information - dierent aesthetics are only added as they add
information, thus compressing more knowledge in a single graph
• Self-contained - visuals need to be fully understandable and lead to correct
conclusions even outside context
We will survey most common visualizations in base R and see what data they are suitable
for.
We are going to use the mtcars dataset to illustrate usage. The data was extracted from
the 1974 Motor Trend US magazine, and comprises fuel consumption and 10 aspects of
automobile design and performance for 32 automobiles (1973–74 models).
Scatterplot
Shows how two variables are interrelated with each other. We investigate the link between
displacement and weight:
33
plot(mtcars$disp, mtcars$wt)
5
mtcars$wt
4
3
2
100 200 300 400
mtcars$disp
Adding axis titles, and main title and coloring:
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Connection between Displacement and Weight in Retro Cars",
col = "steelblue")
34
Connection between Displacement and Weight in Retro Ca
5
4
Weight
3
2
100 200 300 400
Displacement
There are numerous graphical paramaters that can be adjusted, e.g. the type of dots:
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Connection between Displacement and Weight in Retro Cars",
col = "steelblue", pch=15)
35
Connection between Displacement and Weight in Retro Ca
5
4
Weight
3
2
100 200 300 400
Displacement
We can add elements to this graph until we construct the visualization we want. Good
examples are horizontal and vertical lines:
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Connection between Displacement and Weight in Retro Cars",
col = "steelblue", pch=15) + abline(h = 3.5) + abline(v = 275)
36
Connection between Displacement and Weight in Retro Ca
5
4
Weight
3
2
100 200 300 400
Displacement
## integer(0)
In addition to that we can modify those lines just as we modify the graph. Here we change
their color and their line width:
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Connection between Displacement and Weight in Retro Cars",
col = "steelblue", pch=15) + abline(h = 3.5, col="red", lwd=2) +
abline(v = 275, col="green", lwd=2)
37
Connection between Displacement and Weight in Retro Ca
5
4
Weight
3
2
100 200 300 400
Displacement
## integer(0)
We can also add a calculated regreesion (or trend) line, and also set the limits of the two
axes using xlim and ylim:
lm <- lm(mtcars$wt ~ mtcars$disp)
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Connection between Displacement and Weight in Retro Cars",
col = "steelblue", pch=15, xlim = c(0, 600), ylim = c(0,6)) +
abline(reg = lm, lwd=2, col = "darkblue")
38
Connection between Displacement and Weight in Retro Ca
6
5
4
Weight
3
2
1
0
0 100 200 300 400 500 600
Displacement
## integer(0)
Bar Chart
The bar chart is very useful when visualizing total numbers and comparing them across
groups. We now see how many cars have what number of gears:
counts <- table(mtcars$gear)
barplot(counts, main="Frequency of Different Numbers of Gears in Retro Cars",
xlab="Number of Gears", ylab= "Total Cars", col="steelblue")
39
Frequency of Different Numbers of Gears in Retro Cars
14
8 10
Total Cars
6
4
2
0
3 4 5
Number of Gears
This can also be horizontal, instead of vertical:
counts <- table(mtcars$gear)
barplot(counts, main="Frequency of Different Numbers of Gears in Retro Cars",
xlab="Number of Gears", ylab= "Total Cars", col="steelblue", horiz = TRUE)
40
Frequency of Different Numbers of Gears in Retro Cars
5
Total Cars
4
3
0 2 4 6 8 10 12 14
Number of Gears
Histogram
Suitable for charting distributions and gaining overview of what values data takes. We can
chart the frequency of values:
hist(mtcars$wt, main = "Histogram of Weight in Retro Cars",
xlab = "Car Weight", col = "steelblue")
41
Histogram of Weight in Retro Cars
8
Frequency
6
4
2
0
2 3 4 5
Car Weight
We can also chart their probabilities:
hist(mtcars$wt, main = "Histogram of Weight in Retro Cars",
xlab = "Car Weight", col = "steelblue",freq = FALSE)
42
Histogram of Weight in Retro Cars
0.4
Density
0.2
0.0
2 3 4 5
Car Weight
Boxplot
The boxplot is very useful for charting and comparing a single variable across dierent
groups. It gives an idea of the central tendency of the distribution, the dispersion, the
range, and the outliers.
We now investigate the miles per gallon depending on the number of car cylinders:
boxplot(mtcars$mpg ~ mtcars$cyl, col="steelblue", xlab = "Cylinders",
ylab = "Miles per Gallon",
main = "Fuel Effiency with Different Number of Cylinders")
43
Fuel Effiency with Different Number of Cylinders
30
Miles per Gallon
25
20
15
10
4 6 8
Cylinders
Stacked Chart
The stacked chart is in principle close to the bar chart but it shows what proportion of
dierent variables comprises a given bar. As such, the stacked bar chart compresses much
more information and has the potential to be very useful.
We can create it in R as follows, annotate it, and then add an explanatory legend:
counts <- table(mtcars$am, mtcars$gear)
labels = c("Manual", "Automatic")
colors = c("steelblue", "lightblue")
barplot(counts, main="Car Distribution by Gears and Transmission",
xlab="Number of Gears", col=c("steelblue","lightblue"))
legend("topright", title="Transmission", labels, fill=colors)
44
Car Distribution by Gears and Transmission
Transmission
14
Manual
Automatic
8 10
6
4
2
0
3 4 5
Number of Gears
Pie chart
The pie chart classically shows the proportion between parts of a whole. We can investigate
what proportion of the cars are with automatic against those with manual transmission.
First we calculate the two proportions:
auto <- sum(mtcars$am[ mtcars$am == 1]) / length(mtcars$am)
man <- 1-auto
Then we create the pie chart:
pie(x = c(auto, man), labels = c("Automatic, 41%", "Manual, 59%"),
col=c("white", "steelblue"))
45
Automatic, 41%
Manual, 59%
Line Chart
The line chart is particularly useful for following processes that develop over time or some
specic trends. Such graphs are especially common in economic and business.
We load sales data from the BJsales to illustrate this.
data("BJsales")
plot(BJsales, main = "Sales Trend over Time", col = "steelblue", lwd=2)
46
Sales Trend over Time
260
240
BJsales
220
200
0 50 100 150
Time
Multiple Charts
A useful feature of graphing is to create a single visual that consists of multiple graphs
which show relevant and interrelated data. This graphing capability is controlled by the
command par(mfrow), and allows the user to specify what number of graphs will be tiled
on a single plotting space. Here we would like to have 2 columns and 2 rows of graphs, or a
total of four plots:
par(mfrow=c(2,2))
plot(x = mtcars$disp, y = mtcars$wt, xlab = "Displacement", ylab="Weight",
main = "Displacement and Weight",
col = "steelblue", pch=15) + abline(reg = lm, lwd=2, col = "darkblue")
## integer(0)
counts <- table(mtcars$gear)
barplot(counts, main="Numbers of Gears",
xlab="Number of Gears", ylab= "Total Cars",
col="steelblue", horiz = TRUE)
counts <- table(mtcars$am, mtcars$gear)
barplot(counts, main="Car Distribution", xlab="Number of Gears", col=c("steelblue","ligh
plot(BJsales, main = "Sales Trend over Time", col = "steelblue", lwd=2)
47
Displacement and Weight Numbers of Gears
Total Cars
Weight
5
4
3
2
100 200 300 400 0 2 4 6 8 12
Displacement Number of Gears
Car Distribution Sales Trend over Time
260
BJsales
8
200
0
3 4 5 0 50 100 150
Number of Gears Time
Trellis Graphs
An alternative visualization system in R is trellis trhough the lattice package. The
reader is well advised to study it further in case of interest. It provides alternative
commands and visualization for presented types of visuals.
The scatterplot, for example is called by the xyplot command, as follows:
library(lattice)
xyplot(hp ~ disp, data=mtcars, ylab = "Horsepower", xlab="Displacement",
main = "Connection between Horsepower and Displacement")
48
Connection between Horsepower and Displacement
300
250
Horsepower
200
150
100
50
100 200 300 400
Displacement
A particular lattice strength is the easy faceting of data, and looking at it from dierent
points of view and slices. For example if we are interested how the number of cylinders
aects the link between horsepower and displacement:
library(lattice)
xyplot(hp ~ disp|cyl, data=mtcars, ylab = "Horsepower", xlab="Displacement",
main = "Connection between Horsepower and Displacement")
49
Connection between Horsepower and Displacement
100 200 300 400
cyl cyl cyl
300
250
Horsepower
200
150
100
50
100 200 300 400 100 200 300 400
Displacement
While the overall trend is denitely positive, we see that this result truly holds in the cases
of 4 and 8 cylinders but not in the case of 6. This only serves to show that data slicing and
dicing and visualization of many possible cases can only serve to enlighten and build a solid
foundation for the modeling exercise.
50
Session 4: The Grammar of Graphics
The Grammar of Graphics is a formal and consistent way to think about creating
visualizations the same way we use words and rules to create a human language. The
grammar of graphics consists of rules how to express the creation of a visual (the
grammar), and of specic commands (words) which are used in the process. This way of
thinking was pioneered by Hadley Wickham in his groundbreaking work on visualizations
and implemented in R in his package ggplot2. The interested reader is referred to his
excellent book - Wickham, 2016.
The basic idea behind visual is that one creates them layer after way to give increasingly
more information. They go as follows (slightly adapted):
1. The rst layer - empty plot and data to be visualized (the ggplot() command)
2. The second layer - aesthetic mapping - what is the type of graph, and what
variables are to be mapped on it (geom_... command)
3. The third layer - graph aesthetics and coloring - the color, shape, size of the
aesthetic mapping (color, fill, shape, type, alpha, etc.)
4. The fourth layer - statistical transformations - looking at possible transformations
of data such as adding a trend line (stat_smooth), or using a transformed varaible
(log)
5. The fth layer - facetting data - looking at the same visual at dierent slices and
dices of the data set (facet_Wrap)
We will illustrate all this with the mtcars data:
data(mtcars)
Initiating the Graph
The graph is initiated:
ggplot(data=mtcars)
51
As we see this is the rst layer - the empty plot on which we start doing a visualization.
Aesthetic Mapping or Type
We would like to follow if there is any connection between miles per gallon, mpg (fuel
eciency) and gross horsepower, hp (power of the car). A suitable graph would be the
scatter plot:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg))
52
35
30
25
mpg
20
15
10
100 200 300
hp
It seems that the more horsepower, the less miles can a car drive for a gallon of fuel. That
shows how power and fuel eciecy are inversely correlated.
The geom_ command controls the type of graph we are making. Imagine now we would like
to see the histogram of just mpg. We thus use geom_
ggplot(data=mtcars) + geom_histogram(mapping = aes(x = mpg))
## ‘stat_bin()‘ using ‘bins = 30‘. Pick better value with ‘binwidth‘.
53
5
3
count
10 15 20 25 30 35
mpg
Every geom has its own set of relevant options. For the histogram, an example is the
number of bins.
ggplot(data=mtcars) + geom_histogram(mapping = aes(x = mpg), bins = 8)
54
7.5
5.0
count
2.5
0.0
10 20 30
mpg
We can construct the density plot of mpg:
ggplot(data=mtcars) + geom_density(mapping = aes(x =mpg))
0.06
0.04
density
0.02
0.00
10 15 20 25 30 35
mpg
55
We can see how the mpg is related to the type of transmission, am, using a boxplot:
ggplot(data=mtcars) + geom_boxplot(mapping = aes(x = [Link](am), y=mpg))
35
30
25
mpg
20
15
10
0 1
[Link](am)
A classical way to represent data is through a line. Here we plot some index number of a
given car (from 1 to 32) in the dataset against the mpg of this car:
ggplot(data=mtcars) + geom_line(mapping = aes(x = seq(32), y = mpg))
56
35
30
25
mpg
20
15
10
0 10 20 30
seq(32)
Quite obviously, such a graph would be much more insightful if we plotted the development
of a process over time or similar data.
Finally, we can even add more geoms to get the most out of out visualization. If we would
like to divide the graph into two parts with a vertical line (say at x=16), then we can use:
ggplot(data=mtcars) + geom_line(mapping = aes(x = seq(32),
y = mpg)) + geom_vline(xintercept = 16)
57
35
30
25
mpg
20
15
10
0 10 20 30
seq(32)
All in all, there are many available geoms which can be used to create appealing graphs:
• geom_abline(geom_hline, geom_vline)
• geom_bar(stat_count)
• geom_bin2d(stat_bin2d, stat_bin_2d)
• geom_blank
• geom_boxplot(stat_boxplot)
• geom_contour(stat_contour)
• geom_count(stat_sum)
• geom_crossbar(geom_errorbar, geom_linerange, geom_pointrange)
• geom_density(stat_density)
• geom_density_2d(geom_density2d, stat_density2d, stat_density_2d)
• geom_dotplot
• geom_errorbarh
• geom_freqpoly(geom_histogram, stat_bin)
• geom_hex(stat_bin_hex, stat_binhex)
• geom_jitter
• geom_label(geom_text)
• geom_map
• geom_path(geom_line, geom_step)
• geom_point
• geom_polygon
• geom_quantile(stat_quantile)
• geom_raster(geom_rect, geom_tile)
58
• geom_ribbon(geom_area)
• geom_rug
• geom_segment(geom_curve)
• geom_smooth(stat_smooth)
• geom_violin(stat_ydensity)
All Colors and Shapes
For both visual appeal, and for added informational content we can use dierent aesthetic
properties. Taking the scatterplot for hp and mpg we can change the colors:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg),
color = "purple")
35
30
25
mpg
20
15
10
100 200 300
hp
We can also incrase size:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg),
color = "purple", size=3)
59
35
30
25
mpg
20
15
10
100 200 300
hp
We can also change the type of dots:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg),
color = "purple", size=3, shape=8)
60
35
30
25
mpg
20
15
10
100 200 300
hp
This, however, brings no additional information. We can add more insight by mapping a
variable as the shape, color or size of the geom. For example we color the dots by how
many cylinders the car has:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg,
color=[Link](cyl)), size=3)
61
35
30
25 [Link](cyl)
4
mpg
6
20 8
15
10
100 200 300
hp
Note that because now the color is part of the mapping, the variable which gives the color
should go with the other ones in the aes() brackets. Even more information can be added
when we map the type of transmission (again transformed as factor) to points:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg,
color=[Link](cyl), shape=[Link](am)), size=3)
62
35
30
[Link](am)
0
25 1
mpg
[Link](cyl)
20
4
6
8
15
10
100 200 300
hp
Another parameter that may be useful is alpha, which is a measure of transparency.
Higher values of alpha are associated with a more solid color. We now map the variable am
(transmission) to transparency:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg,
color=[Link](cyl), alpha=[Link](am)), size=3)
## Warning: Using alpha for a discrete variable is not advised.
63
35
30
[Link](am)
0
1
25
drat
mpg
20 4.5
4.0
3.5
15
3.0
10
100 200 300
hp
Statistical Transformation
Some statistical transformations can be applied directly to the variables mapped. We now
look at a log-log graphs of mpg and hp:
ggplot(data=mtcars) + geom_point(mapping = aes(x = log(hp), y = log(mpg)),
color = "purple", size=3)
65
3.50
3.25
log(mpg)
3.00
2.75
2.50
4.0 4.5 5.0 5.5
log(hp)
Another common task is to add a trend line to a given graph. This is done with the
stat_smooth function:
ggplot(data=mtcars) + geom_point(mapping = aes(x = hp, y = mpg), size=3) +
stat_smooth(mapping = aes(x = hp, y = mpg))
## ‘geom_smooth()‘ using method = ’loess’ and formula ’y ~ x’
66
Link Between Engine Size and Fuel Efficiency
35
30
Miles per Gallon
25 [Link](gear)
3
4
20
5
15
10
100 200 300 400
Displacement
In addition to that, the user can add to any qplot graph the same elements that can be
added to a ggplot graph, albeit with much less exibility. For example, adding the trend
line:
qplot(x = disp, y = mpg, col = [Link](gear), size = I(3),
data = mtcars, xlab = "Displacement", ylab = "Miles per Gallon",
main = "Link Between Engine Size and Fuel Efficiency") +
stat_smooth(method = "lm", se = FALSE)
## ‘geom_smooth()‘ using formula ’y ~ x’
76