Jak dodać pole atrybutu do istniejącego pliku Shapefile przez Python bez ArcGIS?

24

Mam skrypt w języku Python, który dodaje pole atrybutu do pliku Shapefile, jeśli nie istnieje. Jest to łatwe do zrobienia w ArcGIS (graficznie lub przez Python), ale szukam czegoś, co nie zależy od ArcGIS.

Próbowałem tego bez powodzenia z OGR, ponieważ mój plik Shapefile zawiera funkcje .

Patrzyłem na pyshp , ale podobnie nie ma sposobu, aby zmodyfikować schemat po jego utworzeniu. Nie próbowałem z shapefile (dla Pythona) , ale nie widzę tej funkcji reklamowanej. Nie widzę też, jak można to zrobić, majstrując przy pliku DBF przez dbfpy .

Czy ktoś ma jakieś pomysły?

Mike T.
źródło
Czy akceptowalne byłoby sklonowanie istniejącej struktury pliku kształtu, dodanie nowej kolumny, a następnie wypełnienie jej na podstawie oryginalnego pliku kształtu?
DavidF
możliwy duplikat dodawania niestandardowych atrybutów funkcji do
pliku kształtu
To pytanie powinno zostać zamknięte jako duplikat gis.stackexchange.com/q/3623/664 .
whuber
Tak, zasadniczo to samo. Spojrzałem, ale tego nie widziałem.
Mike T

Odpowiedzi:

4

Dzięki dość nieprzytomnemu formatowi zwanemu DBF, dodawanie pól do plików kształtów z istniejącymi danymi atrybutów nie jest możliwe bez przepisywania lub dodawania dopełniania do DBF. Nie znam gotowego rozwiązania, ale chciałbym napisać skrypt, aby utworzyć nowy plik shapefile w oparciu o istniejący i dodać dodatkowe pola do nowego pliku shapefile. Następnie skopiuj dane geometrii / atrybutu ze starego do nowego pliku kształtu. Na koniec usuń stary plik kształtu i zmień nazwę nowego. Wszystko to można dość łatwo osiągnąć za pomocą powiązań pytona OGR.

Alternatywnie możesz użyć dbfpy, aby wykonać powyższe czynności tylko za pomocą pliku DBF. Kolejność kroków pozostaje taka sama:

  1. Utwórz nowy DBF o identycznej strukturze jak oryginał
  2. Utwórz nowe pola atrybutów w nowym DBF
  3. Skopiuj dane z oryginalnego DBF do nowego DBF
  4. Usuń stary DBF, zmień nazwę nowego DBF na stary DBF

Nie musisz wprowadzać żadnych zmian w samym pliku shapefile (.shp) ani w żadnym innym pliku, ponieważ nie odwołują się one do informacji o atrybutach zawartych w DBF. Musisz jednak zachować dokładnie taką samą kolejność rekordów w starym i nowym DBF.

Sasa Ivetic
źródło
3

DBFpy powinien na to działać. Czy widziałeś wtedy przykład na tej stronie:

http://dbfpy.sourceforge.net/

Upewnij się, że plik kształtu nie jest edytowany przez żadną inną aplikację, w tym ArcGIS, ponieważ może to powodować problemy z blokowaniem.

Rob Clark
źródło
Nie sądzę, że to działa, jeśli masz już dane w pliku DBF. Patrzyłem na to wcześniej, ale pojawia się błąd: „Dodano co najmniej jeden rekord, nie można zmienić struktury”. Czy masz na myśli jakiś konkretny przykład?
Mike T
Ach, pamiętam teraz tak, ponieważ Sasa powiedział, że konieczne będzie utworzenie nowego DBF. Skopiuj schemat (jak w polach itp.), Następnie dodaj go, a następnie skopiuj rekordy. „Świetny” DBF ... :(
Rob Clark
@ Mike Jak został dodany rekord, gdy wszystko, co chcesz zrobić, to dodać pole ? Dodanie rekordu jest błędem, ponieważ niszczy połączenie między atrybutami a kształtami. Dodanie pola w ogóle nie zaszkodzi. Każda biblioteka, która może edytować pliki dbf, wykona zadanie poprawnie.
whuber
@whuber: To jest ich komunikat o błędzie. Otwórz istniejący plik dbf z danymi i zobacz:from dbfpy import dbf; db = dbf.Dbf('my.dbf'); db.addField(("FOO", "C", 15))
Mike T
@ Mike Dziękuję za wyjaśnienie sytuacji. To brzmi jak wynik niepotrzebnego ograniczenia w dbfpy :-(. Mogę zgadnąć dlaczego: dodanie pola w niepustej bazie danych wymaga fizycznego odczytu, rozszerzenia i ponownego zapisania wszystkich rekordów. Dobrym rozwiązaniem jest znaleźć inną bibliotekę dBase lub użyć innego oprogramowania ;-).
whuber
1

Znalazłem rozwiązanie przy użyciu OGR i dzięki pomocy z poprzedniego pytania . Oto kompletny przykład:

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

Mój problem polegał na tym, że layer_defn.AddFieldDefn(new_field)raczej go użyłem layer.CreateField(new_field). Wielkie dzięki za pomoc i przepraszam, że nie sprawdziłem dokładnie tego samego innego pytania.

Mike T.
źródło