Algorithms for Quantitative Pedology
This is an abbreviated version of the "What is new in aqp 2.0?" vignette. Many thanks to @brownag, @smroecker, @pierreroudier, @jskovlin, @jjmaynard, and all of the other contributors to this version of aqp.
This is a major update to aqp that may create some issues for code depending on specific inputs/outputs in aqp < 1.42, particularly those relying on slice()
, slab()
, and profile_compare()
. slice()
and profile_compare()
are now deprecated, but will continue to work for the rest of calendar year 2023. There are no plans to maintain these functions beyond aqp 2.0. The new version of slab()
is a drop-in replacement for the previous version of the function.
New Vignettes:
Notable changes include:
slice()
in favor of the new, faster, more robust implementation in dice()
slab()
, with new arguments, faster back-end, and weighted aggregation implemented (finally)profile_compare()
in favor of the NCSP()
--a complete overhaul based on Maynard et al., 2020
compareSites()
perturb()
and estimatePSCS()
are now vectorized, and optimized for larger collectionsmixMunsell()
now uses mixingMethod = 'exact'
by default for the simulation of subtractive mixturesgower
package moved to SUGGESTSplotColorMixture()
now using grid graphics functions to determine color swatch geometry and setting overlap detection thresholdPMS2Munsell()
and support datacoordinates()<-
and proj4string()<-
in favor of initSpatial()<-
rruff.sample
example XRD patternsget.ml.hz()
no longer uses the name
argumentMajor changes to plotSPC()
:
max.depth
or max(x)
. This means that sketches generated with aqp 2.x will generally have less white space at the bottom of the figure. Make more room for additional annotation or visual effect by setting the desired depth range with the max.depth
argument.electroStatics_1D()
for fixing horizon depth label overlap, solutions are deterministic and almost always betterdepth.axis
, logical or listplot.depth.axis
: set via depth.axis = TRUE
, depth.axis = FALSE
, or customize depth.axis = list(...)
cex.depth.axis
: set via depth.axis = list(cex = 1)
axis.line.offset
: set via depth.axis = list(line = -2)
New features:
wilson2022
quickSPC()
and list / character templatesplotSPC()
via options(.aqp.plotSPC.args = list(...))
fragmentSieve()
and fragmentClasses()
as.data.frame(<SPC>)
as shorthand for as(<SPC>, 'data.frame')
plotSPC()
now marks truncated profiles with a ragged bottomfixOverlap()
now has two label-placement solvers, based on 1) electrostatics and 2) simulated annealingplotSPC()
Incremental changes, should have no effect on previous code:
plotSPC()
when fixLabelCollisions = TRUE
, adjustments suggested to fixOverlap()
are now scaled correctlyexplainPlotSPC()
reports label adjustment index when label collision repair is enabledexplainPlotSPC()
soilColorSignature()
gains arguments and perceptual color distances (dE00) via farver packageas(<SPC>, "data.frame")
: Replace plyr::join()
with merge()
correctAWC()
: NA handling - return NA when frags are NAmutate_profile()
: Faster (data.table-based) evaluation of profile-level expressions (#255)profileApply
: Add support for custom lapply()
-like function (APPLY.FUN
) for processing chunks (#256).interpretHorizonColor()
outputs to last_spc_plot
in aqp.env
for use in custom legend()
(#254)simplify
argument to SoilTextureLevels()
and ssc_to_texcl()
to optionally convert to an ordered factor with maximum of 12 levels (rather than 21). This smaller list of classes excludes sand grain size variants such as fine sand, loamy coarse sand, and very fine sandy loam.checkHzDepthLogic()
when byhz = TRUE
aggregateColor()
now uses mixMunsell
for the estimation of soil color mixturesplotColorMixture()
will respect "names" attribute of colors-to-mix, without erroneous alpha-sortingparseMunsell()
now more robust and faster, c/o P. RoudiermixMunsell
:
exact
for direct conversion of mixture spectra to sRGB or closest Munsell chip (via spec2Munsell()
)glom()
z1
and z2
arguments vectorized to allow for profile-specific intervals
z1
and z2
support non-standard evaluation based on column names in siteNames(p)
, and also can take character vector (length 1) with column names in siteNames(p)
depthOf()
, minDepthOf()
, maxDepthOf()
, getSurfaceHorizonDepth()
, getMineralSoilSurfaceDepth()
, getPlowLayerDepth()
can now be applied to multiple profiles.
SoilProfileCollection
has more than one profile then result is a data.frame
containing profile ID, top or bottom depths, horizon designation and patterncolorChart()
for graphical depiction of Munsell chip frequency by group
unique
method for SoilProfileCollection
objects now returns a SoilProfileCollection
by default
SPC = FALSE
for previous behavior (https://github.com/ncss-tech/aqp/issues/159)PMS2Munsell()
for converting PMS codes -> closest Munsell chip (https://github.com/ncss-tech/aqp/issues/124)mixMunsell
now relies on suggested package {gower} for 5-10x speed bumpplotColorQuantiles()
, now using {lattice} graphicscrit.clay.argillic
rounded to whole numbers per NSSH Part 614, subpart B, sections 614.13 and 614.14mutate_profile
uses data.table::rbindlist(fill=TRUE)
to combine site- and horizon-level transformationshzTopographyCodeToOffset
, hzTopographyCodeToLineType
, hzDistinctnessCodeToOffset
)plotSPC
updates:
hz.boundary.lty
is a horizon-level attribute that contains line type codeshz.topography.offset
a horizon-level attribute that contains representative offsets that encode horizon boundary topographyplotSPC
now encodes hz.topography.offset
using a vertical "bump" (chevron)addBracket
can now accept multiple bracket annotations per profileequivalent_munsell
and method equivalentMunsellChips
for "equivalent" Munsell chips lookup list based on all pairwise dE00 contrasts for integer "chips" in {aqp} munsell
data setL1_profiles
computes multivariate (L1) medians, compare to marginal medians via slab
This release of aqp
marks a significant step towards major changes planed for version 2.0. Since 1.17, there have been major changes to the internals of the SoilProfileCollection
object (thanks to @brownag) and associated methods. We expect some evolution (but less drastic as compared to the previous release) before version 2.0.
See NEWS.md for a complete listing of changes.
estimateSoilDepth
loses top
and bottom
arguments, these are automatically extractedcombine
replaces/expands aqp::union
due to conflicts with base::union
split
receives some upgrades to the S4 definition to increase parity with split.default
filter
is now an alias for new method subset
, which mirrors base::subset
hzID
) is now a character
data typeSoilProfileCollection
Internalsduplicate
will makes copies of profiles within a SoilProfileCollection
munsell2SPC
, spc2mpspline
glom(..., invert=TRUE)
, glomApply
, and better testsglomApply
: trunc
for cases when top and bottom depth interval is the same for all profiles in a SoilProfileCollection
spc_in_sync
(https://github.com/ncss-tech/aqp/pull/152)[
subset method and optional use of data.table
(https://github.com/ncss-tech/aqp/pull/155)depths<-
has been optimized and minimally validates input datacombine
uses depths<-
internally; explicitly enforcing profile ID + top depth order in horizon data is safer but results in different ordering if union
-ing IDs that "intermingle" (need to be re-sorted).permute_profile
; similar to sim
but for boundaries. The interface to this function is likely to change/be expanded.tbl_df
and data.table
to SoilProfileCollection
aqp_df_class
to determine class name in use in a SoilProfileCollection object[i,]
[,j]
subset methods for data.frame-based slots (https://github.com/ncss-tech/aqp/issues/135)mutate
, mutate_profile
(https://github.com/ncss-tech/aqp/issues/118)[[
subsetting method; an "ambivalent" accessor for site- or horizon-level propertiesgrepSPC
, filter
, subApply
for use in %>%
-linesmixMunsell
plotColorMixture
for visualization of spectra / mixturetextureTriangleSummary
:
soiltexture
package for visualization (plotrix
implementation dropped)sim = TRUE
argument, see bootstrapSoilTexture
for a better approachbootstrapSoilTexture
for simulating realistic sand/silt/clay compositionsreturnData
argument to contrastChart
plotSPC
upgrades (https://github.com/ncss-tech/aqp/pull/146)mollic.thickness.requirement
, hasDarkColors
estimateSoilDepth
-like methods for depth to multiple features via pattern matching: depthOf
, minDepthOf
, maxDepthOf
ssc_to_texcl
, texcl_to_ssc
, texmod_to_fragvoltot
, texture_to_taxpartsize
c/o @smroeckersegment
c/o @smroeckerpms.munsell.lut
for converting Pantone spot color codes to (closest) Munsell chipus.state.soils
: 50 state soils + PR and VI soilsNULL
through $<-
and horizons<-
or site<-
(https://github.com/ncss-tech/aqp/issues/163)data.table
with character vector (not formula) interfaceplotSPC
plot
generic to show aqp::plot
in ?plot
getSurfaceHorizonDepth
with buried horizons / non-contiguous instances of matching horizons (https://github.com/ncss-tech/aqp/issues/132)plotSPC
with small number of profiles (https://github.com/ncss-tech/aqp/issues/128)[
j-index subset ((https://github.com/ncss-tech/aqp/issues/125)slab.structure[2] > max(x)
The SoilProfileCollection
object is now compatible with {magrittr} pipe %>%
based workflows. Here is an example using select soil morphologic data from Jacobs (2002) "Redoximorphic Features as Indicators of Seasonal Saturation, Lowndes County, Georgia", a sample dataset available in {aqp} (jacobs2000
)
# {aqp} + {magrittr} pipes
library(aqp)
library(magrittr)
# see ?jacobs2000 for details
data("jacobs2000", package = "aqp")
# create a base plot to inspect full dataset
par(mar=c(0,0,0,2))
plot(jacobs2000, color = "matrix_color",
plot.order = order(jacobs2000$time_saturated))
# select 3 profiles along gradient, and truncate 50-150cm interval
jacobs.sub <- jacobs2000 %>%
subset(profile_id(.) %in% c("92-2","92-4",'92-7')) %>%
trunc(50, 150)
# create a base plot
plot(jacobs.sub, color = "matrix_color")
# add redox concentrations
jacobs.sub %>% addVolumeFraction('concentration_pct',
col = .$concentration_color,
pch = 16, cex.max = 1)
# add redox depletions
jacobs.sub %>% addVolumeFraction('depletion_pct',
col = .$depletion_color,
pch = 16, cex.max = 1)
This is the last major release of the 1.x series. Future development will focus on the 2.x series of releases.
SoilProfileCollection
Pre-v1.17 soilProfileCollection
objects can be checked and rebuilt using ideas from #74. Further documentation pendning.
Structure before v1.17.
Formal class 'SoilProfileCollection' [package "aqp"] with 7 slots
..@ idcol : chr "soil"
..@ depthcols : chr [1:2] "top" "bottom"
..@ metadata :'data.frame': 1 obs. of 1 variable:
..@ horizons :'data.frame': 1539 obs. of 18 variables:
..@ site :'data.frame': 296 obs. of 1 variable:
..@ sp :Formal class 'SpatialPoints' [package "sp"] with 3 slots
..@ diagnostic:'data.frame': 0 obs. of 0 variables
Structure as of v1.17, note the new hzidcol
slot.
Formal class 'SoilProfileCollection' [package "aqp"] with 8 slots
..@ idcol : chr "soil"
..@ hzidcol : chr "hzID"
..@ depthcols : chr [1:2] "top" "bottom"
..@ metadata :'data.frame': 1 obs. of 1 variable:
..@ horizons :'data.frame': 1539 obs. of 18 variables:
..@ site :'data.frame': 296 obs. of 1 variable:
..@ sp :Formal class 'SpatialPoints' [package "sp"] with 3 slots
..@ diagnostic:'data.frame': 0 obs. of 0 variables
rbind.SoilProfileCollection
Has been deprecated in favor of aqp::union()
, and gains new functionality.
aggregateColor()
gets a new feature, similar colors can be grouped via cluster::pam()
previewColors()
, colorQuantiles()
, plotColorQuantiles()
SoilProfileCollection
ManagementhorizonDepths()<-
, edit top/bottom names after SoilProfileCollection
initprofile_id()<-
, edit profile IDs after init; be careful!hzID()
and hzID()<-
, get/set unique horizon IDshzidname()
and hzidname()<-
, get/set column containing unique horizon IDscheckSPC
and rebuildSPC
argillic.clay.increase.depth
crit.clay.argillic
estimatePSCS
get.increase.depths
get.increase.matrix
getArgillicBounds
getSurfaceHorizonDepth
glom
) Relatedclod.hz.ids
glom
horizonNames()<-
Note that some un-used sample data have been removed. The sp5
sample dataset has been re-made to include the new @hzidcol
slot.