PyQGIS – Legend Doesn’t Update with Renderer

legendpyqgisrasterrendering

I am using QGIS 3.22.2.

I am relatively new to QGIS and have been trying to automate part of a workflow, including changing the rendering of a raster. Following the PyQGIS cookbook, I have this code:

stats = rlayer.dataProvider().bandStatistics(1, QgsRasterBandStats.All)
min = stats.minimumValue
max = stats.maximumValue

fnc = QgsColorRampShader()
fnc.setColorRampType(QgsColorRampShader.Interpolated)

lst = [  QgsColorRampShader.ColorRampItem(min, QColor(255, 0, 0)),
  QgsColorRampShader.ColorRampItem(max, QColor(0, 0, 255))]
  
fnc.setColorRampItemList(lst)

shader = QgsRasterShader()
shader.setRasterShaderFunction(fnc)

renderer = QgsSingleBandPseudoColorRenderer(rlayer.dataProvider(), 1, shader)

rlayer.setRenderer(renderer)
rlayer.triggerRepaint()

This works grand, and changes how a selected raster renders as shown below.

enter image description here

However, the legend doesn't update as expected. In this case, instead of an interpolated color bar between red and blue and specified values minmax, I get an almost completely blue color bar (the last color in my variable lst) between values 0-255. This is shown in the image below. The left hand legend is what I get when manually changing the rendering, and the right hand image is the result when running the above code.

enter image description here

How might I go about updating the legend programmatically?

Best Answer

You can use the script below (just change your layer name in the first line):

layer_name = 'your_layer_name'
rl = QgsProject.instance().mapLayersByName(layer_name)[0]
prov = rl.dataProvider()
stats = prov.bandStatistics(1, QgsRasterBandStats.All, rl.extent(), 0)
min = stats.minimumValue
max = stats.maximumValue
renderer = QgsSingleBandPseudoColorRenderer(rl.dataProvider(), 1)
color_ramp = QgsGradientColorRamp(QColor(255, 0, 0), QColor(0, 0, 255))
renderer.setClassificationMin(min)
renderer.setClassificationMax(max)
renderer.createShader(color_ramp)
rl.setRenderer(renderer)
rl.triggerRepaint()

Results on a test DEM layer:

enter image description here

enter image description here

You can also pass different ramp types and classifaction modes, along with a number of classes to the createShader() method. For example, here I reversed the color ramp and changed this line:

renderer.createShader(color_ramp)

To:

renderer.createShader(color_ramp, QgsColorRampShader.Discrete, QgsColorRampShader.EqualInterval, 15)

Results:

enter image description here

enter image description here

Docs for QgsSingleBandPseudoColorRenderer

I also got some hints by looking through the Python unit tests for QgsRasterLayer here.

Related Question