Home » Projects » Rangeland Soil Management and Hydrology » Watershed-scale Hydropedology » Hydrologic Modeling in Oak Woodland Soilscapes » SFREC » Generation of Vegetation Sampling Areas » Processing Transect Data
Processing Transect Data
Input File Format (see attached CSV file)
start stop species transect block transect.length notes
0 27 open t01 b1 344
68 93 open t01 b1 344
137 148 open t01 b1 344
160 177 open t01 b1 344
209 219 open t01 b1 344
237 318 open t01 b1 344
332 344 open t01 b1 344
27 68 blue oak t01 b1 344
93 137 blue oak t01 b1 344
148 160 blue oak t01 b1 344
177 209 blue oak t01 b1 344
219 237 blue oak t01 b1 344
318 332 blue oak t01 b1 344
[...]
Setup
## load libs
library(lattice)
## read in the data
## note that this contains multiple blank lines
x.data <- read.csv('sfrec_canopy_coverage.csv')
## remove a mistake: there is overlap between black oak and open cover types
x.data <- x.data[-125,]
Example visualization (see attached PDF below)
dotplot(species ~ start + stop | transect, data=x.data,
layout=c(3,6), as.table=TRUE, subscripts=TRUE,
xlab='Transect Distance (ft)', ylab='Cover Type',
key=list(columns=2, text=list(c('Measured', 'Estimated')), lines=list(lty=c(1,1), col=c(1,2))),
panel=function(x, y, subscripts, groups, ...)
{
## plot the points, and setup the graph
panel.dotplot(x, y, subscripts=subscripts, groups=groups, pch=NA, ...)
## convert factor level to number
y_num <- as.numeric(y)
## create a table of the distance, factor level, and start/stop flag
d <- data.frame(x=x, y=y_num, groups=groups[subscripts])
## get the start points
xy_i <- subset(d, select=c(x,y), subset=groups=='start')
## get the stop points
xy_f <- subset(d, select=c(x,y), subset=groups=='stop')
##
## make a line color, based on the notes field
## first level = black
## second level = red (estimated)
lcol=as.numeric(x.data$notes[subscripts])
## plot the lines
panel.segments(xy_i$x, xy_i$y, xy_f$x, xy_f$y, lwd=2, col=lcol)
}
)
Convert to matrix representation
d <- list()
for(j in levels(x.data$transect))
{
## work with a subset of the data:
y <- subset(x.data, subset=transect == j)
## init a matrix to hold the transect data: wide format
## fill with 0's
z <- matrix(0, ncol=length(levels(y$species)), nrow=max(y$stop))
## for each level of species, populate the corresponding cells of the matrix
for(i in 1:nrow(y))
{
## increment the start by one (shrinking the number of cells by 1)
y_start <- y$start[i] + 1
y_stop <- y$stop[i]
y_col <- as.numeric(y$species[i])
## encode the canopy type
## using powers of 2
z[y_start:y_stop, y_col] <- 2^y_col
}
eval(parse(text=paste('d$', j, ' <- z', sep='')))
}
Matrix representation and canopy overlap simplification
## generate an example
cbind(d$t10[300:320,], rowSums(d$t10[300:320,]))
*
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 8 0 8
[2,] 0 0 8 0 8
[3,] 0 0 8 0 8
[4,] 2 0 8 0 10
[5,] 2 0 8 0 10
[6,] 2 0 8 0 10
[7,] 2 0 8 0 10
[8,] 2 0 8 0 10
[9,] 2 0 8 0 10
[10,] 2 0 8 0 10
[11,] 0 0 8 0 8
[12,] 0 0 8 0 8
[13,] 0 0 8 0 8
[14,] 0 0 8 0 8
[15,] 0 0 8 0 8
[16,] 0 0 8 0 8
[17,] 0 0 0 16 16
[18,] 0 0 0 16 16
[19,] 0 0 0 16 16
[20,] 0 0 0 16 16
[21,] 0 0 0 16 16
Convert codes
## generate the canopy cover combination table
## using powers of 2
## note that we are leaving out canopy type '5' (open), as there should be no overlap
g <- t(combn(2^(1:3), 2))
g.lookup <- data.frame(apply(g, 2, function(i) levels(x.data$species)[logb(i, base=2)]), code=rowSums(g))
g.lookup.overlap <- data.frame( canopy_type=paste(g.lookup$X1, g.lookup$X2, sep=' / '), code=g.lookup$code)
## now the lookup table to non-overlapping regions
g.lookup.no_overlap <- data.frame(canopy_type=levels(x.data$species), code=2^(1:length(levels(x.data$species))))
## combine
g.lookup.final <- rbind(g.lookup.no_overlap, g.lookup.overlap)
## for each transect compute the linear totals for each canopy type, including overlap
t_sums <- lapply(d, function(i) table(rowSums(i)) )
## re-create the table with the correct canopy type for each transect
t_sums <- lapply(t_sums, function(i) data.frame(canopy=g.lookup.final$canopy_type[match(names(i), g.lookup.final$code)], t_part=as.vector(i)) )
Re-attach transect and block id
## convert to dataframe by "row-binding"
t_sums.df <- do.call('rbind', t_sums)
## re-add the transect id
t_sums.df$transect <- substr(row.names(t_sums.df), 1, 3)
## make a lookup table containing transect -> block relationship
t_b.lookup <- unique(subset(x.data, select=c(transect, block, transect.length)))
## join block data
t_b_sums.df <- merge(x=t_sums.df, y=t_b.lookup)
Compute percent cover by transect
pct_cover_by_transect <- sweep(tapply(t_b_sums.df$t_part, list(t_b_sums.df$canopy, t_b_sums.df$transect), sum, na.rm=TRUE), 2, t_b.lookup$transect.length, '/') * 100
write.csv(pct_cover_by_transect, na='', file='pct_cover_by_transect.csv')
print(pct_cover_by_transect, digits=1)
Compute percent cover by block
pct_cover_by_block <- sweep(tapply(t_b_sums.df$t_part, list(t_b_sums.df$canopy, t_b_sums.df$block), sum, na.rm=TRUE), 2, tapply(t_b.lookup$transect.length, t_b.lookup$block, sum), '/') * 100
write.csv(pct_cover_by_block, na='', file='pct_cover_by_block.csv')
print(pct_cover_by_block, digits=1)
Compute percent cover across all data
pct_cover <- data.frame(pct_cover=tapply(t_b_sums.df$t_part, list(t_b_sums.df$canopy), sum, na.rm=TRUE) / sum(sapply(d, function(i) nrow(i))) * 100)
write.csv(pct_cover, na='', file='pct_cover.csv')
print(pct_cover, digits=1)