Czy automatyzacja pola tabeli atrybutów QGIS?

9

Pracuję w taki sposób, aby tworzyć projekty hydrologiczne za pomocą QGIS i arkusza programu Excel, który mam. Aby to zrobić, chcę wyodrębnić niektóre informacje o liniach zawartych w warstwie wektorowej, która reprezentuje odcinek rury.

Informacje, które muszę wyodrębnić to:

  • Numer identyfikacyjny
  • Długość
  • Współrzędne początkowe i końcowe X, Y

Znalazłem sposób na przechwycenie tego pola za pomocą „$ length” i innego algorytmu dla współrzędnych X i Y, ale w tym celu muszę otworzyć tabelę Atrybuty, umieścić wyrażenia w każdej kolumnie atrybutu i kliknąć, aby zaktualizować pola.

Czy istnieje sposób, aby po narysowaniu linii pola te były wypełniane automatycznie? To znaczy, rysuję / edytuję linię (rozpoczynam edycję lub koniec węzła), a kiedy otwieram tabelę atrybutów, pola długości i współrzędne X, Y są wypełniane i aktualizowane.

LeoNazareth
źródło
1
Nie jestem pewien, czy jest to możliwe w trybie edycji, ponieważ odbywa się to w tabeli tymczasowej. Ale możesz rzucić okiem na działania. Możesz ich użyć na przykład do uruchomienia kodu Pythona w celu wypełnienia obliczeń. Cóż, musisz nacisnąć dodatkowy przycisk, aby uruchomić go z tabeli atrybutów. Możesz spojrzeć na dostępne możliwości i sprawdzić, czy pasuje to do Twojego pomysłu.
Matte

Odpowiedzi:

7

Jeśli potrzebujesz tylko tych pól w QGIS , możesz użyć pól wirtualnych. Pozwalają one na użycie wyrażenia (podobnego $length) zależnego od innych wartości lub geometrii.

Otwórz kalkulator pola, dodaj nowe pole o długości nazwy, zaznacz pole wyboru „Pole wirtualne” i wprowadź $lengthjako wyrażenie (lub coś innego dla pozostałych pól).

Nie zostaną one jednak zapisane w pliku programu Excel.

Jeśli chcesz synchronizować plik programu Excel z plikiem shp dla geometrii i dołączać pola pochodne do pliku programu Excel, istnieje wtyczka o nazwie ShpSync, która zna tę koncepcję i automatycznie aktualizuje pola, gdy funkcje są zmieniane, dodawane lub usuwane.

Matthias Kuhn
źródło
W rzeczywistości poniższa odpowiedź działa dokładnie tak, jak chcę, ale ta wtyczka, o której mówiłeś, zadziała w następnym etapie mojego projektu. Dziękuję za pomoc
LeoNazareth,
15

Interesujące pytanie! Nie znam żadnego innego sposobu osiągnięcia tego, co chcesz, ale używając PyQGIS.

Przeczytaj poniższy kod. Ma pewne teksty w niej: 'lines', 'length', 'startX', 'startY', 'endX', 'endY'. Możesz dostosować te nazwy w skrypcie, aby działał on na twoich danych. Pierwszy to nazwa warstwy, a reszta odpowiada nazwom pól. Zakładam, że twoja warstwa liniowa ma te pola (w końcu chcesz, żeby tam były zapisane wartości).

Po dostosowaniu nazwy warstwy i nazw pól, które mają być automatycznie aktualizowane, skopiuj i wklej skrypt do konsoli QGIS Python.

Jeśli wszystko pójdzie dobrze, powinieneś zobaczyć, że wartości pól są automatycznie aktualizowane w dwóch scenariuszach: 1) Po dodaniu nowych elementów i 2) Po modyfikacji geometrii.

# Initialize required variables
myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
lengthField = myLayer.fieldNameIndex( 'length' )
startXField = myLayer.fieldNameIndex( 'startX' )
startYField = myLayer.fieldNameIndex( 'startY' )
endXField = myLayer.fieldNameIndex( 'endX' )
endYField = myLayer.fieldNameIndex( 'endY' )

# Slot, updates field values
def updateFeatureAttrs( fId, geom=None ):
    f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
    if not geom:
        geom = f.geometry() 
    myLayer.changeAttributeValue( fId, lengthField, geom.length() )
    myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
    myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
    myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
    myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )

# Update feature attributes when new features are added or geometry changes
myLayer.featureAdded.connect( updateFeatureAttrs )
myLayer.geometryChanged.connect( updateFeatureAttrs )

Tak to działa:

Automatyczne aktualizacje pól w QGIS

Jeśli masz problem z uruchomieniem skryptu, dodaj komentarz poniżej tej odpowiedzi.

Może się przydać, aby ta funkcja była już dostępna po otwarciu projektu QGIS. Jeśli tak jest, powiedz mi, że mogę zamieścić instrukcje, aby to zrobić.


EDYTOWAĆ:

Aby ta funkcja była dostępna za każdym razem, gdy otwierasz swój projekt QGIS (tj. .qgsPlik zawierający między innymi warstwę liniową), musisz wykonać następujące kroki:

  1. Przejdź do QGIS->Project->Project Properties->Macros, zaznacz Python macrosopcję i zastąp cały kod tym kodem (dostosuj wartości wskazujące nazwy warstw i pól):

    from qgis.core import QgsMapLayerRegistry, QgsFeatureRequest
    def openProject():    
        # Initialize required variables
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
    
        # Update feature attributes when new features are added or geometry changes
        myLayer.featureAdded.connect( updateFeatureAttrs )
        myLayer.geometryChanged.connect( updateFeatureAttrs )
    
    # Slot, updates field values
    def updateFeatureAttrs( fId, geom=None ):
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
        lengthField = myLayer.fieldNameIndex( 'length' )
        startXField = myLayer.fieldNameIndex( 'startX' )
        startYField = myLayer.fieldNameIndex( 'startY' )
        endXField = myLayer.fieldNameIndex( 'endX' )
        endYField = myLayer.fieldNameIndex( 'endY' )
        f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
        if not geom:
            geom = f.geometry() 
        myLayer.changeAttributeValue( fId, lengthField, geom.length() )
        myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
        myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
        myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
        myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )
    
    def saveProject():
        pass
    
    def closeProject():
        pass
    
  2. Upewnij się włączyć makra nad projektem, w ten sposób: Settings->Options->General->Enable macros: Always.

  3. Zapisz swój projekt QGIS.

Teraz za każdym razem, gdy otwierasz .qgswłaśnie zapisany plik, atrybuty warstwy linii będą automatycznie aktualizowane po dodaniu nowej operacji lub modyfikacji geometrii (tj. Nie trzeba już niczego kopiować do konsoli Python QGIS).


2. EDYCJA:

Właśnie opublikowałem wtyczkę o nazwie AutoFields, aby pomóc ludziom rozwiązać tego rodzaju problemy. Zrobiłem nawet film pokazujący, jak rozwiązać twój problem, możesz go obejrzeć na:

https://vimeo.com/germap/autofields-geometric-properties

Dokumentacja AutoFields: http://geotux.tuxfamily.org/index.php/en/geo-blogs/item/333-autofields-plugin-for-qgis

Germán Carrillo
źródło
2
Właśnie tego szukałem. Właściwie użyłem twojego kodu, by złapać współrzędne X, Y, które znalazłem w twojej starej odpowiedzi w tym linku do posta , tak samo jak teraz. Już przetestowałem automatyzację i działa ona idealnie. Zapisałem kod Pythona jako plik „.pycl”. Jeśli możesz mi wyjaśnić, w jaki sposób może być dostępny, kiedy otwieram mój projekt QGIS, będzie świetnie. Dziękuję za pomoc.
LeoNazareth,
1
Niemiecki, to była niesamowita odpowiedź! Dzięki! Wiele się nauczyłem od tego, co napisałeś!
jbgramm 21.04.16
1
Właściwie pracuję nad wtyczką, która pozwoli ci dokładnie to zrobić. Ponieważ mogę poświęcić na jego rozwój tylko mój wolny czas, nie mogę powiedzieć wam o oczekiwanej dacie wydania. W międzyczasie możesz uruchomić mój pierwszy fragment kodu po dodaniu pliku Tramo.shp, dostosowując: myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'Tramo' )[0]Jeśli naprawdę interesuje Cię moja wtyczka w przyszłości, prześlij mi wszelkie sugestie. Doceniam to. Możesz się ze mną skontaktować na GeoTux .
Germán Carrillo,
1
To będzie dla mnie świetne (i oczywiście dla wielu osób), już używam kodu z tą sugestią, którą zasugerowałeś. Z niecierpliwością czekam na twoją nową wtyczkę, a jeśli pomyślę o czymś przydatnym, skontaktuję się z tobą. Dziękuję Ci za wszystko.
LeoNazareth,
1
@LeoNazareth, czy chcesz przetestować wtyczkę? Szykuje się, ale chciałbym wykonać kilka testów przed wydaniem. Jeśli chcesz to przetestować, wyślij mi e-mail .
Germán Carrillo
2

W przypadku QGIS 3 przejdź do Layers Properties=> Attributes Form=> wybierz pole z wartościami geometrii (na przykład area) => wpisz $areaodpowiednie Defaults valuepole i zaznacz Apply default value on update. To również może być przydatna: $perimeter, $y, $x,$id

Towarzyszu Che
źródło
1

Umieściłbym dane w bazie danych (PostGIS) i wyodrębniłem je do QGIS w (prawdopodobnie zmaterializowanym) widoku.

nielsgerrits
źródło