diff --git a/AQP/aqp/genhz-distance-eval.Rmd b/AQP/aqp/genhz-distance-eval.Rmd index 22c1b57..03ff086 100644 --- a/AQP/aqp/genhz-distance-eval.Rmd +++ b/AQP/aqp/genhz-distance-eval.Rmd @@ -49,8 +49,8 @@ hzdesgnname(loafercreek) <- 'hzname' x <- loafercreek[20:40, ] # modify default arguments for some flair -par(mar = c(0, 0, 0, 0)) -plotSPC(x, width = 0.3, name.style = 'center-center', depth.axis = FALSE, hz.depths = TRUE, cex.names = 0.65, print.id = FALSE) +par(mar = c(0, 0, 0, 2)) +plotSPC(x, width = 0.33, name.style = 'center-center', cex.names = 0.65, print.id = FALSE) ``` @@ -88,8 +88,8 @@ table(y$genhz) # add short ID for checking our work site(y)$shortID <- 1:length(y) -par(mar = c(0, 0, 3, 0)) -plotSPC(y, color = 'genhz', width = 0.3, name.style = 'center-center', depth.axis = FALSE, hz.depths = TRUE, cex.names = 0.65, fixLabelCollisions = FALSE, col.label = 'Generalized Horizon Label', label = 'shortID') +par(mar = c(0, 0, 3, 2)) +plotSPC(y, color = 'genhz', width = 0.33, name.style = 'center-center', cex.names = 0.65, fixLabelCollisions = FALSE, col.label = 'Generalized Horizon Label', label = 'shortID') ``` @@ -99,6 +99,7 @@ Add empty horizons to bottom of the profiles with bottom-most horizon depth < 15 z <- fillHzGaps(y, to_top = NA, to_bottom = 150) # label as 'R' +# important to use one of the GHL specified in `genhz` z$hzname[is.na(z$genhz)] <- 'R' z$genhz[is.na(z$genhz)] <- 'R' @@ -193,6 +194,44 @@ mtext("Median distance to all other profiles (not to scale)", side = 1, line = 2 ``` +Another view of median distance to all other profiles, as a set of connected points. This helps demonstrate the scale of differences within the collection. Note that values in the distance matrix `d` range from 0 to 1. We have to use some tricks to get the vertical spacing right. +```{r, fig.width=12, fig.height=6.5} +# trick 1: adjust median distances to fit "above" profiles +# shift down 125cm +# rescale from 0 to 125cm +.yoff <- 125 +med.dist.rescale <- .yoff - aqp:::.rescaleRange(med.dist, 0, .yoff) + +# trick 2: plot profiles, shifting "down" 150cm +# use y.offset argument +par(mar = c(0.25, 1.5, 3, 1.5)) +plotSPC(z, plot.order = idx, color = 'genhz', width = 0.33, name.style = 'center-center', cex.names = 0.65, col.label = 'Generalized Horizon Label', label = 'shortID', scaling.factor = 1, y.offset = 150) + +# add the scaled + shifted median distances as points connected by lines +lines(x = 1:length(z), y = med.dist.rescale, type = 'b') + +# trick 3: make a special axis describing median distance +# compute "pretty" intervals for the axis, on the shifted and scaled values +.p <- pretty(med.dist.rescale) + +# use a linear model to convert between shifted/scaled and original values +# slope ~ scale +# intercept ~ shift +.m <- lm(med.dist ~ med.dist.rescale) + +# convert pretty axis values back to original scale +.lab <- predict(.m, data.frame(med.dist.rescale = .p)) + +# add axis +axis(side = 2, at = .p, labels = round(.lab, 2), line = -1.5, las = 1, cex.axis = 0.75) + +# annotate +mtext('Median distance to all other profiles (max = 1)', side = 3, at = 1, adj = 0, line = -2) +``` + + + + Use `plotProfileDendrogram()` from the sharpshootR package to align profile sketches with the terminal leaves of a dendrogram. When applied to other data, you may have to tinker with the `scaling.factor` and `y.offset` arguments. ```{r, fig.width=12, fig.height=8} par(mar = c(1, 0, 3, 2)) @@ -232,7 +271,11 @@ axis(1, at = pos$relative.pos, labels = round(pos$grad, 3), line = 0, cex.axis = mtext("Distance from 1st Profile", side = 1, line = 2.25) ``` -Create an ordination from pair-wise distances using non-metric multidimensional scaling (`MASS::sammon`). +Create an ordination from pair-wise distances using non-metric multidimensional scaling (`MASS::sammon`). It is necessary to add a small amount of distance back to the distance matrix before ordination for two reasons: + + 1. we chose to rescale distances to the interval of [0,1] (recall `rescaleResult = TRUE` argument to `NCSP()`) + 2. there are duplicate soil profiles in the collection + ```{r fig.width=8, fig.height=4.5} # add tiny amount for 0-distance pairs (duplicate profiles) d <- d + 0.001 diff --git a/AQP/aqp/genhz-distance-eval.html b/AQP/aqp/genhz-distance-eval.html index af0e14e..5bf81bd 100644 --- a/AQP/aqp/genhz-distance-eval.html +++ b/AQP/aqp/genhz-distance-eval.html @@ -11,7 +11,7 @@ - +
Apply generalized horizon labels using overly-simplistic rules. This is only a demonstration.
# new labels
@@ -426,9 +426,9 @@ 2024-03-13
# add short ID for checking our work
site(y)$shortID <- 1:length(y)
-par(mar = c(0, 0, 3, 0))
-plotSPC(y, color = 'genhz', width = 0.3, name.style = 'center-center', depth.axis = FALSE, hz.depths = TRUE, cex.names = 0.65, fixLabelCollisions = FALSE, col.label = 'Generalized Horizon Label', label = 'shortID')
-
+par(mar = c(0, 0, 3, 2))
+plotSPC(y, color = 'genhz', width = 0.33, name.style = 'center-center', cex.names = 0.65, fixLabelCollisions = FALSE, col.label = 'Generalized Horizon Label', label = 'shortID')
+Add empty horizons to bottom of the profiles with bottom-most horizon
depth < 150cm, label with ‘R’ GHL. Truncate deeper profiles to 150cm.
See ?fillHzGaps
and ?trunc
for details.
Another view of median distance to all other profiles, as a set of
+connected points. This helps demonstrate the scale of differences within
+the collection. Note that values in the distance matrix d
+range from 0 to 1. We have to use some tricks to get the vertical
+spacing right.
# trick 1: adjust median distances to fit "above" profiles
+# shift down 125cm
+# rescale from 0 to 125cm
+.yoff <- 125
+med.dist.rescale <- .yoff - aqp:::.rescaleRange(med.dist, 0, .yoff)
+
+# trick 2: plot profiles, shifting "down" 150cm
+# use y.offset argument
+par(mar = c(0.25, 1.5, 3, 1.5))
+plotSPC(z, plot.order = idx, color = 'genhz', width = 0.33, name.style = 'center-center', cex.names = 0.65, col.label = 'Generalized Horizon Label', label = 'shortID', scaling.factor = 1, y.offset = 150)
+
+# add the scaled + shifted median distances as points connected by lines
+lines(x = 1:length(z), y = med.dist.rescale, type = 'b')
+
+# trick 3: make a special axis describing median distance
+# compute "pretty" intervals for the axis, on the shifted and scaled values
+.p <- pretty(med.dist.rescale)
+
+# use a linear model to convert between shifted/scaled and original values
+# slope ~ scale
+# intercept ~ shift
+.m <- lm(med.dist ~ med.dist.rescale)
+
+# convert pretty axis values back to original scale
+.lab <- predict(.m, data.frame(med.dist.rescale = .p))
+
+# add axis
+axis(side = 2, at = .p, labels = round(.lab, 2), line = -1.5, las = 1, cex.axis = 0.75)
+
+# annotate
+mtext('Median distance to all other profiles (max = 1)', side = 3, at = 1, adj = 0, line = -2)
+Use plotProfileDendrogram()
from the sharpshootR package
to align profile sketches with the terminal leaves of a dendrogram. When
applied to other data, you may have to tinker with the
@@ -569,7 +607,14 @@
Create an ordination from pair-wise distances using non-metric
-multidimensional scaling (MASS::sammon
).
MASS::sammon
). It is necessary to
+add a small amount of distance back to the distance matrix before
+ordination for two reasons:
+rescaleResult = TRUE
argument to NCSP()
)# add tiny amount for 0-distance pairs (duplicate profiles)
d <- d + 0.001