Suite

Utiliser PyShp pour convertir des polygones dans des fichiers *.csv en fichiers *.shp ?

Utiliser PyShp pour convertir des polygones dans des fichiers *.csv en fichiers *.shp ?


Je convertis les données csv en fichiers de formes à l'aide de la bibliothèque pyshp python. Ce que je veux faire est très similaire à Utiliser pyshp pour convertir un fichier .csv en .shp ?, sauf que je ne sais pas comment gérer les polygones.

Mes données sont dans un fichier csv. Chaque ligne correspond à un rectangle nommé, c'est-à-dire une chaîne et les coordonnées de latitude ou de longitude de chaque côté du rectangle : côté gauche (xl), côté droit (xr), haut (yt) et bas (yb).

Mes données ressemblent donc à ceci :

nom,xl,xr,yt,yb un nom,-25,3125,22,5,47,517193,31,353634 un autre nom,-103,359375,-0,703125,80,87282,74,40216…

Et mon code python est assez simple. Il n'est que légèrement modifié par rapport à l'exemple des points. Mais lorsque j'essaie d'importer ces données dans Google Maps, il y a des erreurs d'analyse. Donc je pense que je fais quelque chose de mal, mais je ne sais pas quoi ?

#Configurer des listes vides pour le nom des données, polyPart = [],[] #lire les données du fichier csv et les stocker dans des listes avec open(in_file, 'rb') en tant que csvfile : r = csv.reader(csvfile, delimiter=", ") for i,row in enumerate(r): if i > 0: #skip header # analyse les données dans un tableau de points représentant le cadre de délimitation xl = float(row[1]) xr = float(row[2]) yt = float(row[3]) yb = float(row[4]) tl = [xl, yt] tr = [xr, yt] br = [xr, yb] bl = [xl, yb] parr = [tl, tr, br, bl, tl] # tableau d'une "partie", la partie est un tableau de points polyPart.append([parr]) name.append(row[0]) #Configurer le rédacteur de fichier de formes et créer des champs vides maxStringLength = 50 w = shp.Writer(shp.POLYGON) w.field('name','C',maxStringLength) # parcourez les données et écrivez le shapefile pour j, nom dans énumérer(nom) : w.poly(parties =polyPart[j]) w.record(name) #Save shapefile w.save(out_file)

Votre approche est bonne, mais vous pourriez rendre les choses plus claires en utilisant des dictionnaires au lieu de liste et le module csv le permet.
De plus, votre script utilise deux boucles alors qu'il est possible de simplifier en n'en utilisant qu'une (la deuxième boucle est redondante, une ligne du fichier csv = un enregistrement du shapefile).

1) Avec des dictionnaires :

Lecture du fichier csv :

avec open('votre.csv', 'rb') en tant que f: reader = csv.DictReader(f) pour la ligne dans le lecteur: print row {'xr': '22.5', 'yb': '31.353634', 'name ': 'un nom', 'xl': '-25.3125', 'yt': '47.517193'} {'xr': '-0.703125', 'yb': '74.40216', 'nom': 'un autre nom' , 'xl' : '-103.359375', 'yt' : '80.87282'}

Vous pouvez maintenant utiliser row['xr'] ou row['name'] au lieu de row[n] (plus explicite)

Donc votre script devient :

importer csv polyName, polyPart = [],[] avec open('votre.csv', 'rb') comme f: reader = csv.DictReader(f) pour la ligne dans le lecteur : bl = [float(row['xl' ]),float(row['yb'])] tl = [float(row['xl']),float(row['yt'])] br = [float(row['xr']),float (row['yb'])] tr = [float(row['xr']),float(row['yt'])] parr = [tl, tr, br, bl, tl] polyName.append(row ['nom']) polyPart.append(parr)

Écriture du fichier de formes de polygones

Si vous regardez PyShpDocs, vous pouvez voir que :

Un polygone est défini par :

w = shapefile.Writer(shapefile.POLYGON) w.line(parts=[[[1,5],[5,5],[5,1],[3,3],[1,1]]])

et le script, comme vous l'avez écrit est :

import shapefile # créer le fichier de formes de polygones w = shapefile.Writer(shapefile.POLYGON) # le champ w.field('name','C',maxStringLength) # écrire les polygones dans le shapefile pour part,name in zip(polyPart, polyName): w.poly(parts=[part]) w.record(name) #enregistrer le shapefile w.save('votre.shp')

2) Solution finale utilisant une seule boucle

Mais la deuxième boucle n'est pas nécessaire ici : vous pouvez tout faire avec une seule boucle (lecture du fichier csv et écriture du fichier de formes sans utiliser les listes polyName et polyPart).

w = shapefile.Writer(shapefile.POLYGON) w.field('name','C',50) avec open('your.csv', 'rb') comme f: reader = csv.DictReader(f) pour la ligne dans le lecteur : bl = [float(row['xl']),float(row['yb'])] tl = [float(row['xl']),float(row['yt'])] br = [float(row['xr']),float(row['yb'])] tr = [float(row['xr']),float(row['yt'])] parr = [tl, tr, br, bl, tl] w.poly(parts=[parr]) w.record(row['nom']) w.save("votre.shp')

Résultat dans QGIS :


Ce n'est pas une bonne pratique de codage de définir votre variable d'itérateur dans une boucle for sur le même nom de la liste que vous parcourez. Vous devriez changer l'un desNomvariables.

J'ai exécuté votre code sur ma machine avec votre petit ensemble de données et il a correctement créé le fichier de formes. Je peux l'afficher dans ArcMap, avec la table attributaire. Bien sûr, il n'y a pas de référence spatiale associée à ces données, vous voudrez donc probablement en définir une, comme décrit ici. Je mettrais certainement cela en œuvre avant d'aller plus loin.

En tout cas, vous trouverez peut-être plus facile de travailler avec cela. J'ai (espérons-le) simplifié quelques choses :

import shapefile as shp import csv in_file = "C:/users/paul/desktop/test.csv" out_file = "C:/users/paul/desktop/test.shp" #Configurer des listes vides pour les données polyName, polyPart = [ ],[] #lire les données du fichier csv et les stocker dans des listes avec open(in_file, 'rb') en tant que csvfile : r = csv.reader(csvfile, delimiter=",") #Sauter automatiquement l'en-tête. next(r, None) for row in r: # analyse les données dans un tableau de points représentant le cadre de délimitation xl = float(row[1]) xr = float(row[2]) yt = float(row[3]) yb = float(ligne[4]) tl = [xl, yt] tr = [xr, yt] br = [xr, yb] bl = [xl, yb] parr = [tl, tr, br, bl, tl] # tableau d'une "partie", la partie est un tableau de points polyPart.append([parr]) polyName.append(row[0]) #Configurez le rédacteur de fichier de formes et créez des champs vides maxStringLength = 50 w = shp.Writer(shp .POLYGON) w.field('name','C',maxStringLength) # parcourez les données et écrivez le fichier de formes pour part,name dans zip(polyPart, polyName): w.poly(parts=part) w.record( nom) #Save shapefile w.save(out_file)

Vous pouvez le faire en quelques lignes avec shapely et GeoPandas (qui utilise Fiona sous le capot pour les entrées/sorties de fichiers). Vous pouvez utilisershapely.geometry.boxpour créer les rectangles, convertissez-le en unGeoDataFrame, et utilisez levers_fichierméthode pour enregistrer en tant que fichier de formes :

de pandas importer DataFrame de geopandas importer GeoDataFrame de shapely.geometry import box data = DataFrame.from_csv('rect.csv') boxes = [box(row['xl'], row['yb'], row['xr' ], ligne['yt']) pour la clé, ligne dans data.iterrows()] df = GeoDataFrame(boxes, colonnes=['geometry'], index=data.index) df.to_file('out.shp', driver="ESRI Shapefile")

voici le code écrit avec shapefile importer chaque ligne bien commentée pour écrire le code de manière efficace. il écrit le shapefile avec projection.

import shapefile import csv import ast # read csv with open(r"Sample_Data.csv", encoding="utf8") as csvfile: # dict create dictReader=csv.DictReader(csvfile) # create shapefile inscriptible w = shapefile.Writer(' Sample_Data.shp') # créer l'attribut w.field('id', 'C') w.field('nieghborho', 'C') w.field('plan_no', 'C') # ligne de dict pour ligne dans dictReader : # écrire l'attribut de ligne w.record(row['id'], row['nieghborhood'], row['plan_no']) # écrire geom w.poly([ast.literal_eval(row['geom'] )]) # créer un fichier prj prj = open("Sample_Data.prj", "w") epsg = 'GEOGCS["WGS 84",' epsg += 'DATUM["WGS_1984",' epsg += 'SPHEROID[" WGS 84",6378137,298.257223563]]' epsg += ',PRIMEM["Greenwich",0],' epsg += 'UNIT["degree",0.0174532925199433]]' # enregistrer le fichier prj prj.write(epsg) # fermer au-dessus du fichier de formes w.close()

Voir la vidéo: Pinta-alan yksiköitä