The basic anatomy of an R-based GP script tool is like so:
tool_exec <- function(in_params, out_params) { # <1>
# ... do things here..
out_params #<2>
}
- Two arguments capture input and output parameters
- 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
:
tool_exec <- function(in_params, out_params) {
# fetch the date parameter
date_str <- in_params[["date"]]
# parse it using {anytime}
clean_date <- anytime::anytime(date_str)
# ... 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.
See Using R script tools with arcpy
.
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["...."]" |
Data type mapping {.striped tbl-colwidths=“[25,75]”}
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()
.
tool_exec <- function(in_params, out_params) {
fclass <- arcgisbinding::arc.open(in_params[["fc_path"]])
fclass_selected <- arcgisbinding::arc.select(
fclass,
# fields = c("optional", "fields", "to", "read"),
# where_clause = "optional sql where clause to filter"
)
fclass_sf <- arcgisbinding::arc.data2sf(fclass_selected)
}
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.
tool_exec <- function(in_params, out_params) {
# extract the path to write to
out_fp <- out_params[["output_fclass"]]
# write the `sf_object` to a geodatabase
arcgisbinding::arc.write(out_fp, sf_object)
}
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:
install_if_not <- function(pkg) {
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.
tool_exec <- function(in_params, out_params) {
# 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)
tool_exec <- function(in_params, out_params) {
# read feature class
arc.progress_label("Reading Feature Class")
fclass <- arc.open(in_params[["input_fclass"]])
# convert to sf
arc.progress_label("Converting Feature Class to sf")
sf_obj <- arc.data2sf(arc.select(fclass))
# do other things
arc.progress_label("Doing other computations")
return(out_params)
}