Dokonaj aktualizacji warstwy Qgis ze zmienionego źródła danych

13

Usiłuję uzyskać automatyczne aktualizowanie warstw po zmianie źródła danych. Używam R do pisania pliku kształtu z atrybutem i kolorowania zgodnie z tym atrybutem w QGIS.

Chcę napisać nowy plik kształtu z różnymi wartościami atrybutów i zaktualizować kolory mapy Qgis. Krok 1 uruchamia ten proces, krok 2 powoduje ponowne załadowanie warstwy ze zmodyfikowanego pliku kształtu. Jego krok 2 Martwię się tutaj.

Inne pytania / rozmowy na liście mailowej wspominają używanie triggerRepaintna warstwie - to nie działa. Inne sugestie obejmują setCacheImage(None)i znowu to nie działa. Warstwa ostatecznie się aktualizuje, ale naprawdę nie widzę logiki, a czasem dzieje się to z zaskoczenia, gdy nic nie zrobiłem. A może zrobiłem coś dwie minuty temu.

Jedynym odtwarzalnym sposobem uzyskania aktualizacji jest skopiowanie warstwy z menu legendy - duplikat zawsze pobiera dane z bieżącego pliku kształtu, a oryginalna warstwa aktualizuje się sama! Więc musi być jakiś sposób na to.

Myślę, że działało to lepiej w 2.8, ale jest to 2.10, więc może gdzieś jest nowy błąd.

Powiązane, ale nie działa dla mnie w 2.10:

Jak automatycznie ponownie ładować warstwy rastrowe, jeśli źródło zostanie zmienione w QGIS?

Inne rzeczy, których próbowałem:

  • layer.dataProvider().dataChanged.emit() - pracował raz, a potem nie na tej samej warstwie

Wydaje mi się, że wyśledziłem, dlaczego działa duplikacja warstwy - jeśli utworzę nową warstwę wysuwaną na podstawie zaktualizowanej warstwy, a następnie wywołam .triggerRepaint()zaktualizowaną warstwę, nastąpi aktualizacja na kanwie mapy:

QgsVectorLayer( layer.source(), "layer copy", layer.providerType() )
layer.triggerRepaint()

Jeśli użyję innego źródła warstwy, to nie działa, więc wydaje się, że tak jest, jeśli utworzysz obiekt warstwy na podstawie tego samego źródła warstwy ...

Szybki test właśnie teraz z warstwą rastrową (z GeoTIFF) i samo wywołanie rlayer.triggerRepaint()wydaje się niezawodnie aktualizować widok rastra na kanwie mapy.

Spacedman
źródło
Może być konieczne opublikowanie przykładowego kodu.
Nathan W
@NathanW większość tego, co robię, pochodzi z GUI - wczytaj warstwę, stylizuj ją - wtedy po prostu pobiera warstwę i kilka wierszy w konsoli Pythona. Nie jestem skłonny trzymać tego w ramach wtyczki, dopóki nie będę wiedział, że mogę sprawić, by zasada działała! Miałem nadzieję, że pojawi się szybka odpowiedź („call layer.updateFromNewDataYouFool ()”), ale później wypełnię to większym kodem (w tym kodem R, aby utworzyć pliki kształtów).
Spacedman
Dla pewności próbowałeś później użyć obu poleceń: layer.setCacheImage(None)i layer.triggerRepaint()?
Matthias Kuhn
Tak @MatthiasKuhn - chociaż czasem to działa, ale nie często. Właśnie napisałem zmodyfikowany plik kształtu, zrobiłem obie te rzeczy w konsoli Pythona (na prawej warstwie), bez aktualizacji wizualnej. Najprostszą rzeczą, która do tej pory działała w 100%, jest utworzenie nowego obiektu warstwy wysuwanej na podstawie oryginalnego źródła warstwy, jak wspomniano powyżej, a następnie triggerRepaint()na oryginalnej warstwie. v 2.10.1-Piza
Spacedman
Podejrzewam, że może to być związane z wprowadzeniem puli połączeń OGR. Czy możesz wykonać kilka testów, jeśli istnieje różnica, jeśli zamienisz plik na dysku lub edytujesz istniejący plik?
Matthias Kuhn

Odpowiedzi:

5

Jest to związane z wprowadzeniem puli połączeń OGR. [1]

Przed wersją QGIS 2.10 plik był otwierany ponownie przy każdym dostępie (np. Odmalowanie).

Od QGIS 2.10 uchwyt pliku jest otwarty, co oznacza, że ​​jeśli plik zostanie zastąpiony, uchwyt nadal wskazuje stary plik w systemach uniksowych.

QGIS 2.10: obejście

Niestety nie ma interfejsu API, który ładnie zmusiłby QGIS do ponownego otwarcia pliku w QGIS 2.10. Aby obejść ten problem, możesz użyć brzydkiego hacka:

layer.dataProvider().changeAttributeValues( { -1: { 0: 0 } } )
layer.triggerRepaint()

QGIS 2.12: rozwiązanie

Właśnie wprowadziłem nową metodę, która będzie dostępna od QGIS 2.12:

layer.dataProvider().forceReload()
layer.triggerRepaint()

Ogólne podejście

Jeśli masz możliwość kontrolowania sposobu nadpisywania pliku, możesz otworzyć istniejące pliki z uprawnieniami do zapisu i zmienić zawartość zamiast całkowicie zastępować pliki (usuwać / odtwarzać) na dysku.

[1] Pula połączeń została wprowadzona w celu znacznego przyspieszenia dostępu do niektórych źródeł danych.

Matthias Kuhn
źródło
Wygląda na najlepsze rozwiązanie. Pojawia .changeAttributeValuessię komunikat „BŁĄD 1: Próba odczytu kształtu o identyfikatorze funkcji (-1) poza dostępnym zakresem”. ale to dobrze.
Spacedman
2

Jeśli przesuniesz mapę lub w inny sposób odświeżysz mapę, powinna ona zostać zaktualizowana.

W tym artykule opisano , że w PyQGIS można używać następujących elementów:

myLayer.triggerRepaint()

Aby odświeżyć wszystkie warstwy, można użyć następującej funkcji:

def refresh_layers(self):
    for layer in qgis.utils.iface.mapCanvas().layers():
         layer.triggerRepaint()
Alex Leith
źródło
Jak powiedziałem w moim pytaniu i jak wspomniano w linku, który podałem, triggerRepaint()nie działa. refresh()na mapie płótno nie działa. Ustawienie obrazu pamięci podręcznej na None(który jest już nieaktualny w dokumentach API) nie działa. Właśnie wypróbowałem te wszystkie rzeczy na nowo zmodyfikowanej warstwie pliku kształtów, przeglądałem mapę, włączałem i wyłączałem, to nie działało. „Duplikuj” warstwę, ale aktualizuje się ona natychmiast. Próbowałeś tych rzeczy sam (na 2.10)?
Spacedman
Myślę, że potrzebujemy @ nathan-w, aby odpowiedzieć na to pytanie. Sam tego nie próbowałem ...
Alex Leith,
Próbowałem na #qgis na IRC, ale może muszę wysłać na listę mailingową qgis-dev ...
Spacedman