I'm trying to apply a custom colour ramp to a single band QgsRasterLayer using PyQGIS. The colour ramp comes from matplotlib. For the map-canvas this works fine. However, in the TOC the values reach from 0 to 255 (rather than the actual min/max values), though the colour ramp seems correct (for the tiny range). In the style panel it shows the last colour ramp I used (even after restarting QGIS). Is it possible to update these correctly?
In the following example I apply viridis.
Example Code:
from matplotlib import colormaps
import numpy as np
lyr = iface.activeLayer()
if isinstance(lyr, QgsRasterLayer):
if lyr.bandCount() == 1:
# define color map by name
map = colormaps['viridis']
# get min/max values
stats = lyr.dataProvider().bandStatistics(1, QgsRasterBandStats.All)
val_min = stats.minimumValue
val_max = stats.maximumValue
# limit number of color steps to 20
if map.N > 20:
colors = map(np.linspace(1, map.N, 20, dtype=np.int16))
else:
colors = map(range(1,map.N))
colorsN = len(colors)
# raster values for the color steps
valList = np.linspace(val_min, val_max, colorsN)
# making a colorRamp-list with
colorsList = []
for idx, col in enumerate(colors):
qcol = QColor(int(col[0]*255), int(col[1]*255), int(col[2]*255))
val = valList[idx]
#print(val, qcol)
colorsList.append( QgsColorRampShader.ColorRampItem(val, qcol) )
# apply code (cf. https://docs.qgis.org/3.34/en/docs/pyqgis_developer_cookbook/raster.html#single-band-rasters)
fcn = QgsColorRampShader()
fcn.setColorRampType(QgsColorRampShader.Interpolated)
fcn.setColorRampItemList(colorsList)
shader = QgsRasterShader()
shader.setRasterShaderFunction(fcn)
renderer = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, shader)
lyr.setRenderer(renderer)
lyr.renderer().createLegendNodes(QgsLayerTreeLayer(lyr.id()))
lyr.triggerRepaint()
lyr.emitStyleChanged()
With the help of this answer I could solve it eventually:
renderer.setClassificationMin
and Max most problems go away; just in the style panel the color ramp isn't shown in the dropdownSo the working code is:
from matplotlib import colormaps
import numpy as np
lyr = iface.activeLayer()
if isinstance(lyr, QgsRasterLayer):
if lyr.bandCount() == 1:
# define color map by name
map = colormaps['viridis']
# get min/max values
stats = lyr.dataProvider().bandStatistics(1, QgsRasterBandStats.All)
val_min = stats.minimumValue
val_max = stats.maximumValue
# limit number of color steps to 20
if map.N > 20:
colors = map(np.linspace(1, map.N, 20, dtype=np.int16))
else:
colors = map(range(1,map.N))
colorsN = len(colors)
# making a colorRamp-list with
colorsList = []
for idx, col in enumerate(colors):
qcol = QColor(int(col[0]*255), int(col[1]*255), int(col[2]*255))
if idx == 0:
startColor = qcol
elif idx == colorsN - 1:
endColor = qcol
else:
val = idx * 1/colorsN
colorsList.append( QgsGradientStop((idx + 1) * 1 / (colorsN - 1), qcol) )
colorRamp = QgsGradientColorRamp(startColor, endColor, False, colorsList)
renderer = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1)
renderer.setClassificationMin(val_min)
renderer.setClassificationMax(val_max)
renderer.createShader(colorRamp)
lyr.setRenderer(renderer)
lyr.triggerRepaint()