Making Geoprocessing Tools
The basic anatomy of an R-based GP script tool is like so:
my-geoprocessing-tool.R
- 1
- Two arguments capture input and output parameters
- 2
- Output parameters are returned to be captured by ArcGIS Pro
R-based GP script tools are defined in a standalone R script. The GP tool is defined by a function called tool_exec()
. tool_exec()
takes exactly two arguments capturing input and output parameters. tool_exec()
should always return the output parameter argument.
Input and Output Parameters
There must be two arguments that correspond to input parameters and output parameters. The conventional names of these arguments are in_params
and out_params
. The first argument will always refer to the input parameters and the second to the outputs.
in_params
and out_params
are named lists. The elements of these lists are determined by the direction of a parameter.
If the direction is Input
, it will be contained in in_params
. Likewise, if the direction is Output
, it will be contained in out_params
.
Using parameters
Values can be extracted from the in_params
and out_params
lists by the name or position of the parameter. It is strongly recommended to use name-based indexing rather than position-based indexing for clarity.
The name of the parameter must match the value in the Name (not Label) column in the Parameters
tab of the Tool Properties.
This is an example of a function to parse a date
parameter with the name date
:
<- function(in_params, out_params) {
tool_exec # fetch the date parameter
<- in_params[["date"]]
date_str
# parse it using {anytime}
<- anytime::anytime(date_str)
clean_date
# ... do additional things
# return values to ArcGIS Pro
out_params }
Returning values to ArcGIS Pro
At the end of the tool_exec()
function above, the out_params
object is returned. Returning the output parameters using this syntax allows ArcGIS Pro to capture and use the outputs of the script tool.
Notably, the output parameters are useful in linking one tool to another, for example via use in ModelBuilder or in an arcpy
script.
Parameter types
There are number of different parameter types that can be provided to a geoprocessing (GP) tool. The type of parameter that is chosen determines how that parameter will appear in the Geoprocessing pane. Each ArcGIS Pro parameter type can be represented by a basic scalar R type: integer
, double
, character
, logical
, or NULL
.
A scalar value is a vector with only a single element.
It is incumbent upon the developer to take these parameter inputs and use them appropriately in R. Not every type of parameter can be processed correctly by arcgisbinding
. Below are examples of common parameter types and how they are handled by arcgisbinding
:
ArcGIS Pro Parameter Type | R Data Type |
---|---|
String | character |
Boolean | logical |
Double | numeric |
Date | character in the format of your system e.g. "11/17/2023 4:35:57 PM" |
Field | character the field name of a feature class |
Folder | character absolute path e.g. "C:\\Users\username\Documents" |
Feature Class | character absolute path e.g. "C:\\Users\username\mydatabase.gdb\\feature_class |
Spatial Reference | character a string representation of the spatial reference e.g. "PROJCS["...."]" |
For a complete list of parameter data types, see Geoprocessing data types.
Multiple Values
When selecting the Multiple values
check box in the parameter data type dialog box, users can then provide multiple inputs of that type.
When the Multiple values
option is enabled, the parameter returns a list containing each of the input values.
Note that when multiple values are provided, they will be captured in R as a list of scalars. Take the below input, for example:
In R, this parameter value would be list("string 1", "string 2")
and not c("string 1", "string 2")
.
To turn a list of scalars of the same type—e.g. double, integer, logical, or character—into a vector, use unlist()
. For example unlist(list("string 1", "string 2"))
returns c("string 1", "string 2")
.
Common Patterns
Reading a Feature Class
Reading a feature class using arcgisbinding
and bringing the results into R as an sf object is a common pattern. To do this, use the functions arc.open()
, arc.select()
, and arc.data2sf()
.
<- function(in_params, out_params) {
tool_exec
<- arcgisbinding::arc.open(in_params[["fc_path"]])
fclass
<- arcgisbinding::arc.select(
fclass_selected
fclass,# fields = c("optional", "fields", "to", "read"),
# where_clause = "optional sql where clause to filter"
)
<- arcgisbinding::arc.data2sf(fclass_selected)
fclass_sf }
To filter or select columns from a dataset, consider using the fields
and where_clause
arguments of arc.select()
to reduce the amount of data read into memory.
arc.select()
returns a data.frame
with fields and a special geometry column which is incompatible with sf. Use arc.data2sf()
to convert it to an sf object.
Writing a Feature Class
It is quite common to write the results of an analysis to a file geodatabase. This can be done with arc.write()
. A Feature Class type parameter can be used in the out_params
list object to capture a user-defined output path.
arc.write()
requires two arguments. The first is the output path to write to and the second is the object to write. The accepted types of objects are data.frame
, sf
, RasterLayer
or RasterBrick
.
Support for {terra}
is planned to accompany the ArcGIS Pro 3.3 release.
<- function(in_params, out_params) {
tool_exec
# extract the path to write to
<- out_params[["output_fclass"]]
out_fp
# write the `sf_object` to a geodatabase
::arc.write(out_fp, sf_object)
arcgisbinding
}
Installing Required Packages
When sharing R-based GP tools with other users, they may not have the packages that the script tool needs to execute code. In this case, required packages can be automatically installed the first time the script tool is executed.
The script tool can check to see if the required package is installed and, if not, install it. Below is a helper function to include at the top of the script if there are multiple packages to check:
<- function(pkg) {
install_if_not if (!requireNamespace(pkg)) {
message("Installing required package `{", pkg, "}`")
install.packages(pkg)
} }
This function uses requireNamespace()
which attempts to load the provided package. If it succeeds, it returns TRUE
, and if not it returns FALSE
. The function checks to see if FALSE
is returned and, if so, installs the package and prints an informative message.
For example, if the script requires the package {spdep}
and it is not installed, the function will print the message and install the package.
<- function(in_params, out_params) {
tool_exec # check for required packages
install_if_not("spdep")
# do other things with spdep
# ...
}
Using Progressors
Geoprocessing tools have a progressor, which includes both a progress label and a progress bar. The default progressor continuously moves back and forth to indicate the script is running. Using arc.progress_label()
and arc.progress_pos()
allows fine control over the script progress. Updating the progressor isn’t necessary, but is useful in situations where solely outputting messages to the dialog is insufficient to communicate script progress.
Read more in the Understanding the progressor in script tools article.
Using arc.progress_label()
allows control over the label that is displayed at the top of the running script. For example, it might be used to display the current step of the analysis taking place. Using arc.progress_pos()
allows control over the progressor position displayed at the top of the running script. The position is an integer percentage, 0 to 100, that the progress bar should be set to, with 100 indicating the script has completed (100%).
library(arcgisbinding)
<- function(in_params, out_params) {
tool_exec
# read feature class
arc.progress_label("Reading Feature Class")
<- arc.open(in_params[["input_fclass"]])
fclass
# convert to sf
arc.progress_label("Converting Feature Class to sf")
<- arc.data2sf(arc.select(fclass))
sf_obj
# do other things
arc.progress_label("Doing other computations")
return(out_params)
}