Le blog francophone consacré
aux technologies Esri

Utiliser Arcade pour vos expressions dynamiques dans ArcGIS

Arcade est un langage d'expressions pouvant être utilisé sur l'ensemble du système ArcGIS. Basé sur une syntaxe simple (inspirée de Python et de JavaScript), Arcade est supporté dans l'ensemble des applications web, mobiles et bureautiques ArcGIS. Par exemple, une expression définie sur les étiquettes d'une couche dans ArcGIS Pro sera également exécutée une fois les contenus publiés et affichés dans une carte web, et inversement. Arcade peut être utilisé dans différents contextes pour :

  • contrôler le rendu des entités d'une couche,
  • définir le texte de vos étiquettes,
  • personnaliser le contenu des fenêtres contextuelles,
  • calculer les valeurs d'un champ,
  • définir des comportements dans vos formulaires intelligents,
  • personnaliser des sources de données dans vos tableaux de bord,
  • ...


Il devient important aujourd'hui de savoir l'utiliser pour pouvoir tirer profit de tout son potentiel. Dans de nombreux cas, avec de simples expressions vous implémenterez des comportements avancés et vous vous simplifierez grandement la vie. Comme je l'ai fait il y a quelques années avec Python, qui reste toujours un langage incontournable pour l'automatisation des tâches d'administration et d'analyse dans ArcGIS, je vous propose une série d'exemples d'expressions qui, je l'espère, couvriront la majorité de vos besoins :


Quelques éléments de base avant de commencer...

L'objectif du langage d'Arcade est de pouvoir définir une expression plus ou moins évoluée qui au final doit renvoyer une valeur. Pour cela, il dispose d'une librairie de fonctions et de variables prédéfinies simples et performantes pour répondre aux besoins du contexte dans lequel vous exécutez cette expression (calcul de champ, rendu de couche, étiquetage, fenêtre contextuelle, ...).

Lors de la rédaction de votre expression, elle pourra être écrite sur une seule ligne ou sur plusieurs lignes. Par exemple, l'expression ci-dessous calcule le pourcentage d'évolution entre les valeurs du champ POP_2016 et POP_2017.
// Retour implicite
($feature.POP_2017 / $feature.POP_2016) * 100
Dans l'expression ci-dessus, la valeur de l'expression est retournée de manière explicite. L'utilisation explicite de l'instruction "return" permettra de lever toute ambiguïté le cas échéant.
// Retour explicite
return ($feature.POP_2017 / $feature.POP_2016) * 100
Dans le contexte d'une expression plus évoluée, rédigée sur plusieurs lignes, il sera d'autant plus important de définir la valeur à retourner que votre expression contiendra probablement plusieurs variables.

Vous pourrez préciser de manière implicite la variable à retourner en la mentionnant à la fin de votre expression, comme ici avec la variable "somme":
// Retour implicite
var tableau = [10,20,30,40,50,60,70]
var somme = 0;
for(var n in tableau){
	somme += tableau[n];
}
somme;
Cependant, il est préférable de définir la valeur à retourner de manière explicite, notamment pour sa lisibilité, en utilisant l'instruction "return" évoquée précédemment.
// Retour explicite
var tableau = [10,20,30,40,50,60,70]
var somme = 0;
for(var n in tableau){
	somme += tableau[n];
}
return somme;
Un autre point important du langage Arcade concerne les variables globales. Commençant par le caractère "$", elles permettent d'accéder à des objets spécifiques hérités du contexte (profil) dans lequel est exécuté l'expression. Par exemple, la variable "$feature" représente chacune des entités d'une couche lorsque vous calculez un champ ou une expression d'étiquetage. Autre exemple, la variable "$map" représentera la carte courante dans le contexte d'une expression d'étiquetage.

L'expression ci-dessous permet de diviser par 1000 les valeurs du champ contenant le chiffre d'affaires de chacun des magasins de ma table.
$feature.CA2017 / 1000
On notera également qu'à la différence d'autre langages (comme Python par exemple), Arcade ne possède qu'un seul type d'objet numérique : Number.

Enfin, dernier élément important avant de découvrir différents exemples, vous noterez qu'Arcade est un langage qui n'est pas sensible à la casse.


Expressions sur les chaînes de caractères


Concaténer deux champs de type chaîne de caractères:
$feature.MonChamp1 + $feature.MonChamp2
Concaténer deux champs de type chaîne de caractères avec un espace entre les deux chaînes:
$feature.MonChamp1 + ' ' + $feature.MonChamp2
ou
Concatenate([$feature.MonChamp1,$feature.MonChamp2],' ')
Concaténer plusieurs champs dont certains sont de type numérique (ici: le champ Hauteur):
'La hauteur du bâtiment ' + $feature.IdBat + ' est de ' + Text($feature.Hauteur) + ' m.'
Concaténer plusieurs champs de type chaîne de caractères en intégrant un saut de ligne (Attention, pour le moment ce saut de ligne n'est pas reconnu dans le cas d'une expression utilisé pour un étiquetage):
$feature.MonChamp1 + TextFormatting.NewLine + $feature.MonChamp2
Calculer le nombre de caractères d'une chaîne:
Count($feature.MonChamp)
Remplacer un caractère par un autre caractère:
Replace($feature.MonChamp, 'é', 'e')

Remplacer les valeurs nulles du champ par la chaîne "Aucune donnée":
DefaultValue($feature.MonChamp, 'Aucune donnée')
Extraire le premier caractère d'une chaîne:
Left($feature.MonChamp,1)
Extraire le deuxième caractère d'une chaîne:
Mid($feature.MonChamp,1,1)
Extraire le dernier caractère d'une chaîne:
Right($feature.MonChamp,1)
Extraire l'avant-dernier caractère d'une chaîne:
Mid($feature.MonChamp,Count($feature.MonChamp)-2,1)
Extraire les 5 premiers caractères d'une chaîne:
Left($feature.MonChamp,5)
Extraire les 3 derniers caractères d'une chaîne:
Right($feature.MonChamp,3)
Extraire une partie quelconque d'une chaîne (ici: neuvième, dixième et onzième caractère):
Mid($feature.MonChamp,8,3)
Extraire le 4ième mot d'une chaîne (dont les mots sont séparés par un espace):
Split($feature.MonChamp,' ')[3]
Extraire la 5ième mot d'une chaîne dont les mots sont séparés par une virgule:
Split($feature.MonChamp,',')[4]
Retirer les espaces inutiles en fin de chaîne:
var end_spaces = 0
for(var i=Count($feature.MonChamp)-1; i>0; i--) {
  if($feature.MonChamp[i]==' ')
  {
    end_spaces += 1;
  }
  else
  {
    break
  }
}
return Left($feature.MonChamp,Count($feature.MonChamp)-end_spaces);
Retirer les espaces inutiles en début de chaîne:
var end_spaces = 0
for(var i=Count($feature.MonChamp)-1; i>0; i--) {
  if($feature.MonChamp[i]==' ')
  {
    end_spaces += 1;
  }
  else
  {
    break
  }
}
return Left($feature.MonChamp,Count($feature.MonChamp)-end_spaces);
Retirer les espaces inutiles en début et fin de chaîne:
var end_spaces = 0
for(var i=0; i
$feature.MonChamp)); i++) {  if($feature.MonChamp[i]==' ')
  {
    end_spaces += 1;
  }
  else
  {
    break
  }
}
return Right($feature.MonChamp,Count($feature.MonChamp)-end_spaces);
Mettre tous les caractères des valeurs d'un champ en minuscule:
Lower($feature.MonChamp)
Mettre tous les caractères des valeurs d'un champ en majuscule:
Upper($feature.MonChamp)
Mettre le premier caractère en majuscule et le reste en minuscule:
Proper($feature.MonChamp, firstword)
Mettre une majuscule au début de chaque mot:
Proper($feature.MonChamp, everyword)
Insérer une simple-quote dans une chaîne:
'Voici l\'insertion d\'apostrophes'
Insérer une double-quote dans une chaîne:
'Voici \"la citation\"'
Choisir une chaîne de manière aléatoire parmi une liste de chaîne:
var my_list = ['Pomme','Poire','Orange','Kiwi','Fraise']
return my_list[Floor(Random()*Count(my_list))]
Compter le nombre de lettres distinctes dans une chaîne de caractères:
var my_string = $feature.MonChamp;
var my_array = [];
for(var i=0; my_string; i++) {
    my_array[i]= my_string[i]
}
return Count(Distinct(my_array))


Expressions sur les valeurs numériques


Convertir une chaîne en numérique:
Number($feature.MonChamp)
Remplacer les valeurs nulles par la valeur 0:
DefaultValue($feature.MonChamp,0)
Arrondir à l'entier inférieur ou supérieur selon les règles mathématiques classiques:
Round($feature.MonChamp)
Arrondir à l'entier supérieur:
Ceil($feature.MonChamp)
Arrondir à l'entier inférieur:
Floor($feature.MonChamp)
Arrondir à la 3ème décimale:
Round($feature.MonChamp,3)
Générer un nombre entier aléatoire entre 0 et 9:
Round(Random()*9)
Générer un nombre décimal aléatoire entre 0 et 1:
Random()
Générer un nombre décimal aléatoire entre 20 et 80:
20 + (Random()*60)
Calculer la valeur absolue d'un nombre:
Abs($feature.MonChamp)
Calculer l'opposé d'un nombre:
var myNumber = $feature.MonChamp
return -myNumber
Calculer le modulo d'un nombre:
$feature.MonChamp % 360
Calculer le carré d'un nombre:
Pow($feature.MonChamp,2)
Calculer le cube d'un nombre
Pow($feature.MonChamp,3)
Calculer la racine carrée d'un nombre
Sqrt($feature.MonChamp)
Calculer la racine cubique d'un nombre
Pow($feature.MonChamp,1/3)
Calculer le volume d'une sphère à partir du champ contenant le rayon (exemple d'utilisation de la constant Pi):
4 / 3 * PI * Pow($feature.Rayon,3)
Calculer la valeur minimum de plusieurs champs
Min([$feature.Champ1,$feature.Champ2,$feature.Champ3,$feature.Champ4])
Calculer la valeur maximum de plusieurs champs
Max([$feature.Champ1,$feature.Champ2,$feature.Champ3,$feature.Champ4])
Calculer la somme des valeurs de plusieurs champs
Sum([$feature.Champ1,$feature.Champ2,$feature.Champ3,$feature.Champ4])
Calculer la moyenne des valeurs de plusieurs champs
Mean([$feature.Champ1,$feature.Champ2,$feature.Champ3,$feature.Champ4])
Calculer l'écart-type des valeurs de plusieurs champs
Stdev([$feature.Champ1,$feature.Champ2,$feature.Champ3,$feature.Champ4])
Calculer la différence entre la valeur du champ et la valeur minimum de ce champ sur l'ensemble de la table (ou la couche)
$feature.Champ1 - Min($layer,"Champ1")
Calculer la différence entre la valeur du champ et la valeur maximum de ce champ sur l'ensemble de la table (ou la couche)
$feature.Champ1 - Max($layer,"Champ1")
Calculer la différence entre la valeur du champ et la valeur moyenne de ce champ sur l'ensemble de la table (ou la couche)
$feature.Champ1 - Mean($layer,"Champ1")


Expressions sur les dates


Calculer la date courante:
Now()
ou
Date()
Calculer la date courante en tant que chaîne de caractères:
Text(Now(),'DD/MM/Y')
  //Retourne cette chaîne: "26/12/2018"
Créer une date et heure courante:
Text(Now(), 'DD/MM/Y HH:mm:ss')
//Retourne cette chaîne: "26/12/2018 15:46:27"
Créer une date et heure spécifique (standard ISO 8601):
Date('2017-03-19T13:57:45')
//Retourne cette date: 19/03/2017 13:57:45
Créer une date spécifique:
Date('2017-03-19')
Créer une date à partir d'une époque Unix (depuis 01/01/1970 en millisecondes):
Date(1476987783555)
Calculer le nombre de jours compris entre la date actuelle et la date d'un champ:
var startDate = Date()
var endDate = $feature.MonChampDate;
return DateDiff(startDate, endDate, 'days');
Calculer le nombre de secondes compris entre la date actuelle et la date d'un champ:
var startDate = Date()
var endDate = $feature.MonChampDate;
return DateDiff(startDate, endDate, 'seconds');
Calculer une date en ajoutant 3 mois à la date d'un champ:
var myDate = $feature.MonChampDate;
return DateAdd(myDate, 3, 'months');
Calculer une date en ajoutant 10 jours à la date d'un champ:
var myDate = $feature.MonChampDate;
return DateAdd(myDate, 10, 'days');
Calculer une date en ajoutant 12 heures à la date d'un champ:
var myDate = $feature.MonChampDate;
return DateAdd(myDate, 12, 'hours');
Calculer le jour de la semaine (1, 2, 3,...) de la date d'un champ:
Weekday($feature.MonChampDate);
Calculer le jour de la semaine (par exemple: lundi) de la date d'un champ:
var j = Weekday($feature.MonChampDate);
var jour = Decode(j, 
           1, 'Lundi', 
           2, 'Mardi', 
           3, 'Mercredi',
           4, 'Jeudi',
           5, 'Vendredi',
           6, 'Samedi',
           7, 'Dimanche','');
return jour
Calculer une date à partir d'un champ contenant des timestamps:
Date($feature.MonChampTimestamp)
Calculer des timestamps à partir d'un champ contenant des dates:
Number($feature.MonChampDate)
Calculer une date locale à partir d'un champ contenant des dates UTC:
ToLocal($feature.MonChampDate)
Calculer une date UTC à partir d'un champ contenant des dates locales:
ToUTC($feature.MonChampDate)


Expressions sur les géométries


Calculer le X du centroïde des géométries des entités:
Centroid($feature).x
Calculer le Y du centroïde des géométries des entités:
Centroid($feature).y
Calculer le Z du centroïde des géométries des entités:
Centroid($feature).z
Calculer le périmètre des polygones ou la longueur des polylignes dans les unités de la couche:
Length($feature)
Calculer le périmètre géodésique des polygones ou la longueur géodésique des polylignes dans les unités de la couche:
LengthGeodetic($feature)
Calculer le périmètre des polygones ou la longueur des polylignes dans les unités de votre choix (ici en kilomètres):
Length($feature, 'kilometers')
Calculer le périmètre des polygones 3D ou la longueur des polylignes 3D dans les unités de la couche en tenant compte du Z des entités :
Length3D($feature)
Calculer le périmètre des polygones 3D ou la longueur des polylignes 3D dans les unités de votre choix (ici en mètres) en tenant compte du Z des entités :
Length3D($feature, 'meters')
Calculer la superficie des polygones dans les unités de la couche:
Area($feature)
Calculer la superficie géodésique des polygones dans les unités de la couche:
AreaGeodetic($feature)
Calculer la superficie des polygones dans les unités de votre choix (ici en km2):
Area($feature, 'square-kilometers')
Calculer la superficie des polygones dans les unités de votre choix (ici en hectares):
Area($feature,'hectares')
Calculer le X du premier sommet des polylignes:
var myPath = Geometry($feature).paths[0]
return myPath[0].x
Calculer le X du premier sommet des polygones:
var myRing = Geometry($feature).rings[0]
return myRing[0].x
Calculer le X du dernier sommet des polylignes (dans le cas de polygone mono-partie, le premier et le dernier sommet sont les mêmes):
var myPath = Geometry($feature).paths[0]
return myPath[Count(myPath)-1].x
Calculer le X du dernier sommet des polylignes (dans le cas de polygone mono-partie, le premier et le dernier sommet sont les mêmes):
var myRing = Geometry($feature).rings[0]
return myRing[Count(myRing)-1].x
Calculer le X du coin inférieur-gauche de l'enveloppe des polylignes ou des polygones:
var ext = Extent($feature)
return ext.xmin
Calculer le Y du coin inférieur-gauche de l'enveloppe des polylignes ou des polygones:
var ext = Extent($feature)
return ext.ymin
Calculer la largeur de l'enveloppe des polylignes ou des polygones:
var ext = Extent($feature)
return ext.xmax - ext.xmin
Calculer la hauteur de l'enveloppe des polylignes ou des polygones:
var ext = Extent($feature)
return ext.ymax - ext.ymin
Calculer le nombre de parties composant la géométrie d'entités linéaires:
var myPaths = Geometry($feature).paths
return Count(myPaths)
Calculer le nombre de parties composant la géométrie d'entités surfaciques:
var myRings = Geometry($feature).rings
return Count(myRings)
Calculer le nombre de sommets composant la géométrie d'entités linéaires:
var myPaths = Geometry($feature).paths;
var nb_points = 0;
for (var i=0;myPaths;i++){
    var myPath = myPaths[i];
    nb_points += Count(myPath);
}
return nb_points
Calculer le nombre de sommets composant la géométrie d'entités surfaciques:
var myRings = Geometry($feature).rings;
var nb_points = 0;
for (var i=0;imyRings);i++){
    var myRing = myRings[i];
    nb_points += Count(myRing);
}
return nb_points


Accéder à des données d'autres couches


Récupérer la valeur d'un champ depuis une entité située dans une autre couche. Ici on récupère le code de la zone (CodeZone) dans la couche "Zones" dans laquelle se trouve l'entité ($feature) ponctuelle, linéaire ou surfacique:
for (var my_zone in FeatureSetByName($map,"Zones")){
    if (Intersects($feature, Geometry(my_zone))){
        return my_zone.CodeZone;
    }
}
Compter le nombre d'entités (ici des bâtiments) contenus dans la géométrie courante (ici des parcelles cadastrales). Vous noterez que l'on fait tout d'abord une intersection puis la comparaison avec les centroïdes des bâtiments pour ne pas garder les bâtiments qui touchent la limite de la parcelle tout en étant à l'extérieur de celle-ci:
var intersected_features = Intersects(FeatureSetByName($map,"Bâtiments"), $feature);
var n=0;
for (var my_feature in intersected_features)
{
    var my_centroid = Centroid(my_feature);
    Console(my_centroid);
    if (Within(my_centroid,$feature)){
        n++;
    }
}
return Text(n, '#');
Récupérer la distance minimum entre l'entité courante et l'entité la plus proche dans une autre couche (ici la couche "Mes Enseignes"). Dans cet exemple, la distance maximum de recherche est fixée à 100 kilomètres:
var my_buffer = Buffer($feature, 100, 'kilometers');
var dist_min = Infinity;
for (var my_feature in Intersects(FeatureSetByName($map,"Mes Enseignes"),my_buffer))
{
  var d = Distance($feature,my_feature,'kilometers');
  dist_min = IIF(d < dist_min, d, dist_min);
}
return dist_min


Manipuler des tableaux de données


Vous aurez peut-être besoin de manipuler des tableaux de données. Voici donc quelques fonctions intéressantes...

Créer un tableau:
var couleurs = ['orange', 'rouge', 'vert']
Récupérer le deuxième élément d'un tableau:
var couleurs = ['orange', 'rouge', 'vert']
couleurs[1]
// retourne 'rouge'
Connaître le nombre d'éléments d'un tableau:
var couleurs = ['orange', 'rouge', 'vert']
Count(couleurs)
// retourne 3
Ajouter une valeur à un tableau:
var couleurs = ['orange', 'rouge', 'vert'];
couleurs.Push('Noir');
// couleurs = ['orange', 'rouge', 'vert', 'Noir']
Trier les éléments d'un tableau par ordre croissant :
var couleurs = ['orange', 'rouge', 'vert', 'bleu', 'violet']
Sort(couleurs)
// retourne ['bleu', 'orange', 'rouge', 'vert', 'violet']
Trier les éléments d'un tableau par ordre décroissant (pour des éléments simples ou plus complexes comme des tableaux de tableaux):
var couleurs = ['orange', 'rouge', 'vert', 'bleu', 'violet']
Sort(couleurs)
// retourne ['violet', 'vert', 'rouge', 'orange', 'bleu']
Trier les éléments d'un tableau par ordre décroissant (pour des éléments simples de type String ou Number):

var couleurs = ['orange', 'rouge', 'vert', 'bleu', 'violet']
Reverse(Sort(couleurs))
// retourne ['violet', 'vert', 'rouge', 'orange', 'bleu']
Récupérer et supprimer la dernière valeur d'un tableau:
var couleurs = ['orange', 'rouge', 'vert'];
derniereCouleur = Pop(couleurs);
// derniereCouleur = 'vert' et couleurs = ['orange', 'rouge']
Compter le nombre de valeurs uniques dans un tableau:
var couleurs = ['orange', 'orange', 'vert', 'rouge', 'vert']
var couleursUniques = Distinct(couleurs)
// couleursUniques = ['orange', 'vert', 'rouge']
Tester si certaines valeurs sont vides dans un tableau:
var tableau = [$feature.champ1, $feature.champ2, $feature.champ3, $feature.champ4]
Any(tableau, isEmpty)
// retourne True si une des valeurs est vide, sinon retourne False


Autres expressions utiles


Retourner une valeur vide (Null):
Null
Construire une chaîne à partir des valeurs de différents champs en utilisant un séparateur:
Concatenate([$feature.Jour,$feature.Mois,$feature.Annee],"/")
Construire une chaîne en mettant les "0" nécessaires à droite de la valeur numérique (ici un exemple où on force le nombre à faire 4 caractères, par exemple pour 0.75 on obtiendra la chaîne "0.750":
Text($feature.MonChampNum, '0.000')
Construire une chaîne en mettant les "0" nécessaires à gauche de la valeur numérique (ici un exemple où on force le nombre à faire 4 caractères, par exemple pour 82 on obtiendra la chaîne "0082":
Text($feature.MonChampNum, '0000')
Retourner le nom de l'utilisateur actuellement connecté:
var userInfo = GetUser();
if(HasValue(userInfo, "username")){
	return userInfo.username;
}
Retourner le nom complet de l'utilisateur actuellement connecté:
var userInfo = GetUser();
if(HasValue(userInfo, "fullName")){
	return userInfo. fullName;
}
Retourner l'ID de l'utilisateur actuellement connecté:
var userInfo = GetUser();
if(HasValue(userInfo, "id")){
	return userInfo.id;
}
Retourner l'email de l'utilisateur actuellement connecté:
var userInfo = GetUser();
if(HasValue(userInfo, "email")){
	return userInfo.email;
}
Retourner les groupes auxquels appartient l'utilisateur actuellement connecté:
var userInfo = GetUser();
if(HasValue(userInfo, "groups")){
	return userInfo.groups;
}
Retourner la langue du contexte applicatif exécutant l'expression Arcade:
var env = GetEnvironment()
var locale = IIF(HasValue(env, "locale"), env.locale, "");
return locale;
// retourne par exemple 'en-us', 'fr-fr', ...
Retourner la version du contexte applicatif exécutant l'expression Arcade:
var env = GetEnvironment()
var locale = IIF(HasValue(env, "version"), env.version , "");
return locale;
// retourne par exemple '1.23'
Retourner la version du contexte applicatif exécutant l'expression Arcade:
var env = GetEnvironment()
var locale = IIF(HasValue(env, "application"),
env. application,"");
// retourne par exemple 'ArcGISMapViewer'


Pour plus d'informations sur les différents profils, le guide de référence des fonctions et la syntaxe des expressions Arcade, il est important de consulter la documentation en ligne.

Note: Cet article a été publié initialement le 23/01/2019 et mis à jour le 17/08/2023

Partager cet article:

Rejoindre la discussion

    Les commentaires à propos de cet article:

2 comments :

Unknown a dit…

Bonjour !
Dans une mise en page de série de cartes sur ArcGIS Pro, je souhaiterais intégrer des sauts de lignes dans l'affichage d'un attribut de table, selon un délimiteur défini.

Dans mon cas, j'ai un champ "codeident" qui regroupe 1 à n identifiants sous la forme : xxx xxx, xxx xxx, xxx xxx, xxx xxx (identifiants séparés par des virgules).

Dans mon texte dynamique, j'aimerais que chaque identifiant s'écrive sur une seule ligne et dans les cas où il y a plus de deux items, que le deuxième item s'écrive sous le premier ... et ainsi de suite, pour obtenir, dans ma mise en page, un tableau sous la forme :

xxx xxx
xxx xxx
xxx xxx

J'espère que cela est possible !

Merci d'avance,

Unknown a dit…

Bonjour,

j'aimerais savoir comment coder et où le coder?

Dans field maps j'ai créer un formulaire avec les chapms suivant (Type, EssenceFr, EssenceLa)

J'aimerais que quand l'utilisateur saisie l'essence en français, le champs d'essence en latin se peuple automatiquement!

J'ai créer mes domaines d'attributs, je les ais associés et même créer des valeurs conditionnelles.

Est-ce que je doit mettre une règles attributaire avec FeatureSetByName ?


Merci !