################################################################################ ### R BASICS WORKSHOP ### ### PRESENTATION 9: FLOW CONTROL ### ### ### ### Center for Conservation and Sustainable Development ### ### Missouri Botanical Garden ### ### Website: rbasicsworkshop.weebly.com ### ################################################################################ ### INTRODUCTION ############################################################### # In R there is a series of elements that allow the control of flow of commands # in a script. There are 3 main ways of flow control: # 1. Loops: *for* # 2. Loops: *while* # 3. Conditionals: *if* / *else* # 4. Breaks # For this presentation, we will concentrate on *for*, *while* and *if* ## IMPORTANT: for help with flow control: help(Control) ###################### ## A useful example ## ###################### # The objective of the example is to create a map that shows the distribution # of species of trees across a forest plot. Each species is supposed to be # represented with a different color. # Open a randomized version of the Tyson Forest Dynamics Plot census data. The # dataset contains information on the identity and distribution of individual # trees across a 25ha area in the Tyson Research Center, near St. Louis, MO. # (the data has been randomized. Thanks to Jonathan A. Myers for the data.) tyson <- read.table(file=file.choose(), header=TRUE, sep="\t") # Check that the open data looks right head(tyson) # Now, lets make a plot of the distribution of tree species in the forest plot # OPTION 1: NO LOOP # sp.list <- unique(tyson$spcode) colors <- sample(adjustcolor(rainbow(length(sp.list)), alpha.f=0.8)) tiff(filename="TysonForestMap_1.tif", width=10, height=10, units="in", res=300) # Creates an empty plot plot(tyson$gx, tyson$gy, xlab="x", ylab="y", asp=1, type="n", cex.lab=1.5, cex.axis=1.5) # Plots trees of species "ulmrub" points(tyson$gx[tyson$spcode=="ulmrub"], tyson$gy[tyson$spcode=="ulmrub"], pch=16, col=colors[1]) # Plots trees of species "lonmaa" points(tyson$gx[tyson$spcode=="lonmaa"], tyson$gy[tyson$spcode=="lonmaa"], pch=16, col=colors[2]) # etc. points(tyson$gx[tyson$spcode=="asitri"], tyson$gy[tyson$spcode=="asitri"], pch=16, col=colors[3]) points(tyson$gx[tyson$spcode=="acerub"], tyson$gy[tyson$spcode=="acerub"], pch=16, col=colors[4]) points(tyson$gx[tyson$spcode=="diovir"], tyson$gy[tyson$spcode=="diovir"], pch=16, col=colors[5]) points(tyson$gx[tyson$spcode=="linben"], tyson$gy[tyson$spcode=="linben"], pch=16, col=colors[6]) points(tyson$gx[tyson$spcode=="cercan"], tyson$gy[tyson$spcode=="cercan"], pch=16, col=colors[7]) points(tyson$gx[tyson$spcode=="celocc"], tyson$gy[tyson$spcode=="celocc"], pch=16, col=colors[8]) points(tyson$gx[tyson$spcode=="unknown"], tyson$gy[tyson$spcode=="unknown"], pch=16, col=colors[9]) points(tyson$gx[tyson$spcode=="plaocc"], tyson$gy[tyson$spcode=="plaocc"], pch=16, col=colors[10]) points(tyson$gx[tyson$spcode=="pruser"], tyson$gy[tyson$spcode=="pruser"], pch=16, col=colors[11]) points(tyson$gx[tyson$spcode=="ostvir"], tyson$gy[tyson$spcode=="ostvir"], pch=16, col=colors[12]) points(tyson$gx[tyson$spcode=="carcor"], tyson$gy[tyson$spcode=="carcor"], pch=16, col=colors[13]) points(tyson$gx[tyson$spcode=="tilame"], tyson$gy[tyson$spcode=="tilame"], pch=16, col=colors[14]) points(tyson$gx[tyson$spcode=="prusp"], tyson$gy[tyson$spcode=="prusp"], pch=16, col=colors[15]) points(tyson$gx[tyson$spcode=="celten"], tyson$gy[tyson$spcode=="celten"], pch=16, col=colors[16]) points(tyson$gx[tyson$spcode=="quesp"], tyson$gy[tyson$spcode=="quesp"], pch=16, col=colors[17]) points(tyson$gx[tyson$spcode=="morrub"], tyson$gy[tyson$spcode=="morrub"], pch=16, col=colors[18]) points(tyson$gx[tyson$spcode=="malioe"], tyson$gy[tyson$spcode=="malioe"], pch=16, col=colors[19]) points(tyson$gx[tyson$spcode=="cordru"], tyson$gy[tyson$spcode=="cordru"], pch=16, col=colors[20]) points(tyson$gx[tyson$spcode=="aceneg"], tyson$gy[tyson$spcode=="aceneg"], pch=16, col=colors[21]) points(tyson$gx[tyson$spcode=="quemue"], tyson$gy[tyson$spcode=="quemue"], pch=16, col=colors[22]) points(tyson$gx[tyson$spcode=="junvir"], tyson$gy[tyson$spcode=="junvir"], pch=16, col=colors[23]) points(tyson$gx[tyson$spcode=="carsp"], tyson$gy[tyson$spcode=="carsp"], pch=16, col=colors[24]) points(tyson$gx[tyson$spcode=="quealb"], tyson$gy[tyson$spcode=="quealb"], pch=16, col=colors[25]) points(tyson$gx[tyson$spcode=="querub"], tyson$gy[tyson$spcode=="querub"], pch=16, col=colors[26]) points(tyson$gx[tyson$spcode=="quevel"], tyson$gy[tyson$spcode=="quevel"], pch=16, col=colors[27]) points(tyson$gx[tyson$spcode=="corflo"], tyson$gy[tyson$spcode=="corflo"], pch=16, col=colors[28]) points(tyson$gx[tyson$spcode=="quemar"], tyson$gy[tyson$spcode=="quemar"], pch=16, col=colors[29]) points(tyson$gx[tyson$spcode=="cartex"], tyson$gy[tyson$spcode=="cartex"], pch=16, col=colors[30]) points(tyson$gx[tyson$spcode=="amearb"], tyson$gy[tyson$spcode=="amearb"], pch=16, col=colors[31]) points(tyson$gx[tyson$spcode=="cargla"], tyson$gy[tyson$spcode=="cargla"], pch=16, col=colors[32]) points(tyson$gx[tyson$spcode=="carova"], tyson$gy[tyson$spcode=="carova"], pch=16, col=colors[33]) points(tyson$gx[tyson$spcode=="fraame"], tyson$gy[tyson$spcode=="fraame"], pch=16, col=colors[34]) points(tyson$gx[tyson$spcode=="cartom"], tyson$gy[tyson$spcode=="cartom"], pch=16, col=colors[35]) points(tyson$gx[tyson$spcode=="queste"], tyson$gy[tyson$spcode=="queste"], pch=16, col=colors[36]) points(tyson$gx[tyson$spcode=="pruame"], tyson$gy[tyson$spcode=="pruame"], pch=16, col=colors[37]) points(tyson$gx[tyson$spcode=="jugnig"], tyson$gy[tyson$spcode=="jugnig"], pch=16, col=colors[38]) points(tyson$gx[tyson$spcode=="sasalb"], tyson$gy[tyson$spcode=="sasalb"], pch=16, col=colors[39]) points(tyson$gx[tyson$spcode=="ailalt"], tyson$gy[tyson$spcode=="ailalt"], pch=16, col=colors[40]) points(tyson$gx[tyson$spcode=="crasp"], tyson$gy[tyson$spcode=="crasp"], pch=16, col=colors[41]) points(tyson$gx[tyson$spcode=="vibruf"], tyson$gy[tyson$spcode=="vibruf"], pch=16, col=colors[42]) points(tyson$gx[tyson$spcode=="fracar"], tyson$gy[tyson$spcode=="fracar"], pch=16, col=colors[43]) points(tyson$gx[tyson$spcode=="sidlan"], tyson$gy[tyson$spcode=="sidlan"], pch=16, col=colors[44]) points(tyson$gx[tyson$spcode=="gletri"], tyson$gy[tyson$spcode=="gletri"], pch=16, col=colors[45]) points(tyson$gx[tyson$spcode=="acesac"], tyson$gy[tyson$spcode=="acesac"], pch=16, col=colors[46]) dev.off() # OPTION 2: YES PLEASE, LOOP! # sp.list <- unique(tyson$spcode) colors <- adjustcolor(rainbow(length(sp.list)), alpha.f=0.8) tiff(filename="TysonForestMap_2.tif", width=10, height=10, units="in", res=300) plot(tyson$gx, tyson$gy, xlab="x", ylab="y", asp=1, type="n", cex.lab=1.5, cex.axis=1.5) for(i in 1:length(sp.list)) points(tyson$gx[tyson$spcode==sp.list[i]], tyson$gy[tyson$spcode==sp.list[i]], pch=16, col=colors[i]) dev.off() # How would you need to modify the code in the no loop and the yes loop options # to change the size of the symbols that represent each tree? ################################################################################ ### 1. LOOPS: *for* ############################################################ ################################################################################ # A loops allows you to re-run a piece of code multiple times without needing to # re-write the code. # *for* is the most common way to build a loop, repeating a piece of code a # predetermined number of times. # The general structure of a *for* loops is: # # for(variable in vector) # { # code # } # This translates approximately to: # # for each value that variable takes from vector, repeat: # { # this code # } #################### ## Easy example 1 ## #################### for(i in 1:10) { print(i) } # This would translate to: # # Create a sequence from 1 to 10 and save it into a vector named *v* # # For each values that *i* takes from vector *v*, do the following: #{ # print the value of *i* #} #################### ## Easy example 2 ## #################### letters for(i in letters) { print(i) } #################### ## Easy example 3 ## #################### length(letters) result <- 0 for(i in letters) { print(i) result <- result + 1 } result #################### ## Easy example 4 ## #################### v <- c(1,3,5,2,4) result <- 0 for(i in 1:length(v)) { print( c(i, v[i]) ) result <- result + v[i] } result #################### ## Easy example 5 ## #################### # The Fibonacci sequence is a famous sequence in mathematics. The first two # elements are 1 and 1. The subsequent elements are defined as the sum of the # preceding 2. For example, the third element is 2 (1+1), the forth element is # 3 (2+1), and so on. In this example, we will calculate the first 'n' # numbers in the Fibonacci sequence. # This creates a variable that determines the length of the Fibonacci sequence: n <- 50 # It is often useful to create an empty object that will store values created # at each iteration of a loop. In this case, we create an empty vector of # length 'n': fibonacci <- rep(NA, times=n) # Check the contencts of 'fibonacci': fibonacci # By definition, the first two elements of the sequence are 1: fibonacci[1] <- 1 fibonacci[2] <- 1 # This loop will calculate the elements 3 to 'n' of the sequence: for(i in 3:n) { # The element 'i' is calculated as the sum of elements 'i-1' and 'i-2' fibonacci[i] <- fibonacci[i-1] + fibonacci[i-2] } # You can now check the sequence: fibonacci #################### ## Easy example 6 ## #################### # For this example, we will use the Iris dataset. This dataset already exists # in R and can be loaded by typing: data(iris) # Loops can also be used to modify plots, in this example, we will use it to # add data for different species to a plot of sepal length against sepal width. # To find the names of the variables in the dataset, type: colnames(iris) # To make an initial plot that will be modified by each iteration, type: plot(iris$Sepal.Length ~ iris$Sepal.Width, type="n") # Note that by setting the argument 'type' to '"n"', the plot is constructed # without any points inside of it. Now, with a loop, we can add points for each # species: spp.list <- unique(iris$Species) spp.cols <- c("darkorange", "darkolivegreen3", "white") for(i in 1:length(spp.list)) { which.sp <- which(iris$Species == spp.list[i]) points(iris$Sepal.Length[which.sp]~iris$Sepal.Width[which.sp], cex=1.5, pch=21, col="grey50", bg=spp.cols[i]) } # Note how the looping variable 'i' is used in multiple places for indexing, # thus defining the data and color to be used for each species.