12

How to automatically reloaded raster layer if source is changed? (The path is the same but inside source file are changes)

I use:

 qgis.utils.iface.mapCanvas().refresh()

but layer not refresh.

# # #

The maps are repainting but there are still the same image (source file is changed on disc)

I use:

  layers = qgis.utils.iface.legendInterface().layers()
  for layer in layers:
      layer.triggerRepaint()
0

3 Answers 3

16

I suppose your question does not include change detection, as your sample only concerns QgsMapCanvas.refresh()

Instead you have to call QgsRasterLayer.triggerRepaint()

If your layer is called myLayer:

myLayer.setCacheImage( None )
myLayer.triggerRepaint()

The same method exists for vector layers as well.

For low overhead file change notification I'd propose looking into Qt's QFileSystemWatcher, which makes use of inotify on linux and similar techniques on other platforms.

from PyQt4.QtCore import QFileSystemWatcher

def refreshLayer():
    myLayer.setCacheImage( None )
    myLayer.triggerRepaint()

watcher = QFileSystemWatcher()
watcher.addPath( '/path/to/your/raster' )
watcher.fileChanged.connect( refreshLayer )

Of course this can be combined with an MD5 check as proposed by nickves or a modification time check with os.stat (Nathan W proposal).

2
+25

You can check if the file hash has changed between intervals

eg:

def md5checksum(fp):
        import hash
    with open(fp, 'rb') as fh:
        m = hashlib.md5()
        while True:
            data = fh.read(8192)
            if not data:
                break
            m.update(data)
        return m.hexdigest()

import time
import copy

a,b = str(),str()
while True:
    a =  md5checksum(fp) # file
    if a != b:  # the file has changed, do what you want
        myLayer.triggerRepaint()
        b = copy.copy(a) #shallow copy, otherwise a and b will point at the same object
    else:
        sleep.time(1) #wait for 1 sec, then recheck

It's a bit hackish, but the underline idea is valid

(The md5 hash check found here)

0
1

The excellent answer from Matthias Kuhn is nearly 10 years old and can be adapted to more recent (as of 2023) QGIS by using Qt5 and a different newer reload method. It is also possible to automatically take the filename from the currently selected raster layer:

from PyQt5.QtCore import QFileSystemWatcher
rasterLayer = iface.activeLayer()
watcher = QFileSystemWatcher()
watcher.addPath(rasterLayer.dataProvider().dataSourceUri())
watcher.fileChanged.connect(rasterLayer.dataProvider().reloadData)

In my experience on QGIS 3.16.16 this filesystem watcher approach works well, with the QGIS display updating and providing immediate feedback as soon as my external application changes the file.

I was having no success with setCacheImage(None), triggerRepaint(), and other older suggestions. QGIS seemed to only present fragments of the new data together with cached fragments of the previous version.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.