Note: Support for 3D on mobile devices may vary, view the system requirements for more information.
This sample demonstrates how use an Arcade expression in a PopupTemplate to summarize points from one layer that intersect a polygon in a different layer.
The map in this sample contains two layers: a polygon layer representing block groups in San Diego and a point layer representing the locations of crimes. Each crime has a desc_ field describing the type of crime committed. It also has a is_night field containing either a 1 (crime committed at night) or a 0 (crime committed during the day). This app uses a single Arcade expression to do the following each time the user clicks a feature and opens the popup:
- Query the of crimes that intersect a selected polygon.
- Group those intersecting points by crime type and return the total count and average is_nightvalue within each category.
- Sort the groups in descending order by count.
These three steps are reflected in the expression below.
<script type="text/arcgis-arcade" id="crimes-arcade">
  // 1. Query the number of crimes that intersect a selected polygon
  var crimes = Intersects(
    $feature,
    FeatureSetByName($map,"San Diego crimes", ["desc_", "is_night"])
  );
  // 2. Group the intersecting points by crime type and return the total count
  // and average `is_night` value within each category of crimes
  var stats = GroupBy(crimes, ["desc_"],
    [ { name: "total", expression: "1", statistic: "count" },
      { name: "night_avg", expression: "is_night", statistic: "avg" }
    ]
  );
  // 3. Sort the crime types in descending order by count.
  var topCrimes = Top(OrderBy(Filter(stats, "desc_ <> ''"), "total desc"), 3);
  var output = "";
  if(Count(topCrimes) == 0){
    return "No crimes committed in this area";
  }
  var num = 0;
  // Format the results for display
  for(var item in topCrimes){
    num++;
    var num_crimes = item.total;
    var crimeType = item["desc_"];
    // The isNight field has values of either 1 or 0.
    // If the average value (night_avg) is high, then most crimes
    // occurred at night. If the average is low, then
    // the crimes typically occurred during daytime hours.
    var timeOfDay = When(
      item.night_avg >= 0.6, "at night",
      item.night_avg <= 0.4, " during the daytime hours",
    " at both night and day");
    // Display crime type with count and whether the
    // incident occurred during the day or nighttime hours
    output += num + ". " + crimeType + "\n" +
      "-- Total offenses: " + Text(num_crimes, "#,###") + "\n" +
      "-- Most crimes were reported " + timeOfDay + "\n\n";
  }
  return output;
</script>
The Arcade documentation for GroupBy() contains additional information for how to query multiple statistics (e.g. sum, min, max, average, standard deviation, variance) in Arcade with a single function call.
After authoring the Arcade expression, you can reference it in JavaScript as a string value and set it to the expression property of the expressionInfos in the layer's popupTemplate.
const arcadeScript = document.getElementById("crimes-arcade").text;
const blockGroups = new FeatureLayer({
        title: "U.S. Census Block Groups",
        portalItem: {
          id: "181b322639d44fcba6e37d8b82910daf"
        },
        popupTemplate: {
          title: "Tract: {Tract}, Block Group: {BLKGRP}",
          content: "Top 3 crimes: <br\><br\>" +
            "{expression/top-crimes}",
          expressionInfos: [{
            // the name is used to reference the expression value in the template
            name: "top-crimes",
            title: "Top crimes",
            // the Arcade expression stored as text
            expression: arcadeScript
          }]
        }
      });
See the Popup profile of the Arcade expressions guide and the Reference Arcade expressions in PopupTemplate sample for more information about writing Arcade expressions for popups.