-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vignette on using QGIS expressions with qgisprocess #143
Merged
Merged
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
e561c0f
Vign QGIS expressions: start
florisvdh 2ba7669
Vign QGIS expressions: examples for QGIS expression args
florisvdh bd696b4
Vign QGIS expressions: use kable() for acceptable values
florisvdh 9829c4a
Vign QGIS expressions: minor updates
florisvdh 8d5e43e
Vign QGIS expressions: add data-defined override example
florisvdh a78c42e
Vign QGIS expressions: adjust date
florisvdh f0d53f1
Vign QGIS expressions: rename file
florisvdh 0c90e4c
Vign QGIS expressions: make qgisprocess boldface
florisvdh 3ed0df2
Vign QGIS expressions: move code to child document *
florisvdh d6b02ce
Merge branch 'main' into vign_qgis_3.30
florisvdh 8c9fe04
Vign QGIS expressions: update chunk options
florisvdh 176fecc
Vign QGIS expressions: use rprojroot for pkgdown GHA workflow
florisvdh 21f9b13
Vign QGIS expressions: fix GHA R-CMD-check on Windows *
florisvdh e4a6c7e
slightly rewrite intro
jannes-m 32575c3
restructure and slighly clarify
jannes-m b1e32ec
add missing to
jannes-m 1b34d3b
address minor issues
jannes-m 7a73118
Vign QGIS expressions: clarify 'INPUT geometry'
florisvdh c74f495
Vign QGIS expressions: show geometry type of buffer object
florisvdh 35958a0
Vign QGIS expressions: minor updates
florisvdh 971e777
Vign QGIS expressions: add @jannes-m as author
florisvdh 90b3e05
Vign QGIS expressions: update date
florisvdh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# Introduction | ||
|
||
Many QGIS processing algorithms provide the possibility to use [QGIS expressions](https://docs.qgis.org/latest/en/docs/user_manual/expressions/index.html). | ||
If an algorithm argument expects a QGIS expression, this is typically marked by a button in the QGIS processing dialog that opens the QGIS expression builder (e.g. in `native:extractbyexpression`), or by a directly integrated QGIS expression builder (e.g. in `native:fieldcalculator`). | ||
Such arguments are of type `expression`, as seen in the output of `qgis_arguments()`. | ||
|
||
```{r} | ||
qgis_arguments("native:fieldcalculator") |> subset(name == "FORMULA") | ||
``` | ||
|
||
Secondly, one can use expressions for _data-defined_ overriding. | ||
This means, that an algorithm argument that is usually a fixed (numeric or boolean) value can _also_ take on the value of another field or the result of an expression. | ||
In the QGIS processing dialog, such arguments have a '[data-defined override](https://docs.qgis.org/latest/en/docs/user_manual/introduction/general_tools.html#data-defined)' button. | ||
An example is provided by the `DISTANCE` argument of `native:buffer`, for which we query the acceptable values below. | ||
|
||
```{r} | ||
qgis_arguments("native:buffer") |> | ||
subset(name == "DISTANCE") |> | ||
dplyr::select(acceptable_values) |> | ||
tidyr::unnest(cols = acceptable_values) |> | ||
knitr::kable() | ||
``` | ||
|
||
# Examples where the argument expects a QGIS expression | ||
|
||
In these cases, provide the expression as a string in R. | ||
|
||
As example data, we use a lake polygon and a set of points that have lake depth as attribute. | ||
|
||
```{r} | ||
longlake_path <- system.file("longlake/longlake.gpkg", package = "qgisprocess") | ||
longlake_depth_path <- system.file("longlake/longlake_depth.gpkg", package = "qgisprocess") | ||
``` | ||
|
||
```{r} | ||
nrow(read_sf(longlake_depth_path)) | ||
``` | ||
|
||
Using a QGIS expression to filter points by depth: | ||
|
||
```{r} | ||
qgis_run_algorithm( | ||
"native:extractbyexpression", | ||
INPUT = longlake_depth_path, | ||
EXPRESSION = '"DEPTH_M" > 1', | ||
.quiet = TRUE | ||
) |> | ||
st_as_sf() | ||
``` | ||
|
||
More often, you will want to use QGIS functions in expressions, and look at the relationship between geometries or create new geometries. | ||
|
||
Let's calculate the distance between the points and the lake border, and add it as an attribute to the points. | ||
For that we will use the `native:fieldcalculator` algorithm. | ||
|
||
We first create the lake border: | ||
|
||
```{r} | ||
lake_border_path <- qgis_run_algorithm( | ||
"native:polygonstolines", | ||
INPUT = longlake_path, | ||
.quiet = TRUE | ||
) |> | ||
qgis_output("OUTPUT") | ||
``` | ||
|
||
Next, build the QGIS expression. | ||
Referring the `INPUT` geometry is done with the `@geometry` variable. | ||
|
||
```{r} | ||
expr <- glue::glue("distance( | ||
@geometry, | ||
geometry( | ||
get_feature_by_id( | ||
load_layer('{lake_border_path}', 'ogr'), | ||
1 | ||
) | ||
) | ||
)") | ||
``` | ||
|
||
Referring the lake border geometry in the expression is a bit more involved, since it needs several QGIS functions. | ||
The layer can be loaded from a filepath with the `load_layer()` function, then the first (and only) feature is selected with `get_feature_by_id()`, and the geometry of that feature is referred by `geometry()`. | ||
These steps are needed because the `distance()` function needs geometries to work on, not features, layers or filepaths. | ||
|
||
Use the QGIS expression builder to look up function documentation, or consult the online [QGIS function documentation](https://docs.qgis.org/latest/en/docs/user_manual/expressions/functions_list.html). | ||
|
||
Note: the `load_layer()` function is only available since QGIS 3.30.0! | ||
In earlier versions, you needed to refer the layer's name as present in an _existing_ QGIS project, and refer the project path in `qgis_run_algorithm()` with the special `PROJECT_PATH` argument. | ||
The `load_layer()` approach since QGIS 3.30.0 avoids the need for a QGIS project. | ||
|
||
Now we can run the algorithm: | ||
|
||
```{r eval=(package_version(strsplit(qgis_version(), "-")[[1]][1]) >= "3.30.0") && !is_windows()} | ||
qgis_run_algorithm( | ||
"native:fieldcalculator", | ||
INPUT = longlake_depth_path, | ||
FIELD_NAME = "distance", | ||
FORMULA = expr | ||
) |> | ||
st_as_sf() | ||
``` | ||
|
||
# Example applying a data-defined override | ||
|
||
Suppose that we want to create a buffer around the points with a dynamic radius expressed as a function of `DEPTH_M`, e.g. 10 times the depth at each point. | ||
We will use `native:buffer` for that purpose. | ||
Note: applying a data-defined override with **qgisprocess** is only possible since since QGIS 3.30.0! | ||
|
||
Because `DISTANCE` by default expects a numeric value, you have to use the prefix `expression:` if you want to pass an expression string. | ||
Double quotes are used in QGIS expressions to denote fields (attributes), but you can also omit them. | ||
|
||
Let's try: | ||
|
||
```{r} | ||
buffer <- qgis_run_algorithm( | ||
"native:buffer", | ||
INPUT = longlake_depth_path, | ||
DISTANCE = 'expression: "DEPTH_M" * 10', | ||
.quiet = TRUE | ||
) |> | ||
st_as_sf() | ||
``` | ||
|
||
Plot the result: | ||
|
||
```{r} | ||
par(mar = rep(0.1, 4)) | ||
plot(read_sf(lake_border_path) |> st_geometry()) | ||
plot(buffer[, "DEPTH_M"], add = TRUE) | ||
``` | ||
|
||
If you just want to refer the value of another attribute, then you can also use the `field:` prefix instead, _without_ double quotes around the attribute name and _without_ spaces: | ||
|
||
```{r eval=FALSE} | ||
qgis_run_algorithm( | ||
"native:buffer", | ||
INPUT = longlake_depth_path, | ||
DISTANCE = "field:DEPTH_M" | ||
) |> | ||
st_as_sf() | ||
``` | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
--- | ||
title: "How to use QGIS expressions in qgisprocess?" | ||
author: "Floris Vanderhaeghe" | ||
date: "Last updated: 2023-03-24" | ||
output: rmarkdown::html_vignette | ||
vignette: > | ||
%\VignetteIndexEntry{How to use QGIS expressions in qgisprocess?} | ||
%\VignetteEngine{knitr::rmarkdown} | ||
%\VignetteEncoding{UTF-8} | ||
--- | ||
|
||
```{r, include = FALSE} | ||
knitr::opts_chunk$set( | ||
collapse = TRUE, | ||
comment = "#>" | ||
) | ||
``` | ||
|
||
```{r setup, message=FALSE} | ||
library(qgisprocess) | ||
library(sf) | ||
``` | ||
|
||
```{r child=if (has_qgis()) file.path(rprojroot::find_root(rprojroot::is_r_package), "man/vignette_childs/_qgis_expressions.Rmd")} | ||
``` | ||
|
||
```{r eval=!has_qgis(), echo=FALSE, results="asis"} | ||
cat("This vignette has been built in absence of a QGIS installation.\n\n") | ||
cat("Read it online at <https://r-spatial.github.io/qgisprocess/articles/qgis_expressions.html>.") | ||
``` | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With QGIS 3.28.2 this results it:
Not sure, if this is the desired result
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, later on you say that this is only possible with QGIS 3.30 onwards, ok