Mais

Usando PyShp para converter polígonos em arquivos * .csv para * .shp?


Estou convertendo dados csv em shapefiles usando a biblioteca pyshp python. O que desejo fazer é muito semelhante a Usar pyshp para converter arquivo .csv em .shp ?, exceto que não sei como lidar com polígonos.

Meus dados estão em um arquivo csv. Cada linha corresponde a um retângulo nomeado, ou seja, uma string e as coordenadas de latitude ou longitude de cada lado do retângulo: lado esquerdo (xl), lado direito (xr), superior (yt) e inferior (yb).

Então, meus dados são assim:

nome, xl, xr, yt, yb algum Nome, -25.3125,22.5,47.517193,31.353634 outro Nome, -103.359375, -0.703125,80.87282,74.40216…

E meu código python é muito simples. É apenas ligeiramente modificado a partir do exemplo de pontos. Mas quando tento importar esses dados para o google maps, ocorrem alguns erros ao analisá-los. Acho que estou fazendo algo errado, mas não tenho certeza do quê?

# Configure listas em branco para o nome dos dados, polyPart = [], [] # leia os dados do arquivo csv e armazene em listas com aberto (in_file, 'rb') como csvfile: r = csv.reader (csvfile, delimiter = ", ") para i, linha em enumerar (r): if i> 0: #pular cabeçalho # analisa os dados em uma matriz de pontos que representa a caixa delimitadora xl = float (linha [1]) xr = float (linha [2]) yt = float (linha [3]) yb = float (linha [4]) tl = [xl, yt] tr = [xr, yt] br = [xr, yb] bl = [xl, yb] parr = [tl, tr, br, bl, tl] # array de uma "parte", a parte é um array de pontos polyPart.append ([parr]) name.append (row [0]) #Configure o gravador de shapefile e crie campos vazios maxStringLength = 50 w = shp.Writer (shp.POLYGON) w.field ('name', 'C', maxStringLength) #loop através dos dados e escrever o shapefile para j, nome em enumerar (nome): w.poly (partes = polyPart [j]) w.record (nome) #Save shapefile w.save (out_file)

Sua abordagem é boa, mas você pode tornar as coisas mais claras usando dicionários em vez de lista e o módulo csv permite isso.
Além disso, seu script usa dois loops enquanto é possível simplificar usando apenas um (o segundo loop é redundante, uma linha do arquivo csv = um registro do shapefile).

1) Com dicionários:

Lendo o arquivo csv:

com open ('your.csv', 'rb') como f: reader = csv.DictReader (f) para linha no leitor: imprimir linha {'xr': '22 .5 ',' yb ': '31 .353634', 'nome ':' algum nome ',' xl ':' -25.3125 ',' yt ': '47 .517193'} {'xr': '-0.703125', 'yb': '74 .40216 ',' nome ':' outro nome ' , 'xl': '-103.359375', 'yt': '80 .87282 '}

Agora você pode usar linha ['xr'] ou linha ['nome'] em vez de linha [n] (mais explícito)

Portanto, seu script se torna:

import csv polyName, polyPart = [], [] com open ('your.csv', 'rb') como f: reader = csv.DictReader (f) para linha no leitor: bl = [float (row ['xl' ]), float (row ['yb'])] tl = [float (row ['xl']), float (row ['yt'])] br = [float (row ['xr']), float (linha ['yb'])] tr = [float (linha ['xr']), float (linha ['yt'])] parr = [tl, tr, br, bl, tl] polyName.append (linha ['nome']) polyPart.append (parr)

Escrevendo o shapefile do polígono

Se você olhar para PyShpDocs, verá que:

Um polígono é definido por:

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

e o script, como você escreveu é:

import shapefile # cria o shapefile de polígono w = shapefile.Writer (shapefile.POLYGON) # o campo w.field ('name', 'C', maxStringLength) # escreve os polígonos no shapefile para parte, nome em zip (polyPart, polyName): w.poly (parts = [part]) w.record (name) #save the shapefile w.save ('your.shp')

2) Solução final usando apenas um loop

Mas o segundo loop não é necessário aqui: você pode fazer tudo com um loop (ler o arquivo csv e escrever o arquivo de forma sem usar as listas polyName e polyPart).

w = shapefile.Writer (shapefile.POLYGON) w.field ('name', 'C', 50) com open ('your.csv', 'rb') como f: reader = csv.DictReader (f) para linha no leitor: 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 (partes = [parr]) w.record (linha ['nome']) w.save ("seu.shp ')

Resultado no QGIS:


Não é uma boa prática de codificação definir sua variável iteradora em um loop for com o mesmo nome da lista que você está executando em loop. Você deve mudar um dosnomevariáveis.

Eu executei seu código na minha máquina com seu pequeno conjunto de dados e ele criou corretamente o shapefile. Consigo visualizá-lo no ArcMap, junto com a tabela de atributos. Obviamente, não há referência espacial associada a esses dados, então provavelmente você desejará definir uma, conforme descrito aqui. Eu definitivamente implementaria isso antes de prosseguir.

De qualquer forma, você pode achar mais fácil trabalhar com isso. Eu (espero) simplifiquei algumas coisas:

import shapefile as shp import csv in_file = "C: /users/paul/desktop/test.csv" out_file = "C: /users/paul/desktop/test.shp" # Configure listas em branco para os dados polyName, polyPart = [ ], [] #ler dados do arquivo csv e armazenar em listas com open (in_file, 'rb') como csvfile: r = csv.reader (csvfile, delimiter = ",") #Pular cabeçalho automaticamente. próximo (r, Nenhum) para linha em r: # analisa os dados em uma matriz de pontos que representa a caixa delimitadora xl = float (linha [1]) xr = float (linha [2]) yt = float (linha [3]) yb = float (linha [4]) tl = [xl, yt] tr = [xr, yt] br = [xr, yb] bl = [xl, yb] parr = [tl, tr, br, bl, tl] # matriz de uma "parte", a parte é uma matriz de pontos polyPart.append ([parr]) polyName.append (linha [0]) #Configure o gravador do arquivo de forma e crie campos vazios maxStringLength = 50 w = shp.Writer (shp .POLYGON) w.field ('name', 'C', maxStringLength) #loop através dos dados e escrever o arquivo de forma para parte, nome em zip (polyPart, polyName): w.poly (partes = parte) w.record ( nome) #Save shapefile w.save (out_file)

Você poderia fazer isso em algumas linhas com shapely e GeoPandas (que usa Fiona sob o capô para o arquivo i / o). Você pode usarshapely.geometry.boxpara criar os retângulos, converta-os em umGeoDataFrame, e usar oarquivarmétodo para salvar como um arquivo de forma:

from pandas import DataFrame from geopandas import GeoDataFrame from shapely.geometry import box data = DataFrame.from_csv ('rect.csv') boxes = [box (linha ['xl'], linha ['yb'], linha ['xr' ], linha ['yt']) para chave, linha em data.iterrows ()] df = GeoDataFrame (caixas, colunas = ['geometry'], index = data.index) df.to_file ('out.shp', driver = "ESRI Shapefile")

aqui está o código escrito com shapefile import cada linha bem comentada para escrever o código de maneira eficiente. ele escreve o shapefile com projeção.

import shapefile import csv import ast # ler csv com open (r "Sample_Data.csv", encoding = "utf8") como csvfile: # dict criar dictReader = csv.DictReader (csvfile) # criar shapefile gravável w = shapefile.Writer (' Sample_Data.shp ') # criar atributo w.field (' id ',' C ') w.field (' nieghborho ',' C ') w.field (' plan_no ',' C ') # linha de dict para linha em dictReader: # write row attribute w.record (row ['id'], row ['nieghborhood'], row ['plan_no']) # write geom w.poly ([ast.literal_eval (row ['geom'] )]) # criar arquivo 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 + =' UNIDADE [" grau ", 0.0174532925199433]] '# salvar arquivo prj prj.write (epsg) # fechar acima do arquivo de forma w.close ()


Assista o vídeo: PyShp - Reading Shapefile Python (Outubro 2021).