Quantcast
Channel: arcOrama
Viewing all articles
Browse latest Browse all 2035

Modifier la structure et les données de vos couches d'entités avec l'API Python ArcGIS

$
0
0
Je poursuis ma série de tutoriels consacrés à l'usage de l'API ArcGIS for Python. Aujourd'hui, je vous propose de voir un ensemble d'instructions permettant la modification des données des couches d'entités de votre portail ArcGIS. Le tutoriel ci-dessous montre également comment modifier la structure des couches.

     
Le Notebook présenté ci-dessous est téléchargeable ici.

Tuto 4: Modifier la structure et les données de vos couches d'entités

Ce tutoriel a pour objectif d'illustrer les possibilités de l'API Python ArcGIS en termes de mise à jour des données et de la structure des couches d'entités hébergées sur votre portail ArcGIS. A l'aide des exemples de code ci-dessous, vous pourrez élaborer des scripts plus évolués automatisant la mise à jour des données de vos couches, l'ajout et le calcul de champs, l'ajout de domaines de valeurs, de pièces jointes, ...
In [81]:
fromIPython.displayimportdisplay
fromarcgis.gisimportGIS

my_gis=GIS('https://www.arcgis.com','username','password')
In [82]:
my_gis

Lister les champs d'une couche d'entités

Commençons tout d'abord par récupérer la couche d'entités. Par exemple, en utilisant son "ItemID".
In [83]:
my_item=my_gis.content.get('5f227e966acf46d7b2b254f2af85a27e')
my_item
Out[83]:
Salles_de_cinemas_en_France
Salles_de_cinemas_en_FranceFeature Layer Collection by glavenu_esrifrance
Last Modified: octobre 28, 2018
0 comments, 4 views
La séquence d'instructions suivante permet de récupérer la liste des champs de la couche d'entités hébergée.
In [84]:
fromarcgis.featuresimportFeatureLayer
my_FL=FeatureLayer.fromitem(my_item,0)
my_fields=my_FL.properties.fields
Profitons-en pour utiliser les capacités de présentation de Jupyter pour présenter cette liste en exploitant les capacités de la syntaxe Markdown !
In [46]:
fromIPython.displayimportMarkdown,display
strMarkdown="Name | Alias | Type | SQL Type"
strMarkdown+="\n"+"-|-|-|-"
forfieldinmy_fields:
strMarkdown+="\n"+field.name+" | "+field.alias+" | "+field.type+" | "+field.sqlType

display(Markdown(strMarkdown))
NameAliasTypeSQL Type
objectIdobjectIdesriFieldTypeOIDsqlTypeOther
IDIDesriFieldTypeIntegersqlTypeOther
NomNomesriFieldTypeStringsqlTypeOther
RegionRegionesriFieldTypeStringsqlTypeOther
AdresseAdresseesriFieldTypeStringsqlTypeOther
ComplementComplementesriFieldTypeStringsqlTypeOther
Code_INSEECode_INSEEesriFieldTypeStringsqlTypeOther
CommuneCommuneesriFieldTypeStringsqlTypeOther
Pop_CommunePop_CommuneesriFieldTypeIntegersqlTypeOther
DepartementDepartementesriFieldTypeStringsqlTypeOther
Num_Unite_UrbaineNum_Unite_UrbaineesriFieldTypeStringsqlTypeOther
Unite_UrbaineUnite_UrbaineesriFieldTypeStringsqlTypeOther
Pop_Unite_UrbainePop_Unite_UrbaineesriFieldTypeIntegersqlTypeOther
Situation_GeographiqueSituation_GeographiqueesriFieldTypeStringsqlTypeOther
EcransEcransesriFieldTypeIntegersqlTypeOther
FauteuilsFauteuilsesriFieldTypeIntegersqlTypeOther
Semaines_activiteSemaines_activiteesriFieldTypeIntegersqlTypeOther
SeancesSeancesesriFieldTypeIntegersqlTypeOther
EntreesEntreesesriFieldTypeIntegersqlTypeOther
Tranches_EntreesTranches_EntreesesriFieldTypeStringsqlTypeOther
ProprietaireProprietaireesriFieldTypeStringsqlTypeOther
ProgrammateurProgrammateuresriFieldTypeStringsqlTypeOther
AEAEesriFieldTypeStringsqlTypeOther
Categorie_Art_et_EssaiCategorie_Art_et_EssaiesriFieldTypeStringsqlTypeOther
AE_RDAE_RDesriFieldTypeStringsqlTypeOther
AE_JPAE_JPesriFieldTypeStringsqlTypeOther
AE_PRAE_PResriFieldTypeStringsqlTypeOther
Label_Art_et_EssaiLabel_Art_et_EssaiesriFieldTypeStringsqlTypeOther
GenreGenreesriFieldTypeStringsqlTypeOther
MultiplexeMultiplexeesriFieldTypeStringsqlTypeOther
Categorie_ExploitationCategorie_ExploitationesriFieldTypeStringsqlTypeOther
Zone_CommuneZone_CommuneesriFieldTypeStringsqlTypeOther
QPVQPVesriFieldTypeStringsqlTypeOther
Nombre_Films_ProgrammesNombre de films programmésesriFieldTypeStringsqlTypeOther
Nombre_FilmsNombre_FilmsesriFieldTypeStringsqlTypeOther
PDM_Entrees_Films_FrancaisPDM_Entrees_Films_FrancaisesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_AméricainsPDM_Entrees_Films_AmericainsesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_EuropeensPDM_Entrees_Films_EuropeensesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_AutresPDM_Entrees_Films_AutresesriFieldTypeSinglesqlTypeOther
Films_Art_et_EssaiFilms_Art_et_EssaiesriFieldTypeStringsqlTypeOther
Part_Seances_Art_et_EssaiPart_Seances_Art_et_EssaiesriFieldTypeSinglesqlTypeOther
Part_Entrees_Art_et_EssaiPart_Entrees_Art_et_EssaiesriFieldTypeSinglesqlTypeOther
Ancien_IDAncien_IDesriFieldTypeDoublesqlTypeOther

Supprimer un champ

Nous souhaitons maintenant supprimer le champ "Ancien_ID". Pour cela, nous devons tout d'abord créer un objet JSON décrivant la propriété "name" du champ (ou des champs) à supprimer. Ensuite, la méthode "delete_from_definition" de l'objet "FeatureLayerManager" va vous permettre de supprimer effectivement le(s) champ(s) de la couche d'entités ou de la table.
In [47]:
field_to_delete={'name':'Ancien_ID'}
my_FL.manager.delete_from_definition({'fields':[field_to_delete]})
Out[47]:
{'success': True}
Reprenons le code précédement utiliser pour accéder à la couche d'entités et lister à nouveau les champs. Le champ "Ancien_ID" a bien été supprimé.
In [48]:
my_FL=FeatureLayer.fromitem(my_item,0)
my_fields=my_FL.properties.fields
strMarkdown="Name | Alias | Type | SQL Type"
strMarkdown+="\n"+"-|-|-|-"
forfieldinmy_fields:
strMarkdown+="\n"+field.name+" | "+field.alias+" | "+field.type+" | "+field.sqlType

display(Markdown(strMarkdown))
NameAliasTypeSQL Type
objectIdobjectIdesriFieldTypeOIDsqlTypeOther
IDIDesriFieldTypeIntegersqlTypeOther
NomNomesriFieldTypeStringsqlTypeOther
RegionRegionesriFieldTypeStringsqlTypeOther
AdresseAdresseesriFieldTypeStringsqlTypeOther
ComplementComplementesriFieldTypeStringsqlTypeOther
Code_INSEECode_INSEEesriFieldTypeStringsqlTypeOther
CommuneCommuneesriFieldTypeStringsqlTypeOther
Pop_CommunePop_CommuneesriFieldTypeIntegersqlTypeOther
DepartementDepartementesriFieldTypeStringsqlTypeOther
Num_Unite_UrbaineNum_Unite_UrbaineesriFieldTypeStringsqlTypeOther
Unite_UrbaineUnite_UrbaineesriFieldTypeStringsqlTypeOther
Pop_Unite_UrbainePop_Unite_UrbaineesriFieldTypeIntegersqlTypeOther
Situation_GeographiqueSituation_GeographiqueesriFieldTypeStringsqlTypeOther
EcransEcransesriFieldTypeIntegersqlTypeOther
FauteuilsFauteuilsesriFieldTypeIntegersqlTypeOther
Semaines_activiteSemaines_activiteesriFieldTypeIntegersqlTypeOther
SeancesSeancesesriFieldTypeIntegersqlTypeOther
EntreesEntreesesriFieldTypeIntegersqlTypeOther
Tranches_EntreesTranches_EntreesesriFieldTypeStringsqlTypeOther
ProprietaireProprietaireesriFieldTypeStringsqlTypeOther
ProgrammateurProgrammateuresriFieldTypeStringsqlTypeOther
AEAEesriFieldTypeStringsqlTypeOther
Categorie_Art_et_EssaiCategorie_Art_et_EssaiesriFieldTypeStringsqlTypeOther
AE_RDAE_RDesriFieldTypeStringsqlTypeOther
AE_JPAE_JPesriFieldTypeStringsqlTypeOther
AE_PRAE_PResriFieldTypeStringsqlTypeOther
Label_Art_et_EssaiLabel_Art_et_EssaiesriFieldTypeStringsqlTypeOther
GenreGenreesriFieldTypeStringsqlTypeOther
MultiplexeMultiplexeesriFieldTypeStringsqlTypeOther
Categorie_ExploitationCategorie_ExploitationesriFieldTypeStringsqlTypeOther
Zone_CommuneZone_CommuneesriFieldTypeStringsqlTypeOther
QPVQPVesriFieldTypeStringsqlTypeOther
Nombre_Films_ProgrammesNombre de films programmésesriFieldTypeStringsqlTypeOther
Nombre_FilmsNombre_FilmsesriFieldTypeStringsqlTypeOther
PDM_Entrees_Films_FrancaisPDM_Entrees_Films_FrancaisesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_AméricainsPDM_Entrees_Films_AmericainsesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_EuropeensPDM_Entrees_Films_EuropeensesriFieldTypeSinglesqlTypeOther
PDM_Entrees_Films_AutresPDM_Entrees_Films_AutresesriFieldTypeSinglesqlTypeOther
Films_Art_et_EssaiFilms_Art_et_EssaiesriFieldTypeStringsqlTypeOther
Part_Seances_Art_et_EssaiPart_Seances_Art_et_EssaiesriFieldTypeSinglesqlTypeOther
Part_Entrees_Art_et_EssaiPart_Entrees_Art_et_EssaiesriFieldTypeSinglesqlTypeOther

Ajouter un nouveau champ

L'objectif est de créer un nouveau champ dans lequel nous allons calculer le ratio entre le nombre d'entrée et le nombre de séances dans chaque cinéma. La première étape consiste à décrire, en JSON, les propriétés du nouveau champ. Se référer à la documentation de l'API Rest ArcGIS pour obtenir la liste des propriétés et valeurs supportées.
In [49]:
new_field={'alias':'Ratio des Entrees-Seances',
'domain':None,
'editable':True,
'length':10,
'name':'ratio_entrees_seances',
'nullable':True,
'sqlType':'sqlTypeOther',
'type':'esriFieldTypeDouble'}
Ensuite, vous utiliserez la méthode "add_to_definition" de l'objet "FeatureLayerManager" pour spécifier la liste des nouveaux champs à ajouter à la définition de la couche d'entités (ou de la table).
In [50]:
my_FL.manager.add_to_definition({'fields':[new_field]})
Out[50]:
{'success': True}
Vérifions que le champ a bien été ajouté en affichant le dernier champ de la table attributaire de la couche.
In [51]:
my_FL=FeatureLayer.fromitem(my_item,0)
my_fields=my_FL.properties.fields
last_field=my_fields[len(my_fields)-1]
last_field
Out[51]:
{
"domain": null,
"editable": true,
"alias": "Ratio des Entrees-Seances",
"nullable": true,
"defaultValue": null,
"sqlType": "sqlTypeOther",
"name": "ratio_entrees_seances",
"type": "esriFieldTypeDouble"
}

Associer un domaine de valeurs à un champ

Les champs d'une couche d'entités hébergée peuvent être associés à des listes de valeurs, l'équivalents des domaines de valeurs dans les Géodatabases. Voyons comment ajouter une liste de valeurs à un champ en utilisant l'API Python ArcGIS.
Tout d'abord, vous décrirez l'objet JSON du champ que vous voulez mettre à jour, en décrivant le domaine comme ci-dessous. Vous noterez que l'on ne décrit pas totalement l'objet "field", uniquement la propriétés "name" et les autres propriétés devant être modifiées, ici la propriété "domain":
In [91]:
updated_field={
'name':"Categorie_Art_et_Essai",
'domain':{
'type':"codedValue",
'name':"Categorie_Art_et_Essai_Domain",
'codedValues':[
{
'name':"Non classé",
'code':"Non classé"
},
{
'name':"Catégorie A",
'code':"Catégorie A"
},
{
'name':"Catégorie B",
'code':"Catégorie B"
}
]
},
'defaultValue':"Non classé"
}
A l'aide de la méthode "update_definition" vous appliquerez les modifications sur votre champ.
In [92]:
my_FL.manager.update_definition({'fields':[updated_field]})
Out[92]:
{'success': True}

Calculer les valeurs d'un champ

Commençons par un premier exemple dans lequel nous souhaitons mettre le champ AE (Année Exploitation) à 2017 pour les cinémas d'Ile-de-France et 2016 pour les autres régions:
In [52]:
my_FL.calculate("Region LIKE 'ILE-DE-FRANCE'",{"field":"AE","value":"2017"})
Out[52]:
{'success': True, 'updatedFeatureCount': 90}
In [53]:
my_FL.calculate("Region NOT LIKE 'ILE-DE-FRANCE'",{"field":"AE","value":"2016"})
Out[53]:
{'success': True, 'updatedFeatureCount': 911}
Ci-dessous, un deuxième exemple visant à calculer la valeur du champ "ratio_entrees_seances" par une division du nombre d'entrées par le nombre de séances, tout cela à l'aide d'une expression SQL. Le calcul sera, cette fois-ci, appliqué à tous les enregistrements de la couche d'entités:
In [54]:
my_FL.calculate("1=1",{"field":"ratio_entrees_seances","sqlExpression":"CAST(Entrees AS FLOAT) / CAST(Seances AS FLOAT)"})
Out[54]:
{'success': True, 'updatedFeatureCount': 1005}

Ajouter une entité à votre couche

Pour ajouter un nouvel enregistrement dans une couche d'entités, il vous faut tout d'abord créer l'objet "Feature" en JSON. Vous noterez que dans notre exemple, ne n'avons pas listé et renseigné tous les champs de la table.
In [55]:
new_feature={"geometry":{"y":68540528,"x":6404123},
"attributes":{"Nom":"CINEMA UGC VELIZY2","Commune":"Vélizy-Villacoublay","Code_Insee":"78640",
"Region":"ILE-DE-France","Fauteuils":750,"Seances":12}}
La méthode "edit_features" permet d'exécuter l'opération de mise à jour. On notera que l'argument "adds" permet de fournir plusieurs entités à l'aide d'un tableau d'objet "feature". A noter également que cette méthode "edit_feature" permet en une seule opération de réaliser des ajouts, des mises à jour et des suppressions.
In [56]:
my_FL.edit_features(adds=[new_feature])
Out[56]:
{'addResults': [{'globalId': None,
'objectId': 1007,
'success': True,
'uniqueId': 1007}],
'deleteResults': [],
'updateResults': []}

Mettre à jour une entité de votre une couche

Pour mettre à jour des entités existantes, il vous faudra tout d'abord les récupérer, par exemple, à l'aide d'une requête ci-dessous. A noter que l'on peut aussi construire entièrement (ou partiellement) l'objet "feature" en JSON.
In [57]:
my_featureset=my_FL.query(where="Nom LIKE 'CINEMA UGC VELIZY2'")
feature_to_update=my_featureset.features[0]
Mettre ensuite à jour les différents attributs de ces entités.
In [58]:
feature_to_update.attributes['Adresse']='Centre commercial Vélizy 2'
feature_to_update.attributes['Multiplexe']='Oui'
Nous utilisons à nouveau la méthode "edit_features" avec l'argument "updates" pour mettre à jour la liste d'objets "feature" à actualiser dans la couche d'entités.
In [59]:
my_FL.edit_features(updates=[feature_to_update])
Out[59]:
{'addResults': [],
'deleteResults': [],
'updateResults': [{'globalId': None,
'objectId': 1002,
'success': True,
'uniqueId': 1002}]}

Supprimer une entité dans une couche

La suppression d'une (ou plusieurs) entité(s) se fait de différentes manières. Vous pouvez utiliser, comme précédement, la méthode "edit_features" peut être utilisée en fournissant la liste des entités en JSON avec leur propriété "ObjectId". Vous pouvez également utiliser la méthode "delete_features" et fournir une requête définissant les entités à supprimer.
In [60]:
my_FL.delete_features(where="Nom LIKE 'CINEMA UGC VELIZY2'")
Out[60]:
{'deleteResults': [{'globalId': None,
'objectId': 1002,
'success': True,
'uniqueId': 1002},
{'globalId': None, 'objectId': 1007, 'success': True, 'uniqueId': 1007}]}

Activer les pièces-jointes sur une couche d'entité

Pour pouvoir ajouter des pièces-jointes (attachments en anglais) aux entités de votre couche, vous devez tout d'abord activer le stockage des pièces-jointes sur la couche. Pour cela, nous passons à nouveau par la modification de la définition de la couche.
In [61]:
attachment_JSON={'hasAttachments':True}
my_FL.manager.update_definition(attachment_JSON)
Out[61]:
{'success': True}

Ajouter des pièces-jointes

Maintenant que la couche dispose de la structure pour le stockage de pièces-jointes, la méthode "add" sur la propriété "attachments" permet d'ajouter votre fichier. Vous noterez que le premier argument de la méthode "add" correspond à l'objectID de l'entité. Recherchons le cinéma "Caméo Commanderie" à Nancy pour lui associer une photo.
In [62]:
my_featureset=my_FL.query(where="Nom LIKE 'Caméo Commanderie Nancy'")
feature_oid=my_featureset.features[0].get_value('objectId')
my_FL.attachments.add(feature_oid,'/Users/glavenu/Documents/SIG/temp/cameo_nancy.jpg')
Out[62]:
{'addAttachmentResult': {'globalId': None, 'objectId': 1, 'success': True}}

Lister les pièces-jointes d'une entité

Pour lister les pièces-jointes d'une entité, il suffira de rechercher l'entité puis d'utiliser la méthode
In [65]:
my_featureset=my_FL.query(where="Nom LIKE 'Kinépolis Nancy'")
feature_oid=my_featureset.features[0].get_value('objectId')
my_attachements=my_FL.attachments.get_list(feature_oid)
my_attachements
Out[65]:
[{'contentType': 'image/jpeg',
'id': 2,
'keywords': '',
'name': 'kinepolis_nancy1.jpg',
'parentObjectId': 1005,
'size': 115106},
{'contentType': 'image/jpeg',
'id': 3,
'keywords': '',
'name': 'kinepolis_nancy2.jpg',
'parentObjectId': 1005,
'size': 9671},
{'contentType': 'image/jpeg',
'id': 4,
'keywords': '',
'name': 'kinepolis_nancy3.jpg',
'parentObjectId': 1005,
'size': 22707},
{'contentType': 'image/jpeg',
'id': 5,
'keywords': '',
'name': 'kinepolis_nancy4.jpg',
'parentObjectId': 1005,
'size': 109055}]

Supprimer des pièces-jointes

Ci-dessous, un exemple de code permettant de supprimer la dernière pièce-jointe de l'entité listé précédement. . La méthode "delete" appliquée à la propriété "attachments" permet de supprimer une pièce jointe en précisant l'ObjectID de l'entité et l'ID de la pièce-jointe.
Pour mémoire, en Python, l'index -1 permet d'accéder au dernier élément d'un tableau ou d'une liste
In [66]:
my_FL.attachments.delete(my_attachements[-1]['parentObjectId'],my_attachements[-1]['id'])
Out[66]:
{'deleteAttachmentResults': [{'globalId': None,
'objectId': 5,
'success': True}]}
In [68]:
my_attachements=my_FL.attachments.get_list(feature_oid)
my_attachements
Out[68]:
[{'contentType': 'image/jpeg',
'id': 2,
'keywords': '',
'name': 'kinepolis_nancy1.jpg',
'parentObjectId': 1005,
'size': 115106},
{'contentType': 'image/jpeg',
'id': 3,
'keywords': '',
'name': 'kinepolis_nancy2.jpg',
'parentObjectId': 1005,
'size': 9671},
{'contentType': 'image/jpeg',
'id': 4,
'keywords': '',
'name': 'kinepolis_nancy3.jpg',
'parentObjectId': 1005,
'size': 22707}]

Télécharger les pièces-jointes

Pour être complet sur la manipulation des pièces-jointes, vois les instruction permettant de les télécharger en local.
In [79]:
img=my_FL.attachments.download(oid=feature_oid,attachment_id=4)
img
Out[79]:
['/var/folders/8q/lxsbl08d1sj4lsjypx2hkk580000gn/T/kinepolis_nancy3.jpg']
Si la pièce-jointe est une image et que vous souhaitez la visualiser dans votre Notebook, vous pouvez utiliser les instructions suivantes:
In [80]:
fromIPython.core.displayimportImage,display
img_path=img[0]
display(Image(img_path))


Viewing all articles
Browse latest Browse all 2035

Trending Articles