Optimiser ses expressions Arcade avec 5 fonctions souvent sous-utilisées
Arcade est
un langage d'expression qui vous permet de créer du contenu personnalisé dans
des fenêtres contextuelles, de formater des étiquettes, de créer des
comportements dans les formulaires intelligents, de créer de nouvelles valeurs
de données pour les cartes web et les tableaux de bord ou encore d'appliquer
des règles dans divers flux de travail. J'ai déjà évoqué sur arcOrama les
fonctions de base d'Arcade
à partir d'exemples concrets
ainsi que des cas d'usages plus avancés. Beaucoup d'entre vous utilise donc Arcade au quotidien
car c'est simple et puissant.
Je vois beaucoup d'expressions Arcade réalisées par des utilisateurs ArcGIS et
je les aide parfois à les améliorer. Au fil du temps, j'ai remarqué que
certaines peuvent être simplifiés ou améliorées en utilisant des fonctions
Arcade prêtes à l'emploi. La plupart du temps, les auteurs d'expressions ne
connaissent pas certaines fonctionnalités d'Arcade qui leur manquent. Dans cet
article, je vais évoquer 5 fonctions Arcade méconnues et donc sous-utilisées
et j'essayerai de vous montrer comment elles peuvent améliorer vos
expressions.
1. La fonction "IIf"
La fonction
IIf
renvoie une valeur si une expression conditionnelle prend la valeur
true,
et renvoie une autre valeur si la condition prend la valeur
false. Ceci est
particulièrement utile dans des scénarios simples tels que l'écriture d'une
expression pour indiquer quand une valeur a atteint un seuil.
Généralement, dans vos expressions, vous utilisez des blocs
if-else
pour renvoyer des valeurs de manière conditionnelle. Par exemple, comme ceci
:
// Si la valeur est supérieure à 100 retourner "fort"
// Sinon, retourner "faible"
var categorie = "";
if($feature.value > 100){
categorie = "fort";
} else {
categorie = "faible";
}
return categorie;
Cependant, la fonction
IIf
simplifie cela en deux lignes sans avoir besoin de plusieurs retours ou
affectations de variables…
// Si la valeur est supérieure à 100 retourner "fort"
// Sinon, retourner "faible"
var categorie = IIF($feature.value > 100, "fort", "faible");
return categorie;
…ou à une seule ligne (grâce aux
retours implicites).
IIF($feature.value > 100, "fort", "faible");
Bien entendu, il n'y a pas d'erreur à utiliser un bloc
if-else
pour renvoyer un contenu conditionnel. En fait, vous devez utiliser des
instructions if-else si vous devez évaluer d'autres instructions qui suivent les mêmes
conditions, y compris l'affectation de valeurs à des variables. Dans l'exemple
suivant, la fonction
IIf
n'est pas appropriée car plusieurs affectations de variables ont lieu si la
condition est vraie.
if($feature.value > 100){
pourcentAuDessus = $feature.value - 100;
categorie = "fort";
} else {
category = "faible";
}
return `${categorie} (${pourcentAuDessus}%)`;
Retenez donc que lorsque vous avez à renvoyer une valeur basée sur une
condition simple,
IIf
condensera et simplifiera votre expression.
2. La fonction "Text"
La fonction
Text
convertit une valeur de n'importe quel
type de données
Arcade en une valeur de type texte équivalente. Vous trouverez cette
fonction particulièrement utile lors du formatage des dates, mais j'ai vu
beaucoup d'expressions qui implémentent des logiques supplémentaires pour le
formatage des nombres alors qu'elles pourraient être évitées simplement en
tirant parti de
Text.
Round(($feature.diplomes/$feature.PopulationAdulte) * 100, 1) + “%”;
// retourne "37.8%";
Cependant,
Text
vous offre une option % afin que vous n'ayez pas à faire le calcul de
conversion d'un nombre décimal (0-1) en pourcentage.
Text($feature.diplomes/$feature.PopulationAdulte, "#.#%");
// retourne "37.8%";
Mais est-ce que votre expression
Text
est vraiment meilleure dans ce cas ? Oui car les deux approches sont
différentes car
Round
renvoie un nombre alors
Text
renvoie une valeur de type texte. Voici pourquoi cette distinction est
importante :
Round
modifie la précision des nombres que vous utilisez pour les calculs dans une
expression sans réellement formater la valeur.
Text
vous permet de formater un nombre en fonction d'un modèle de formatage. Bien
que
Text
permette d'arrondir les nombres, il vous permet également de spécifier des
séparateurs pour les grands nombres. En bref,
Round
peut arrondir vos nombres décimaux, mais la fonction Text
arrondira et ajoutera des séparateurs de chiffres aux grands nombres.
Cependant, le plus grand avantage de l'utilisation
Text
est que la mise en forme définie dans la fonction sera conforme aux
paramètres régionaux de l'application dans laquelle l'expression s'exécute.
Round
ne vous donne pas cet avantage.
Consultez les exemples suivants et notez les différences. Le texte renvoie
toujours un résultat plus propre et plus correct.
var v = 2891.378268263982736;
Round(v, 2);
// retourne 2891.38 en anglais, sans séparateur de milliers
// retourne 2891.38 en français (mauvais séparateur de décimales), sans séparateur de milliers
Text(v, "#,###.##");
// retourne "2,891.38" en anglais, avec séparateurs de milliers
// retourne "2 891,38" en français (bon séparateur de décimales et séparateurs de milliers
Dans de nombreux cas, la division de deux nombres donne un nombre avec de
nombreuses décimales. Le niveau de précision qui en résulte est souvent trop
élevé ou non requis par l'utilisateur final.
Round
vous aide à contrôler la précision de votre formule. Vous devez également
l'utiliser
Round
lorsque vous devez renvoyer le résultat sous forme de nombre (comme dans un
calcul de champ ou une valeur de rendu) ou continuer à l'utiliser comme
entrée pour une autre fonction Arcade lorsque moins de précision est
requise.
Je vois également parfois des utilisateurs se servir de
IIf pour formater des valeurs au-dessus et en dessous d'une valeur seuil,
comme ceci :
var precedente = $feature.pop2020; // 3020
var actuelle = $feature.pop2023; // 3333
var evolution = (actuelle - precedente) / precedente;
IIF(evolution > 0, "⬆", "⬇") + Round(evolution*100, 2) + "%";
// retourne "⬆10.4%" en anglais
// retourne "⬆10.4%" en français (séparateur de décimales incorrect)
Comme indiqué dans les résultats potentiels, cela entraînera un mauvais
formatage dans de nombreux paramètres régionaux non anglais. Le paramètre de
modèle de format de
Text
fournit en fait une option qui vous permet de spécifier un format différent
pour les valeurs positives ou négatives. Séparez simplement les deux motifs
par un point-virgule et Arcade fera le travail pour vous. Il n'y a pas besoin
d'utiliser
IIf
du tout.
var precedente = $feature.pop2020; // 3020
var actuelle = $feature.pop2023; // 3333
var evolution = (actuelle - precedente) / precedente;
Text(evolution, "⬆#.#%;⬇#.#%");
// retourne "⬆10.4%" en anglais
// retourne "⬆10,4%" en français (séparateur de décimales correct)
Les images suivantes montrent comment l'utilisation
Round
entraînera des valeurs contextuelles incorrectes en fonction des paramètres
régionaux.
3. La fonction "Decode"
Decode permet de trouver une correspondance dans un ensemble de codes et de
renvoyer une description correspondant à ce code. Cette fonction peut être
utilisée pour évaluer n'importe quelle expression à une valeur et comparer
le résultat à une liste de valeurs attendues et renvoyer une description,
une catégorie ou une autre valeur correspondante.
Par exemple, l'attribut CodeTech dans l'exemple suivant est une
valeur codée. Je vois souvent des utilisateurs renvoyer la description du
code en utilisant une séquence d'instructions
if-else, comme ceci :
if($feature.CodeTech == 30){
return "Réseau cuivre";
}
if($feature.CodeTech == 40){
return "Réseau câble ";
}
if($feature.CodeTech == 50){
return "Fibre";
}
if($feature.CodeTech == 60){
return "Satellite";
}
if($feature.CodeTech == 70){
return "Sans-fil terrestre";
}
if($feature.CodeTech == 90){
return "Ligne électrique";
}
Bien entendu, cette syntaxe est valide et renvoie un résultat correct. Vous
pouvez également condenser cette expression à l'aide de la fonction
When
:
When(
$feature.CodeTech == 30, "Réseau cuivre",
$feature.CodeTech == 40, "Réseau câble",
$feature.CodeTech == 50, "Fibre",
$feature.CodeTech == 60, "Satellite",
$feature.CodeTech == 70, "Sans-fil terrestre",
$feature.CodeTech == 90, "Ligne électrique",
"Autre"
);
Ceci est également valide et renvoie un résultat correct. Cependant, comme
le code provient d'un seul champ, vous pouvez simplement utiliser
Decode
pour renvoyer plus directement la description :
Decode($feature.CodeTech,
30, "Réseau cuivre",
40, "Réseau câble",
50, "Fibre",
60, "Satellite",
70, "Sans-fil terrestre",
90, "Ligne électrique",
"Autre"
);
Votre expression est ainsi plus compacte et un peu plus facile à lire.
Decode
est préférable pour évaluer une seule expression et comparer le résultat à
une liste de valeurs connues.
When
est préférable pour évaluer plusieurs expressions dans une séquence
hiérarchisée et renvoyer une valeur une fois que l'une des déclarations
est vraie.
Decode
peut également être utilisé de manière astucieuse, par exemple en
comparant plusieurs attributs numériques de catégories concurrentes et en
renvoyant l'alias ou la description du champ pour visualiser la
prédominance.
Par exemple, dans un ensemble de données électorales, vous pouvez avoir
des colonnes qui représentent le nombre total de votes pour des candidats
individuels, mais aucune colonne qui indique le vainqueur (car aucun n'a
encore été déclaré). Vous pouvez utiliser
Decode
pour renvoyer le leader actuel d'une élection lors de la mise à jour des
résultats :
var votesParParti = [
$feature.RN,
$feature.REP,
$feature.LREM,
$feature.LFI,
$feature.EELV,
$feature.SOC,
];
// Récupère le score le plus élevé,
// trouve la correspondance avec le parti correspondant
// et retourne le nom complet du parti leader
var leader = Decode(Max(votesParParti),
$feature.RN, "Rassemblement national",
$feature.REP, "Les républicains",
$feature.LREM, "La république en marche",
$feature.LFI, "La France insoumise",
$feature.EELV, "Europe écologie les verts",
$feature.SOC, "Socialistes",
"Autre"
);
return leader;
4. La fonction "DefaultValue"
DefaultValue
renvoie une valeur si une valeur vide (null ou '') est détectée. Les
utilisateurs souhaitent généralement afficher le texte par défaut au cas
où une valeur n'existe pas. De nombreuses personnes utilisent une
combinaison de
IIf
et
IsEmpty
pour tenir compte des valeurs vides.
// retourne une valeur par défaut de 0 si le champ de données est vide
IIF(!IsEmpty($feature.monchamp), $feature.monchamp, 0);
Cela fonctionne, mais la fonction
DefaultValue
fait tout le travail pour vous. Tout ce que vous avez à faire est de
spécifier la valeur que vous souhaitez vérifier, et la valeur par défaut à
retourner si elle est vide.
L'équivalent de l'expression précédente est plus facile à lire :
// retourne une valeur par défaut de 0 si le champ de données est vide
DefaultValue($feature.monchamp, 0);
Dans les fenêtres contextuelles, il peut être utile d'afficher un message
indiquant qu'aucune donnée n'est disponible afin que l'utilisateur sache que
les données sont collectées dans la couche, mais ne sont pas disponibles
pour l'entité sélectionnée.
// retourne "Aucune donnée disponible" si le champ etat est vide
DefaultValue($feature.etat, "Aucune donnée disponible");
Je suis récemment tombé sur l'expression suivante qui aurait pu être réduite
de moitié si l'auteur de l'expression avait été utilisée
DefaultValue. Vous noterez comment la valeur de retour dans le
if-else
sont presque identiques. La seule différence est d'afficher la valeur d'un
attribut ou d'un autre si le premier est vide.
var ValeurPourcent = Round(($feature.Visiteurs/$feature.TotalVisiteurs)*100, 2) + "%";
var TypeParc = Lower($feature.TYPE_PARC);
var NomParc = $feature.NOM_PARC;
var CodeParc = $feature.CODE_PARC;
if(IsEmpty(NomParc)){
return {
text: "{CodeParc} est un parc de type " + TypeParc + " qui a eu " +
"{$feature.Visiteurs} visiteurs en 2022. " +
"cela représente " + ValeurPourcent + " des visites" +
"de tous les parcs en 2022."
}
} else {
return {
text: "{NomParc} est un parc de type " + TypeParc + " qui a eu " +
"{$feature.Visiteurs} visiteurs en 2022. " +
"Cela représente " + ValeurPourcent + " des visites" +
"de tous les parcs en 2022."
}
}
Il s'agit de l'expression mise à jour tirant parti
DefaultValue
de la variable NomParc, ce qui entraîne moins de duplication de texte
dans l'expression. J'utilise également
Text
pour nettoyer le formatage des nombres et rendre les valeurs sensibles aux
paramètres régionaux.
var ValeurPourcent = Round(($feature.Visiteurs/$feature.TotalVisiteurs)*100, 2) + "%";
var TypeParc = Lower($feature.TYPE_PARC);
var NomParc = DefaultValue($feature.NOM_PARC, $feature.CODE_PARC);
return {
text : NomParc + " est un parc de type " + TypeParc + " qui a eu " +
Text($feature.Visiteurs, "#,###") +
" visiteurs en 2022. Cela représente " +
ValeurPourcent + " des visites de tous les parcs en 2022."
};
5. La fonction "Number"
La fonction
Number
convertit une valeur d'entrée de n'importe quel type en un nombre. Les
gens demandent souvent une fonction pour renvoyer le nombre de
millisecondes depuis le 1er janvier 1970 similaire à la méthode
Date.getTime()
de JavaScript. Cette fonction existe déjà !
Number
le fera si vous transmettez une valeur de date en tant que paramètre à la
fonction.
Number(Date())
// retourne la valeur d'époque
Il est également courant que les utilisateurs stockent des valeurs
binaires en tant qu'attribut d'entité. Certains attributs sont vrais ou
faux, donc la valeur sera stockée sous la forme 0 (false) ou 1
(true).
J'ai parfois vu des expressions faire ce qui suit lors du calcul d'une
valeur dans les workflows de mise à jour :
IIF($feature.etat == "terminé", 1, 0);
// retourne 1 si vrai, 0 si faux
Vous pouvez également tirer parti de
Number
pour renvoyer un 1 ou un 0 lors de l'évaluation d'une expression booléenne.
Number($feature.etat == "terminé");
// retourne 1 si vrai, 0 si faux
Number
peut également être utile si vous avez besoin d'analyser une valeur à partir
d'un texte et de la convertir en nombre pour un calcul ou une visualisation
numérique.
Number("38.7%", "#.#%");
// retourne 0.387
Number("1,000 personnes", "# personnes");
// retourne 1000
Et les plus sous-utilisées des fonctions, ce sont généralement vos
propres fonctions !
Si vous vous retrouvez à écrire du code en double dans une expression,
vous tirerez probablement profit de l'écriture d'une
fonction personnalisée. Les fonctions personnalisées vous permettent d'écrire une fois du code
qui, sinon, devrait être écrit plusieurs fois dans votre expression, et de
leurs donner un nom pour pouvoir les appeler. Cela réduit considérablement
les erreurs qui se glissent avec le copier/coller et peut réduire
considérablement la taille d'une expression.
Conclusion
Comme avec tout autre langage de scripting ou d'expression, il existe
plusieurs façons de résoudre une tâche ou d'arriver à un résultat correct.
Cependant, les fonctions décrites dans cet article (IIf,
Text,
Decode,
DefaultValue,
Number) peuvent simplifier vos expressions, améliorer leur lisibilité et
réduire les bugs. Définir vos propres fonctions peut également vous faire
gagner du temps, réduire la longueur de vos expressions et réduire les
bogues introduits dans les opérations de copier/coller.
0 comments :
Enregistrer un commentaire