# stable packages from CRAN
install.packages('aqp')
install.packages('soilDB')
install.packages('sharpshootR')
install.packages('FactoMineR')
install.packages('cowplot')
# latest versions from GitHub
remotes::install_github("ncss-tech/aqp", dependencies=FALSE, upgrade_dependencies=FALSE)
remotes::install_github("ncss-tech/soilDB", dependencies=FALSE, upgrade_dependencies=FALSE)
remotes::install_github("ncss-tech/sharpshootR", dependencies=FALSE, upgrade_dependencies=FALSE)
library(aqp)
library(soilDB)
library(sharpshootR)
# soil of interest
# https://casoilresource.lawr.ucdavis.edu/gmap/?loc=44.10219,-122.38589,z14
s <- 'peavine'
# s <- 'clarion'
# all siblings
sib <- siblings(s)
# all soils of interest
soils <- c(s, sib$sib$sibling)
# get morphology + extended summaries
osds <- fetchOSD(soils, extended = TRUE)
There may be missing series from either / both SPC and geomorphic summaries. TBC.
# there may be records missing from SPC / hill slope position
nm <- intersect(profile_id(osd$SPC), osd$hillpos$series)
# keep only those series that exist in both
sub <- subset(osd$SPC, profile_id(osd$SPC) %in% nm)
## inverse problem: extra records in hill slope summaries
# subset hillpos
hillpos.sub <- subset(osd$hillpos, subset = series %in% profile_id(sub))
## TODO: use subset objects below
res <- vizHillslopePosition(osds$hillpos)
# re-order hillslope proportions according to clustering
hp <- osds$hillpos[res$order, ]
nm <- names(hp[, 2:6])
series | Toeslope | Footslope | Backslope | Shoulder | Summit | n | shannon_entropy |
---|---|---|---|---|---|---|---|
REMOTE | 0.00 | 0.00 | 0.53 | 0.13 | 0.33 | 30 | 1.40 |
DIGGER | 0.00 | 0.00 | 0.59 | 0.19 | 0.22 | 64 | 1.38 |
FORMADER | 0.00 | 0.00 | 0.43 | 0.36 | 0.21 | 14 | 1.53 |
BOHANNON | 0.00 | 0.00 | 0.46 | 0.37 | 0.18 | 136 | 1.49 |
SHIVIGNY | 0.00 | 0.00 | 0.59 | 0.34 | 0.06 | 32 | 1.23 |
MEDA | 0.00 | 0.25 | 0.25 | 0.25 | 0.25 | 4 | 2.00 |
PEAVINE | 0.13 | 0.13 | 0.31 | 0.23 | 0.21 | 39 | 2.24 |
SLICKROCK | 0.03 | 0.25 | 0.33 | 0.15 | 0.24 | 72 | 2.08 |
PREACHER | 0.10 | 0.21 | 0.40 | 0.06 | 0.23 | 113 | 2.07 |
HONEYGROVE | 0.19 | 0.29 | 0.26 | 0.00 | 0.26 | 80 | 1.98 |
HEMCROSS | 0.18 | 0.38 | 0.21 | 0.00 | 0.23 | 39 | 1.93 |
PANTHER | 0.18 | 0.82 | 0.00 | 0.00 | 0.00 | 146 | 0.68 |
MINNIECE | 0.57 | 0.43 | 0.00 | 0.00 | 0.00 | 7 | 0.99 |
print(res$fig)
par(mar=c(0,0,1,1))
SoilTaxonomyDendrogram(osds$SPC, scaling.factor = 0.015, width = 0.28, name.style = 'center-center')
# colors
par(mar = c(1, 1, 1, 1))
hp.cols <- RColorBrewer::brewer.pal(n = 5, name = 'Set1')[c(2, 3, 4, 5, 1)]
soilPalette(hp.cols, lab = nm)
par(mar = c(0.5, 0, 0, 2))
layout(matrix(c(1,2)), widths = c(1,1), heights = c(2,1))
plotProfileDendrogram(osds$SPC, res$clust, dend.y.scale = 3, scaling.factor = 0.012, y.offset = 0.2, width = 0.32, name.style = 'center-center', cex.names = 0.7, shrink = TRUE, cex.id = 0.55)
matplot(y = hp[, 2:6], type = 'b', lty = 1, pch = 16, axes = FALSE, col = hp.cols, xlab = '', ylab = '', xlim = c(0.5, length(osds$SPC) + 1))
# grid(nx = 0, ny = NULL)
axis(side = 4, line = -1, las = 1, cex.axis = 0.7)
# axis(side = 2, line = -3, las = 1, cex.axis = 0.7)
legend('topleft', legend = rev(nm), col = rev(hp.cols), pch = 16, bty = 'n', cex = 0.8, pt.cex = 2, horiz = TRUE, inset = c(0.01, 0.01))
mtext('Probability', side = 2, line = -2, font = 2)
par(mar = c(0.5, 0, 0, 2))
layout(matrix(c(1,2)), widths = c(1,1), heights = c(2,1))
plotProfileDendrogram(osds$SPC, res$clust, dend.y.scale = 3, scaling.factor = 0.012, y.offset = 0.2, width = 0.32, name.style = 'center-center', cex.names = 0.7, shrink = TRUE, cex.id = 0.55)
sp <- c(1.5, rep(1, times = length(osds$SPC) - 1))
barplot(height = t(as.matrix(hp[, 2:6])), beside = FALSE, width = 0.5, space = sp, col = hp.cols, axes = FALSE, xlab = '', ylab = '', xlim = c(0.5, length(osds$SPC) + 1), ylim = c(0, 1.2))
legend(x = 0.75, y = 1.2, legend = rev(nm), col = rev(hp.cols), pch = 15, bty = 'n', cex = 0.8, pt.cex = 1.25, horiz = TRUE)
mtext('Probability', side = 2, line = -2, font = 2)
res <- vizSurfaceShape(osds$shape_across, title = 'Surface Shape (Across)')
# re-order proportions according to clustering
ss <- osds$shape_across[res$order, ]
nm <- names(ss[, 2:6])
series | Concave | Linear | Convex | Complex | Undulating | n | shannon_entropy |
---|---|---|---|---|---|---|---|
SHIVIGNY | 0.00 | 0.00 | 1.00 | 0 | 0 | 32 | 0.00 |
FORMADER | 0.12 | 0.12 | 0.76 | 0 | 0 | 17 | 1.02 |
DIGGER | 0.13 | 0.09 | 0.77 | 0 | 0 | 53 | 0.99 |
BOHANNON | 0.16 | 0.16 | 0.68 | 0 | 0 | 103 | 1.22 |
SLICKROCK | 0.21 | 0.19 | 0.60 | 0 | 0 | 53 | 1.36 |
REMOTE | 0.41 | 0.07 | 0.52 | 0 | 0 | 27 | 1.30 |
PEAVINE | 0.04 | 0.64 | 0.32 | 0 | 0 | 25 | 1.12 |
PREACHER | 0.28 | 0.34 | 0.38 | 0 | 0 | 109 | 1.58 |
MEDA | 0.33 | 0.47 | 0.20 | 0 | 0 | 15 | 1.51 |
HEMCROSS | 0.45 | 0.39 | 0.16 | 0 | 0 | 49 | 1.48 |
HONEYGROVE | 0.32 | 0.62 | 0.06 | 0 | 0 | 72 | 1.18 |
MINNIECE | 0.33 | 0.67 | 0.00 | 0 | 0 | 9 | 0.92 |
PANTHER | 0.81 | 0.19 | 0.00 | 0 | 0 | 286 | 0.71 |
print(res$fig)
par(mar = c(0.5, 0, 1.5, 2))
plotProfileDendrogram(osds$SPC, res$clust, dend.y.scale = 3, scaling.factor = 0.012, y.offset = 0.2, width = 0.32, name.style = 'center-center', cex.names = 0.7, shrink = TRUE, cex.id = 0.55)
title('Surface Shape (Across)')
library(aqp)
library(soilDB)
library(sharpshootR)
library(FactoMineR)
library(cowplot)
# a classic catena
soils <- c('cecil', 'altavista', 'lloyd', 'wickham', 'wilkes', 'chewacla', 'congaree')
s <- fetchOSD(soils, extended = TRUE)
# create visualizations
hs <- vizHillslopePosition(s$hillpos)
gc <- vizGeomorphicComponent(s$geomcomp)
# montage figures
plot_grid(hs$fig, gc$fig, nrow = 2, rel_heights = c(0.5, 0.5))
Data are from SSURGO components.
# row-wise proportions add to 1
hs.tab <- (s$hillpos[, 2:6])
row.names(hs.tab) <- s$hillpos$series
# row-wise proportions add to 1
gc.tab <- (s$geomcomp[, 2:7])
row.names(gc.tab) <- s$geomcomp$series
## TODO: think about implications:
# * row-wise proportions ignore relationships to other rows
# * table-wise proportions assume equal weights
# * converting to row-wise counts would over-weight series of great extent
# convert row-wise proportions -> table-wise proportions
hs.tab <- hs.tab / sum(hs.tab)
gc.tab <- gc.tab / sum(gc.tab)
# perform CA
hs.ca <- CA(hs.tab, graph = FALSE)
gc.ca <- CA(gc.tab, graph = FALSE)
# plot
plot(hs.ca, autoLab='yes', title='Hillslope Position', cex=0.75, col.col='firebrick', col.row='royalblue')
plot(gc.ca, autoLab='yes', title='Geomorphic Component', cex=0.75, col.col='firebrick', col.row='royalblue')
## combine lattice + ggplot graphics
p2 <- plot(hs.ca, autoLab='yes', title='Hillslope Position', cex=0.75, col.col='firebrick', col.row='royalblue')
plot_grid(hs$fig, p2, nrow = 2, rel_heights = c(0.4, 0.6))
This is close, but doesn’t represent the cross-tabulation of 2D vs. 3D by series. Not sure how to interpret it though.
https://journal.r-project.org/archive/2013/RJ-2013-003/RJ-2013-003.pdf
# prepare 2D table
hs.tab <- (s$hillpos[, 1:6])
# prepare 3D table
gc.tab <- (s$geomcomp[, 1:7])
# inner join
# this is the column-wise concatenation of two cross-tabulations
g <- merge(hs.tab, gc.tab, by = 'series', sort = FALSE)
row.names(g) <- g$series
g$series <- NULL
# ??
# convert to table-wise proportions
g <- g / sum(g)
# multiple factor analysis
m <- MFA(g, group = c(5, 6), type = c('f', 'f'), name.group = c('2D', '3D'), graph = FALSE)
# now... how can this be interpreted?
plot(m, type = 'ind', partial = 'all')
plot(m, type = 'ind')
This document is based on aqp
version 2.0,
soilDB
version 2.7.7, and sharpshootR
version
2.0.