Skip to contents

GIS project assembly and digital field form management. Pull provincial datasets from the BC Data Catalogue, Freshwater Atlas, and cloud-hosted layers, clip to any set of watershed groups, and assemble a fully styled QGIS project with digital field forms — ready to deploy to mobile devices for collaborative offline field collection.

We build and maintain forms for fish passage assessment, habitat confirmation, effectiveness monitoring, restoration site investigation, eDNA sampling, and benthic invertebrate collection — with more added as programs evolve. Data collected in some forms is structured for direct submission to provincial database systems (FISS, PSCIS, CABIN), while other data lands within central database systems we maintain and share with partners. Photos are automatically renamed and organized into site directories. Multiple team members contribute within the same shared project, with changes syncing between field and office.

Installation

pak::pkg_install("NewGraphEnvironment/rfp")

System dependencies

rfp shell scripts require GDAL and several Python CLI tools. Install with:

# GDAL (also needed by R's sf package)
brew install gdal        # macOS
# apt install gdal-bin   # Linux

# Python CLI tools (bcdata, fio, rio, mergin)
pip install uv
uv sync --project "$(Rscript -e 'cat(system.file("python", package = "rfp"))')"

Verify everything is available:

Quick start

library(rfp)

# Create a field-ready QGIS project
rfp_project_create(
  name = "elk_river_2026",
  watershed_groups = c("ELKR"),
  template = "bcfishpass_mobile",
  forms = c("pscis", "fiss_site")
)

# Apply cartographic styles from the gq registry
rfp_styles_apply("~/Projects/gis/elk_river_2026/background_layers.gpkg")

# Push to Mergin Maps for mobile field collection
rfp_mergin_create("newgraph/elk_river_2026", "~/Projects/gis/elk_river_2026")
rfp_mergin_share("newgraph/elk_river_2026", "field_tech_1", "writer")

# Audit who changed what, when
rfp_mergin_collaborators("newgraph/elk_river_2026")
rfp_mergin_history("newgraph/elk_river_2026", since = "2026-01-01")

# Which rows in a layer changed between two points in time?
# e.g. watershed groups added to the Fraser project since 2025-03-31
rfp_mergin_diff(
  project = "newgraph/sern_fraser_2024",
  path    = "background_layers.gpkg",
  layer   = "whse_basemapping.fwa_watershed_groups_poly",
  from    = "2025-03-31",
  key     = "watershed_group_code"
)

See the package documentation for vignettes and function reference.

How the pieces fit together

rfp is built around a layered workflow — each layer is independently usable, and they compose into a field-and-web pipeline. The same QGIS project is the unit of work for mobile field collection (Mergin Maps) and for web map deployment (QWC2):

Layer Functions / artefacts Role
Layer sources rfp_source(), rfp_source_bcdata(), rfp_source_csv(), rfp_source_url() Pluggable abstraction for where a layer comes from: BC Data Catalogue, CSVs on disk, cloud URLs, test fixtures. Project assembly reads the registry.
Project assembly rfp_project_create(), rfp_project_layers(), rfp_project_subset(), rfp_project_templates(); inst/templates/{bcfishpass_mobile,bcrestoration_mobile}.qgs Stitch a styled QGIS project together from background layers + forms + templates + methods PDFs. rfp_project_subset() derives a focused child project from a heavy parent (e.g. a one-watershed mobile deploy or a browser-renderable subset from a multi-region parent).
Forms rfp_form_types(), rfp_form_create(); inst/lookups/rfp_form_types.csv Package-internal registry of field-form GeoPackages (PSCIS, FISS, eDNA, habitat confirmation, restoration, CABIN). Add a form to a project, deploy with the project, sync back as data.
QGIS authoring rfp_qgs_rename(), rfp_qgs_themes(), rfp_qgs_theme_apply(), rfp_qgs_theme_export() xml2-based transformations on .qgs files: WMS-safe layer naming, inspect map themes (visibility presets) in a project, and transfer themes between projects so a styling change made in one project propagates to others.
Cartography (via gq) rfp_styles_apply(); inst/pyqgis/apply_styles.py, render_map.py Apply cartographic styles maintained centrally in gq — QGIS, tmap, leaflet, and web all share the same registry. PyQGIS scripts drive the headless application + map rendering.
Field deployment (Mergin Maps) rfp_mergin_create/share/pull/push/sync/diff/history/... (12 fns) Deploy projects to Mergin, share with collaborators by role, sync changes between field and office, audit history with row-level diffs.
Web deployment (QWC2) rfp_qgs_themes_config()qwc_config.csv; consumed by rtj’s qwc_project-add.sh Generate the QWC2 themesConfig + visibility-preset entry for a project. Theme keep-list, initial theme, locked layers, bbox override, project title, URL suffix — all driven from the .qgs map themes. WMS-spec name compliance is handled by rfp_qgs_rename() so QWC2’s flattened group hierarchy doesn’t collide.
Field artefacts rfp_photo_metadata_rm(), rfp_gpx_import(), rfp_gpkg_to_geojson() Photo metadata scrubbing, GPS track import, format conversion.
Provincial metadata rfp_meta_bcd_xref(), rfp_meta_bcd_xref_col_comments() Cross-reference layers to BC Data Catalogue records for documentation + lineage; surfaces WMS endpoints for downstream consumption.

The mobile-and-web dual deployment is the design intent: one QGIS project, two delivery surfaces. rfp_project_subset() is the data-thinning primitive that makes the same project legible in a browser (full provincial layers won’t render in QWC2).

Roadmap

  • Form lifecycle deepening — registry expansion (more form types, partner-defined types) and tighter coupling to downstream database submission for FISS / PSCIS / CABIN. A CSV-driven form-builder (QML generation from tabular definitions) is in design (#24).
  • Style-registry tightening — connect QGIS layer_styles tables to the central gq style registry so a style edit propagates to every project that references it (#15, #17).
  • QGIS version support — bump templates to QGIS 4.0 once stable (#68); multi-version schema fixtures for qgs/subset tests (#69).
  • Layer-source plugins — extend rfp_source_*() to additional cloud-hosted sources beyond BC Data Catalogue, direct URLs, and CSV.

Issues and feature requests live in GitHub Issues.