ArcGIS Field Maps

Common calculated expressions for ArcGIS Field Maps

Calculated expressions in ArcGIS Field Maps streamline all kinds of data collection workflows from storing location as an attribute, to pulling attributes from related records or other layers in the map. In this blog post, we’ll walk through some of the most common use cases and provide sample code to get you up and running with calculated expressions in your own forms.

If you’re not familiar with Arcade, you can read the documentation or try using it in the playground. For step-by-step instructions on how to add expressions to the form in Field Maps, see Add calculated expressions. Let’s jump right in and see what’s possible!

 

1. Fetch an attribute from an underlying polygon

Sometimes, it can be valuable to store the geographic area a feature was collected in. In the past, this could be done manually by selecting the region from a list of values or by post processing the data. Now, this can be streamlined and automatically captured in the field by using a form calculation that performs a spatial intersection of the current location and a layer of polygons representing the geographic areas.

Example: I am recording bird sightings and want to automatically store the region I’m in.



// Create a feature set using the 'Regions' layer in the map
var regions = FeatureSetByName($map, 'Regions', ['name'])

// Intersect the current location with the regions and 
// get the first region
var region = First(Intersects($feature, regions))

// If the current location does intersect a feature, 
// return the name of the region. Otherwise, return null
if (!IsEmpty(region)) {
    return region['name']
} else {
    return null
}

 

Bird Sightings Example

2. Fetch an attribute from a related record

When performing inspections, it’s often necessary to store information about the parent feature such as the address, or type of asset. These attributes can be pulled from the parent layer by querying the related records and accessing the necessary attributes.

Example: I’m inspecting hydrants and need to record the Facility ID with each inspection.


// Get the feature set for the hydrants
var hydrants = FeatureSetByRelationshipName($feature, 'wHydrant', ['facilityid'], true)

// Get the first hydrant (should only be one)
var hydrant = First(hydrants)

// If there was a hydrant, return the facilityid of it,
// Otherwise, return null
if (!IsEmpty(hydrant)) {
    return hydrant['facilityid']
} else {
    return null
}

 

Hydrant Inspections ID

3. Store a user’s name, email address, or username

When performing inspections or collecting new data, editor tracking works great for storing the username of the person who created or edited the feature, but it doesn’t store the user’s full name or email address. Having these extra attributes can make it much easier to understand the data when displayed in reports, maps, and dashboards. This can be accomplished by getting the signed in user’s info via Arcade.

Example: I’m filling out a damage inspection report and need to provide my name.


GetUser($layer).fullName

Note: At version 22.3 of Field Maps, this does not work if the device is offline.

 

Inspectors Name

4. Calculate the current date and time

When performing inspections, it’s often useful to set the inspection date to the current date and time. While the mobile worker can do this in the mobile app with a few taps, it can be more efficient to auto-populate this information using an Arcade expression.

Example: I’m filling out a damage inspection report and need to set the inspection date.


Now()

 

Damage Assessment

5. Store the geometry as an attribute

When integrating with other systems, it can be useful to store the x, y, z, or m values as separate attributes. This can be done by accessing the feature’s geometry via Arcade.

Example: I need to store the x and y locations as separate attributes so I can import it into some other system without out post-processing.


// Get the X value
var geom = Geometry($feature)
if (IsEmpty(geom)) {
    return null
} else {
    return geom.X
}

Sometimes, the raw x and y location are not what you need. You might need the latitude and longitude. If your map and data are using Web Mercator Projection you can write code to calculate the latitude and longitude from the x, y meter values.

Example: I need to store the latitude and longitude values to conform to some standard data collection specification.


// Create a function to convert meters to lat, long
// Source: http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
function MetersToLatLon(geometry) {
    if (IsEmpty(geometry)) {
        return [null, null]
    }
    var originShift = 2.0 * PI * 6378137.0 / 2.0    
    var lon = (geometry.x / originShift) * 180.0
    var lat = (geometry.y / originShift) * 180.0 
    lat = 180.0 / PI * (2.0 * Atan( Exp( lat * PI / 180.0)) - PI / 2.0)    
    return [Round(lat, 6), Round(lon, 6)]
}

// Call the function and return the latitude or longitude value
MetersToLatLon(Geometry($feature))[0]

 

Store Geometry Attributes

6. Calculate a value from other fields

Often, it can be useful to calculate a value based on one or more fields that the mobile user fills out.

Example: I need to calculate the score when doing a damage assessment report. Certain things (e.g., the roof, foundation, habitability.) are scored based on their damage level. I need to sum all these independent scores into a single value to use for filtering and visualization.


$feature["foundation_condition"] + $feature["roof_condition"] + $feature["habitability"]

 

Damage Assessment Score

7. Store info about a nearby feature

When installing new assets or planting trees, it’s often useful to store the nearest address.

Example: I’m planting new trees in a neighborhood and want to store the nearest address using existing parcel data.


// If feature doesn't have geometry return null
if (IsEmpty(Geometry($feature))) { return null }

// Get the parcels layer
var parcels = FeatureSetByName($map, 'Parcels')

// Buffer the current location and intersect with parcels
var bufferedLocation = Buffer($feature, 100, 'feet')
var candidateParcels = Intersects(parcels, bufferedLocation)

// Calculate the distance between the parcel and the current location
// Store the feature and distance as a dictionary and push it into an array
var featuresWithDistances = []
for (var f in candidateParcels) {
    Push(featuresWithDistances, 
        {
            'distance': Distance($feature, f, 'feet'),
            'feature': f
        }
    )
}

// Sort the candidate parcels by distance using a custom function
function sortByDistance(a, b) {
    return a['distance'] - b['distance']
}
var sorted = Sort(featuresWithDistances, sortByDistance)

// Get the closest feature
var closestFeatureWithDistance = First(sorted)

// If there was no feature, return null
if (IsEmpty(closestFeatureWithDistance)) { return null }

// Return the address
return `${closestFeatureWithDistance['feature']['ADDNUM']} ${closestFeatureWithDistance['feature']['ADDRESSNAM']}`
Nearest address

Summary

We’ve shown quite a few different examples here, there’s so much more that you can do with Arcade and form calculations though! If you have any questions or would like to share how you use form calculations please post in the ArcGIS Field Maps Community forum or email us at arcgisfieldmaps@esri.com.

About the authors

Aaron is a lead Product Engineer on the Field Apps team primarily focused on location sharing, smart forms, and automation. In his free time, you can often find him hiking, camping, or kayaking throughout Central New York.

Connect:

Josh is a Product Writer with a background in geography and comparative literature. When he isn't writing for the field apps team, he enjoys reading short stories and playing his bass clarinet.

Connect:
8 Comments
Oldest
Newest
Inline Feedbacks
View all comments

Next Article

FCC Form 477 Broadband Layer Updated to June 2021

Read this article