3

I'm trying to automate a process where we bring in a DEM, extract the contours as a new vector layer, then set the dem to render the band between each contour line a separate colour.

I want to do is the equivalent of setting up the symbology property box like the screenshot below (with differing max, min and classes values calculated from the dem)

Can anyone suggest a good way to do that?

ColourBandExample

2

There is a new class in the QGIS3 api that builds a colour ramp for you.

I got it working, and here is the code I used. I don't claim its the right way, but it did work, and I hope it helps someone down the line.

#initial setup
import qgis.core
import math
templatePath="C:/qgis templates"

print("adding layer dtm colour bands")

#load raster DTM
targetPath = currentProject.homePath() + "/dtm"
targetFile = targetPath + "/test_dtm.tif"
colourBandLayer = iface.addRasterLayer(targetFile, projectName + " dtm colour bands")

#load initial style
colourBandLayer.loadNamedStyle(templatePath + "/Colour Banding.qml" )

#extract stats from the raster
cbStats=colourBandLayer.dataProvider().bandStatistics(1,QgsRasterBandStats.All,colourBandLayer.extent(),0)

#round Up and round Down for max and min values to the nearest 1m higher and lower than the values in the DTM (to match 1m contours)
cbMaxHeight = math.ceil(cbStats.maximumValue)
cbMinHeight = math.floor(cbStats.minimumValue)

#find the number of meters height in the DTM
cbHeightRange=cbMaxHeight - cbMinHeight

#Output to the console
print("Max: " + str(cbMaxHeight))
print("Min: " + str(cbMinHeight))
print("Rng: " + str(cbHeightRange))

#extract list of default styles in QGIS
myStyle = QgsStyle().defaultStyle()
defaultColorRampNames = myStyle.colorRampNames()

#print the name of the style I want to confirm correct one is selected (spectral, number 25)
print(defaultColorRampNames[25]) 
#create a colour ramp based on style 25
targetColorRamp=myStyle.colorRamp(defaultColorRampNames[25])

#set the max and min heights we found earlier
colourBandLayer.renderer().setClassificationMin(cbMinHeight)
colourBandLayer.renderer().setClassificationMax(cbMaxHeight)

#create a new shader using the new shader option in QGIS 3
colourBandLayer.renderer().createShader(targetColorRamp, QgsColorRampShader.Discrete, QgsColorRampShader.EqualInterval,cbHeightRange,False)
colourBandLayer.triggerRepaint()
0

Ad-hoc my first idea was to apply a formula like int(dem / d) * d to your dem using some raster calculator (where dem: your raster, d: your isoline equidistance) in order to split your dem into classes matching your isolines (i.e. for raster value = 126.5 would calculate to int(126.5 / 100) * 100 = 100 etc.).

Unfortunatly I didn't make it with any of the raster calculation approaches in QGIS 2 and 3 (QGIS raster calculator, GRASS r.mapcalc, GDAL Raster Calculator, SAGA Raster Calculator), either I got totally weird results or there is no function like int, round, floor, ceil, ... available as QGIS Raster Calculator.

By means of this, my answer may just point you to some direction and deeper dive into raster calculation in QGIS...

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.