Skip to contents

It’s all about style.

Cartographic style management across QGIS, tmap, leaflet, MapLibre GL, and ggplot2. One canonical registry; every rendering target reads from it.

gq extracts symbology from QGIS projects (QML), stores it in a canonical JSON registry alongside hand-curated layers, and serves it back to whatever R / web mapping target needs it — so a colour edit in QGIS, or a width tweak in the registry, propagates to every static report, leaflet popup, and web tile without copying values around.

Installation

pak::pak("NewGraphEnvironment/gq")

The Python-side extractor (python/gq/) needs PyQGIS — install via your system’s QGIS Python or a conda environment with pyqgis. The R side has no PyQGIS dependency: registries ship in inst/registry/, and you only re-run the extractor when QGIS projects change.

Architecture

                                ┌──────────────────────────┐
                                │  Hand-curated CSVs:      │
                                │  groups / templates /    │
                                │  themes / xref_layers    │
                                └──────────┬───────────────┘
QGIS Project (.qgs / .qgz)                 │
        │ PyQGIS extract                   │ gq_reg_custom()
        ▼                                  │
   QML files (.qml)                        │
        │ parse                            │
        ▼                                  ▼
   per-project registry JSON ──── gq_reg_merge() ─── reg_main.json
        (reg_qgis_restoration,                       (master registry)
         reg_qgis_fishpassage)                              │
                                                            │ gq_style()
                                                            │ gq_*_style()
                                                            ▼
                                        ┌─────────┬──────────┬─────────────┬─────────┐
                                        │  tmap   │ leaflet  │ MapLibre GL │ ggplot2 │
                                        │  (R)    │   (R)    │   (JSON)    │  (R)    │
                                        └─────────┴──────────┴─────────────┴─────────┘

Quick start

library(gq)

# Read the master registry shipped with the package
reg <- gq_reg_main()

# Backend-agnostic resolver — by layer name
gq_style(reg, "lake")
gq_style(reg, "Crossings - PSCIS assessment")
#> $type
#> [1] "polygon"
#> $fill
#> $fill$color
#> [1] "#3b8bd2"
#> ...

# tmap rendering — categorical scales wired up for you
tmap::tm_shape(lakes_sf) +
  gq_tmap_style(reg, "lake")

# MapLibre GL style spec (returns JSON-ready list)
gl_style <- gq_mapgl_style(reg, "crossings_pscis_assessment")

# Compose a project from groups + themes (drives QGIS project assembly + QWC2 visibility presets)
gq_themes()            # the theme roster, per template
gq_group_layers("Crossings")
gq_template_layers("bcrestoration_mobile")

# QGIS-native style — the full QML, for anything that speaks to QGIS
gq_style_qml("lake")
gq_style_qml("land_ownership", template = "bcfishpass_mobile")

# Composition — bbox padding, basemap blending, legends, keymap insets
bbox <- gq_bbox_aspect(aoi_sf, asp = 7 / 9)
basemap <- gq_basemap_blend(
  gq_basemap_tiles(bbox, provider = "Esri.WorldGrayCanvas"),
  gq_basemap_tiles(bbox, provider = "Esri.WorldShadedRelief")
)
leg <- gq_tmap_legend(reg, c("lake", "railway", "roads_dra"))

Concepts

Concept What it is
Registry The canonical JSON — per-layer styling (color, opacity, stroke, mark, font, label, classification breaks). Shipped under inst/registry/; one per QGIS project family (reg_qgis_restoration, reg_qgis_fishpassage) plus a merged reg_main.json master.
Groups Named bundles of layers with nesting + z-order (e.g. Crossings, Streams, Base - misc). Drives QGIS legend tree and front-end layer pickers.
Templates Project-level compositions — which groups belong to which QGIS project (bcfishpass_mobile, bcrestoration_mobile). Project-assembly tools read templates to decide which layers belong in a new field project.
Themes Per-layer visibility presets, extracted from the templates (e.g. High Detail - Crossings, Land Tenure). Keyed by template as well as theme, because a theme name is not global — Land Tenure ships in one template only, and the templates can drift independently. Drives QGIS map themes and is exportable as QWC2 web-map visibility config.
xref_layers Cross-reference table mapping registry keys to source-system layer names (BC Data Catalogue WMS layers, fwapg views, internal pgsql schemas) so consumers can look up the underlying data when they want it.
QML corpus The same styles in QGIS’s own format, shipped under inst/styles/. The registry models roughly 20 symbol properties and one symbol layer, because that is what tmap and MapLibre can render; a QML carries everything QGIS authored — multi-layer symbols, casing and overlay, labelling, per-class dash. Shared vector styles, with per-template overrides for the few layers whose symbology genuinely differs, plus raster and service styles.

Producer ⇄ consumer

Side What it does Where
Producer Extract from .qgs / .qml via PyQGIS → write per-project registry JSON. Update only when QGIS projects change. python/gq/, gq_qgs_extract(), data-raw/.
Consumer Read the registry, resolve a layer name to a backend-specific style. Pure R, no PyQGIS dependency. gq_style(), gq_tmap_style(), gq_mapgl_style(), gq_reg_main(), gq_reg_read().

The registry JSON is the contract between the two: producers don’t know about tmap or MapLibre, and a consumer rendering to those backends never touches QGIS.

Consumers rendering to QGIS are the exception, and gq_style_qml() serves them. Round-tripping a style through the registry is lossy by design; the QML corpus is the lossless path, so a Mergin field project, a QGIS Server / QWC2 deployment or a layer_styles table gets the symbology QGIS actually authored rather than the subset tmap needs.

Roadmap

Active issues track the in-flight scope:

  • Symbol size/shape translator for tmap + mapgl (#16)
  • Composition helpers for tmap (#17), mapgl (#18), leaflet (deferred — #19)
  • Project-specific style overrides convention so reports can override registry defaults without forking the registry (#20)
  • Multi-layer symbol extraction — casing + overlay layers in gq_qgs_extract() so complex highway/road styles round-trip (#24)
  • QLR file support in the extractor so layer-definition files outside .qgs projects can contribute styles (#23)
  • Shiny layer picker module so projects can be assembled interactively from the registry (#22)
  • gq_tmap_legend() helper — pending tmap upstream review (#27)

The long-term direction is OGC API Styles — once the spec is widely adopted by GIS tooling, the canonical registry becomes a server endpoint and the per-target translators become thin client wrappers.

Vignettes

  • gq-intro — registry concepts, the four registries shipped with the package, name-based lookup.
  • gq-tmap-composition — composing a full tmap from the registry.

License

MIT (see LICENSE).