Fast and Easy Compilation of Vascular Plants Occurrence Records from 'GBIF'
Overview
'GBIF' https://www.gbif.org/ hosts over 500 million occurrence records of tracheophyte (vascular plants). However, dealing with them typically involves lots of workflows and time, posing significant challenges for researchers. To address these limitations, we present 'VasGBIF', a fast and easy 'R' package to parse and merge enormous tracheophyte records.
*Internal-consistency release. The documented workflow shrinks from eight steps to seven: issue counting becomes an internal detail of customized_filter(), and the coordinate stage is renamed par_clean_coordinates(). The two native-status detectors stop demanding a CoordinateRefined object and become plain table functions with explicit column-name arguments, and their classification columns are simplified.*
Breaking Changes
Function renames
- **
clean_coordinates()is renamedpar_clean_coordinates().** The old name collided withCoordinateCleaner::clean_coordinates(), which the function calls, and said nothing about how it works. The new name records that the CoordinateCleaner tests are distributed acrossthreadsworkers throughforeach/doParallel. The signature changes fromclean_coordinates(customized_filtered, threads = 4, tests = ...)topar_clean_coordinates(input = NA, species = "Accepted_name_id", longitude = "decimalLongitude", latitude = "decimalLatitude", threads = 4, tests = ...). The first argument is renamed and the three column-name arguments are new; see *Improvements*. - **
extract_gbif_issues()is renamedextract_issues()and is no longer exported.** Issue counting was never a decision the user had to make: it only feeds thegbif_issues_maxrule ofcustomized_filter(), which now calls it internally. The"issue"class and itsprint.issue()method are gone with the export.
detect_native_coord() and detect_native_country() now take a table
- **Both functions accept any table-like object instead of a
CoordinateRefinedobject.**detect_native_coord(cleaned_coordinates = NA, buffer_km = 10, buffer_chunk_size = 2000)becomesdetect_native_coord(input = NA, species = "Accepted_name", longitude = "decimalLongitude", latitude = "decimalLatitude", buffer_km = 10, buffer_chunk_size = 2000), anddetect_native_country(cleaned_coordinates = NA)becomesdetect_native_country(input = NA, species = "Accepted_name", country = "countryCode"). Anythingdata.table::as.data.table()can convert is accepted, so theinherits()check on the input class is gone. Pass the concrete table, for examplepar_clean_coordinates(...)$CoordinateCleaned, rather than the wrapper object. - **The species and coordinate columns no longer have to carry GBIF field names.** They are named by the
species,longitude,latitudeandcountryarguments, which default to the GBIF names. A column that happens to share a name with one of the arguments (aspeciescolumn, say) does not interfere: the column vectors are extracted before the internaldata.tableexpression is evaluated. - **
detect_native_country()no longer requires coordinates and no longer inspectsCoordinateProblematic.** It classifies every record handed to it throughcountryCode, so it also works on records that do have coordinates but are better classified without geometry. - **A missing
gbifIDis filled in.** Both functions previously relied on it as a join key; an input without one now gets a character sequence number instead of failing.
Classification columns
- **
native_status_sourcevalues renamed.** In the spatial result,spatialandspatial_bufferedbecomeexactandbuffered. In the country-code result,country_codeandcountry_code_no_entrybecomecountryandno_entry. Theunmatchedvalue is unchanged in both.
Show all changes in 3.7.1Hide the rest of the changes in 3.7.1
- **The
bufferedlogical column has been removed.** It was fully implied bynative_status_source == "buffered", and was alwaysFALSEin the country-code result, so it carried no information of its own. Both results now append exactly three classification columns:LEVEL3_COD,native_status,native_status_source.
Other signature changes
- **
customized_filter()no longer takesgbif_issue.** The argument had to be filled with the output ofextract_gbif_issues(), which is now called internally, so the signature drops tocustomized_filter(occ_import, taxa_checked, filter_countryCode = TRUE, filter_coordinateUncertainty = 10000, filter_date = FALSE, filter_identifiedBy = FALSE, filter_recordedBy = FALSE, filter_gbif_issues_max = 5). - **
export_records()gains anative_detected_countryargument and renames its output files.** The signature becomesexport_records(native_detected_coord = NA, native_detected_country = NA, export_path = NA). Each classification supplied is written as its own pair -all_records_coord.csv.gz/native_records_coord.csv.gzandall_records_country.csv.gz/native_records_country.csv.gz- replacingall_records.csv.gz/native_records.csv.gz. The two sets are never bound into a combined table. - **
map_records()gains aspeciesargument.** The signature becomesmap_records(native_detected_coord = NA, species = "all", precision = 3, cex = 3), so a single species can be mapped without subsetting the table by hand. A name that selects nothing stops with an error rather than rendering an empty map. - **
import_records()accepts an already-extracted occurrence table, andremove_tempfiledefaults toTRUE.** The default wasNULL, which resolved toTRUEfor an auto-created directory butFALSEfor a user-supplied one; it is now a plainTRUE. The extension check onpathis gone: a non-ZIP file is no longer rejected on its suffix but probed for agbifIDfirst column, which rejects non-GBIF files including comma-separated ones whose header would otherwise arrive as a single column.
Dependency and documentation
- **The
rnaturalearthdatadependency has been removed.** Theseastest is evaluated against the bundledWorldLandMapobject, which is passed explicitly asseas_ref, so the package was never imported at run time. - **The documented workflow is now seven steps:**
import_records()-\>check_taxon()-\>customized_filter()-\>par_clean_coordinates()-\>detect_native_coord()/detect_native_country()-\>map_records()-\>export_records(). Every step number was decremented after the removal of the issue-extraction step.
Bug Fixes
- **
par_clean_coordinates()returned different results for adata.tableand adata.frame.**CoordinateCleaner::clean_coordinates()behaves differently on the two: insidecc_outl()it subsets withk[, c(species, lon, lat)], which on adata.tablereturns a three-element character vector rather than the columns, silently changing which records are flagged as outliers. The table is now converted withas.data.frame()before it is handed over, so the same input always yields the same output. This was a reproducibility defect: the result depended on the class of the caller's object rather than on its contents. - **
import_records()could delete a directory the caller supplied.** Cleanup ranunlink(ex_path, recursive = TRUE)unconditionally whentempdirwas given, so a user-supplied directory was removed in full even though it may have held unrelated files. An auto-created directory is still removed whole, but a caller-supplied one now has only the extracted members unlinked. - **
set_threads()stopped with"illegal !!!".** A non-positivexnow stops with `xmust be a single positive number.` instead of an unexplained exclamation. - **
par_clean_coordinates()rejects a wholecustomFilteredobject with a usable message.** Passing the object rather than the table it contains previously failed deep inside the coordinate tests; it now stops with `inputis acustomFilteredobject, not a table. Pass the table it contains, for examplepar_clean_coordinates(filtered$occ_filtered).The guard tests for the class, so an ordinary list ordata.frame` input is unaffected.
Improvements
- **
par_clean_coordinates()names its columns and chunks by species.** Thespecies,longitudeandlatitudearguments free the input from GBIF field names, and the parallel split runs per species so a chunk never straddles a taxon boundary. Theseastest is evaluated against the bundledWorldLandMapland polygons buffered by 5 km. - **
customized_filter()reports per-rule verdicts.** Each rule now evaluates the whole table and stores a logicalfilter_*column, so one record can be audited against several rules at once.occ_filteredcarries no verdict columns; the verdicts are returned separately inocc_marked, one column per applied rule.summarygainsfailed(records the rule rejects on its own terms) andonly_failed_here(records it rejects and no other rule does) alongside the existing sequentialdropped/remaining, whose sums differ on overlapping rules. - **
extract_issues()returns one tidy table.** The previous"issue"object bundled a wide logical matrix with a per-code summary; the internal function returns a singledata.tableofgbifIDand a numericissue_count, which is all thegbif_issues_maxrule needs. - **
export_records()validates and documents both channels.** The coordinate channel requiresgbifID,native_status,decimalLongitudeanddecimalLatitude, and rejects a record with a missing coordinate; the country-code channel requires onlygbifIDandnative_status. Supplying one argument leaves the files of the other untouched. - **The country-code stage keeps every record.** A
countryCodethat is blank,NA, or maps to no WGSRPD Level 3 area is retained asunknown/unmatchedrather than dropped, and a country that maps but has no distribution entry for the taxon isunknown/no_entry. The two are distinct innative_status_source, so a genuinely absent country is never confused with a taxon that has no record there.
Documentation
- Package-level documentation, README,
Example.Rmd, andApplication.Rmdrewritten for the seven-step workflow, the renamed functions, and the new column contracts. - Every
clean_coordinates(),refine_coordinates(),custom_filter()andextract_gbif_issues()reference has been updated acrossR/, README, and the vignettes. References to the internalextract_gbif_issues()are cross-links to the unexportedextract_issues(). _pkgdown.ymlstep headings renumbered to match, and the removedprint.issuemethod dropped from the reference index.- Rd files regenerated for the renamed and updated functions.
Testing
test-custom_filter.Rrewritten for the verdict-column contract: thegbif_issueargument is gone, raw pipe-separatedissuestrings are built in the fixtures, and thefailed/only_failed_heresemantics are pinned against overlapping and disjoint rules.test-detect_native_coord.Randtest-detect_native_country.Rrewritten for the table input, the auto-generatedgbifID, and the renamed classification values; both add a regression test that a column namedspeciesdoes not shadow thespeciesargument.test-par_clean_coordinates.Radded, replacingtest-refine_coordinates.R. It covers the renamed argument, table-like inputs, thecustomFilteredguard, and a thread-independence check thatthreads = 1andthreads = 2returnidentical()results.test-extract_issues.Radded, replacingtest-extract_gbif_issues.R. It asserts the new return contract and that the function stays internal with noprint.issuemethod.test-export_records.Rextended to the country-code channel and the renamed files; the fixtures now create their own temporary directories.test-import_records.R,test-map_records.R, andtest-set_threads.Rupdated for the newtempdirsemantics, the header probe error, thespeciesargument, and the reworded thread error. Theset_threadssnapshot was re-recorded.
From NEWS.md in the release
Install
Health
- OK7 OKNow
- OK5 OK2026-10-21
Documentation
- Help pages
- 21 (1 internal)
- Examples that run
- 100%9 run in a plain check (8 of them under a condition)
- Exported functions with examples
- 89%
- Documented parameters
- 81%
- Return-value docs
- 100%
- Help pages citing references
- 33%
Downloads
Repository
Repository github.com/wyx619/vasgbif is linked, but repository-practices checks have not run for it yet.
Dependencies
Installing VasGBIF adds 110 packages (62 with compiled code, 108 MB of source tarballs). Heaviest: stringi 11 MB, sf 9.3 MB, ggplot2 6.0 MB.
Code & Tests
Datasets
People & History
- 3.7.1Latest2026-10-21 · current release ·
10 days in CRAN's queue
Listed in CRAN's incoming queue from 2026-10-11 18:33 to 2026-10-21 10:55 UTC, in 54 readings. It was also listed earlier, first on 2026-10-03 21:57 UTC, and left the queue for more than a day before this stay. - RR 4.6.0 released · 2026-04-24
Package metadata
- First published
- 2026-10-21
- Total releases
- 1 / 1 yrs
- License
- GPL (>= 3.0)
- Minimum R
- ≥ 4.1
- Bundled data
- 6.5 MB / 5 files
- Download size
- 8.8 MB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("VasGBIF")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-23, which the citation names so these numbers can be found later. More on citing and the projects behind them.