| Title: | Functions Used in the Plant Module of the Biodiversa+ Pilot on Invasive Alien Species |
|---|---|
| Description: | Tools used in the work with the vehicle mounted CamAlien system for monitoring plants. The package provides functions to interact with the CamAlien database. |
| Authors: | Lars Dalby [aut, cre] (ORCID: <https://orcid.org/0000-0002-7270-6999>) |
| Maintainer: | Lars Dalby <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.6.0 |
| Built: | 2026-10-01 12:41:11 UTC |
| Source: | https://gitlab.au.dk/ecos/biodiversa/camalien/camalienr |
Convert data.frame to Simple Feature collection by converting the position column (pg_geometry) to sfc.
ca_as_sf(tbl)ca_as_sf(tbl)
tbl |
The data.frame to be converted |
tbl as Simple Feature collection
Establish a connection to a camalien database. This function is a wrapper around DBI::dbConnect. The function will create a connection using RPostgres::Postgres as a driver. For the function to work you need to have the following environment variables set in your .REnviron file:
CAMALIEN_HOST
CAMALIEN_USER
CAMALIEN_PASSWORD
ca_connect(host = NULL, dbname = NULL, port = NULL)ca_connect(host = NULL, dbname = NULL, port = NULL)
host |
character The host to connect to. Defaults to the CAMALIEN_HOST environment variable. |
dbname |
character The name of the database. Defaults to the
CAMALIEN_DB environment variable, or |
port |
The port to connect on. Defaults to the CAMALIEN_PORT
environment variable, or |
All three are required and the function fails with an informative error
if any of them are missing. There is deliberately no default host, so you
never connect to a database you did not ask for. The database name and the
port default to camalien and 5432 respectively, and can be changed with
the optional CAMALIEN_DB and CAMALIEN_PORT variables. Set-but-empty
variables count as unset. Arguments given to the function take precedence
over the environment, which is handy for a one-off connection to another
camalien database.
To modify or create an .REnviron file we suggest you use usethis::edit_r_environ. Calling this function from RStudio will open the file for you to edit. Simply insert the variables, save and restart R.
PqConnection
## Not run: # Use the target given by the environment variables: con <- ca_connect() # Override it for a single connection: con <- ca_connect(host = "ecos-postgis-snapshot.cjqc9gl8vdbe.eu-north-1.rds.amazonaws.com") ## End(Not run)## Not run: # Use the target given by the environment variables: con <- ca_connect() # Override it for a single connection: con <- ca_connect(host = "ecos-postgis-snapshot.cjqc9gl8vdbe.eu-north-1.rds.amazonaws.com") ## End(Not run)
This is a simple wrapper around DBI::dbDisconnect to use when disconnecting from a database. It is good practice to disconnect when no longer using the connection.
ca_disconnect(con)ca_disconnect(con)
con |
DBIConnection The connection object which in the case of camalien will be a PqConnection. |
TRUE, invisibly
Get tables from the data schema of the camalien database. These functions only return a lazy table and will not download any data to your session. Use dplyr::collect when you actually want to download the data. Normally you would want to do some selection and filtering before calling collect()
ca_get_image(con) ca_get_job(con) ca_get_plantnetcall(con) ca_get_detection(con) ca_get_detectionsummary(con) ca_get_imagemeta(con) ca_get_species(con) ca_get_chunk(con) ca_get_partner(con) ca_get_imagefile(con) ca_get_imagedata(con) ca_get_additionalimagedata(con) ca_get_session(con)ca_get_image(con) ca_get_job(con) ca_get_plantnetcall(con) ca_get_detection(con) ca_get_detectionsummary(con) ca_get_imagemeta(con) ca_get_species(con) ca_get_chunk(con) ca_get_partner(con) ca_get_imagefile(con) ca_get_imagedata(con) ca_get_additionalimagedata(con) ca_get_session(con)
con |
PqConnection The connection to the camalien database |
ca_get_image(), ca_get_imagemeta() and ca_get_detectionsummary()
reach tables that only exist on hosts using the v1 image model, and
ca_get_imagefile(), ca_get_imagedata(), ca_get_additionalimagedata()
and ca_get_session() reach the v2 tables that replaced them. See
ca_get_tbl() for the mapping between the two, and ca_image_model() to
ask a connection which one it carries.
A lazy table
A common task is to filter e.g. detections made within one of the
partner countries. This involves a number of joins to carry the partner
name all the way through to the image or detection table.
This function sets up the required joins and can filter the resulting table
to a single partner by supplying the partner_name argument.
ca_get_join_tbl(con, partner_name = NULL)ca_get_join_tbl(con, partner_name = NULL)
con |
PqConnection The connection to the camalien database |
partner_name |
chr Name of the partner |
This is the ownership chain of the v1 image model, partner → job → chunk,
and it is joined to ca_get_image() on chunkid. On a host using the v2
image model use ca_get_session_tbl() instead: data2.imagefile still has
a chunkid, but it is not filled in for every image, so the chunk chain
silently loses rows there.
A lazy table
This function will extract the relevant information from a JSON file returned from the Plantnet API.
ca_get_polygon(pn_json)ca_get_polygon(pn_json)
pn_json |
The JSON object (read by e.g. jsonlite::read_json) |
list of center_x, center_y and size
The v2 counterpart of ca_get_join_tbl(). Images in the v2 model belong to
a session rather than to a chunk, so ownership runs partner → session →
imagedata. Join the result to ca_get_imagedata() on sessionid.
ca_get_session_tbl(con, partner_name = NULL)ca_get_session_tbl(con, partner_name = NULL)
con |
PqConnection The connection to the camalien database |
partner_name |
chr Name of the partner |
A lazy table with sessionid, session, year, partnerid and
partner
## Not run: con <- ca_connect() con |> ca_get_imagedata() |> dplyr::inner_join(ca_get_session_tbl(con, "Denmark"), by = "sessionid") ## End(Not run)## Not run: con <- ca_connect() con |> ca_get_imagedata() |> dplyr::inner_join(ca_get_session_tbl(con, "Denmark"), by = "sessionid") ## End(Not run)
Get any table from any schema of the camalien database. The ca_get_*()
functions are thin wrappers around this one, and it is the way to reach the
tables that have no wrapper of their own — the gbif, tasks and backup
schemas, and the parts of data2 that are not about images.
ca_get_tbl(con, table, schema = "data")ca_get_tbl(con, table, schema = "data")
con |
PqConnection The connection to the camalien database |
table |
character Name of the table |
schema |
character Name of the schema holding the table. Defaults to
|
This function only returns a lazy table and will not download any data to your session. Use dplyr::collect when you actually want to download the data. Normally you would want to do some selection and filtering before calling collect().
The table layout differs between camalien hosts. Hosts that still carry the
original image model keep images in the data schema; hosts that have been
migrated retired those tables and hold images in data2 in a different
shape:
v1 (data) |
v2 (data2) |
accessor |
image |
imagefile |
ca_get_imagefile() |
imagemeta |
imagedata |
ca_get_imagedata() |
additionalimagedata |
ca_get_additionalimagedata() |
|
session |
ca_get_session() |
|
detectionsummary |
detectionsummary |
ca_get_tbl(con, "detectionsummary", schema = "data2")
|
The two models are not interchangeable: imagefile carries the file
(filename, path, type, chunkid) and imagedata the capture
(position, timestamp, tagged), where v1 had image and imagemeta.
Asking for a table the host does not carry therefore fails with an error
naming the replacement rather than quietly returning a different table.
Use ca_image_model() to ask which model a connection carries.
A lazy table
## Not run: con <- ca_connect() # The same as ca_get_partner(con): ca_get_tbl(con, "partner") # Reach a table with no wrapper of its own: ca_get_tbl(con, "taxon_detection_summary", schema = "data2") ## End(Not run)## Not run: con <- ca_connect() # The same as ca_get_partner(con): ca_get_tbl(con, "partner") # Reach a table with no wrapper of its own: ca_get_tbl(con, "taxon_detection_summary", schema = "data2") ## End(Not run)
Camalien hosts do not all hold images the same way. The original (v1) model
keeps them in data.image and data.imagemeta, owned through the
partner → job → chunk → image chain. The v2 model retires both tables and
splits them into data2.imagefile and data2.imagedata, owned through
partner → session → imagedata. Use this to branch when you need code that
runs against either.
ca_image_model(con)ca_image_model(con)
con |
PqConnection The connection to the camalien database |
"v1" or "v2"
## Not run: con <- ca_connect() ca_image_model(con) ## End(Not run)## Not run: con <- ca_connect() ca_image_model(con) ## End(Not run)
Draw an image and show the polygon where the detection was made as a polygon on top of the image.
ca_img_detection(data, height = 3000L, border = NA, col = NA, lwd = 4)ca_img_detection(data, height = 3000L, border = NA, col = NA, lwd = 4)
data |
data.frame Data.frame with |
height |
Integer specifying the height of the desired plot. Width is scaled proportionally. |
border |
chr Polygon outline color |
col |
chr Color to use if plotting filled polygons. The format is #RRGGBBAA where AA is the alpha channel for transparency |
lwd |
int Polygon outline line width |
## Not run: images[1,] |> ca_img_detection(height = 500, border = "red") images |> ca_img_detection(height = 500, col ="#FF000040") ## End(Not run)## Not run: images[1,] |> ca_img_detection(height = 500, border = "red") images |> ca_img_detection(height = 500, col ="#FF000040") ## End(Not run)
Draw a polygon and annotate it with ID
ca_img_draw_polygon( center_x, center_y, size, border = "red", col, lwd = 4, scale )ca_img_draw_polygon( center_x, center_y, size, border = "red", col, lwd = 4, scale )
center_x, center_y
|
int coordinates of the centre of the polygon |
size |
int size of the polygon |
border |
chr Polygon outline color |
col |
chr Color to use if plotting filled polygons. The format is #RRGGBBAA where AA is the alpha channel for transparency |
lwd |
int Polygon outline line width |
scale |
double Scaling factor if the image is not rendered full size |
Plot a grid of multiple images.
ca_img_grid(img_paths, ncol = 3, nrow = 3, height = 300L)ca_img_grid(img_paths, ncol = 3, nrow = 3, height = 300L)
img_paths |
Vector of paths (can be URLs). Should be of length
|
ncol, nrow
|
Int, the number of rows and columns |
height |
Integer specifying the height of the desired plot. Width is scaled proportionally. |
## Not run: images$imageurl |> ca_img_grid(ncol = 5, nrow = 1) ## End(Not run)## Not run: images$imageurl |> ca_img_grid(ncol = 5, nrow = 1) ## End(Not run)
Plot and optionally scale image
ca_img_plot(img, height = 3000L)ca_img_plot(img, height = 3000L)
img |
magick-image object read by |
height |
Integer specifying the height of the desired plot. Width is scaled proportionally. |
Read image file for viewing or further manipulation
ca_img_read(url)ca_img_read(url)
url |
URL to the image to be read. |
magick-image object
A simple wrapper around jsonlite::read_json().
ca_json_read(path)ca_json_read(path)
path |
chr Path to the json file to read. |
list with content of json file being read
Parse json files with information about the individual chunks of images from the CamAlien uploader.
ca_parse_chunks(path)ca_parse_chunks(path)
path |
chr Path to the json file to read. |
The function will read all the chunk files in the directory at
path.
data.frame with content of json files being read
Parse json files with information about the job from the CamAlien uploader.
ca_parse_job(path)ca_parse_job(path)
path |
chr Path to the json file to read. |
data.frame with content of json file being read
Calculate statistics on the images uploaded by each partner
ca_stat_images(con)ca_stat_images(con)
con |
PqConnection The connection to the camalien database |
The query follows whichever image model the host carries (see
ca_image_model()). On a v1 host the count is of jpg images, reached
through partner → job → chunk. On a v2 host it is of captures in
data2.imagedata, reached through partner → session, which is the same
quantity — one capture yields one jpg — but counted on the chain that is
filled in there.
lazy_tbl
Calculate sizes on the upload jobs that each partner has started. There is some inaccuracies relating to this as we can't see if images in one job are also part of other jobs.
ca_stat_jobsize(con)ca_stat_jobsize(con)
con |
PqConnection The connection to the camalien database |
The Danish images were uploaded with an early version of the uploader
which did not report the size of the job and therefore total_size is
NA here.
lazy_tbl
Calculate the number and ratio of tagged images.
ca_stat_tagged(con)ca_stat_tagged(con)
con |
PqConnection The connection to the camalien database |
The query follows whichever image model the host carries (see
ca_image_model()). On a v1 host an image counts as tagged when its
imagemeta row has a tag; on a v2 host data2.imagedata carries a
tagged flag of its own.
lazy_tbl with partner, n_tagged, n and prop
Each partner has their own list of invasive alien species which they targeted during the field campaign. The same species can be on the list of multiple partners. Target species can be an entire genus. The scientific and the canonical name are from a lookup on GBIF.
iasias
Data.frame with gbifid and name
chr, The partner name
chr, The canonical name from GBIF with the modification that for genera we add .sp
chr, The scientific taxon name
int, The gbifid used by Plantnet and in the camalien database
int, The ID used by Plantnet (hence pnid) and in the camalien database
chr, The GBIF key for the taxon name
chr, The taxon rank, either species or genus. Derived from GBIF rankMarker
Modified graphics::legend function to draw small boxes with ID information on top of images
id_box( x, y = NULL, legend, col = par("col"), border = "black", angle = 45, bty = "o", bg = "white", box.lwd = par("lwd"), box.lty = par("lty"), box.col = par("fg"), cex = 1, xjust = 0, yjust = 1, adj = c(0.25, 0), text.width = NULL, text.col = par("col"), text.font = NULL, ncol = 1, horiz = FALSE, inset = 0, xpd, seg.len = 1 )id_box( x, y = NULL, legend, col = par("col"), border = "black", angle = 45, bty = "o", bg = "white", box.lwd = par("lwd"), box.lty = par("lty"), box.col = par("fg"), cex = 1, xjust = 0, yjust = 1, adj = c(0.25, 0), text.width = NULL, text.col = par("col"), text.font = NULL, ncol = 1, horiz = FALSE, inset = 0, xpd, seg.len = 1 )
x, y
|
the x and y co-ordinates to be used to position the legend.
They can be specified by keyword or in any way which is accepted by
|
legend |
a character or expression vector
of length |
col |
the color of points or lines appearing in the legend. |
border |
the border color for the boxes (used only if
|
angle |
angle of shading lines. |
bty |
the type of box to be drawn around the legend. The allowed
values are |
bg |
the background color for the legend box. (Note that this is
only used if |
box.lty, box.lwd, box.col
|
the line type, width and color for
the legend box (if |
cex |
character expansion factor relative to current
|
xjust |
how the legend is to be justified relative to the legend x location. A value of 0 means left justified, 0.5 means centered and 1 means right justified. |
yjust |
the same as |
adj |
numeric of length 1 or 2; the string adjustment for legend
text. Useful for y-adjustment when |
text.width |
the width of the legend text in x ( |
text.col |
the color used for the legend text. |
text.font |
the font used for the legend text, see |
ncol |
the number of columns in which to set the legend items (default is 1, a vertical legend). |
horiz |
logical; if |
inset |
inset distance(s) from the margins as a fraction of the plot region when legend is placed by keyword. |
xpd |
if supplied, a value of the graphical parameter |
seg.len |
the length of lines drawn to illustrate |
Small example dataset with scores, boxes and urls.
imagesimages
Data.frame with the following columns:
chr, ID of the Plantnet call
float, The model confidence score from Plantnet
int, Size of the polygon where the detection was made
int, The center x coordinate of the polygon
int, The center y coordinate of the polygon
int, The plantnet species ID
int, The image ID
int, The public URL to the image file
List of partners and their acronyms
partnerspartners
Data.frame with partner and partner_acronym
chr, Name of the partner
chr, The acronym used in the Biodiversa+ project