Making Geoprocessing Tools

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>
}
  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.

gp tool properties

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 characterabsolute 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.

gp parameter 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:

gp multiple strings

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.

Default Progressor
Step Progressor

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)
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.