Alt + - gives <- This is
the assignment operator which is seen below.
Ctrl + Shift + M gives
|> but if using either the
magrittr, tidyverse or other packages it will
give %>%. Whether these are different is unknown.
Further keyboard commands are at:
R Markdown Stuff for further analysis
To find information on a function, type ? in the console
below followed by the function name to display help.
Like a Rubic’s cube an array is a 3-dimensional “table”.
The syntax is straight forward:
array(data, dim, dimnames)
Where:
Example:
a1 <- array(c(1:75), dim = c(5, 5, 3), dimnames = list(letters[1:5], c(1:5), LETTERS[1:3]))
a1
## , , A
##
## 1 2 3 4 5
## a 1 6 11 16 21
## b 2 7 12 17 22
## c 3 8 13 18 23
## d 4 9 14 19 24
## e 5 10 15 20 25
##
## , , B
##
## 1 2 3 4 5
## a 26 31 36 41 46
## b 27 32 37 42 47
## c 28 33 38 43 48
## d 29 34 39 44 49
## e 30 35 40 45 50
##
## , , C
##
## 1 2 3 4 5
## a 51 56 61 66 71
## b 52 57 62 67 72
## c 53 58 63 68 73
## d 54 59 64 69 74
## e 55 60 65 70 75
Accessing an element in an array is the same as a matrix but add the 3rd dimension i.e. row, column & dimension:
a1[4, 3, 2]
## [1] 39
Like matrices, rows or columns use the same syntax; 2nd row from 2nd matrix:
a1[2,, 2]
## 1 2 3 4 5
## 27 32 37 42 47
3rd column from 1st matrix:
a1[, 3, 1]
## a b c d e
## 11 12 13 14 15
Or even the entire matrix:
a1[,, 3]
## 1 2 3 4 5
## a 51 56 61 66 71
## b 52 57 62 67 72
## c 53 58 63 68 73
## d 54 59 64 69 74
## e 55 60 65 70 75
All loops form a recurring function:
“When this condition is happening… do this.”
The format is generally the same:
when (something here is TRUE) {
do this
}
All loops have a block. The block is considered to be
everything between the {} .
A function that iterates over a set number of values to perform a repeating task. In its simplest form it says:
“For every value in this list - do this - but only after the condition is tested“
# Print the square of each number from 1 to 10 inclusive. This also stores the value into a vector
for (i in 1:10) {
x1 <- i^2
print(x1)
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100
# Looping over a vector:
x2 <- c("Fred", "George", "Ginny", "Ron", "Percy")
for (i in x2) {
print(i)
}
## [1] "Fred"
## [1] "George"
## [1] "Ginny"
## [1] "Ron"
## [1] "Percy"
# A for loop can also iterate over a vector to create further data:
for (i in x2) {
print(paste("The name", i, "contains", nchar(i), "characters."))
}
## [1] "The name Fred contains 4 characters."
## [1] "The name George contains 6 characters."
## [1] "The name Ginny contains 5 characters."
## [1] "The name Ron contains 3 characters."
## [1] "The name Percy contains 5 characters."
# Note that spaces do not need to be added to the printed output
For loops can be nested to create integrated? values. This example uses the first 3 LETTERS of the alphabet and pastes then against the first 3 letters of the alphabet:
for (i in 1:3) {
for (j in 1:3) {
print(paste(LETTERS[i], letters[j], sep = " "))
}
}
## [1] "A a"
## [1] "A b"
## [1] "A c"
## [1] "B a"
## [1] "B b"
## [1] "B c"
## [1] "C a"
## [1] "C b"
## [1] "C c"
A while loop will also run the condition before the block is executed but will not iterate to the next value automatically; it needs to be executed in the block. It also requires an assigned vector beforehand:
In its simplest form it says:
“Whilst this condition is true - do this - but only after the condition is tested“
x <- 0
while (x < 5) {
print(x)
x <- x + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
Perhaps not a loop as the condition only executes once. Simply put:
“Do this if the condition is met”
x <- 10
if(x == 10) {
print("X is equal to 10")
}
## [1] "X is equal to 10"
An extension to the if loop that simply says:
“Do this if the condition is met - if it is not met do this instead”
x <- 10
if (x < 10) {
print("x is lower than 10")
} else if (x > 10) {
print("x is greater than 10")
} else {
print("x is 10")
}
## [1] "x is 10"
As the name suggests these repeat until a further
condition is met. They will read the block first. That
further condition is an if loop:
“Repeat this condition until the secondary condition is met then execute that block”
x <- 1
repeat {
print(x)
x <- x + 1
if(x == 10) {
break
}
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
This last loop is perhaps more of a statement than a loop and is the
only loop function that is not enclosed in { }It only
iterates once as it will read the block before executing the
condition. Note the commas in the example. Also note,
only character switches have a default.
x <- 8
switch (x,
"Yes it's 1",
"Yes it's 2",
"Yes it's 3",
"Yes it's 4",
)
# If the vector is a character each case needs to be defined:
y <- "x"
switch(y,
fred = "It's Fred",
george = "It's George",
ron = "It's Ron",
ginny = "It's Ginny",
percy = "It's Percy",
"It's no-one"
)
## [1] "It's no-one"
For numeric switches, the default is to return NULL it
will display nothing. To return a value add the below after the
switch:
if (is.null(expression)) expression <- "No value"
If a .csv file contains blank cells, these can be replaced with NA’s:
read.csv("file", na.strings = " ", NA)
class() gives the type of vector
head() gives the first 10 rows of a dataframe. This is
the default setting
nchar() gives the number of characters in a vector
view() displays the dataframe
sheetindex = lets read.csv select the
sheet
sort() a function to sort data by increasing or
decreasing values
table() gives a tabulated frequency count
tail() gives the last 10 rows of a dataframe. This is
the default setting
unique() similar to table() but only gives
unique values
replace(vector, position, value) replace values in a
vector
print() print characters etc
paste()
letters() lower case letters
LETTERS() upper case letters
Assign a variable outside a function <<-
To get the current directory:
getwd()
## [1] "C:/Users/steve/Desktop/R Files, Examples etc/Bibble"
# An alternative is:
path.expand("~/")
## [1] "C:/Users/steve/Documents/"
But this only returns the value to the penultimate folder and gives it in this format, however, when you set the working directory the / has to become \\.
setwd("C:\\Users\\steve\\Desktop\\R Files, Examples etc\\TEST")
# Display directory
getwd()
## [1] "C:/Users/steve/Desktop/R Files, Examples etc/TEST"
The alternate to having to change all the slashes is:
setwd(chartr("\\", "/", r"(C:\Users\steve\Desktop\V2C)"))
Dataframes are a type of table but differ significantly [define difference].
The syntax for a dataframe is:
data.frame(data, row.names, check.rows, check.names, fix.empty.names, stringAsFactors)
Where:
data - the data to use
row.names - optional - specifies a column to be used as row names (like column 1)
check.rows - optional - if TRUE rows are checked for consistency
check.names - optional - if TRUE syntactically checks the names of the variables in the dataframe
fix.empty.names - optional - argument for replacing empty names
stringAsFactors - optional - should character vectors be converted to factors?
df <- data.frame(
A = 1:5,
B = 6:10,
C = 11:15,
D = 16:20,
E = 21:25
)
# View the df
df
## A B C D E
## 1 1 6 11 16 21
## 2 2 7 12 17 22
## 3 3 8 13 18 23
## 4 4 9 14 19 24
## 5 5 10 15 20 25
You can view the dataframes using the data() function
but this will not save anything to a variable; to do this you need the
below format (note the head() function that displays the
first x rows of code - tail() in-turn displays the
last x rows of code):
df1 <- Seatbelts
df1 <- as.data.frame(df1)
head(df1)
## DriversKilled drivers front rear kms PetrolPrice VanKilled law
## 1 107 1687 867 269 9059 0.1029718 12 0
## 2 97 1508 825 265 7685 0.1023630 6 0
## 3 102 1507 806 319 9963 0.1020625 12 0
## 4 87 1385 814 407 10955 0.1008733 8 0
## 5 119 1632 991 454 11823 0.1010197 10 0
## 6 106 1511 945 427 12391 0.1005812 13 0
These files require a library to be opened. There are two ways to do this:
library(readxl)readxl::read_xlsxThe simplest way to create a dataframe is to create a matrix then convert it to a dataframe:
m1 <- matrix(c(1:30), 5, 6)
m1 <- as.data.frame(m1)
m1
## V1 V2 V3 V4 V5 V6
## 1 1 6 11 16 21 26
## 2 2 7 12 17 22 27
## 3 3 8 13 18 23 28
## 4 4 9 14 19 24 29
## 5 5 10 15 20 25 30
The easiest way to get a dataframe is to download one if you have one to hand.
df2 <- read.csv(chartr("\\", "/", r"(C:\Users\steve\Desktop\R Files, Examples etc\Bibble\10by10.csv)"))
A .csv file is normally set to the first column. If these need
splitting use sep = ", " to split the data up.
To easily review a dataset (although this does not print here it is displayed within the RStudio environment):
View(df2)
Or to get the structure of the data:
str(df2)
## 'data.frame': 10 obs. of 10 variables:
## $ A: int 1 11 21 31 41 51 61 71 81 91
## $ B: int 2 12 22 32 42 52 62 72 82 92
## $ C: int 3 13 23 33 43 53 63 73 83 93
## $ D: int 4 14 24 34 44 54 64 74 84 94
## $ E: int 5 15 25 35 45 55 65 75 85 95
## $ F: int 6 16 26 36 46 56 66 76 86 96
## $ G: int 7 17 27 37 47 57 67 77 87 97
## $ H: int 8 18 28 38 48 58 68 78 88 98
## $ I: int 9 19 29 39 49 59 69 79 89 99
## $ J: int 10 20 30 40 50 60 70 80 90 100
Or the summary:
summary(df2)
## A B C D E
## Min. : 1.0 Min. : 2.0 Min. : 3.0 Min. : 4.0 Min. : 5.0
## 1st Qu.:23.5 1st Qu.:24.5 1st Qu.:25.5 1st Qu.:26.5 1st Qu.:27.5
## Median :46.0 Median :47.0 Median :48.0 Median :49.0 Median :50.0
## Mean :46.0 Mean :47.0 Mean :48.0 Mean :49.0 Mean :50.0
## 3rd Qu.:68.5 3rd Qu.:69.5 3rd Qu.:70.5 3rd Qu.:71.5 3rd Qu.:72.5
## Max. :91.0 Max. :92.0 Max. :93.0 Max. :94.0 Max. :95.0
## F G H I J
## Min. : 6.0 Min. : 7.0 Min. : 8.0 Min. : 9.0 Min. : 10.0
## 1st Qu.:28.5 1st Qu.:29.5 1st Qu.:30.5 1st Qu.:31.5 1st Qu.: 32.5
## Median :51.0 Median :52.0 Median :53.0 Median :54.0 Median : 55.0
## Mean :51.0 Mean :52.0 Mean :53.0 Mean :54.0 Mean : 55.0
## 3rd Qu.:73.5 3rd Qu.:74.5 3rd Qu.:75.5 3rd Qu.:76.5 3rd Qu.: 77.5
## Max. :96.0 Max. :97.0 Max. :98.0 Max. :99.0 Max. :100.0
Which provides:
min - the minimum value
1st quantile - the first 25% of the value
median - the middle value
mean - the mean value (total / amount)
3rd quantile - the first 75% of the value
max- the maximum value
NA - the number of NAs
Very useful in a table, matrix or dataframe. This deletes columns 1, 3 & 4 from df2.
df2 <- df2[-c(1, 3:4)]
df2
## B E F G H I J
## 1 2 5 6 7 8 9 10
## 2 12 15 16 17 18 19 20
## 3 22 25 26 27 28 29 30
## 4 32 35 36 37 38 39 40
## 5 42 45 46 47 48 49 50
## 6 52 55 56 57 58 59 60
## 7 62 65 66 67 68 69 70
## 8 72 75 76 77 78 79 80
## 9 82 85 86 87 88 89 90
## 10 92 95 96 97 98 99 100
# Deleting rows is exactly the same except a comma is added before the closing bracket ]
df2 <- df2[-c(3),]
df2
## B E F G H I J
## 1 2 5 6 7 8 9 10
## 2 12 15 16 17 18 19 20
## 4 32 35 36 37 38 39 40
## 5 42 45 46 47 48 49 50
## 6 52 55 56 57 58 59 60
## 7 62 65 66 67 68 69 70
## 8 72 75 76 77 78 79 80
## 9 82 85 86 87 88 89 90
## 10 92 95 96 97 98 99 100
# To delete a row that contains a value
df2 <- df2[!grepl("46", "F"),]
df2
## B E F G H I J
## 1 2 5 6 7 8 9 10
## 2 12 15 16 17 18 19 20
## 4 32 35 36 37 38 39 40
## 5 42 45 46 47 48 49 50
## 6 52 55 56 57 58 59 60
## 7 62 65 66 67 68 69 70
## 8 72 75 76 77 78 79 80
## 9 82 85 86 87 88 89 90
## 10 92 95 96 97 98 99 100
Changing these is easy and there are several styles to change them to.
df <- read.csv(chartr("\\", "/", r"(C:\Users\steve\Desktop\R Files, Examples etc\Bibble\10by10.csv)"))
# All examples work for both rows and columns
rownames(df) <- c("Row 1", "Row 2", "Row 3", "Row 4", "Row 5", "Row 6", "Row 7", "Row 8", "Row 9", "Row 10")
df
## A B C D E F G H I J
## Row 1 1 2 3 4 5 6 7 8 9 10
## Row 2 11 12 13 14 15 16 17 18 19 20
## Row 3 21 22 23 24 25 26 27 28 29 30
## Row 4 31 32 33 34 35 36 37 38 39 40
## Row 5 41 42 43 44 45 46 47 48 49 50
## Row 6 51 52 53 54 55 56 57 58 59 60
## Row 7 61 62 63 64 65 66 67 68 69 70
## Row 8 71 72 73 74 75 76 77 78 79 80
## Row 9 81 82 83 84 85 86 87 88 89 90
## Row 10 91 92 93 94 95 96 97 98 99 100
# Or
colnames(df) <- c(letters[1:10])
df
## a b c d e f g h i j
## Row 1 1 2 3 4 5 6 7 8 9 10
## Row 2 11 12 13 14 15 16 17 18 19 20
## Row 3 21 22 23 24 25 26 27 28 29 30
## Row 4 31 32 33 34 35 36 37 38 39 40
## Row 5 41 42 43 44 45 46 47 48 49 50
## Row 6 51 52 53 54 55 56 57 58 59 60
## Row 7 61 62 63 64 65 66 67 68 69 70
## Row 8 71 72 73 74 75 76 77 78 79 80
## Row 9 81 82 83 84 85 86 87 88 89 90
## Row 10 91 92 93 94 95 96 97 98 99 100
# Or
colnames(df) <- c(LETTERS[1:10])
df
## A B C D E F G H I J
## Row 1 1 2 3 4 5 6 7 8 9 10
## Row 2 11 12 13 14 15 16 17 18 19 20
## Row 3 21 22 23 24 25 26 27 28 29 30
## Row 4 31 32 33 34 35 36 37 38 39 40
## Row 5 41 42 43 44 45 46 47 48 49 50
## Row 6 51 52 53 54 55 56 57 58 59 60
## Row 7 61 62 63 64 65 66 67 68 69 70
## Row 8 71 72 73 74 75 76 77 78 79 80
## Row 9 81 82 83 84 85 86 87 88 89 90
## Row 10 91 92 93 94 95 96 97 98 99 100
To replace NAs in a dataframe:
# First, introduce an NA
df2[7,8] <- NA
# Then use is.na to replace
df2[is.na(df2)] <- 'A'
Length of row:
length(df2[,1])
## [1] 9
Or column:
length(df2[1,])
## [1] 8
# Dimensions
dim(df)
## [1] 10 10
# Get row names (without changing them)
rownames(df)
## [1] "Row 1" "Row 2" "Row 3" "Row 4" "Row 5" "Row 6" "Row 7" "Row 8"
## [9] "Row 9" "Row 10"
# Ditto column names
colnames(df)
## [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
A single cell, row, rows and/or columns in a dataframe can be saved to a vector:
# get row 3, column E
v1 <- df[3, 5]
# Get column B
v2 <- df2$B
# Get rows 2 & 3
v3 <- df2$c[2:3]
# Want multiple cells? Columns 1, 3, 5 - 7 of row 1
v4 <- df2$A[1, c(1, 3, 5:7)]
Dataframes (and other types of storage vectors) will, at some point, contain blank data which will need to be dealt with. Dependant on the way the blank data is presented dictates the process required but an easy rule is:
var[data == "?"] <- NA
Meaning that any cell containing a ? will be replaced
with NA. var & data is the
name of the dataframe. This is shown below:
df4 <- data.frame(matrix(c(1:4, "?", 6:11, "?", 13:15, "?", 17:23, "?", "?"), 5, 5))
df4
## X1 X2 X3 X4 X5
## 1 1 6 11 ? 21
## 2 2 7 ? 17 22
## 3 3 8 13 18 23
## 4 4 9 14 19 ?
## 5 ? 10 15 20 ?
df4[df4 == "?"] <- NA
df4
## X1 X2 X3 X4 X5
## 1 1 6 11 <NA> 21
## 2 2 7 <NA> 17 22
## 3 3 8 13 18 23
## 4 4 9 14 19 <NA>
## 5 <NA> 10 15 20 <NA>
Once all blank data is formatted to the same variable a further function can be used to bring the dataframe back together:
Checks a variable for missing data.
v1 <- c(99L, 43L)
# Returns FALSE for valid data
is.na(v1)
## [1] FALSE FALSE
# Returns TRUE for valid data. Note the ! at the beginning
!is.na(v1)
## [1] TRUE TRUE
There are 5 types of vectors:
{r} v1 <- c(TRUE, FALSE, FALSE) # c() Allows for a range of values to be stored}
Integer - whole numbers
{r} v2 <- c(99L, 43L) # The 'L' specifies integer}
Numeric - mixed numbers
{r} v3 <- c(15, 19.35, 0.86, 32.456, 18.2)}
Complex - algebraic numbers
{r} v4 <- c(4+3i, 8+7i) # The 'i' specifies a complex number}
Character - strings
{r} v5 <- c("This", 'is', "today") # n.b. This will print "Thisistoday" as spaces need to be added. Note each word is braced by either ' or " - these must be paired for each brace and not eg. "This'}
Variables can be concatenated together:
{r} v6 <- v2 + v2 v6}
Can be checked against:
{r} v2 > 44}
And a single value, or a range of values can be taken:
{r} v3[2] v3[c(3:5)]}
{r} x1 <- c((1:3), (1:3)) x1 class(x1) x2 <- as.character(x1) x2 class(x2) x3 <- as.factor(x1) x3 class(x3) x4 <- as.integer(x3) x4 class(x4)}
Back ticks form the basis of small bits of code.
Three back ticks create a chunk of code: ```
A chunk of code
The chunk must be closed of by three back ticks too.
A single line of code can be written with just one back tick:
A line of code
And must be closed with another single back tick. Or click the
</> button on the menu (next to the
bold and italics buttons).
Bold text is encapsulated by ** whereas
Italics are encapsulated by *
Code can be inserted into these chunks to. This:
“I counted ‘r sum(c(1, 2, 3))’ blue cars on the motorway.”
Becomes: “I counted 6 blue cars on the motorway.”
\u00C0 → À
\u00C1 → Á
\u00C2 → Â
\u00C3 → Ã
\u00C4 → Ä
\u00C5 → Å
\u00E0 → à
\u00E1 → á
\u00E2 → â
\u00E3 → ã
\u00E4 → ä
\u00E5 → å
\u00C7 → Ç
\u00E7 → ç
\u00C8 → È
\u00C9 → É
\u00CA → Ê
\u00CB → Ë
\u00E8 → è
\u00E9 → é
\u00EA → ê
\u00EB → ë
\u00CC → Ì
\u00CD → Í
\u00CE → Î
\u00CF → Ï
\u00EC → ì
\u00ED → í
\u00EE → î
\u00EF → ï
\u00D1 → Ñ
\u00F1 → ñ
\u00D2 → Ò
\u00D3 → Ó
\u00D4 → Ô
\u00D5 → Õ
\u00D6 → Ö
\u00F2 → ò
\u00F3 → ó
\u00F4 → ô
\u00F5 → õ
\u00F6 → ö
\u00D9 → Ù
\u00DA → Ú
\u00DB → Û
\u00DC → Ü
\u00F9 → ù
\u00FA → ú
\u00FB → û
\u00FC → ü
\u00DD → Ý
\u00FD → ý
\u00FF → ÿ
\u00C6 → Æ # Ash
\u00E6 → æ
\u0152 → Œ # Ethel
\u0153 → œ
\u00DF → ß
\u00AB → «
\u00BB → »
\u00A3 → £
\u20AC → €
\u0391 → Α # Alpha
\u03B1 → α
\u0392 → Β # Beta
\u03B2 → β
\u0393 → Γ # Gamma
\u03B3 → γ
\u0394 → Δ # Delta
\u03B4 → δ
\u0395 → Ε # Epsilon
\u03B5 → ε
\u0396 → Ζ # Zeta
\u03B6 → ζ
\u0397 → Η # Eta
\u03B7 → η
\u0398 → Θ # Theta
\u03B8 → θ
\u0399 → Ι # Iota
\u03B9 → ι
\u039A → Κ # Kappa
\u03BA → κ
\u039B → Λ # Lambda
\u03BB → λ
\u039C → Μ # Mu
\u03BC → μ
\u039D → Ν # Nu
\u03BD → ν
\u039E → Ξ # Xi
\u03BE → ξ
\u039F → Ο # Omicron
\u03BF → ο
\u03A0 → Π # Pi
\u03C0 → π
\u03A1 → Ρ # Rho
\u03C1 → ρ
\u03A3 → Σ # Sigma
\u03C3 → σ
\u03C2 → ς (used if the last letter in a word is s)
\u03A4 → Τ # Tau
\u03C4 → τ
\u03A5 → Υ # Upsilon
\u03C5 → υ
\u03A6 → Φ # Phi
\u03C6 → φ
\u03A7 → Χ # Chi
\u03C7 → χ
\u03A8 → Ψ # Psi
\u03C8 → ψ
\u03A9 → Ω # Omega
\u03C9 → ω
\u00D7 → ×
\u00F7 → ÷
\u2260 → ≠
\u2264 → ≤
\u2265 → ≥
\u2248 → ≈
\u223C → ∼
\u00B1 → ±
\u221E → ∞
\u221A → √
\u222B → ∫
\u222C → ∬
\u222D → ∭
\u2220 → ∠
\u00B0 → °
\u2208 → ∈
\u2282 → ⊂
\u2283 → ⊃
\u2227 → ∧
\u2228 → ∨
\u00AC → ¬
\u2190 → ←
\u2192 → →
\u2191 → ↑
\u2193 → ↓
\u21D2 → ⇒
\u21D4 → ⇔
These will only work on the numerical side of a keyboard.
0227
0128
a = á
A = Á
e = é
E = É
Details on Markdown can be found here http://rmarkdown.rstudio.com. To paste a weblink encapsulate the url in < and >.
To generate a report from the file, run the render
command:
Working Directories
# Get working directory
getwd()
## [1] "C:/Users/steve/Desktop/R Files, Examples etc/Bibble"
# Set working directory
# When the path is pasted into setwd() each \ needs to be replaced with / so:
# setwd("C:\Users\steve\Desktop\R Files, Examples etc\Bibble")
# fails but:
setwd("C:/Users/steve/Desktop/R Files, Examples etc/Bibble")
# or do this:
df <- read.csv(chartr("\\", "/", r"(C:\Users\steve\Desktop\V2C\EPCs.csv)"))
This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.