Today a great blog was posted by Paul Barker on the new FeatureSet functions: What’s new with Arcade: Taking a stroll through FeatureSets (Part 1) and also Kelly Gerrow shared a great document on this topic: https://community.esri.com/community/gis/web-gis/arcgisonline/blog/2018/12/10/overlapping-features-i... .
I didn't wanted to be left behind, so I thought I would share some examples using hydrants, the maintenance history and sub sectors and hydraulic sectors to show what you can achieve with the new Arcade functions released in ArcGIS Online on December 5th
Consider we have a web map with several layers and a table:
- Hidrantes is a point layer with hydrants
- Sub Sector is a polygon layer with a sub division of the area of interest
- Sector Hidraulico is a polygon layer merging sub sectors into hydraulic sectors
- Hist Mantenimiento is a table with the historic maintenance records for each hydrant
First of all, let’s apply some Arcade to visualize the hydrants based on their age. This was already possible in the previous release, so no new things here yet. We have the installation date stored in the field FECHAINSTALACION and we can use the DateDiff and Now functions to determine the age in years, which happens on the first two lines. After this we classify the value into significant ranges:
var fecha_inst = $feature.FECHAINSTALACION;
var edad = DateDiff(Now(), fecha_inst, "years");
var clase_edad = "";
if (edad > 50) {
clase_edad = "Mayor a 50 años";
} else if (edad > 40) {
clase_edad = "Entre 40 y 50 años";
} else if (edad > 30) {
clase_edad = "Entre 30 y 40 años";
} else if (edad > 20) {
clase_edad = "Entre 20 y 30 años";
} else if (edad > 10) {
clase_edad = "Entre 10 y 20 años";
} else if (edad > 5) {
clase_edad = "Entre 5 y 10 años";
} else {
clase_edad = "Menor a 5 años";
}
return clase_edad;
The result is a text describing the age, for which we can define representative symbols (here using the Firefly symbols):
No fancy symbols for the other two polygon layers to avoid distracting the attention from the hydrants.
We would like to show in the pop-up window of each hydrant the list of all maintenance carried out on the hydrant. Both the maintenance history table and the hydrant layer contain the ID of the hydrant. The table also contains the dates and type of maintenance.
In the configuration of the pop-up of the hydrants we can add an Arcade expression like this one:
var tbl = FeatureSetByName($datastore,"Hist_Mantenimiento");
var codigo = $feature["COD_HIDRANTE"];
var sql = "COD_HIDRANTE = '" + codigo + "'";
Console(sql);
var mantenimientos = Filter(tbl, sql);
var cnt = Count(mantenimientos);
var historia = "";
if (cnt > 0) {
historia = cnt + " Mantenimiento(s):";
for (var mantenimiento in mantenimientos) {
var txt_fecha = Text(mantenimiento.Fecha_Mantenimiento, ' - (Y/MM/DD) ');
var txt_man = txt_fecha + mantenimiento.Mantenimiento;
historia += TextFormatting.NewLine + txt_man;
}
} else {
historia = "No hay mantenimientos";
}
return historia;
First of all, we access the table with the maintenance history and assign it to a variable tbl. Then we read the id of the current hydrant for which we want to create the pop-up. We define a SQL expression using the hydrant ID which is then used to filter the history table. The result is stored in a variable called mantenimientos. We can do a Count to obtain the number of maintenance carried out on the hydrant. If the count (cnt) is larger than 0, we start reading out the details and construct a list of maintenance including the date and type of maintenance.
The result will appear like this after we configure a simple custom html to show the attributes and result of the Arcade expression in the pop-up:
Now let’s continue with doing something with these new Arcade functions to get some data hydrants at the sub sector level. Since the number of maintenance obviously depend on the age of the hydrant, it would be nice to get some details on this at the sub sector level.
In the pop-up configuration of the sub sectors we can add the following Arcade expression:
var fs = FeatureSetByName($datastore,"Hidrantes");
var hidrantes = Intersects(fs, $feature);
var cnt = Count(hidrantes);
var edad_tot = 0;
for (var hidrante in hidrantes) {
var edad = DateDiff(Now(), hidrante.FECHAINSTALACION, "years");
edad_tot += edad;
}
var resultado = "";
if (cnt > 0) {
var edad_media = edad_tot / cnt;
resultado = "Hay " + cnt + " hidrantes en el sub sector";
resultado += TextFormatting.NewLine + "La edad media de los hidrantes es de " + Round(edad_media, 2) + " años";
} else {
resultado = "No hay hidrantes en el sub sector";
}
return resultado;
This expression will:
- Access the Hydrants layer
- Do an intersect with the current sub sector feature
- Count the number of hydrants in the sub sector
- Calculate the age for each hydrant and some all ages
- Calculate the mean age of the hydrants and format the text with this information
The result will appear like this:
In this case there are 93 hydrants in the sub sector and the mean age is 20.64 years.
This is fun, but can we also show the names of the sub sectors that are contained by a hydraulic sector using these new Arcade functions? The answer is yes. Let’s add the following expression to the hydraulic sectors:
var fs = FeatureSetByName($datastore,"Sub Sector");
var subsectores = Intersects(fs, $feature);
var cnt = Count(subsectores);
var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
resultado += TextFormatting.NewLine + subsector.IDSAP;
}
return resultado;
Just access the sub sectors layer and Intersect with the current hydraulic sector and voila…, rights? No, not so right. When you use an Intersect between two polygon layers, it will probably return too many features due to the fact that when two polygons have a matching boundary they will probably be included in the result, leading to more sub sectors than we want.
A way to avoid this is to use a small negative buffer on the hydraulic sector and do the Intersect with that buffered geometry like this:
var fs = FeatureSetByName($datastore,"Sub Sector");
var feature_buf = Buffer($feature, -100, 'meters');
var subsectores = Intersects(fs, feature_buf);
var cnt = Count(subsectores);
var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
resultado += TextFormatting.NewLine + subsector.IDSAP;
}
return resultado;
Notice the Buffer with a negative distance that is created on line 2 and used on line 3 to get the rights polygons.
The resulting pop-up will show like this:
To be honest, I don’t like the unsorted list of sub sectors, so let’s order this list using OrderBy:
var fs = FeatureSetByName($datastore,"Sub Sector");
var feature_buf = Buffer($feature, -100, 'meters');
var subsectores = OrderBy(Intersects(fs, feature_buf), 'IDSAP ASC');
var cnt = Count(subsectores);
var resultado = "Listado de los " + cnt + " Subsectores:";
for (var subsector in subsectores) {
resultado += TextFormatting.NewLine + subsector.IDSAP;
}
return resultado;
Which will result in a sorted list of sub sectors:
I hope that these examples will help you to understand what is possible using Arcade with the latest update in ArcGIS Online, but before you jump in and start creating fabulous Arcade expressions I want to quote Uncle Ben (Spider-Man) for a moment:
With great power comes great responsibility...
As Paul Barker mentions in his blog, be careful and always validate that the performance of your expressions yield in an acceptable response time for your end-user.