Write layer styling into a spatial data source so QGIS picks it up on layer
open, with no .qgs project needed. For GeoPackage/SQLite the style goes
into the layer_styles table; for file-based formats (GeoJSON, Shapefile,
KML) a .qml sidecar is written beside the file.
Usage
rfp_styles_apply(
path,
qgs = NULL,
qml = NULL,
registry = NULL,
layers = NULL,
xref_layers = NULL,
style_name = "default",
image = NULL
)Arguments
- path
Character. Path to a spatial data file (GPKG, GeoJSON, Shapefile, KML) or a directory containing them. Directories are searched recursively, so the one-GeoPackage-per-layer layout works.
- qgs
Character. Path to a
.qgsproject to take styles from.- qml
Character path to a directory of
.qmlfiles, or a data frame withtableandpath_qmlcolumns.- registry
List. A gq registry object (e.g. from
gq::gq_reg_main()), orTRUEto load the main registry explicitly.- layers
Character vector. Which layers to style.
NULL(default) styles every layer with a matching style.- xref_layers
Named character vector mapping source layer names to target table names. Names are layer names in the style source, values are table names in the data.
- style_name
Character. Name recorded for the style. Default
"default". Ignored forqgs, where the QGIS layer name is used so a table styled several ways keeps each style distinguishable.- image
Character or
NULL. Docker image for headless QGIS, used only by the registry path.NULL(default) uses the digest rfp pins, so the styles written are reproducible rather than following whatever:latestwas last re-pushed. Pass a reference to override.The pinned image is amd64-only, so rfp adds
--platformfor it; an image rfp knows nothing about is run without one, and you own its platform.
Value
Invisibly, a tibble of what was written - table, file,
style_name - for the qgs and qml paths. The registry path instead
returns path invisibly: the writing happens inside the container, and
reconstructing the same tibble would mean parsing that container's stdout,
which is exactly the brittle signal this package avoids elsewhere.
Details
Three sources of style, in order of fidelity:
qgsLift the styles straight out of a QGIS project. Lossless - the QML QGIS writes for a layer is that layer's project node minus its source binding, so symbology, labelling, diagrams and form config all come across verbatim. Pure R; no Docker. See
rfp_qgs_style_export().qmlA directory of
.qmlfiles, or a data frame as returned byrfp_qgs_style_export(). For a directory the file stem names the target table.registryRebuild symbols from the gq cartographic registry via headless PyQGIS in Docker. Approximate - the registry is a cross-backend abstraction extracted from QGIS to drive tmap and mapgl, so styling QGIS from it is a lossy round-trip: it models one symbol layer and about twenty properties, carries no labelling, and drops per-class dash patterns. Use it only for layers no
.qgsstyles.
Supplying none of the three keeps the historical behaviour and uses the gq registry.
Examples
# Build a GeoPackage holding the two tables the bundled fixture styles
gpkg <- file.path(tempdir(), "styles_demo.gpkg")
pt <- sf::st_sf(
id = 1L,
geom = sf::st_sfc(sf::st_point(c(1470000, 900000)), crs = 3005)
)
sf::st_write(pt, gpkg, layer = "form_exceedance", quiet = TRUE)
sf::st_write(pt, gpkg, layer = "roads_dra", quiet = TRUE,
append = TRUE)
# Style it straight from a QGIS project - no Docker, no .qgs at run time
qgs <- system.file("testdata", "styles_fixture.qgs", package = "rfp")
rfp_styles_apply(gpkg, qgs = qgs)
#> ✔ Exported 2 styles to: /tmp/RtmpfSNDuG/rfp_styles_1c08605dfde8
#> ✔ Applied 2 styles to 1 file
# QGIS now reads the styling from the file itself
con <- DBI::dbConnect(RSQLite::SQLite(), gpkg)
DBI::dbGetQuery(
con, "SELECT f_table_name, styleName, length(styleQML) AS qml_bytes
FROM layer_styles"
)
#> f_table_name styleName qml_bytes
#> 1 form_exceedance form_exceedance 75624
#> 2 roads_dra roads_dra 98722
DBI::dbDisconnect(con)
