11# ' Get SSURGO ZIP files from Web Soil Survey 'Download Soils Data'
22# '
3- # ' Download ZIP files containing spatial (ESRI shapefile) and tabular (TXT) files with standard
4- # ' SSURGO format; optionally including the corresponding SSURGO Template Database with
5- # ' `include_template=TRUE`.
6- # '
7- # ' To specify the Soil Survey Areas you would like to obtain data you use a `WHERE` clause for query
8- # ' of `sacatalog` table such as `areasymbol = 'CA067'`, `"areasymbol IN ('CA628', 'CA067')"` or
9- # ' `areasymbol LIKE 'CT%'`.
3+ # ' Download ZIP files containing spatial (ESRI shapefile) and tabular (TXT) files in standard SSURGO
4+ # ' format. To specify the Soil Survey Areas you would like to download, use a `WHERE` clause for
5+ # ' query of `sacatalog` table, for example: `areasymbol = 'CA067'`, `"areasymbol IN ('CA628',
6+ # ' 'CA067')"`, or `areasymbol LIKE 'CT%'`.
107# '
118# ' @param WHERE _character_. A SQL `WHERE` clause expression used to filter records in `sacatalog`
129# ' table. Alternately `WHERE` can be any spatial object supported by `SDA_spatialQuery()` for
1815# ' not yet exist. Each ZIP file will extract to a folder labeled with `areasymbol` in this
1916# ' directory. Default: `destdir`
2017# ' @param include_template _logical_. Include the (possibly state-specific) MS Access template
21- # ' database? Default: `FALSE`
18+ # ' database? Default: `FALSE`
2219# ' @param include_spatial _logical_ or _character_. Extract spatial data layers from ZIP file?
2320# ' Default: `TRUE` inserts all spatial tables. If `include_spatial` is a _character_ vector
2421# ' containing table names, only that set is extracted from the downloaded ZIP files. e.g.
2522# ' `include_spatial=c("mupolygon", "featpoint")` extracts only the shapefiles (with side car
2623# ' files) for mapunit polygons and special feature points.
27- # ' @param include_tabular _logical_ or _character_. Include tabular data layers in database?
28- # ' Default: `TRUE` inserts all tabular tables. If `include_tabular` is a _character_ vector
29- # ' containing table names, only that set is extracted from the downloaded ZIP files. e.g.
24+ # ' @param include_tabular _logical_ or _character_. Extract tabular data from ZIP file? Default:
25+ # ' `TRUE` inserts all tabular tables. If `include_tabular` is a _character_ vector containing
26+ # ' table names, only that set is extracted from the downloaded ZIP files. e.g.
3027# ' `include_tabular=c("mapunit", "muaggatt")` writes only the `mapunit` and `muaggatt` tables.
3128# ' Note that special feature descriptions are stored in table `"featdesc"` and metadata for each
3229# ' soil survey area are stored in `"soil_metadata"` tables.
3330# ' @param db _character_. Either `"SSURGO"` (default; detailed soil map) or `"STATSGO"` (general
3431# ' soil map).
3532# ' @param extract _logical_. Extract ZIP files to `exdir`? Default: `TRUE`
33+ # ' @param LAPPLY.FUN _function_. `lapply()`-like function to use for iteration during `extract`
34+ # ' phase. Only used if `extract=TRUE`. This allows for the `utils::unzip()` operations to be run
35+ # ' in parallel instead of sequential, custom progress reporting, or similar.
36+ # ' @param LAPPLY.FUN.ARGS _list_. Optional list of additional arguments to pass to `LAPPLY.FUN`.
3637# ' @param remove_zip _logical_. Remove ZIP files after extracting? Default: `FALSE`
3738# ' @param overwrite _logical_. Overwrite by re-extracting if directory already exists? Default:
3839# ' `FALSE`
5152# ' have prefix `soilmu_` (mapunit), `soilsa_` (survey area), `soilsf_` (special features). There
5253# ' will also be a TXT file with prefix `soilsf_` describing any special features. Shapefile names
5354# ' then have an `a_` (polygon), `l_` (line), `p_` (point) followed by the soil survey area symbol.
54- # ' When `db="STATSGO"` the `WHERE` argument is not supported. Allowed `areasymbols` include
55- # ' `"US"` and two-letter state codes e.g. `"WY"` for the Wyoming general soils map.
55+ # ' When `db="STATSGO"` the `WHERE` argument is not supported. Allowed `areasymbols` include `"US"`
56+ # ' and two-letter state codes e.g. `"WY"` for the Wyoming general soils map.
5657# '
57- # ' As in `createSSURGO()`, the `include_spatial` and `include_tabular` arguments either take a
58- # ' logical value (default `TRUE`) or a character vector of the specific table names to include. Note
59- # ' that when used in `downloadSSURGO()` the required metadata files are _always_ extracted to
60- # ' facilitate mapping to user-facing table names. These arguments allow for customizing the files
61- # ' that get extracted from ZIP files, not just filtering on file names (as is implemented with
62- # ' pre-existing `pattern` argument). This can dramatically improve efficiency of extraction and the
63- # ' overall size of the data in `exdir`. These arguments can be used in conjunction with the
64- # ' `pattern` argument to fine-tune the files included in the generated snapshot database.
58+ # ' As in `createSSURGO()`, the `include_spatial` and `include_tabular` arguments either take a
59+ # ' logical value (default `TRUE`) or a character vector of the specific table names to include.
60+ # ' Note that when used in `downloadSSURGO()` the required metadata files are _always_ extracted to
61+ # ' facilitate mapping to user-facing table names. These arguments allow for customizing the files
62+ # ' that get extracted from ZIP files, not just filtering on file names (as is implemented with
63+ # ' pre-existing `pattern` argument). This can dramatically improve efficiency of extraction and
64+ # ' the overall size of the data in `exdir`. These arguments can be used in conjunction with the
65+ # ' `pattern` argument to fine-tune the files included in the generated snapshot database.
6566# '
6667# ' @return _character_. Paths to downloaded ZIP files (invisibly). May not exist if `remove_zip =
6768# ' TRUE`.
@@ -75,6 +76,8 @@ downloadSSURGO <- function(WHERE = NULL,
7576 include_tabular = TRUE ,
7677 db = c(' SSURGO' , ' STATSGO' ),
7778 extract = TRUE ,
79+ LAPPLY.FUN = lapply ,
80+ LAPPLY.FUN.ARGS = NULL ,
7881 remove_zip = FALSE ,
7982 overwrite = FALSE ,
8083 quiet = FALSE ) {
@@ -139,8 +142,7 @@ downloadSSURGO <- function(WHERE = NULL,
139142 dir.create(exdir , recursive = TRUE )
140143 }
141144
142- res <- lapply(seq_along(paths2 ), function (i ) {
143- ssa <- gsub(" .*wss_SSA_(.*)_.*" , " \\ 1" , paths2 [i ])
145+ UNZIP.FUN <- function (i ) {
144146 if (isTRUE(include_spatial ) && isTRUE(include_tabular )) {
145147 lz <- NULL
146148 } else {
@@ -150,18 +152,24 @@ downloadSSURGO <- function(WHERE = NULL,
150152 " ^(mstab|mdstattabs|MetadataTable|mstabcol|mdstattabcol|MetadataColumnLookup|msidxdet|mdstatidxdet|MetadataIndexDetail)$" ,
151153 tools :: file_path_sans_ext(basename(lz ))
152154 )], exdir = exdir )
153- inv <- .inventory_ssurgo_files(lz , exdir = exdir , include_spatial = include_spatial , include_tabular = include_tabular )
155+
156+ # explicitly fetch internal function our namespace to support parallel workers
157+ INV.FUN <- get(" .inventory_ssurgo_files" , envir = asNamespace(" soilDB" ))
158+ inv <- INV.FUN(lz , exdir = exdir , include_spatial = include_spatial , include_tabular = include_tabular )
159+
154160 lz <- unlist(c(inv $ f.shp.sc , inv $ f.txt.grp ))
155161 }
156162 uz <- utils :: unzip(paths2 [i ], files = lz , exdir = exdir )
157- if (( ! dir.exists(file.path( exdir , ssa )) || overwrite ) && length(uz ) == 0 ) {
163+ if (length(uz ) == 0 ) {
158164 message(paste(' Invalid zipfile:' , paths2 [i ]))
159165 } else {
160166 if (! quiet ) {
161167 message(" Extracted: " , paths2 [i ])
162168 }
163169 }
164- })
170+ }
171+
172+ res <- do.call(LAPPLY.FUN , c(list (seq_along(paths2 ), UNZIP.FUN ), LAPPLY.FUN.ARGS ))
165173
166174 if (remove_zip ) {
167175 file.remove(paths2 )
@@ -182,15 +190,15 @@ downloadSSURGO <- function(WHERE = NULL,
182190# ' you encounter issues using specific DBI connection types, please report in the soilDB issue
183191# ' tracker.
184192# '
185- # ' @param filename _character_. Output file name (e.g. `'db.sqlite'` or `'db.gpkg'`). Only used when `con` is not
186- # ' specified by the user.
187- # ' @param exdir _character_. Path containing containing input SSURGO spatial (.shp) and tabular (.txt) files,
188- # ' downloaded and extracted by `downloadSSURGO()` or similar.
193+ # ' @param filename _character_. Output file name (e.g. `'db.sqlite'` or `'db.gpkg'`). Only used when
194+ # ' `con` is not specified by the user.
195+ # ' @param exdir _character_. Path containing containing input SSURGO spatial (.shp) and tabular
196+ # ' (.txt) files, downloaded and extracted by `downloadSSURGO()` or similar.
189197# ' @param conn A _DBIConnection_ object. Default is a `SQLiteConnection` used for writing .sqlite or
190198# ' .gpkg files. Alternate options are any DBI connection types. When `include_spatial=TRUE`, the
191199# ' sf package is used to write spatial data to the database.
192- # ' @param pattern _character_. Optional regular expression to use to filter subdirectories of `exdir`.
193- # ' Default: `NULL` will search all subdirectories for SSURGO export files.
200+ # ' @param pattern _character_. Optional regular expression to use to filter subdirectories of
201+ # ' `exdir`. Default: `NULL` will search all subdirectories for SSURGO export files.
194202# ' @param include_spatial _logical_ or _character_. Include spatial data layers in database?
195203# ' Default: `TRUE` inserts all spatial tables. If `include_spatial` is a _character_ vector
196204# ' containing table names, only that set are written to file. e.g. `include_spatial=c("mupolygon",
@@ -202,20 +210,19 @@ downloadSSURGO <- function(WHERE = NULL,
202210# ' descriptions are stored in table `"featdesc"` and metadata for each soil survey area are stored
203211# ' in `"soil_metadata"` tables.
204212# ' @param dissolve_field _character_. Dissolve geometries to create MULTIPOLYGON features? Column
205- # ' name
206- # ' specified is the grouping variable. Default: `NULL` does no aggregation, giving 1 `POLYGON`
207- # ' feature per delineation. `"mukey"` aggregates all related delineations within a soil survey
208- # ' area.
209- # ' @param maxruledepth _integer_. Maximum rule depth for `"cointerp"` table. Default `0` includes only
210- # ' shallowest ratings for smaller database size.
213+ # ' name specified is the grouping variable. Default: `NULL` does no aggregation, giving 1
214+ # ' `POLYGON` feature per delineation. `"mukey"` aggregates all related delineations within a soil
215+ # ' survey area.
216+ # ' @param maxruledepth _integer_. Maximum rule depth for `"cointerp"` table. Default `0` includes
217+ # ' only shallowest ratings for smaller database size.
211218# ' @param overwrite _logical_. Overwrite existing layers? Default: `FALSE`
212219# ' @param append _logical_. Append to existing layers? Default: `FALSE`
213220# ' @param header _logical_. Passed to `read.delim()` for reading pipe-delimited (`|`) text files
214221# ' containing tabular data.
215222# ' @param quiet _logical_. Suppress messages and other output from database read/write operations?
216223# ' @param ... Additional arguments passed to `write_sf()` for writing spatial layers.
217224# '
218- # ' @return Character . Vector of layer/table names in `filename`.
225+ # ' @return _character_ . Vector of layer/table names in `filename`.
219226# ' @seealso [downloadSSURGO()]
220227# ' @export
221228# ' @examples
@@ -294,7 +301,8 @@ createSSURGO <- function(filename = NULL,
294301 if ((missing(conn ) || is.null(conn )) && ! IS_GPKG ) {
295302
296303 if (! requireNamespace(" RSQLite" )) {
297- stop(" package 'RSQLite' is required (when `conn` is not specified)" , call. = FALSE )
304+ stop(" package 'RSQLite' is required (when `conn` is not specified)" ,
305+ call. = FALSE )
298306 }
299307
300308 conn <- DBI :: dbConnect(DBI :: dbDriver(" SQLite" ),
@@ -306,7 +314,11 @@ createSSURGO <- function(filename = NULL,
306314 }
307315
308316 if (nrow(inv $ shp.grp ) > = 1 && ncol(inv $ shp.grp ) == 3 && include_spatial ) {
309- f.shp.grp <- split(inv $ f.shp , list (feature = inv $ shp.grp [, 1 ], geom = inv $ shp.grp [, 2 ]), drop = TRUE )
317+
318+ f.shp.grp <- split(inv $ f.shp ,
319+ list (feature = inv $ shp.grp [, 1 ],
320+ geom = inv $ shp.grp [, 2 ]),
321+ drop = TRUE )
310322
311323 if (IS_DUCKDB ) {
312324 DBI :: dbExecute(conn , " INSTALL spatial; LOAD spatial;" )
0 commit comments