formatMunsell() for safely formatting Munsell colors from hue, value, and chromalaunderMunsell() gains additional formatting fixes / failures to NAoptions(.aqp.verbose = TRUE) default: FALSEestimateSoilColor() much faster when given duplicate colors to estimateCRAN release
new example data Ohz.colors, useful for estimating organic soil material color
new function launderMunsell() for fixing encoding of neutral colors
new function validateMunsell() for checking Munsell color notation (#339)
colorVariation() updates:
m contains non-standard Munsell notationestimateSoilColor() updates:
method and returnMunsellmethod = 'ols'new argument to plotSPC() -> offset.id used to manually adjust vertical offset to all profile IDs (c/o Daniel Saurette)
bug fix in col2Munsell() when passed 0-length character
bug fix in plotSPC(x, max.depth != NULL) when x contains degenerate profiles (no horizons)
bug fix in colorChart() when using groups and neutral colors
bug fix in soilColorSignature(), NA incorrectly interpreted when color argument is supplied hex encoded sRGB
bug fix in soilColorSignature(), cluster::pam() optimization would very rarely hang
pamonce = >=5) - AMELAR OSD, moist colorsmajor changes to hzAbove() and hzBelow():
offset = NULL selects all horizons above or below reference horizonssingle for lumping multiple reference horizons into a contiguous compositemajor changes to addBracket():
plotSPC()labcol (label column), agg (aggregate multiple brackets / profile), hzDepths (override bracket top and bottom depth column names)code-completion and preview for SPC objects in RStudio (@brownag)
mu_confusion_matrix() (@smroecker)colorVariation() for describing color variation in terms of average human color perceptionshuffle() for re-ordering horizon data or horizons within a SoilProfileCollection object (#328).detectColorSpec() is a new internal function for detecting a color specificationcolorContrast() will now compute contrast data for pair-wise combinations of m1 when m2 is not specified (#330)plotProfileDendrogram() gets better default arguments for scaling, offset, etc.warpHorizons() gains scaleTo argument for scaling profiles to specific soil depthsoilColorSignature() changes (#335):
color and spaceperceptualDistMat = TRUEr, g, b, RescaleLightnessBy, warning issued until the next major releaseelectroStatics_1D() now accepts vector of charge density q or single value (original implementation)estimateSoilColor() transformation parameters updatedspc2mpspline() gains ability to process multiple variables in one call. Requires mpspline2 (>=0.1.9)rp() convenience wrapper to random_profile()NCSP() via caching pair-wise distancesunroll() has not been used since aqp < 2.0, it has been removed.evalGenHz() now uses stats::cmdscale() instead of MASS:isoMDS()plotProfileDendrogram()aggregateColorPlot()hz_segment() and NCSP() with data.table SoilProfileCollection objects (#320)generalize.hz() to handle missing depths better and added na.rm argument (#321)profile_compare() removed, see NCSP()munsell2rgb() now safely selects the closest Munsell value and chroma to those available in the package LUTsoilTextureColorPal() for suggesting a color palette suitable for soil texture class@sp slot of the SoilProfileCollection object, and dependency on sp package, has been removed.
SoilProfileCollection objects previously written to file (.rda, .rds) with aqp <2.1.x will need to be rebuilt using rebuildSPC() due to changes to S4 object structureestimatePSCS() gains argument "lieutex" for in lieu textures which are used in the new routine for identification of the particle size control section of organic soilscollapseHz() combines and aggregates data for adjacent horizons matching a pattern or sharing a common IDmutate_profile_raw() for building sets of dynamic mutate expressions. Also mutate_profile() gains col_names argument for dynamic naming of columns.addVolumeFraction() now more robust to very thin horizons x low volume fractions; also skips horizons without sufficient or relevant valuesplotSPC() now adjusted as function of number of profiles and device widthplotSPC() saved to last_spc_plot in aqp.envsimulateColor() gains new method mvnorm for simulating plausible colors
profileInformationIndex(), dice(), slab(), spc2mpspline(), fillHzGaps(), and flagOverlappingHz()huePositionCircle()thicknessOf() used for calculating thickness of horizons within each profile of a SoilProfileCollection based on horizon-level logical expressions encoded in a function. Default behavior uses pattern matching on the horizon designation name.evalMissingData()col2Munsell() generalizes and replaces rgb2munsell() (thanks Shawn Salley for the suggestion)
rgb2munsell() will be deprecated in aqp 2.1warpHorizons() for warping horizon thickness (inflate/deflate) (thanks Shawn Salley for idea / inspiration)plotColorMixture() when final mixed color does not exist in spectral librarygroupedProfilePlot()profileInformationIndex() (vignette pending)flagOverlappingHz() for identifying horizons with perfect overlapfillHzGaps(), dice(), slab(), and several other functions now safely handle horizons with perfect overlap (#296)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.
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:
wilson2022quickSPC() 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.getArgillicBounds(), getCambicBounds(), mollic.thickness.requirement(), getSurfaceHorizonDepth() and related functions have been optimized and now work on SoilProfileCollection objects with length > 1reduceSPC() function for selecting a subset of minimal plus additional specified columns from a SoilProfileCollection.NHZ for use with SoilProfileCollection [ method
object[,,.NHZ] returns a vector with the number of horizons in each profileplotSPC() gains new arguments for controlling horizon depth labelsplotSPC() gains horizon depth annotation collision fixes (https://github.com/ncss-tech/aqp/issues/240)plotSPC() minor bugfix for cases when n != length(x)plotSPC() important change! y.offset is now automatically re-ordered by plot.orderbase::aggregate (thanks AGB)depthOf() and related functions: better handling of NA results from FUNpanel.depth_function() that affected plotting of grouped data, created by slab()plotSPC() now uses variable (vertical) text alignment for horizon depth labelsprofileInformationIndex()estimateSoilDepth() now requires a valid horizon designation (no longer attempts a guess)group_by(), summarize(), mutate()f.noise() and resample.twotheta(): use {powdR} package insteadtexture_to_texmod() and fragvol_to_texmod() c/o @smroeckerslice() implemented as dice()colorChart() can now show neutral hues in a skinny panelcolorContrast(), parseMunsell(), and huePosition() to work properly with neutral hueshuePosition() gains new arguments and functionality: origin and directionhuePositionCircle() for helping visualize differences in Munsell hue on the unit circleplotSPC defaults change:
width = 0.25: slightly wider profile sketchesname = hzdesgnname(x): use metadata if present, no longer guessing. This may cause your figures to "lose" previously guessed horizon names, specify with name = 'column name' or set metadata with hzdesgnname(x) <- 'hzname'checkHzDepthLogic() when byhz = TRUEsimulateColor() for simulation of reasonable colorscolorChart() for graphical depiction of Munsell chip frequency by groupunique method for SoilProfileCollection objects now returns a SoilProfileCollection by default
SPC = FALSE for previous behavior (https://github.com/ncss-tech/aqp/issues/159)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())PMS2Munsell() for converting PMS codes -> closest Munsell chip (https://github.com/ncss-tech/aqp/issues/124)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 patternSoilProfileCollection methods that conflict with {dplyr} 1.0+ have been deprecated:
filter, mutate, group_by, summarizesubset, "mutate" -> transform, "combine" -> c*SPC syntax: filterSPC, mutateSPC, groupSPC, summarizeSPCdplyr::combine (deprecated in {dplyr} 0.7) still conflictsaqp::union(), previously deprecated, has been removed from namespace
c() or combine() for SoilProfileCollection inputcombine() or pbindlist() for list inputplotSPC() gains vectorized y.offset support (demonstrated in: http://ncss-tech.github.io/AQP/aqp/genhz-distance-eval.html)plotSPC() gains argument shrink.thin for shrinking horizon designation labels when horizons are thinalignTransect() for simplifying relative positioning of profile sketchesplotMultipleSPC() gains ability to automatically merge thematic legendscoordinates<- will check formula terms (unique coordinates) in the @horizons slot, if needed.spec2Munsell() for converting reflectance spectra into sRGB coordinates or closest Munsell chipmixMunsell:
mixingMethod argument for selecting several mixing strategiespanel.depth_function when plotting grouped step-functions[,j]-index extraction using {data.table}.LAST, .FIRST and .HZID SoilProfileCollection "k-keywords"perturb() is the new generalized replacement for sim() and permute_profile()checkHzDepthLogic() now has a byhz argument for checking logic by horizon rather than profilefillHzGaps now has to_top and to_bottom arguments for filling above shallowest top / deepest bottom by profilefixOverlap() more flexible and will usually settle on a solution in fewer iterations:
overlapMetrics() instead of findOverlap() for part of objective functionT0 and k argumentsalignTransect helper function for computing relative positions and ordering vector supplied to plotSPCplotSPC() automatically converts logical data supplied to color argument into factorglom() is now vectorized over profilesestimateAWC introduced for testing lookup table estimation of available water capacity (AWC) of fine-earth fractioncorrectAWC introduced for testing corrections of AWC estimates for rock fragment and saltsfillHzGaps: new function for fixing horizon depth topological errors and padding top/bottom of profiles with placeholder (empty) horizonsmixMunsell now relies on suggested package {gower} for 5-10x speed bumpplotColorQuantiles(), now using {lattice} graphicsequivalent_munsell and method equivalentMunsellChips for "equivalent" Munsell chips lookup list based on all pairwise dE00 contrasts for integer "chips" in {aqp} munsell data setcrit.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)L1_profiles computes multivariate (L1) medians, compare to marginal medians via slabplotSPC 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 profilepms.munsell.lut for converting Pantone spot color codes to (closest) Munsell chipduplicate will makes copies of profiles within a SoilProfileCollectionus.state.soils: 50 state soils + PR and VI soilsmixMunsell
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 compositionscombine replaces/expands aqp::union due to conflicts with base::unionsplit receives some upgrades to the S4 definition to increase parity with split.defaultfilter is now an alias for new method subset, which mirrors base::subsetestimateSoilDepth loses top and bottom arguments, these are automatically extractedmunsell2SPC, spc2mpsplinereturnData argument to contrastChartglom(..., invert=TRUE), glomApply, and better testsglomApply: aqp::trunc for cases when top and bottom depth interval is the same for all profiles in a SoilProfileCollectionNULL through $<- and horizons<- or site<- (https://github.com/ncss-tech/aqp/issues/163)data.table with character vector (not formula) interfacespc_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 datahzID) is now a character data typeaqp::union 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.segment c/o @smroeckerplotSPCplot generic to show aqp::plot in ?plottbl_df and data.table to SoilProfileCollectionaqp_df_class to determine class name in use in a SoilProfileCollection objectplotSPC upgrades (https://github.com/ncss-tech/aqp/pull/146)mollic.thickness.requirement, hasDarkColorsestimateSoilDepth-like methods for depth to multiple features via pattern matching: depthOf, minDepthOf, maxDepthOfssc_to_texcl, texcl_to_ssc, texmod_to_fragvoltot, texture_to_taxpartsize)[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)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)[[ subsetting method; an "ambivalent" accessor for site- or horizon-level propertiesgrepSPC, filter, subApply for use in %>%-lineshzDesgn(), get horizon designations from a SPChzdesgnname()/hzdesgnname()<- and hztexclname()/hztexclname()<- get/set column containing horizon designations and texture classesglom()profileApply() enhancement for large SoilProfileCollection objects (https://github.com/ncss-tech/aqp/issues/112)
profileApply() frameify argument for data.frame output (https://github.com/ncss-tech/aqp/issues/111)checkHzDepthLogic() replaces test_hz_logic()rgb2munsell() and colorQuantiles() now uses the CIE2000 distance metric for color comparisoncolorQuantiles until farver 2.0.2 is available on CRANSoilProfileCollection object gains new slot: @restrictions, fix old objects with rebuildSPC()evalMissingData() gets new argument for relative vs. absolute evaluation of missing data
horizonColorIndices(), harden.rubification(), harden.melanization(), thompson.bell.darkness() and associated functions in soilColorIndices.Rrowley2019Hmisc (hdquantile), loading aqp is now much faster
slab() now uses stats::quantile() as the default slab functionslab() can be activated via argument: slab.fun = aqp:::.slab.fun.numeric.HDgeneralize.hz() gets a \dots argument for passing additional arguments to grep(), e.g. perl=TRUE
addVolumeFraction() can now accept a vector of colors, as many as number of horizonsjacobs2000, pending documentationaggregateColor() faster and more accurate, using delta-E00 for quantized colors c/o {farver} (see https://github.com/ncss-tech/aqp/issues/98)contrastChart() and soilPalette()plotSPC() gains a new argument for relative positioning: relative.pos
fixOverlap(), see manual page for examplesexplainPlotSPC(), addDiagnosticBracket(), and addVolumeFraction() updated accordinglyplotSPC() will now attempt to create multi-row legends when using a factor > n.legend levelsplotSPC() will now generate > 10 colors for legends associated with a factor (https://github.com/ncss-tech/aqp/issues/9)munsell2rgb() will now return CIE LAB coordinates if requested (https://github.com/ncss-tech/aqp/issues/69)aggregateColor() gets a new feature, similar colors can be grouped via cluster::pam()previewColors(), colorQuantiles(), plotColorQuantiles()horizonDepths()<-, edit top/bottom names after SPC 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 IDsrbind.SoilProfileCollection() has been deprecated in favor of union(), gains new functionality: https://github.com/ncss-tech/aqp/issues/71horizonNames()<-explainPlotSPC from SPC tutorial to aqp::explainPlotSPC()
plotSPC() is a little better at estimating "extra" vertical / horizontal space, still needs work (https://github.com/ncss-tech/aqp/issues/62)plotSPC() gets a new argument, n.legend: approximate number of classesaggregateColor() for cases when horizon depths are missing or top/bottom logic flippedaddVolumeFraction() when fragment volume > 100%addDiagnosticBracket() allowing for specification of column containing diagnostic feature kind
addBracket() now requires a data.frame with plotting details, see manual pageshannonEntropy(), confusionIndex(), and brierScore()
get.ml.hz() for horizon names that start with number or punctuationget.ml.hz() now uses internal aqp functions for Shannon entropy and Brier scoresmissingDataGrid() relaxing slice() with strict=FALSEmunsell look-up tableplotSPC() now able to deal with missing horizon data (thanks Stephen R.)
rgb2munsell() now uses CIELAB colorspace for lookup, results are more accurate as compared to using sRGB colorspacetexture.triangle.low.rv.high() renamed to textureTriangleSummary(). The old name still works, but a message is issued
textureTriangleSummary() texture.names: for toggling texture class namestextureTriangleSummary(..., sim=TRUE), previous simulated compositional data was not correct because the stats::var() was being used vs. compositions::var.acomp(). the variance / covariance values were 2-5x too small.tauW(), added by D.G. Rossiter: see manual page for referencesrbind-ingsoil_minerals with some common soil mineral colors source: http://www.nrcs.usda.gov/wps/portal/nrcs/detail/soils/edu/?cid=nrcs142p2_054286
getClosestMunsellChip()
sp6) based on http://www.sciencedirect.com/science/article/pii/S0016706111001972munsell2rgb() can now accommodate neutral hues (N), and values of "2.5", see manual page for detailssoilColorSignature(), see manual page
parseMunsell() for converting strings of '10YR 2/2' into R colors or RGB triplets
munsell2rgb on parsed strings of full Munsell notationprofile_compare(), getting ready for a complete overhaul to this function
evalMissingData(), see manual pagegenhzTableToAdjMat, hzTransitionProbabilitiesrbind.SoilProfileCollection() related to object re-ordering
+ in aqp < 1.9.3: there was a chance than profile_id(x) and site(x)[[idname(x)]]) would not match
+ bugs like this will no longer be a possibility after aqp 2.0, new SPC object structure plannedgroupedProfilePlot() gains some new arguments and better documentation (see manual page)
plot.SoilProfileCollection gains argument: default.color (see manual page)munsell2rgb()
guessGenHzLevels()aggregateColor() and associated helper function sharpshootR::aggregateColorPlot()R CMD check --as-cran happyprofileApply() manual pagedigest::digest is now imported by defaultSoilProfileCollection objectsx.idx.offset: allows for plotting of multiple SPC objects within the same figure, see examplesplot.depth.axis: enable / disable depth axis, useful for multi-collection plotsprofileGroupLabels: simple annotation for groups of profiles within a profile sketch, see manual page for examplesplotMultipleSPC: plot several SPC objects on the same axis, see manual page for examplesaddBrackets(), panel.depth_function(), and plotSPC()
addBrackets() allow for annotation of bracketsspatial_subset(): this functionality can be accomplished outside of AQP and removes dependency on rgeos packageattr(x, 'original.levels').label, used to set site-level attribute containing profile labelsaqp.env
texture.triangle.low.rv.high() plots texture data with low-high range defined by quantilesslab() and profileApply() via 'parallel' packageplotSPC() gets a density argument for shaded coloring of horizonsslab() re-written from scratch, resulting in reduced memory footprint and quicker running time
! older code based on slab() is likely to now broken- sorry, it won't happen again
+ the new code is much slimmer and based on aggregate() rather than ddply
+ function arguments have changed so be sure to check the manual page
+ user-supplied functions are now much simpler to write and rely on vectors rather than data.frames (= faster)
+ the next major release will contain additional examples of how to use the new featuressim() for simulation based on a template soil profile, proper documentation pending...subsetProfiles() for simpler subsetting of SoilProfileCollection objects via site or horizon-level attributes
get.ml.hz() now returns a 'confidence' for each horizon (as a percent)site(SCP) <- d now tries to merge data from SPC@site with 'd' via left join
+ this means that all new SPC objects will have a single column of @site data, containing profile IDs
strict argument to many functions, to gracefully account for bad horizon data
SoilProfileCollection
+ this supersedes the (now removed) S3 SoilProfileList classes
+ basic accessors/setters are in place, subject to change
SoilProfileCollection class
new functions for getting data out of PedonPC (MS Access) databases [windows only for now] + get_site_data_from_pedon_db() : site and pedon aggregate data + get_hz_data_from_pedon_db() : horizon level data + get_colors_from_pedon_db() : formats and mixes multiple colors / horizon
mapunit_geom_by_ll_bbox() : get map unit geometry by bounding boxMUKEYS_by_ll_bbox() : get map unit keys by bounding boxSDA_query() : retrieve soil tabular data via query written in SQLplotSPCprofile_compare() now calculates slice-wise dissimilarity matrices in 1/3 the time (thanks llply!)