3

I want to alter a raster layer with Python code and update the style afterwards. The style part is out of reach because I encountered the following problem:

I added a Float64 raster layer to my project using the "Create constant raster layer" processing tool. The layer is in my project's table of contents, named "Constant".

Then I run this script in the Python console:

import struct

layer = QgsProject.instance().mapLayersByName('Constant')[0]
data_provider = layer.constDataProvider()
block = data_provider.block(1, layer.extent(), layer.width(), layer.height())

new_data = struct.pack("dd", *[-99, 99])  # two double values
block.setData(new_data)

data_provider.setEditable(enabled=True)
data_provider.writeBlock(block, 1)
data_provider.setEditable(enabled=False)

The TIF file is rewritten now. If I open it manually, I see the new values in the first two pixels in the top left of the image.

But the "Constant" layer that was already in my ToC and on which I operated, still shows the same old constant value as its min and max values. I tried setting the "Min / Max Value Settings"' "Accuracy" to "Actual (slower)" with no success. I also tried data_provider.reload() and layer.triggerRepaint() without success.

Altered layer that was in the ToC already Layer file loaded the project manually afterwards

I do not want to set the min and max values manually, but have QGIS execute whatever it does when I set the "Min / Max Value Settings"' "Accuracy" to "Actual (slower)".

How do I make QGIS recognize the new data in the layer and update its statistics?

3
  • 1
    What does your code do, I have not seen struct before – BERA Nov 1 '20 at 14:11
  • I used struct to pack two double values into bytes. Is there a nicer way to do that in pyqgis (maybe using Qt's functions?)? – bugmenot123 Nov 1 '20 at 14:40
  • I have no idea :) – BERA Nov 1 '20 at 14:41
3

Interesting work!

The minimum and maximum values are configured with a QgsContrastEnhancement assigned to a renderer.

Try incorporating this code with a singleBandGray symbology

capa=iface.activeLayer()
provider=capa.dataProvider()
stats = provider.bandStatistics(1, QgsRasterBandStats.All, extent)
min = stats.minimumValue
max = stats.maximumValue

renderer=capa.renderer() #current renderer
myType = renderer.dataType(1)

GrayRenderer = QgsSingleBandGrayRenderer(provider,1) #create a new renderer
contrast_enhancement = QgsContrastEnhancement.StretchToMinimumMaximum
myEnhancement.setContrastEnhancementAlgorithm(contrast_enhancement,True)
myEnhancement.setMinimumValue(min)   #Set the minimum value you want
myEnhancement.setMaximumValue(max)   #Put the maximum value you want 
capa.setRenderer(GrayRenderer)
capa.renderer().setContrastEnhancement(myEnhancement)
capa.triggerRepaint()
1
  • Thanks! I do not want to set the min and max values manually though, but have QGIS execute whatever it does when I set the "Min / Max Value Settings"' "Accuracy" to "Actual (slower)". Well, if that it is at all easily triggerable from pyqgis. Otherwise I would have to care about NODATA etc myself and probably write something slow. – bugmenot123 Nov 1 '20 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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