Führen Sie ein Qgis-Layer-Update aus einer geänderten Datenquelle durch

13

Ich versuche, Layer automatisch zu aktualisieren, wenn sich ihre Datenquelle ändert. Ich benutze R, um ein Shapefile mit einem Attribut zu schreiben und es gemäß diesem Attribut in QGIS einzufärben.

Ich möchte ein neues Shapefile mit verschiedenen Attributwerten schreiben und die Qgis-Kartenfarben aktualisieren. Schritt 1 löst diesen Prozess aus, Schritt 2 bewirkt, dass die Ebene aus dem modifizierten Shapefile neu geladen wird. Sein Schritt 2 mache ich mir hier Sorgen.

Andere Fragen / Mailinglisten-Chatter erwähnen die Verwendung triggerRepaintauf der Ebene - das funktioniert nicht. Andere Vorschläge beinhalten setCacheImage(None)und wieder funktioniert das nicht. Die Ebene wird letztendlich aktualisiert, aber ich kann die Logik wirklich nicht erkennen, und manchmal passiert es überraschend, wenn ich nichts getan habe. Oder vielleicht habe ich vor zwei Minuten etwas getan.

Die einzige reproduzierbare Möglichkeit zum Aktualisieren besteht darin, die Ebene aus dem Legendenmenü zu duplizieren. Das Duplikat bezieht seine Daten immer aus dem aktuellen Shapefile, und die ursprüngliche Ebene aktualisiert sich auch selbst! Also muss es einen Weg geben, es zu tun.

Ich denke, es hat in 2.8 besser funktioniert, aber das ist 2.10, also gibt es vielleicht irgendwo einen neuen Bug.

Verwandt, funktioniert aber in 2.10 nicht für mich:

Wie lade ich Rasterlayer automatisch neu, wenn die Quelle in QGIS geändert wird?

Andere Dinge, die ich ausprobiert habe:

  • layer.dataProvider().dataChanged.emit() - einmal gearbeitet, dann wieder nicht auf der gleichen Ebene

Ich denke, ich habe herausgefunden, warum das Duplizieren der Ebene funktioniert. Wenn ich eine neue Wegwerfebene basierend auf der aktualisierten Ebene erstelle und dann .triggerRepaint()die aktualisierte Ebene aufrufe, wird sie auf der Kartenoberfläche aktualisiert:

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

Wenn ich eine andere Ebenenquelle verwende, funktioniert dies nicht. Es scheint also so, als ob Sie ein Ebenenobjekt erstellen, das auf derselben Ebenenquelle basiert ...

Ein schneller Test mit einer Rasterebene (aus einem GeoTIFF) und dem einfachen Aufrufen rlayer.triggerRepaint()scheint die Ansicht des Rasters im Kartenbereich zuverlässig zu aktualisieren.

Raumfahrer
quelle
Möglicherweise müssen Sie einen Beispielcode veröffentlichen.
Nathan W
@NathanW Das meiste, was ich tue, kommt aus der GUI-Ladeebene, stylen Sie sie - dann bekommen Sie nur die Ebene und diese wenigen Zeilen in der Python-Konsole. Ich bin nicht geneigt, dies im Rahmen eines Plugins zu verstecken, bis ich weiß, dass ich das Prinzip zum Laufen bringen kann! Ich hatte gehofft, dass es eine schnelle Antwort geben würde ("call layer.updateFromNewDataYouFool ()"), aber ich werde dies später mit mehr Code (einschließlich R-Code, um die Shapefiles zu erstellen) ergänzen.
Spacedman
Um sicherzugehen, haben Sie versucht, beide Befehle nacheinander zu verwenden: layer.setCacheImage(None)und layer.triggerRepaint()?
Matthias Kuhn
Ja @MatthiasKuhn - das klappt zwar manchmal , aber nicht oft. Ich habe gerade ein modifiziertes Shapefile geschrieben, beide Dinge in der Python-Konsole (auf der rechten Ebene) gemacht, kein visuelles Update. Das Einfachste, was bisher zu 100% funktioniert hat, ist das Erstellen eines neuen Wegwerfebenenobjekts auf der Basis der ursprünglichen Ebenenquelle, wie oben erwähnt, und dann triggerRepaint()auf der ursprünglichen Ebene. v 2.10.1-Pisa
Spacedman
Ich habe den Verdacht, dass dies mit der Einführung des OGR-Verbindungspools zusammenhängt. Können Sie einige Tests durchführen, wenn ein Unterschied besteht, wenn Sie die Datei auf der Festplatte ersetzen oder die vorhandene Datei bearbeiten ?
Matthias Kuhn

Antworten:

5

Dies hängt mit der Einführung des OGR-Verbindungspools zusammen. [1]

Vor QGIS 2.10 wurde bei jedem Zugriff eine Datei neu geöffnet (zB Repaint).

Seit QGIS 2.10 bleibt das Datei-Handle geöffnet. Wenn also eine Datei ersetzt wird, verweist das Handle weiterhin auf die alte Datei auf Unix-basierten Systemen.

QGIS 2.10: Problemumgehung

Leider gibt es keine API, um QGIS zu zwingen, die Datei in QGIS 2.10 erneut zu öffnen. Als Workaround können Sie einen hässlichen Hack verwenden:

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

QGIS 2.12: Lösung

Ich habe gerade eine neue Methode eingeführt, die ab QGIS 2.12 verfügbar sein wird:

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

Allgemeiner Ansatz

Wenn Sie die Möglichkeit haben zu steuern, wie die Datei überschrieben wird, können Sie die vorhandenen Dateien mit Schreibberechtigungen öffnen und den Inhalt ändern, anstatt die Dateien vollständig auf der Festplatte zu ersetzen (löschen / neu erstellen).

[1] Der Verbindungspool wurde eingeführt, um den Zugriff auf bestimmte Datenquellen erheblich zu beschleunigen.

Matthias Kuhn
quelle
Sieht nach der besten Lösung aus. Das .changeAttributeValuesbringt einen „ERROR 1: Versuchen Form mit Funktion ID zu lesen (-1) aus dem zur Verfügung stehenden Bereichs.“ aber das ist OK.
Spacedman
2

Wenn Sie die Karte verschieben oder auf andere Weise aktualisieren, sollte sie aktualisiert werden.

In diesem Artikel heißt es, dass Sie in PyQGIS Folgendes verwenden können:

myLayer.triggerRepaint()

Um alle Ebenen zu aktualisieren, kann folgende Funktion verwendet werden:

def refresh_layers(self):
    for layer in qgis.utils.iface.mapCanvas().layers():
         layer.triggerRepaint()
Alex Leith
quelle
Wie ich in meiner Frage gesagt habe und wie in dem Link erwähnt, den ich gegeben habe, triggerRepaint()funktioniert es nicht. refresh()Auf der Karte funktioniert Canvas nicht. Das Festlegen des Cache-Abbilds auf None(das jetzt in den API-Dokumenten veraltet ist) funktioniert nicht. Ich habe all diese Dinge auf einer neu modifizierten Shapefile-Ebene ausprobiert, die Karte verschoben, ein- und ausgeschaltet, es hat nicht funktioniert. "Duplizieren" Sie die Ebene und es wird jedoch sofort aktualisiert. Haben Sie diese Dinge selbst ausprobiert (am 2.10)?
Spacedman
Ich denke, wir brauchen @ nathan-w, um das zu beantworten. Ich habe es nicht selbst ausprobiert ...
Alex Leith
Ich habe #qgis im IRC ausprobiert, muss aber vielleicht auf die Mailingliste von qgis-dev
schreiben