Le blog francophone consacré
aux technologies Esri

Utiliser Python pour calculer vos champs dans ArcGIS

Cet article est une version actualisée de l'article Utiliser Python pour calculer vos champs dans ArcGIS posté en 2015. 



Depuis la version 9.2 d'ArcGIS, la calculatrice (ou l'outil de géotraitement correspondant) permet de calculer des valeurs de champs en utilisant soit le langage VBScript, soit le langage Python. Même si pendant plusieurs années l'usage de l'un ou de l'autre est agnostique, il devient incontournable de laisser tomber VBScript et de rédiger désormais ses expressions de calcul en Python. Tout d'abord parce que Python offre des fonctionnalités plus puissantes mais surtout parce que VBScript n'est pas supporté dans les contextes d'exécution 64 bits:
  • lors de l'utilisation de l'option d'exécution des géotraitements en arrière plan 64 bits dans ArcMap, ArcScene ou ArcGlobe.
  • lors de l'utilisation des géotraitements avec ArcGIS Server (nativement 64 bits)
  • lors de l'utilisation des géotraitements conjointement avec ArcGIS Pro (nativement 64 bits)

Si vous n'êtes pas encore un expert des expressions de calcul en Python, je vous propose de le devenir à l'aide de la série d'exemples qui, je l'espère, couvriront la majorité de vos besoins:


Quelques éléments de base

L'utilisation de l'outil "Calculer un champ" disponible aussi bien dans ArcMap, ArcScene, ArcGlobe et ArcGIS Pro, permet de spécifier une expression Python pour calculer les valeurs d'un champ. 

Il peut s'agir d'un calcul simple basé sur une expression rédigée sur une seule ligne.

Expression de calcul simple dans ArcMap

Il peut s'agir d'un calcul plus avancé nécessitant la rédaction d'une expression et d'un bloc de code. Dans ce cas, l'expression appelle généralement une fonction (def MaFonction():) écrite en Python dans le bloc de code.

Expression de calcul avec bloc de code dans ArcGIS Pro

Lors de l'utilisation d'un bloc de code, Python applique une indentation du code dans le cadre de la syntaxe pour définir les différents niveaux logiques du code. Vous devrez donc utiliser deux ou quatre espaces pour définir chaque indentation. Vous alignerez le début et la fin des blocs d'instruction en restant cohérent.

Vous noterez que les noms des champs dans les expression de calcul Python sont délimités par des points d'exclamation (!!).

Lorsque vous nommez des variables, n'oubliez pas que Python respecte la casse. Ainsi, la variable "ratio" n'est pas équivalent à la variable "Ratio".

Après la saisie des instructions, vous pouvez cliquer sur le bouton "Exporter" si vous souhaitez les enregistrer dans un fichier. Le bouton "Importer" vous invite à rechercher et sélectionner un fichier de calcul existant.

Expressions sur les chaînes de caractères



Concaténer plusieurs champs de type chaîne de caractères:
Expression:
!Mon_Champ1! + ' ' + !Mon_Champ2!

Concaténer plusieurs champs dont certains sont de type numérique (ici: le champ Hauteur):
Expression:
'La hauteur du bâtiment ' + !Id_bat! + ' est de ' + str(!Hauteur!) + ' m."

Concaténer plusieurs champs de type chaîne de caractères en intégrant un saut de ligne (peut servir, par exemple, dans le cas d'un champ utilisé pour un étiquetage):
Expression:
!Mon_Champ1! + '\n' + !Mon_Champ2!
  
Calculer le nombre de caractères d'une chaîne:
Expression:
len(!Mon_Champ!)
  
Remplacer un caractère par un autre caractère:
Expression:
!Mon_Champ!.replace(u'é',u'e')

Remplacer les valeurs nulles par une chaîne vide:
Bloc de code:
def UpdateField(value):
  if value is None:
     return ''
  else:
    return value

Expression:
UpdateField(!Mon_Champ!)

Extraire le premier caractère d'une chaîne:
Expression:
!Mon_Champ![0]

Extraire le deuxième caractère d'une chaîne:
Expression:
!Mon_Champ![1]

Extraire le dernier caractère d'une chaîne:
Expression:
!Mon_Champ![-1]

Extraire l'avant-dernier caractère d'une chaîne:
Expression:
!Mon_Champ![-2]

Extraire les 5 premiers caractères d'une chaîne:
Expression:
!Mon_Champ![:5]

Extraire les 3 derniers caractères d'une chaîne:
Expression:
!Mon_Champ![-5:]

Extraire une partie quelconque d'une chaîne (ici: deuxiène, troisième et quatrième caractère):
Expression:
!Mon_Champ![1:4]

Extraire le 3ième mot d'une chaîne:
Bloc de code:
def ExtractWord(value, index):
  tablo = value.split(' ')
  if (len(tablo)>index):
    return tablo[index-1]
  else:
    return None

Expression:
ExtractWord(!Mon_Champ!,3)

Extraire la 4ième mot d'une chaîne dont les mots sont séparés par une virgule:
Bloc de code:
def ExtractWord(value, index):
  tablo = value.split(',')
  if (len(tablo)>index):
    return tablo[index-1]
  else:
    return None

Expression:
ExtractWord(!Mon_Champ!,4)

Retirer les espaces inutiles en fin de chaîne:
Expression:
!Mon_Champ!.rstrip()

Retirer les espaces inutiles en début de chaîne:
Expression:
!Mon_Champ!.lstrip()

Retirer les espaces inutiles en début et fin de chaîne:
Expression:
!Mon_Champ!.strip()

Retirer les espaces, tabulations, sauts de ligne et retours chariot en début et fin de chaîne:
Expression:
!Mon_Champ!.strip(' \t\n\r')

Mettre tout en minuscule:
Expression:
!Mon_Champ!.lower()

Mettre tout en majuscule:
Expression:
!Mon_Champ!.upper()

Mettre le premier caractère en majuscule et le reste en minuscule:
Expression:
!Mon_Champ!.capitalize()

Mettre une majuscule au début de chaque mot:
Expression:
!Mon_Champ!.title()

Insérer une simple-quote dans une chaîne:
Expression:
'Voici l\'insertion d\'une apostrophe'

Insérer une double-quote dans une chaîne:
Expression:
'Voici \"la citation\"'

Choisir une chaîne de manière aléatoire parmi une liste de chaîne:
Bloc de code:
import random
mylist = ['Pomme','Poire','Orange','Kiwi','Fraise']

Expression:
mylist[random.randrange(len(mylist))]

   
Expressions sur les valeurs numériques



Convertir une chaîne en entier court:
Expression:
int(!Mon_Champ_Text!)

Convertir une chaîne en entier long:
Expression:
long(!Mon_Champ_Text!)

Convertir une chaîne en nombre décimal:
Expression:
float(!Mon_Champ_Text!)

Remplacer les valeurs nulles par la valeur 0:
Bloc de code:
def UpdateField(value):
  if value is None:
     return 0
  else:
    return value

Expression:
UpdateField(!Mon_Champ!)

Arrondir à l'entier inférieur ou supérieur selon les règles mathématiques classiques:
Expression:
round(!Mon_Champ_Decimal!)

Arrondir à l'entier supérieur:
Expression:
math.ceil(!Mon_Champ_Decimal!)

Arrondir à l'entier inférieur:
Expression:
math.floor(!Mon_Champ_Decimal!)

Arrondir à la 3ème décimale:
Expression:
round(!Mon_Champ_Decimal!,3)

Générer un nombre entier aléatoire entre 0 et 9:
Bloc de code:
import random

Expression:
random.randint(0,9)

Générer un nombre décimal aléatoire entre 0 et 1:
Bloc de code:
import random

Expression:
random.random()

Générer un nombre décimal aléatoire entre 20 et 80:
Bloc de code:
import random

Expression:
20 + (random.random()*60)

Calculer la valeur absolue d'un nombre:
Expression:
math.fabs(!Mon_Champ!)

Calculer l'opposé d'un nombre:
Expression:
-!Mon_Champ!

Calculer le modulo d'un nombre:
Expression:
!Mon_Champ_Decimal! % 360

Calculer le carré d'un nombre:
Expression:
!Mon_Champ! ** 2

Calculer le cube d'un nombre
Expression:
!Mon_Champ! ** 3

Calculer la racine carrée d'un nombre
Expression:
!Mon_Champ! ** (1./2.)

Calculer la racine cubique d'un nombre
Expression:
!Mon_Champ! ** (1./3.)

Calculer le volume d'une sphère à partir du champ contenant le rayon (utilisation de la constant Pi): 
Expression:
4.0 / 3.0 * math.pi * !Rayon! ** 3

Calculer la valeur minimum entre plusieurs champs
Expression:
min([!Champ1!,!Champ2!,!Champ3!,!Champ4!])

Calculer la valeur maximum entre plusieurs champs
Expression:
max([!Champ1!,!Champ2!,!Champ3!,!Champ4!])

Calculer la somme des valeurs entre plusieurs champs
Expression:
sum([!Champ1!,!Champ2!,!Champ3!,!Champ4!])

Calculer la moyenne des valeurs entre plusieurs champs
Expression:
avg([!Champ1!,!Champ2!,!Champ3!,!Champ4!])
 
Incrémenter une valeur enregistrement après enregistrement, à partir d'une valeur de départ et d'un intervalle (ici on part de 0 avec un pas de 3):
Bloc de code:
rec='first'
def autoIncrement(start,step):
  global rec
  if (rec=='first'):
    rec = start
  else: 
    rec = rec + step
  return rec

Expression:
autoIncrement(0,3)

Accumuler les valeurs d'un champ, enregistrement après enregistrement. La valeur du dernier enregistrement correspond à la somme de toutes les valeurs de ce champs:
Bloc de code:
total = 0
def accumulate(increment):
    global total
    if total:
        total += increment
    else:
        total = increment
    return total

Expression:
accumulate(!Mon_Champ_Num!)



Expressions sur les dates



Calculer la date courante:
Expression:
time.strftime("%d/%m/%Y")

Calculer la date et l'heure courante:
Expression:
datetime.datetime.now()

Insérer une date spécifique (ici le 5 décembre 2015)::
Expression:
datetime.datetime(2015, 12, 5)

Calculer le nombre de jours compris entre la date actuelle et la date d'un champ:
Expression:
(datetime.datetime.now() - arcpy.time.ParseDateTimeString(!Mon_Champ_Date!)).days

Calculer le nombre de secondes compris entre la date actuelle et la date d'un champ:
Expression:
(datetime.datetime.now() - arcpy.time.ParseDateTimeString(!Mon_Champ_Date!)).seconds

Calculer une date en ajoutant 3 semaines à la date d'un champ:
Expression:
arcpy.time.ParseDateTimeString(!Mon_Champ_Date!) + datetime.timedelta(weeks=3)

Calculer une date en ajoutant 10 jours à la date d'un champ:
Expression:
arcpy.time.ParseDateTimeString(!Mon_Champ_Date!) + datetime.timedelta(days=10)

Calculer une date en ajoutant 12 heures à la date d'un champ:
Expression:
arcpy.time.ParseDateTimeString(!Mon_Champ_Date!) + datetime.timedelta(hours=12)

Calculer le jour de la semaine (par exemple: lundi) de la date d'un champ:
Expression:
arcpy.time.ParseDateTimeString( !Mon_Champ_Date! ).strftime('%A')
 
Calculer une date à partir d'un champ contenant des timestamps:
Bloc de code:
from datetime import datetime

Expression:
datetime.utcfromtimestamp(!Mon_Champ_Timestamp!)

Calculer des timestamps à partir d'un champ contenant des dates:
Bloc de code:
import calendar

def convertToTimestamp(value):
  dt= arcpy.time.ParseDateTimeString(value)
  return calendar.timegm(dt.utctimetuple()) 

Expression:
convertToTimestamp(!Mon_Champ_Date!)


Expressions sur les géométries



Calculer le X du centroïde des géométries des entités:
Expression:
!shape.centroid.x!

Calculer le Y du centroïde des géométries des entités:
Expression:
!shape.centroid.y!

Calculer le Z du centroïde des géométries des entités:
Expression:
!shape.centroid.z!

Calculer le X du barycentre des géométries des entités:
Expression:
!shape.truecentroid.x!

Calculer le X du point d'étiquetage des géométries des entités:
Expression:
!shape.labelpoint.x!

Calculer le périmètre des polygones ou la longueur des polylignes dans les unités de la couche:
Expression:
!shape.length!

Calculer le périmètre des polygonesZ ou la longueur des polylignesZ en prenant en compte le Z des sommets:
Expression:
!shape.length3D!

Calculer le périmètre des polygones ou la longueur des polylignes dans les unités de votre choix (ici en kilomètres):
Expression:
!shape.length@kilometers!

Calculer la superficie des polygones dans les unités de la couche:
Expression:
!shape.area!

Calculer la superficie des polygones dans les unités de votre choix (ici en km2):
Expression:
!shape.area@squarekilometers!

Calculer la superficie des polygones dans les unités de votre choix (ici en hectares):
Expression:
!shape.area@hectares!

Calculer le X du premier sommet des polylignes ou des polygones:
Expression:
!shape.firstpoint.x!

Calculer le X du dernier sommet des polylignes ou des polygones (dans le cas de polygone mono-partie, le premier et le dernier sommet sont les mêmes):
Expression:
!shape.lastpoint.x!

Calculer le X du coin inférieur-gauche de l'enveloppe des polylignes ou des polygones:
Expression:
!shape.extent.xmin!

Calculer le Y du coin inférieur-gauche de l'enveloppe des polylignes ou des polygones:
Expression:
!shape.extent.ymin!

Calculer la largeur de l'enveloppe des polylignes ou des polygones:
Expression:
!shape.extent.width!

Calculer la hauteur de l'enveloppe des polylignes ou des polygones:
Expression:
!shape.extent.height!

Calculer le nombre de parties composant la géométrie des entités:
Expression:
!shape.partcount!

Calculer le nombre de sommets composant la géométrie des entités:
Expression:
!shape.pointcount!

Calculer le Z moyen des sommets de polylignesZ, de polygonesZ ou de multipatch:
Bloc de code:
def AverageZ(feat):    
    avg=0
    partnum = 0
    partcount = feat.partCount
    pntcount = 0

    while partnum < partcount:
        part = feat.getPart(partnum)
        pnt = part.next()

        while pnt:
            pntcount += 1 
            
            if pnt:
                avg=avg + pnt.z

            pnt = part.next()
           
        partnum += 1

    return avg/pntcount

Expression:
AverageZ(!shape!)

Calculer le Z minimum des sommets de polylignesZ, de polygonesZ ou de multipatch:
Bloc de code:
def MinimumZ(feat):    
    min=0
    partnum = 0
    partcount = feat.partCount
    pntcount = 0

    while partnum < partcount:
        part = feat.getPart(partnum)
        pnt = part.next()
        min=pnt.z

        while pnt:
            pntcount += 1 
            
            if pnt:
                if (pnt.z < min):
                    min=pnt.z

            pnt = part.next()


        partnum += 1

    return min

Expression:
MinimumZ(!shape!)

Calculer le Z maximum des sommets de polylignesZ, de polygonesZ ou de multipatch:
Bloc de code:
def MaximumZ(feat):    
    max=0
    partnum = 0
    partcount = feat.partCount
    pntcount = 0

    while partnum < partcount:
        part = feat.getPart(partnum)
        pnt = part.next()
        max=pnt.z

        while pnt:
            pntcount += 1 
            
            if pnt:
                if (pnt.z > max):
                    max=pnt.z

            pnt = part.next()


        partnum += 1

    return max

Expression:
MaximumZ(!shape!)

Calculer le M moyen des sommets de polylignesM ou de polygonesM:
Bloc de code:
def AverageM(feat):    
    avg=0
    partnum = 0
    partcount = feat.partCount
    pntcount = 0

    while partnum < partcount:
        part = feat.getPart(partnum)
        pnt = part.next()

        while pnt:
            pntcount += 1 
            
            if pnt:
                avg=avg + pnt.m

            pnt = part.next()
           
        partnum += 1

    return avg/pntcount

Expression:
AverageM(!shape!)

Mettre à jour la géométrie des points de la couche à l'aide de deux champs X et Y
(expression à appliquer sur le champ "shape"):
Expression:
arcpy.Point(!Champ_X!,!Champ_Y!)

Déplacer les points d'une couche d'une distance de 1000 unités X et 500 unités en Y:
Bloc de code:
def Move(feat,deltaX,deltaY):
    newfeat = arcpy.Point(feat.centroid.X + deltaX ,feat.centroid.Y + deltaY)
    return newfeat

Expression:
Move(!shape!,1000,500)


Autres expressions de calcul

Mettre les valeurs d'un champ à "Null":
Expression:
None

Construire une chaîne à partir des valeurs de différents champs:
Expression:
"{}:{}".format(!Champ_Heures!, !Champ_Minutes!)

Construire une chaîne en forçant l'écriture du signe + ou - devant une valeur numérique:
Expression:
'{:+d}'.format(!Champ_Num!)

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":
Expression:
'{:04d}'.format(!Champ_Num!)

Construire une chaîne à partir d'une date selon le format souhaité:
Expression:
'{:%d-%m-%Y %H:%M}'.format(arcpy.time.ParseDateTimeString(!Champ_Date!))

Construire le code hexadécimal d'une couleur (ex: #FF33AA) à partir de ses composantes Rouge, Vert et Bleu:
Bloc de code:
def rgb2hex(r,v,b):
    hex = "#{:02x}{:02x}{:02x}".format(r,v,b)
    return hex

Expression:
rgb2hex(!Champ_R!,!Champ_V!,!Champ_B!)
   
Construire la chaîne des composantes Rouge, Vert et Bleu à partir du code hexadécimal (ex: #FF33AA) d'une couleur:
Bloc de code:
def hex2rgb(hexcode):
rvb = tuple(map(ord,hexcode[1:].decode('hex')))

return rvb

Expression:

hex2rgb(!Champ_Hexa!)

Partager cet article:

Rejoindre la discussion

    Les commentaires à propos de cet article:

1 comments :

Anonyme a dit…

Bonjour Arcorama,
Gaëtan, merci pour cette mine d'information actualisée