Effectuer une mise à jour de la couche Qgis à partir d'une source de données modifiée

13

J'essaie d'obtenir des couches à mettre à jour automatiquement lorsque leur source de données change. J'utilise R pour écrire un fichier de formes avec un attribut et la coloration en fonction de cet attribut dans QGIS.

Je veux écrire un nouveau fichier de formes avec différentes valeurs d'attribut et avoir la mise à jour des couleurs de la carte Qgis. L'étape 1 déclenche ce processus, l'étape 2 effectue le rechargement de la couche à partir du fichier de formes modifié. Son étape 2, je m'inquiète ici.

D'autres questions / bavardages de listes de diffusion mentionnent l'utilisation triggerRepaintde la couche - cela ne fonctionne pas. D'autres suggestions incluent setCacheImage(None)et encore une fois cela ne fonctionne pas. La couche se met finalement à jour, mais je ne vois vraiment pas la logique, et cela arrive parfois par surprise après que je n'ai rien fait. Ou peut-être que j'ai fait quelque chose il y a deux minutes.

La seule façon reproductible de le mettre à jour est de dupliquer le calque à partir du menu légende - le doublon obtient toujours ses données du fichier de formes actuel, et le calque d'origine se met à jour lui-même aussi! Il doit donc y avoir un moyen de le faire.

Je pense que cela fonctionnait mieux en 2.8, mais c'est 2.10 donc peut-être qu'il y a un nouveau bug quelque part.

Associé, mais ne fonctionne pas pour moi en 2.10:

Comment recharger automatiquement les couches raster si la source est modifiée dans QGIS?

J'ai essayé d'autres choses:

  • layer.dataProvider().dataChanged.emit() - travaillé une fois, puis pas à nouveau sur la même couche

Je pense que j'ai trouvé pourquoi la duplication de la couche fonctionne - si je crée une nouvelle couche jetable basée sur la couche mise à jour et que j'appelle ensuite .triggerRepaint()la couche mise à jour, elle se met à jour sur le canevas de la carte:

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

Si j'utilise une source de calque différente, cela ne fonctionne pas, il semble donc que si vous créez un objet de calque basé sur la même source de calque ...

Un test rapide en ce moment avec une couche raster (à partir d'un GeoTIFF), et un simple appel rlayer.triggerRepaint()semble mettre à jour de manière fiable la vue du raster dans le canevas de carte.

Spacedman
la source
Vous devrez peut-être publier un exemple de code.
Nathan W
@NathanW la plupart de ce que je fais vient de l'interface utilisateur - charger la couche, le styliser - puis il suffit d'obtenir la couche et ces quelques lignes dans la console Python. Je ne suis pas disposé à coller cela dans le cadre d'un plugin jusqu'à ce que je sache que je peux faire fonctionner le principe! J'espérais qu'il y aurait une réponse rapide ("appelez layer.updateFromNewDataYouFool ()") mais je le remplirai avec plus de code (y compris le code R pour créer les fichiers de formes) plus tard.
Spacedman
Pour être sûr, vous avez essayé d'utiliser les deux commandes par la suite: layer.setCacheImage(None)et layer.triggerRepaint()?
Matthias Kuhn
Oui @MatthiasKuhn - bien que parfois cela fonctionne, mais pas souvent. Je viens d'écrire un fichier de formes modifié, j'ai fait ces deux choses dans la console Python (sur la couche de droite), pas de mise à jour visuelle. La chose la plus simple qui a fonctionné à 100% jusqu'à présent est de créer un nouvel objet de calque jetable basé sur la source de calque d'origine comme mentionné ci-dessus, puis triggerRepaint()sur le calque d'origine. v 2.10.1-Pisa
Spacedman
Je soupçonne que cela pourrait être lié à l'introduction du pool de connexions OGR. Pouvez-vous effectuer des tests s'il y a une différence si vous remplacez le fichier sur le disque ou modifiez le fichier existant?
Matthias Kuhn

Réponses:

5

Cela est lié à l'introduction du pool de connexions OGR. [1]

Avant QGIS 2.10, un fichier était rouvert à chaque accès (par exemple repeindre).

Depuis QGIS 2.10, le descripteur de fichier reste ouvert et cela signifie que si un fichier est remplacé, le descripteur pointe toujours vers l'ancien fichier sur les systèmes basés sur Unix.

QGIS 2.10: solution de contournement

Malheureusement, il n'y a pas d'API pour forcer gentiment QGIS à rouvrir le fichier dans QGIS 2.10. Comme solution de contournement, vous pouvez utiliser un hack laid:

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

QGIS 2.12: solution

Je viens de présenter une nouvelle méthode qui sera disponible à partir de QGIS 2.12:

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

Approche générale

Si vous avez la possibilité de contrôler la façon dont le fichier est écrasé, vous pouvez ouvrir les fichiers existants avec des autorisations d'écriture et modifier le contenu au lieu de remplacer complètement les fichiers (supprimer / recréer) sur le disque.

[1] Le pool de connexions a été introduit pour accélérer considérablement l'accès à certaines sources de données.

Matthias Kuhn
la source
Ressemble à la meilleure solution. Le .changeAttributeValuesfait apparaître une "ERREUR 1: tentative de lecture de la forme avec l'ID de fonctionnalité (-1) hors de la plage disponible". mais ça va.
Spacedman
2

Si vous effectuez un panoramique ou actualisez la carte, elle doit être mise à jour.

Cet article indique que vous pouvez utiliser les éléments suivants dans PyQGIS:

myLayer.triggerRepaint()

Pour actualiser toutes les couches, la fonction suivante peut être utilisée:

def refresh_layers(self):
    for layer in qgis.utils.iface.mapCanvas().layers():
         layer.triggerRepaint()
Alex Leith
la source
Comme je l'ai dit dans ma question, et comme mentionné dans le lien que j'ai donné, triggerRepaint()cela ne fonctionne pas. refresh()sur le canevas de la carte ne fonctionne pas. La définition de l'image de cache sur None(qui est désormais déconseillée dans les documents de l'API) ne fonctionne pas. J'ai juste essayé toutes ces choses sur un calque de fichier de formes nouvellement modifié, j'ai fait un panoramique de la carte, activé et désactivé la vis, cela n'a pas fonctionné. "Dupliquez" le calque et il se met à jour instantanément cependant. Avez-vous essayé ces choses vous-même (au 2.10)?
Spacedman
Je pense que nous avons besoin de @ nathan-w pour répondre à cette question. Je ne l'ai pas essayé moi-même ...
Alex Leith
J'ai essayé sur #qgis sur IRC mais peut-être que je dois poster sur la liste de diffusion qgis-dev ...
Spacedman