ArcGIS in R

ArcGIS is a set of powerful propriety geospatial tools developed by ESRI. It is widely used in the industry and academia. In this blog, I will explore the arcgis R package by getting data from the Australian tree crop map database, hosted on ArcGIS.


Australian tree crop map

The Australian tree crop map is a database of tree crops in Australia. The map is the work of the Applied Agricultural Remote Sensing Centre at the University of New England.

The dashboard is hosted online at the following link: https://experience.arcgis.com/experience/6cde8c0467e542398fb0afd1dde48a73/

The data informing the dashboard is hosted on ArcGIS and can be accessed at the following link: https://www.arcgis.com/home/item.html?id=12bdb57eec7548dd90409603645cfd5e




Installation

Full documentation can be found at the following link on installation and setup. This is hosted on R-universe.

arcgis is a meta-package for arcgisutils, arcgislayers, arcgisgeocode and arcgisplaces. For me successful installation required the indication of the location on the r-universe repository.

install.packages("arcgis", repos = c("https://r-arcgis.r-universe.dev", "https://cloud.r-project.org"))

Next lets load the library into the R environment, and the simple features (sf) library.

library(arcgis)
## Attaching core arcgis packages:
## → arcgisutils v0.3.1.9000
## → arcgislayers v0.3.1.9000
## → arcgisgeocode v0.2.2
## → arcgisplaces v0.1.1
library(sf) # also needed for working with spatial data
## Linking to GEOS 3.12.2, GDAL 3.9.3, PROJ 9.4.1; sf_use_s2() is TRUE
library(leaflet) # for plotting onto interactive maps




Points feature layer

There are two feature layers as part of the Australian tree crop map database. A Points database and a polygon database, we will try querying each of these for the northern rivers area of New South Wales, Australia.

We set the point URL using the arc_open function, which stores the database location and some metadata about the feature layer.

atcm_pts <- arc_open("https://services5.arcgis.com/3foZbDxfCo9kcPwP/ArcGIS/rest/services/AARSC_treecrop_point/FeatureServer/0")
atcm_pts
## <FeatureLayer>
## Name: atcm_20241024_points
## Geometry Type: esriGeometryPoint
## CRS: 7844
## Capabilities: Query

This feature server contains point geometry, a coordinate reference system (CRS) 7844 and is capable of being queried.


Query features

We can obtain more metadata information from the feature server using the list_fields() function.

list_fields(atcm_pts)
##        name                type     alias      sqlType nullable editable domain
## 1  OBJECTID    esriFieldTypeOID  OBJECTID sqlTypeOther    FALSE    FALSE     NA
## 2 commodity esriFieldTypeString commodity sqlTypeOther     TRUE     TRUE     NA
## 3    source esriFieldTypeString    source sqlTypeOther     TRUE     TRUE     NA
## 4      year esriFieldTypeString      year sqlTypeOther     TRUE     TRUE     NA
## 5  hectares esriFieldTypeDouble  hectares sqlTypeOther     TRUE     TRUE     NA
##   defaultValue length
## 1           NA     NA
## 2           NA    255
## 3           NA    255
## 4           NA    255
## 5           NA     NA


Selecting data

The data can be queried with the arc_select function, which is effectively a wrapper for the api and uses syntax similar to querying a SQL database.

arc_select(atcm_pts, where = c("commodity = 'avocado'"))
## Registered S3 method overwritten by 'jsonify':
##   method     from    
##   print.json jsonlite
## Simple feature collection with 2166 features and 5 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: 113.6694 ymin: -41.18715 xmax: 153.5533 ymax: -15.7996
## Geodetic CRS:  GDA2020
## First 10 features:
##    OBJECTID commodity  source year  hectares                   geometry
## 1         1   avocado Imagery 2021 22.962312 POINT (145.1045 -17.16699)
## 2         2   avocado Imagery 2021  1.241645 POINT (145.3262 -16.24474)
## 3         3   avocado Imagery 2021  0.495399  POINT (145.964 -17.60302)
## 4         4   avocado Imagery 2021  1.546013 POINT (145.3421 -17.02106)
## 5         5   avocado Imagery 2021  0.739951  POINT (145.342 -17.01513)
## 6         6   avocado Imagery 2021  4.507486 POINT (145.3132 -17.16463)
## 7         7   avocado Imagery 2021  0.962824 POINT (145.3401 -17.02179)
## 8         8   avocado Imagery 2021 10.928766 POINT (145.2054 -17.19938)
## 9         9   avocado Imagery 2021  3.613079 POINT (145.3156 -17.16684)
## 10       10   avocado   Field 2022  9.129086 POINT (152.1197 -24.99829)

The package functions returnsf simple features objects.


Query data by spatial reference

From a 10km radius around a point. I will choose the centre of Alstonville in Northern New South Wales. This area is known to contain lots of Avocado and Macadamia farms.

# Define a point (e.g., coordinates for a location)
point_coords <- c(153.4404,-28.8421)  # Example coordinates (longitude,latitude)

# Create a sf spatial point feature
# We will use the crs 7844 specified in the ATCM metadata
alston <- st_sfc(st_point(point_coords), crs = 7844)

# Buffer the point to create a polygon (e.g., 10 kilometres)
buffer_alston <- st_buffer(alston, 10000)

# transform the data to WGS84 so we can plot it on a leaflet map
buffer_alston <- st_transform(buffer_alston, 4326)

# plot onto a interactive leaflet map
leaflet(buffer_alston) |>
  addProviderTiles(provider = "Esri.WorldImagery")|>
  addMarkers(lng = point_coords[1], lat = point_coords[2], 
             popup = "Alstonville")|> # add the centre point as a marker
  addPolygons(color = "green", fillOpacity = 0.2) # add the polygon buffer layer

Now lets query and download only the data from inside the buffer polygon. This is done as before with the arc_select function. The filter_geom argument is used to specify sf class objects such as bbox, sfc or sfg to filter the database on the arcgis server side. This limits the data download to only what is required by the user. We also need to specify how this layer should be queried with the predicate argument. We will specify intersects as the predicate.

alston_farms <- 
  arc_select(atcm_pts, 
             filter_geom = buffer_alston,
             predicate = "intersects")

head(alston_farms)
## Simple feature collection with 6 features and 5 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: 153.4086 ymin: -28.8758 xmax: 153.4478 ymax: -28.83944
## Geodetic CRS:  GDA2020
##   OBJECTID commodity  source year  hectares                   geometry
## 1       75   avocado   Field 2022  1.712882  POINT (153.4445 -28.8758)
## 2       76   avocado   Field 2022 17.237826   POINT (153.44 -28.85337)
## 3       80   avocado   Field 2022  2.003204  POINT (153.4476 -28.8748)
## 4      278   avocado Imagery 2022  0.796033 POINT (153.4478 -28.87576)
## 5      279   avocado Imagery 2022  0.551528 POINT (153.4312 -28.86598)
## 6      280   avocado Imagery 2022  0.412121 POINT (153.4086 -28.83944)

Next we can plot this on an interactive leaflet map with the WGS84 coordinate reference system.

# transform the data to WGS84 so we can plot it on a leaflet map
alston_farms <- st_transform(alston_farms, 4326)

leaflet(alston_farms) |>
  addProviderTiles(provider = "Esri.WorldImagery")|>
  addCircleMarkers(color = "orange", 
                   weight = 1, # circle marker edge width
                   fillOpacity = 0.8,
                   radius = 4,
                   popup = alston_farms$commodity)|>
  addMarkers(lng = point_coords[1], lat = point_coords[2], 
             popup = "Alstonville")




Polygon feature layer

Lets do this again for the polygon feature layer.

atcm_poly <- arc_open("https://services5.arcgis.com/3foZbDxfCo9kcPwP/ArcGIS/rest/services/AARSC_treecrop_polygon/FeatureServer/0")
list_fields(atcm_poly)
##            name                type         alias       sqlType nullable
## 1      OBJECTID    esriFieldTypeOID      OBJECTID  sqlTypeOther    FALSE
## 2     commodity esriFieldTypeString     commodity  sqlTypeOther     TRUE
## 3        source esriFieldTypeString        source  sqlTypeOther     TRUE
## 4          year esriFieldTypeString          year  sqlTypeOther     TRUE
## 5      hectares esriFieldTypeDouble      hectares  sqlTypeOther     TRUE
## 6   Shape__Area esriFieldTypeDouble   Shape__Area sqlTypeDouble     TRUE
## 7 Shape__Length esriFieldTypeDouble Shape__Length sqlTypeDouble     TRUE
##   editable domain defaultValue length
## 1    FALSE     NA           NA     NA
## 2     TRUE     NA           NA    255
## 3     TRUE     NA           NA    255
## 4     TRUE     NA           NA    255
## 5     TRUE     NA           NA     NA
## 6    FALSE     NA           NA     NA
## 7    FALSE     NA           NA     NA

For a different method we will use a bounding box to query and the polygon layer.

# lets get the data from inside a bounding box of the buffer polygon
buffer_box <- 
  st_as_sfc(st_bbox(buffer_alston))

# request only the data in the box
alston_farms <- 
  arc_select(atcm_poly, 
             filter_geom = buffer_box,
             predicate = "intersects")

# transform the data to WGS84 so we can plot it on a leaflet map
alston_farms <- st_transform(alston_farms, 4326)

leaflet(alston_farms) |>
  addProviderTiles(provider = "Esri.WorldImagery")|>
  addPolygons(color = "orange", 
                   weight = 1, 
                   fillOpacity = 0.8,
                   popup = alston_farms$commodity)|>
  addPolygons(data = buffer_box, color = "green", weight = 2, fillOpacity = 0.2)

Conclusion

I hope this helps your spatial data analysis in R. I know I will find this a useful reference for my work into the future. Feel free to reach out and let me know how you are using this package in different interesting ways.