Como adicionar um campo de atributo ao Shapefile existente via Python sem ArcGIS?

24

Eu tenho um script Python que adiciona um campo de atributo a um Shapefile, se não existir. Isso é fácil de fazer com o ArcGIS (graficamente ou via Python), mas estou procurando algo que não dependa do ArcGIS.

Tentei isso sem sucesso com o OGR, pois meu Shapefile contém recursos .

Eu olhei para o pyshp , mas da mesma forma não há como modificar o esquema depois que ele foi criado. Não experimentei o shapefile (para Python) , mas não vejo esse recurso anunciado. Também não consigo ver como isso pode ser feito alterando o arquivo DBF via dbfpy .

Alguém tem alguma idéia?

Mike T
fonte
Seria aceitável clonar a estrutura existente do shapefile, adicionar uma nova coluna e preenchê-la com base no shapefile original?
davidf
Esta questão deve ser encerrada como uma duplicata do gis.stackexchange.com/q/3623/664 .
whuber
Sim, essencialmente o mesmo. Eu olhei, mas não vi.
Mike T

Respostas:

4

Graças a um formato de morte cerebral denominado DBF, a adição de campos aos shapefiles com dados de atributos existentes não é possível sem reescrever ou adicionar preenchimento ao DBF. Não conheço uma solução pronta, mas o que eu faria é escrever um script para criar um novo shapefile com base em um existente e adicionar campos extras ao novo shapefile. Em seguida, copie os dados da geometria / atributo do antigo para o novo shapefile. E como etapa final, remova o antigo shapefile e renomeie o novo. Tudo isso é facilmente realizado usando ligações OGR python.

Como alternativa, você pode usar o dbfpy para fazer o acima com apenas o arquivo DBF. A ordem das etapas permanece a mesma:

  1. Crie um novo DBF com estrutura idêntica à original
  2. Crie novos campos de atributo no novo DBF
  3. Copiar dados do DBF original para o novo DBF
  4. Remova o DBF antigo, renomeie o novo DBF para DBF antigo

Você não precisa fazer alterações no próprio shapefile (.shp) ou em qualquer outro arquivo, pois eles não fazem referência às informações de atributo contidas no DBF. No entanto, é necessário manter a ordem dos registros exatamente igual no DBF antigo e no novo.

Sasa Ivetic
fonte
3

DBFpy deve funcionar para isso. Você já viu o exemplo nesta página:

http://dbfpy.sourceforge.net/

Verifique se o shapefile não está sendo editado por nenhum outro aplicativo, incluindo o ArcGIS, no momento, pois isso pode causar problemas através do bloqueio.

Rob Clark
fonte
Eu não acho que isso funcione se você já tiver dados no arquivo DBF. Eu já tinha analisado isso antes, mas recebo um erro: "Pelo menos um registro foi adicionado, a estrutura não pode ser alterada". Você tem algum exemplo específico em mente?
Mike T
Ah, lembro-me agora sim, pois Sasa disse que a criação de um novo DBF seria necessária. Copie o esquema (como nos campos etc.) e, em seguida, faça suas adições e copie os registros. O "ótimo" DBF ... :(
Rob Clark
@ Mike Como foi adicionado um registro quando tudo que você quer fazer é adicionar um campo ? A adição de um registro é um erro porque estraga a conexão entre os atributos e as formas. Adicionar um campo não faz mal algum. Qualquer biblioteca que possa editar arquivos dbf fará o trabalho corretamente.
whuber
@ whuber: Essa é a sua mensagem de erro. Abra um dbf existente que tenha dados e consulte: #from dbfpy import dbf; db = dbf.Dbf('my.dbf'); db.addField(("FOO", "C", 15))
Mike T
@ Mike Obrigado por esclarecer a situação. Isso parece o resultado de uma limitação desnecessária no dbfpy :-(. Eu posso adivinhar o porquê: adicionar um campo em um banco de dados não vazio exige que todos os registros sejam lidos, expandidos e gravados fisicamente novamente. Uma boa solução é para encontrar uma biblioteca dBase diferente ou usar outro software ;-).
whuber
1

Encontrei uma solução usando o OGR e obrigado por ajudar de uma pergunta anterior . Aqui está um exemplo completo:

from osgeo import ogr

# Open a Shapefile, and get field names
source = ogr.Open('my.shp', update=True)
layer = source.GetLayer()
layer_defn = layer.GetLayerDefn()
field_names = [layer_defn.GetFieldDefn(i).GetName() for i in range(layer_defn.GetFieldCount())]
print len(field_names), 'MYFLD' in field_names

# Add a new field
new_field = ogr.FieldDefn('MYFLD', ogr.OFTInteger)
layer.CreateField(new_field)

# Close the Shapefile
source = None

Meu problema era que eu usei layer_defn.AddFieldDefn(new_field)e não layer.CreateField(new_field). Muito obrigado pela ajuda e desculpe-me por não ter verificado completamente a outra pergunta semelhante.

Mike T
fonte