With a recent version of R, it should be possible to get all of the packages that this tutorial depends on via:
# run these commands in the R console
install.packages('aqp', dep=TRUE) # stable version from CRAN + dependencies
install.packages('RODBC', dep=TRUE) # stable version from CRAN + dependencies
install.packages('soilDB', dep=TRUE) # stable version from CRAN + dependencies
install.packages('sharpshootR', dep=TRUE) # stable version from CRAN + dependencies
Setting up this connection is simple, and outlined in this guide. Queries submitted to the national database will load pedons or DMU data into your local database. Functions in soilDB
can only access data in your local database, defined by the "selected set". While it is possible to filter pedon or DMU records within R, it is sometimes simpler to modify the "selected set" in NASIS. In other words:
Before running this code, be sure to read the instructions above on setting up and ODBC connection and selected set. This approach could also be used to load equivalent data from a PedonPC database using fetchPedonPC('path.to.your.data.base.accdb')
. Note that the filtering step described below should be adjusted to fit your data. In this case, we are keeping pedons from the "CA630" survey area, and filtering based on the occurrence of this pattern within the user site ID.
# load required libraries
library(soilDB)
library(lattice)
library(sharpshootR)
library(igraph)
# setup plotting style for later
tps <- list(superpose.line=list(col='RoyalBlue', lwd=2))
# pre-loaded all CA630 pedons
# load all pedons from the selected set, skip filterintg of hz errors
f <- fetchNASIS(from='pedons', rmHzErrors=FALSE)
# keep only thermic STR
f <- f[which(f$taxtempregime == 'thermic'), ]
The table()
function is a great way to count the number of cases of each level of a category, or, cross-tabulation among several categories. Objects returned by table()
can be readily visualized using the dotplot()
function.
# tabulate all bedrock kinds
bt <- table(f$bedrckkind)
# display just the top 20
dotplot(sort(bt, decreasing=TRUE)[1:30], col='black')
There are several bedrock kinds that are functionally similar within CA630, so we can group them into a several "generalized bedrock kinds". Note that we are matching bedorock kind with several possible options using the %in%
operator.
# make a new column to store generalized geology, and fill with NA
f$generalized_bedrock <- rep(NA, times=length(f))
# generate new labels for bedrock kinds that are functionally similar
f$generalized_bedrock[grep('metavolcanic|greenstone', f$bedrckkind, ignore.case = TRUE)] <- 'Metavolcanics'
f$generalized_bedrock[grep('diorite|granite|granodiorite|granitoid|gabbro', f$bedrckkind, ignore.case = TRUE)] <- 'Granite'
f$generalized_bedrock[grep('schist|phyllite|metasedimentary', f$bedrckkind, ignore.case = TRUE)] <- 'Metasedimentary'
f$generalized_bedrock[grep('slate', f$bedrckkind, ignore.case = TRUE)] <- 'Slate'
f$generalized_bedrock[grep('serpentinite|ultramafic', f$bedrckkind, ignore.case = TRUE)] <- 'Serpentinite'
f$generalized_bedrock[grep('volcanic breccias|tuff breccia|sandstone, volcanic|andesite', f$bedrckkind, ignore.case = TRUE)] <- 'Mehrten Fm.'
f$generalized_bedrock[grep('tuff, acidic|tuff, welded|rhyolite', f$bedrckkind, ignore.case = TRUE)] <- 'Valley Springs Fm.'
f$generalized_bedrock[grep('marble', f$bedrckkind, ignore.case = TRUE)] <- 'Marble'
f$generalized_bedrock[grep('latite', f$bedrckkind, ignore.case = TRUE)] <- 'Latite'
For now, lets only aggregate those pedons that we have included within the new generalized bedrock classes. For more information on how this process works, see ?subsetProfiles
.
# subset only those pedons with generalized bedrock
f.sub <- subsetProfiles(f, s="!is.na(generalized_bedrock)")
# re-tabulate number of pedons / generalized bedrock kind
(bedrock.tab <- table(f.sub$generalized_bedrock))
##
## Granite Latite Marble Mehrten Fm. Metasedimentary
## 81 44 33 37 177
## Metavolcanics Serpentinite Slate Valley Springs Fm.
## 262 59 59 28
Check cross-tabulation of original / generalized bedrock within subset via graph.
tab <- table(f.sub$bedrckkind, f.sub$generalized_bedrock)
# convert contingency table -> adj. matrix
m <- genhzTableToAdjMat(tab)
# plot using a function from the sharpshootR package
par(mar=c(1,1,1,1))
plotSoilRelationGraph(m, graph.mode = 'directed', edge.arrow.size=0.5)
See ?slab
for details on how to use this function. Note that this approach combines pedons of all depth-classes. Depending on the number of pedons in the collection, it may take a couple of minutes to finish.
## aggregate properties by generalized bedrock kind
a <- slab(f.sub, generalized_bedrock ~ clay + total_frags_pct + phfield)
# compute mid-point between slice top and bottom depth for plotting
a$mid <- with(a, (top+bottom)/2)
# append the number of pedons to the bedrock label
a$generalized_bedrock <- factor(a$generalized_bedrock, levels=names(bedrock.tab), labels=paste(names(bedrock.tab), ' (', bedrock.tab, ')', sep=''))
Lattice graphics are used to plot the median property bounded by the 25th and 75th percentiles, with data split into panels according to generalized bedrock type. Percentages printed on the right-hand side of each panel describe the fraction of pedons contributing data at each depth. See ?panel.depth_function
for details on how to plot aggregate soils data.
p.clay <- xyplot(mid ~ p.q50 | generalized_bedrock, upper=a$p.q75, lower=a$p.q25, data=a, ylim=c(180,-5), ylab='Depth (cm)', xlab='% Clay', strip=strip.custom(bg='yellow'), as.table=TRUE, panel=panel.depth_function, prepanel=prepanel.depth_function, scales=list(y=list(tick.number=7, alternating=3), x=list(alternating=1)), subset=variable == 'clay', layout=c(9,1), cf=a$contributing_fraction, sync.colors=TRUE, alpha=0.33)
p.rf <- xyplot(mid ~ p.q50 | generalized_bedrock, upper=a$p.q75, lower=a$p.q25, data=a, ylim=c(180,-5), ylab='Depth (cm)', xlab='% Frags', strip=strip.custom(bg='yellow'), as.table=TRUE, panel=panel.depth_function, prepanel=prepanel.depth_function, scales=list(y=list(tick.number=7, alternating=3), x=list(alternating=1)), subset=variable == 'total_frags_pct', layout=c(9,1), cf=a$contributing_fraction, sync.colors=TRUE, alpha=0.33)
p.ph <- xyplot(mid ~ p.q50 | generalized_bedrock, upper=a$p.q75, lower=a$p.q25, data=a, ylim=c(180,-5), ylab='Depth (cm)', xlab='pH', strip=strip.custom(bg='yellow'), as.table=TRUE, panel=panel.depth_function, prepanel=prepanel.depth_function, scales=list(y=list(tick.number=7, alternating=3), x=list(alternating=1)), subset=variable == 'phfield', layout=c(9,1), cf=a$contributing_fraction, sync.colors=TRUE, alpha=0.33)
# apply styling/colors
trellis.par.set(tps)
# combine sub-plots
print(p.clay, split=c(1,1,1,3), more=TRUE)
print(p.rf, split=c(1,2,1,3), more=TRUE)
print(p.ph, split=c(1,3,1,3), more=FALSE)
# subset top 25cm
f.A <- slice(f.sub, 0:24 ~ ., strict = FALSE)
# compute aggregate color data by gen. bedrock from dry colors
colors.by.gen.bedrock <- aggregateColor(f.A, groups = "generalized_bedrock", col = 'dry_soil_color')
# plot
par(mar = c(4.5, 8, 4.5, 0))
aggregateColorPlot(colors.by.gen.bedrock, main = "Dry Colors (0-25cm) by Generalized Bedrock\nThermic STR", print.label = FALSE, rect.border=NA, horizontal.borders=TRUE, horizontal.border.lwd = 1)
This document is based on aqp
version 1.16-2 and soilDB
version 2.2-4.