Effettua un aggiornamento del livello Qgis da un'origine dati modificata


13

Sto cercando di aggiornare automaticamente i layer quando cambia la loro origine dati. Sto usando R per scrivere un file di forma con un attributo e colorare in base a quell'attributo in QGIS.

Voglio scrivere un nuovo shapefile con valori di attributo diversi e avere l'aggiornamento dei colori della mappa Qgis. Il passaggio 1 sta attivando quel processo, il passaggio 2 sta facendo ricaricare il layer dal file di forma modificato. È il passaggio 2 di cui mi preoccupo qui.

Altre domande / chiacchiere triggerRepaintsulla mailing list menzionano l'uso sul livello - che non funziona. Altri suggerimenti includono setCacheImage(None)e di nuovo che non funziona. Alla fine il layer si aggiorna, ma non riesco davvero a vedere la logica, e talvolta succede di sorpresa dopo che non ho fatto nulla. O forse ho fatto qualcosa due minuti fa.

L'unico modo riproducibile per farlo aggiornare è duplicare il livello dal menu della legenda: il duplicato ottiene sempre i suoi dati dal file di forma corrente e anche il livello originale si aggiorna da solo! Quindi ci deve essere un modo per farlo.

Penso che funzionasse meglio in 2.8, ma questo è 2.10 quindi forse c'è un nuovo bug da qualche parte.

Correlato, ma non funziona per me in 2.10:

Come ricaricare automaticamente i livelli raster se l'origine viene modificata in QGIS?

Altre cose che ho provato:

  • layer.dataProvider().dataChanged.emit() - ha funzionato una volta, quindi non di nuovo sullo stesso livello

Penso di aver rintracciato perché la duplicazione del livello funziona: se creo un nuovo livello usa e getta basato sul livello aggiornato e quindi chiamo .triggerRepaint()il livello aggiornato, si aggiorna nell'area di disegno della mappa:

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

Se uso una sorgente di layer diversa, non funziona, quindi sembra che si crei un oggetto layer basato sulla stessa sorgente di layer ...

Un rapido test in questo momento con un livello raster (da un GeoTIFF) e solo la chiamata rlayer.triggerRepaint()sembra aggiornare in modo affidabile la vista del raster nell'area di disegno della mappa.


Potrebbe essere necessario pubblicare un codice di esempio.
Nathan W,

@NathanW la maggior parte di ciò che sto facendo proviene dalla GUI - carica il layer, lo modella - quindi sta solo ottenendo il layer e quelle poche righe nella console di Python. Non sono incline ad attaccarlo nel quadro di un plugin finché non so di poter far funzionare il principio! Speravo che ci sarebbe stata una risposta rapida ("call layer.updateFromNewDataYouFool ()") ma lo riempirò con più codice (incluso il codice R per creare gli shapefile) in seguito.
Spacedman

A dire il vero, hai provato a utilizzare entrambi i comandi successivamente: layer.setCacheImage(None)e layer.triggerRepaint()?
Matthias Kuhn,

Sì @MatthiasKuhn - anche se a volte funziona, ma non spesso. Ho appena scritto un file di forma modificato, ho fatto entrambe le cose nella console di Python (sul livello giusto), nessun aggiornamento visivo. La cosa più semplice che ha funzionato finora al 100% è la creazione di un nuovo oggetto layer usa e getta basato sulla sorgente del layer originale come menzionato sopra e quindi triggerRepaint()sul layer originale. v 2.10.1-Pisa
Spacedman

Ho il sospetto che ciò possa essere correlato all'introduzione del pool di connessioni OGR. Puoi eseguire alcuni test se c'è una differenza se sostituisci il file sul disco o modifichi il file esistente?
Matthias Kuhn,

Risposte:


5

Ciò è correlato all'introduzione del pool di connessioni OGR. [1]

Prima di QGIS 2.10, un file veniva riaperto su ogni singolo accesso (ad esempio ridipingere).

A partire da QGIS 2.10 l'handle del file viene mantenuto aperto e ciò significa che se un file viene sostituito l'handle punta ancora al vecchio file nei sistemi basati su Unix.

QGIS 2.10: soluzione alternativa

Sfortunatamente non esiste un'API per forzare piacevolmente QGIS a riaprire il file in QGIS 2.10. Per ovviare al problema puoi usare un brutto hack:

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

QGIS 2.12: soluzione

Ho appena introdotto un nuovo metodo che sarà disponibile a partire da QGIS 2.12:

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

Approccio generale

Se hai la possibilità di controllare il modo in cui il file viene sovrascritto, puoi aprire i file esistenti con autorizzazioni di scrittura e modificare il contenuto invece di sostituire completamente i file (elimina / ricrea) sul disco.

[1] Il pool di connessioni è stato introdotto per accelerare in modo significativo l'accesso a determinate fonti di dati.


Sembra la soluzione migliore. La .changeAttributeValuesporta ad una "ERROR 1: tentativo di leggere forma con funzione id (-1) fuori gamma disponibile." Ma va bene.
Spacedman

2

Se esegui la panoramica o aggiorni la mappa, questa dovrebbe aggiornarsi.

Questo articolo afferma che è possibile utilizzare quanto segue in PyQGIS:

myLayer.triggerRepaint()

Per aggiornare tutti i livelli è possibile utilizzare la seguente funzione:

def refresh_layers(self):
    for layer in qgis.utils.iface.mapCanvas().layers():
         layer.triggerRepaint()

Come ho detto nella mia domanda, e come menzionato nel link che ho dato, triggerRepaint()non funziona. refresh()sulla mappa la tela non funziona. L'impostazione dell'immagine della cache su None(che ora è deprecata nei documenti API) non funziona. Ho appena provato tutte queste cose su un layer shapefile appena modificato, ho spostato la mappa, attivato e disattivato vis, non ha funzionato. "Duplica" il livello e si aggiorna immediatamente però. Hai provato tu stesso queste cose (il 2.10)?
Spacedman,

Penso che abbiamo bisogno di @ nathan-w per rispondere a questo. Non l'ho provato da solo ...
Alex Leith,

Ho provato #qgis su IRC ma forse devo pubblicare nella mailing list di qgis-dev ...
Spacedman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.