Summarize binned data using Arcade

This sample demonstrates how to summarize binned features by category using charts in a popup. The app visualizes crimes in San Diego, California as bins. Each bin's popup displays a pie chart showing the proportion of crimes committed by category or type, a column chart showing the number of crimes committed during each month of the year, and a table describing the percentage of crimes committed at night by category.

The list and charts are created using ExpressionContent popup elements, which can be used to conditionally build rich text, charts, or field lists with Arcade expressions. Expressions that return popup elements must return a dictionary representing the web map specification of the desired content element. The following popup elements are supported: TextContent, FieldsContent, and MediaContent.

Create an HTML list with Arcade

To return HTML from an Arcade expression, the HTML must be returned as a TextContent element. Expressions for building a text content element must return a dictionary matching the following specification:

Use dark colors for code blocksCopy
1
2
3
4
return {
  type: "text",
  text: "<b>The text to display in the popup</b>"
}

Because TextContent can contain rich text, we can dynamically build HTML elements as a text value within an Arcade expression. Note that you cannot return HTML in Arcade in any other case, such as displaying an expression value from the PopupTemplate.expressionInfos property.

The following expression demonstrates how this works. Read the comments for details.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Expects($aggregatedFeatures, "is_night", "type");

var crimes = $aggregatedFeatures;

// Queries the count of crimes grouped by the "type" field
// and returns the percentage that occurred at night
var stats = GroupBy(crimes, ["type"],
  [
    { name: "total", expression: "1", statistic: "count" },
    { name: "nightPercent", expression: "is_night", statistic: "avg" }
  ]
);

// Orders the results in descending order by the total count
var topCrimes = Top(OrderBy(stats, "total desc"), 5);

if(Count(topCrimes) == 0){
  return {
    type: "text",
    text: "No crimes committed in this area"
  };
}

// Build an HTML table to display the summary of
// crimes by count and how many occurred at night
var cssGray = "style='background-color:#323232;'";
var cssRight = "style='text-align: right;'";
var cssCenter = "style='text-align: center;'";

var table = "<table>";
table += `<tr>
  <td ${cssCenter}><b>Category</b></td>
  <td ${cssCenter}><b>Count</b></td>
  <td ${cssCenter}><b>% at night</b></td>
</tr>`;

var i = 0;
for(var item in topCrimes){
  var num_crimes = Text(item.total, "#,###");
  var night_percent = Text(item.nightPercent, "#%");
  var crimeType = item["type"];

  table += `<tr ${IIF( i % 2 != 0, cssGray, null )}>
    <td>${crimeType}</td>
    <td ${cssRight}>${num_crimes}</td>
    <td ${cssRight}>${night_percent}</td>
  </tr>`;
  i++;
}
table += "</table>";

// Return the table as a text element
return {
  type: "text",
  text: table
};

Create popup charts with Arcade

Expressions for charts must return a dictionary matching the web map specification of a MediaContent element:

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
return {
  type: "media",
  attributes: {
    field1: number,
    field2: number
  },
  title: "Media content title",
  mediaInfos: [
    {
      type: "piechart",  // can also be "columnchart", "linechart", "piechart", "image"
      title: "Chart title",
      value: {
        // the list of attribute values to include in the chart
        fields: [ "field1", "field2" ]
      }
    }
  // you can define more charts here
  ]
}

When implemented in JavaScript, the charts can be defined with a list of field names. However, when dynamically creating charts with Arcade, you must create an attributes dictionary that stores key-value pairs containing the data to use in the chart. The keys are the field names to reference in the fields property of the chart value.

The following expression demonstrates how this works by creating a pie chart and a line chart. Read the comments for details.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
Expects($aggregatedFeatures, "type", "month");
var attributes = {};
var pieFieldNames = [];
var monthFieldNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

var crimes = $aggregatedFeatures;

// Queries the count of crimes grouped by the "type" field
var typeStats = GroupBy(crimes, ["type"],
  [{ name: "total", expression: "1", statistic: "count" }]
);
// Orders the results in descending order by the total count
var topCrimes = Top(OrderBy(typeStats, "total desc"), 10);

// Queries the count of crimes grouped by the "month" field
var monthStats = GroupBy(crimes, ["month"],
  [{ name: "total", expression: "1", statistic: "count" }]
);

if(Count(topCrimes) == 0){
  return {
    type: "text",
    text: "No crimes committed in this area"
  };
}

// Create field names for the number of
// crimes by type/category and push
// the data values to the attributes dictionary
for(var item in topCrimes){
  var num_crimes = item.total;
  var crimeType = item["type"];
  attributes[crimeType] = num_crimes;
  Push(pieFieldNames, crimeType);
}

// Push the total number of crimes for each
// month to the attributes dictionary.
// Since the months are categorized as numbers 1-12,
// We can use the Text function to format these as
// long month names to match the field names defined above.
for(var item in monthStats){
  var num_crimes = item.total;
  var crimeMonth = Text(Date(2010,item.month-1,1), "MMMM");
  attributes[crimeMonth] = num_crimes;
}

// Return the charts as media info objects
return {
  type: "media",
  attributes: attributes,
  title: "Crime summary",
  mediaInfos: [{
    type: "piechart",
    title: "Crimes by type",
    value: {
      fields: pieFieldNames
    }
  }, {
    type: "linechart",
    title: "Crimes by month",
    value: {
      fields: monthFieldNames
    }
  }]
};

The expressions are added directly to an ExpressionContent element within the popupTemplate content.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
layer.featureReduction = {
  type: "binning",
  fields: [{
    name: "aggregateCount",
    statisticType: "count"
  }],
  popupTemplate: {
    title: "Crime summary",
    content: [{
      type: "text",
      text: "{aggregateCount} crimes occurred in this area."
    }, {
      type: "expression",
      expressionInfo: {
        expression: `// chart expression here`
      }
    }, {
      type: "expression",
      expressionInfo: {
        expression: `// table expression here`
      }
    }],
    fieldInfos: [{
      fieldName: "aggregateCount",
      format: {
        digitSeparator: true,
        places: 0
      }
    }]
  }
};

Binning

Learn how to aggregate features spatially using bins.

Image preview of related sample Binning with aggregate fields

Binning with aggregate fields

This sample demonstrates how to define aggregate fields that can be used in the popup, labels, and renderer of a binned layer.

Image preview of related sample Binning - Filter by category

Binning - Filter by category

Demonstrates how to filter binned data by category.

Image preview of related sample Summarize binned data using Arcade

Summarize binned data using Arcade

Use Arcade in popups to summarize binned crimes by type

Image preview of related sample Intro to clustering

Intro to clustering

Intro to clustering

FeatureReductionBinning

Read the Core API Reference for more information.

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