[{"data":1,"prerenderedAt":1689},["ShallowReactive",2],{"doc:\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fapply-color-ramp-to-raster-pyqgis":3},{"id":4,"title":5,"body":6,"description":1682,"extension":1683,"meta":1684,"navigation":143,"path":1685,"seo":1686,"stem":1687,"__hash__":1688},"docs\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fapply-color-ramp-to-raster-pyqgis\u002Findex.md","Apply a Color Ramp to a Raster in PyQGIS",{"type":7,"value":8,"toc":1666},"minimark",[9,13,40,45,84,88,100,104,110,286,319,323,333,470,508,512,519,622,645,649,658,726,753,757,760,891,911,915,921,1116,1140,1144,1147,1396,1408,1412,1419,1488,1493,1497,1515,1526,1540,1551,1561,1565,1587,1591,1606,1621,1636,1642,1646,1662],[10,11,5],"h1",{"id":12},"apply-a-color-ramp-to-a-raster-in-pyqgis",[14,15,16,17,21,22,25,26,29,30,35,36,39],"p",{},"Single-band rasters — elevation models, NDVI grids, temperature surfaces — carry one continuous value per pixel, and a colour ramp is what turns those numbers into a readable map. In PyQGIS this means assembling three classes: a ",[18,19,20],"code",{},"QgsColorRampShader"," that maps values to colours, a ",[18,23,24],{},"QgsRasterShader"," that wraps it, and a ",[18,27,28],{},"QgsSingleBandPseudoColorRenderer"," that draws the band. This page is a focused recipe inside the ",[31,32,34],"a",{"href":33},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002F","Programmatic Layer Styling in PyQGIS"," cluster; where that cluster styles vectors, this one handles the raster path, including how to classify by the band's real data range with ",[18,37,38],{},"QgsRasterBandStats",".",[41,42,44],"h2",{"id":43},"prerequisites","Prerequisites",[46,47,48,56,63,77],"ul",{},[49,50,51,55],"li",{},[52,53,54],"strong",{},"QGIS 3.34 LTR"," (Python 3.12), in the Python Console or a standalone application.",[49,57,58,59,62],{},"A loaded, valid single-band ",[18,60,61],{},"QgsRasterLayer"," (for example a DEM GeoTIFF).",[49,64,65,66,69,70,73,74,39],{},"Imports from ",[18,67,68],{},"qgis.core"," for the shader and renderer classes, and ",[18,71,72],{},"QColor"," from ",[18,75,76],{},"qgis.PyQt.QtGui",[49,78,79,80,83],{},"The band number you want to style (band indexing is ",[52,81,82],{},"1-based"," in the raster API).",[41,85,87],{"id":86},"the-three-class-pipeline-at-a-glance","The three-class pipeline at a glance",[14,89,90,91,93,94,96,97,99],{},"Unlike vector styling, where you mutate a symbol that already exists, raster pseudo-color rendering is built from scratch each time out of three cooperating objects. The ",[18,92,20],{}," is the brain: it holds the value-to-colour mapping and the classification logic. The ",[18,95,24],{}," is a thin adapter that lets the renderer call the shader as a function. The ",[18,98,28],{}," is the painter: it knows which band to read and hands each pixel value to the shader to look up a colour. You always build them inner-to-outer — shader, then raster shader, then renderer — and the recipes below follow that order.",[41,101,103],{"id":102},"recipe-1-read-the-bands-value-range","Recipe 1: Read the band's value range",[14,105,106,107,109],{},"A ramp is only meaningful when stretched across the data's actual range. Pull the minimum and maximum from ",[18,108,38],{}," rather than hard-coding them.",[111,112,117],"pre",{"className":113,"code":114,"language":115,"meta":116,"style":116},"language-python shiki shiki-themes github-dark","from qgis.core import QgsProject, QgsRasterBandStats\n\nraster = QgsProject.instance().mapLayersByName(\"dem\")[0]\nprovider = raster.dataProvider()\n\nband = 1\nstats = provider.bandStatistics(band, QgsRasterBandStats.All)\nv_min = stats.minimumValue\nv_max = stats.maximumValue\nprint(f\"Band {band} range: {v_min:.2f} to {v_max:.2f}\")\n","python","",[18,118,119,138,145,171,182,187,198,209,220,231],{"__ignoreMap":116},[120,121,124,128,132,135],"span",{"class":122,"line":123},"line",1,[120,125,127],{"class":126},"snl16","from",[120,129,131],{"class":130},"s95oV"," qgis.core ",[120,133,134],{"class":126},"import",[120,136,137],{"class":130}," QgsProject, QgsRasterBandStats\n",[120,139,141],{"class":122,"line":140},2,[120,142,144],{"emptyLinePlaceholder":143},true,"\n",[120,146,148,151,154,157,161,164,168],{"class":122,"line":147},3,[120,149,150],{"class":130},"raster ",[120,152,153],{"class":126},"=",[120,155,156],{"class":130}," QgsProject.instance().mapLayersByName(",[120,158,160],{"class":159},"sU2Wk","\"dem\"",[120,162,163],{"class":130},")[",[120,165,167],{"class":166},"sDLfK","0",[120,169,170],{"class":130},"]\n",[120,172,174,177,179],{"class":122,"line":173},4,[120,175,176],{"class":130},"provider ",[120,178,153],{"class":126},[120,180,181],{"class":130}," raster.dataProvider()\n",[120,183,185],{"class":122,"line":184},5,[120,186,144],{"emptyLinePlaceholder":143},[120,188,190,193,195],{"class":122,"line":189},6,[120,191,192],{"class":130},"band ",[120,194,153],{"class":126},[120,196,197],{"class":166}," 1\n",[120,199,201,204,206],{"class":122,"line":200},7,[120,202,203],{"class":130},"stats ",[120,205,153],{"class":126},[120,207,208],{"class":130}," provider.bandStatistics(band, QgsRasterBandStats.All)\n",[120,210,212,215,217],{"class":122,"line":211},8,[120,213,214],{"class":130},"v_min ",[120,216,153],{"class":126},[120,218,219],{"class":130}," stats.minimumValue\n",[120,221,223,226,228],{"class":122,"line":222},9,[120,224,225],{"class":130},"v_max ",[120,227,153],{"class":126},[120,229,230],{"class":130}," stats.maximumValue\n",[120,232,234,237,240,243,246,249,252,255,258,260,263,266,268,271,273,276,278,280,283],{"class":122,"line":233},10,[120,235,236],{"class":166},"print",[120,238,239],{"class":130},"(",[120,241,242],{"class":126},"f",[120,244,245],{"class":159},"\"Band ",[120,247,248],{"class":166},"{",[120,250,251],{"class":130},"band",[120,253,254],{"class":166},"}",[120,256,257],{"class":159}," range: ",[120,259,248],{"class":166},[120,261,262],{"class":130},"v_min",[120,264,265],{"class":126},":.2f",[120,267,254],{"class":166},[120,269,270],{"class":159}," to ",[120,272,248],{"class":166},[120,274,275],{"class":130},"v_max",[120,277,265],{"class":126},[120,279,254],{"class":166},[120,281,282],{"class":159},"\"",[120,284,285],{"class":130},")\n",[14,287,288,291,292,295,296,299,300,303,304,303,307,310,311,314,315,39],{},[52,289,290],{},"Breakdown:"," ",[18,293,294],{},"dataProvider().bandStatistics()"," computes statistics for one band; passing ",[18,297,298],{},"QgsRasterBandStats.All"," requests the full set, exposing ",[18,301,302],{},"minimumValue",", ",[18,305,306],{},"maximumValue",[18,308,309],{},"mean",", and ",[18,312,313],{},"stdDev",". The first argument is the 1-based band number. On very large rasters QGIS samples rather than reading every pixel, so the range is representative, not exhaustive. These bounds feed the ramp classification below. If you need the full statistical picture for analysis rather than styling, see ",[31,316,318],{"href":317},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fcalculate-raster-statistics-pyqgis\u002F","Calculate Raster Statistics in PyQGIS",[41,320,322],{"id":321},"recipe-2-build-a-color-ramp-shader-from-a-gradient","Recipe 2: Build a color ramp shader from a gradient",[14,324,325,326,328,329,332],{},"The ",[18,327,20],{}," holds a list of ",[18,330,331],{},"ColorRampItem"," entries — value\u002Fcolour pairs. The simplest classification spreads N evenly spaced stops across the min–max range.",[111,334,336],{"className":113,"code":335,"language":115,"meta":116,"style":116},"from qgis.core import (\n    QgsColorRampShader, QgsGradientColorRamp,\n)\nfrom qgis.PyQt.QtGui import QColor\n\n# A two-stop gradient: dark teal (low) to amber (high).\nramp = QgsGradientColorRamp(QColor(\"#0f766e\"), QColor(\"#b45309\"))\n\nshader = QgsColorRampShader(v_min, v_max)\nshader.setColorRampType(QgsColorRampShader.Interpolated)\nshader.setSourceColorRamp(ramp)\n\n# Generate N evenly spaced classified items across the range.\nshader.classifyColorRamp(classes=5, band=band, input=provider.input())\n",[18,337,338,349,354,358,370,374,380,402,406,416,421,427,432,438],{"__ignoreMap":116},[120,339,340,342,344,346],{"class":122,"line":123},[120,341,127],{"class":126},[120,343,131],{"class":130},[120,345,134],{"class":126},[120,347,348],{"class":130}," (\n",[120,350,351],{"class":122,"line":140},[120,352,353],{"class":130},"    QgsColorRampShader, QgsGradientColorRamp,\n",[120,355,356],{"class":122,"line":147},[120,357,285],{"class":130},[120,359,360,362,365,367],{"class":122,"line":173},[120,361,127],{"class":126},[120,363,364],{"class":130}," qgis.PyQt.QtGui ",[120,366,134],{"class":126},[120,368,369],{"class":130}," QColor\n",[120,371,372],{"class":122,"line":184},[120,373,144],{"emptyLinePlaceholder":143},[120,375,376],{"class":122,"line":189},[120,377,379],{"class":378},"sAwPA","# A two-stop gradient: dark teal (low) to amber (high).\n",[120,381,382,385,387,390,393,396,399],{"class":122,"line":200},[120,383,384],{"class":130},"ramp ",[120,386,153],{"class":126},[120,388,389],{"class":130}," QgsGradientColorRamp(QColor(",[120,391,392],{"class":159},"\"#0f766e\"",[120,394,395],{"class":130},"), QColor(",[120,397,398],{"class":159},"\"#b45309\"",[120,400,401],{"class":130},"))\n",[120,403,404],{"class":122,"line":211},[120,405,144],{"emptyLinePlaceholder":143},[120,407,408,411,413],{"class":122,"line":222},[120,409,410],{"class":130},"shader ",[120,412,153],{"class":126},[120,414,415],{"class":130}," QgsColorRampShader(v_min, v_max)\n",[120,417,418],{"class":122,"line":233},[120,419,420],{"class":130},"shader.setColorRampType(QgsColorRampShader.Interpolated)\n",[120,422,424],{"class":122,"line":423},11,[120,425,426],{"class":130},"shader.setSourceColorRamp(ramp)\n",[120,428,430],{"class":122,"line":429},12,[120,431,144],{"emptyLinePlaceholder":143},[120,433,435],{"class":122,"line":434},13,[120,436,437],{"class":378},"# Generate N evenly spaced classified items across the range.\n",[120,439,441,444,448,450,453,455,457,459,462,465,467],{"class":122,"line":440},14,[120,442,443],{"class":130},"shader.classifyColorRamp(",[120,445,447],{"class":446},"s9osk","classes",[120,449,153],{"class":126},[120,451,452],{"class":166},"5",[120,454,303],{"class":130},[120,456,251],{"class":446},[120,458,153],{"class":126},[120,460,461],{"class":130},"band, ",[120,463,464],{"class":446},"input",[120,466,153],{"class":126},[120,468,469],{"class":130},"provider.input())\n",[14,471,472,291,474,477,478,481,482,485,486,489,490,493,494,497,498,501,502,504,505,507],{},[52,473,290],{},[18,475,476],{},"QgsGradientColorRamp(c1, c2)"," defines a two-colour gradient; you can add intermediate stops with the ",[18,479,480],{},"stops"," argument if needed. ",[18,483,484],{},"QgsColorRampShader(v_min, v_max)"," anchors the shader to the data range. ",[18,487,488],{},"setColorRampType(Interpolated)"," blends colours smoothly between stops — use ",[18,491,492],{},"Discrete"," for hard class boundaries or ",[18,495,496],{},"Exact"," for categorical rasters. ",[18,499,500],{},"classifyColorRamp()"," populates the item list automatically; passing ",[18,503,251],{}," and ",[18,506,464],{}," lets it align to the actual band. The colours here come straight from this site's palette to keep the example concrete.",[41,509,511],{"id":510},"recipe-3-use-a-named-ramp-from-the-default-style","Recipe 3: Use a named ramp from the default style",[14,513,514,515,518],{},"QGIS ships dozens of named ramps (Viridis, Spectral, RdYlGn). Pull one from ",[18,516,517],{},"QgsStyle.defaultStyle()"," instead of hand-building a gradient.",[111,520,522],{"className":113,"code":521,"language":115,"meta":116,"style":116},"from qgis.core import QgsStyle, QgsColorRampShader\n\nstyle = QgsStyle.defaultStyle()\nprint(style.colorRampNames())   # inspect what is available\n\nramp = style.colorRamp(\"Viridis\")\n\nshader = QgsColorRampShader(v_min, v_max)\nshader.setColorRampType(QgsColorRampShader.Interpolated)\nshader.setSourceColorRamp(ramp)\nshader.classifyColorRamp(classes=7, band=band, input=provider.input())\n",[18,523,524,535,539,549,559,563,577,581,589,593,597],{"__ignoreMap":116},[120,525,526,528,530,532],{"class":122,"line":123},[120,527,127],{"class":126},[120,529,131],{"class":130},[120,531,134],{"class":126},[120,533,534],{"class":130}," QgsStyle, QgsColorRampShader\n",[120,536,537],{"class":122,"line":140},[120,538,144],{"emptyLinePlaceholder":143},[120,540,541,544,546],{"class":122,"line":147},[120,542,543],{"class":130},"style ",[120,545,153],{"class":126},[120,547,548],{"class":130}," QgsStyle.defaultStyle()\n",[120,550,551,553,556],{"class":122,"line":173},[120,552,236],{"class":166},[120,554,555],{"class":130},"(style.colorRampNames())   ",[120,557,558],{"class":378},"# inspect what is available\n",[120,560,561],{"class":122,"line":184},[120,562,144],{"emptyLinePlaceholder":143},[120,564,565,567,569,572,575],{"class":122,"line":189},[120,566,384],{"class":130},[120,568,153],{"class":126},[120,570,571],{"class":130}," style.colorRamp(",[120,573,574],{"class":159},"\"Viridis\"",[120,576,285],{"class":130},[120,578,579],{"class":122,"line":200},[120,580,144],{"emptyLinePlaceholder":143},[120,582,583,585,587],{"class":122,"line":211},[120,584,410],{"class":130},[120,586,153],{"class":126},[120,588,415],{"class":130},[120,590,591],{"class":122,"line":222},[120,592,420],{"class":130},[120,594,595],{"class":122,"line":233},[120,596,426],{"class":130},[120,598,599,601,603,605,608,610,612,614,616,618,620],{"class":122,"line":423},[120,600,443],{"class":130},[120,602,447],{"class":446},[120,604,153],{"class":126},[120,606,607],{"class":166},"7",[120,609,303],{"class":130},[120,611,251],{"class":446},[120,613,153],{"class":126},[120,615,461],{"class":130},[120,617,464],{"class":446},[120,619,153],{"class":126},[120,621,469],{"class":130},[14,623,624,291,626,628,629,632,633,636,637,640,641,644],{},[52,625,290],{},[18,627,517],{}," is the application-wide style database; ",[18,630,631],{},"colorRampNames()"," lists every installed ramp so you can confirm a name before requesting it. ",[18,634,635],{},"colorRamp(\"Viridis\")"," returns a ready-made ",[18,638,639],{},"QgsColorRamp"," clone you can hand straight to ",[18,642,643],{},"setSourceColorRamp()",". Viridis is perceptually uniform and colour-blind friendly, which is why it is a good default for continuous data. Everything downstream is identical to the hand-built gradient case.",[41,646,648],{"id":647},"recipe-4-assemble-the-renderer-and-apply-it","Recipe 4: Assemble the renderer and apply it",[14,650,651,652,654,655,657],{},"The shader goes inside a ",[18,653,24],{},", which goes inside a ",[18,656,28],{},", which becomes the layer's renderer.",[111,659,661],{"className":113,"code":660,"language":115,"meta":116,"style":116},"from qgis.core import QgsRasterShader, QgsSingleBandPseudoColorRenderer\n\nraster_shader = QgsRasterShader()\nraster_shader.setRasterShaderFunction(shader)\n\nrenderer = QgsSingleBandPseudoColorRenderer(\n    provider, band, raster_shader\n)\nraster.setRenderer(renderer)\nraster.triggerRepaint()\n",[18,662,663,674,678,688,693,697,707,712,716,721],{"__ignoreMap":116},[120,664,665,667,669,671],{"class":122,"line":123},[120,666,127],{"class":126},[120,668,131],{"class":130},[120,670,134],{"class":126},[120,672,673],{"class":130}," QgsRasterShader, QgsSingleBandPseudoColorRenderer\n",[120,675,676],{"class":122,"line":140},[120,677,144],{"emptyLinePlaceholder":143},[120,679,680,683,685],{"class":122,"line":147},[120,681,682],{"class":130},"raster_shader ",[120,684,153],{"class":126},[120,686,687],{"class":130}," QgsRasterShader()\n",[120,689,690],{"class":122,"line":173},[120,691,692],{"class":130},"raster_shader.setRasterShaderFunction(shader)\n",[120,694,695],{"class":122,"line":184},[120,696,144],{"emptyLinePlaceholder":143},[120,698,699,702,704],{"class":122,"line":189},[120,700,701],{"class":130},"renderer ",[120,703,153],{"class":126},[120,705,706],{"class":130}," QgsSingleBandPseudoColorRenderer(\n",[120,708,709],{"class":122,"line":200},[120,710,711],{"class":130},"    provider, band, raster_shader\n",[120,713,714],{"class":122,"line":211},[120,715,285],{"class":130},[120,717,718],{"class":122,"line":222},[120,719,720],{"class":130},"raster.setRenderer(renderer)\n",[120,722,723],{"class":122,"line":233},[120,724,725],{"class":130},"raster.triggerRepaint()\n",[14,727,728,291,730,732,733,736,737,740,741,744,745,748,749,752],{},[52,729,290],{},[18,731,24],{}," is a thin wrapper; ",[18,734,735],{},"setRasterShaderFunction()"," plugs in the colour-ramp shader you built. ",[18,738,739],{},"QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)"," ties the renderer to the data provider and the 1-based band number. ",[18,742,743],{},"setRenderer()"," replaces the layer's current renderer, and ",[18,746,747],{},"triggerRepaint()"," redraws the canvas. If the GUI is open, also call ",[18,750,751],{},"iface.layerTreeView().refreshLayerSymbology(raster.id())"," so the legend shows the new ramp.",[41,754,756],{"id":755},"recipe-5-classify-by-quantile-instead-of-linear-minmax","Recipe 5: Classify by quantile instead of linear min\u002Fmax",[14,758,759],{},"Linear min–max stretching washes out when a few outlier pixels stretch the range. Quantile (equal-count) classification distributes class breaks so each holds a similar number of pixels, revealing structure in skewed data.",[111,761,763],{"className":113,"code":762,"language":115,"meta":116,"style":116},"from qgis.core import (\n    QgsColorRampShader, QgsStyle, QgsRasterShader,\n    QgsSingleBandPseudoColorRenderer,\n)\n\nramp = QgsStyle.defaultStyle().colorRamp(\"Spectral\")\nshader = QgsColorRampShader(v_min, v_max)\nshader.setColorRampType(QgsColorRampShader.Interpolated)\nshader.setSourceColorRamp(ramp)\nshader.setClassificationMode(QgsColorRampShader.Quantile)\nshader.classifyColorRamp(classes=6, band=band, input=provider.input())\n\nraster_shader = QgsRasterShader()\nraster_shader.setRasterShaderFunction(shader)\nraster.setRenderer(\n    QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)\n)\nraster.triggerRepaint()\n",[18,764,765,775,780,785,789,793,807,815,819,823,828,853,857,865,869,875,881,886],{"__ignoreMap":116},[120,766,767,769,771,773],{"class":122,"line":123},[120,768,127],{"class":126},[120,770,131],{"class":130},[120,772,134],{"class":126},[120,774,348],{"class":130},[120,776,777],{"class":122,"line":140},[120,778,779],{"class":130},"    QgsColorRampShader, QgsStyle, QgsRasterShader,\n",[120,781,782],{"class":122,"line":147},[120,783,784],{"class":130},"    QgsSingleBandPseudoColorRenderer,\n",[120,786,787],{"class":122,"line":173},[120,788,285],{"class":130},[120,790,791],{"class":122,"line":184},[120,792,144],{"emptyLinePlaceholder":143},[120,794,795,797,799,802,805],{"class":122,"line":189},[120,796,384],{"class":130},[120,798,153],{"class":126},[120,800,801],{"class":130}," QgsStyle.defaultStyle().colorRamp(",[120,803,804],{"class":159},"\"Spectral\"",[120,806,285],{"class":130},[120,808,809,811,813],{"class":122,"line":200},[120,810,410],{"class":130},[120,812,153],{"class":126},[120,814,415],{"class":130},[120,816,817],{"class":122,"line":211},[120,818,420],{"class":130},[120,820,821],{"class":122,"line":222},[120,822,426],{"class":130},[120,824,825],{"class":122,"line":233},[120,826,827],{"class":130},"shader.setClassificationMode(QgsColorRampShader.Quantile)\n",[120,829,830,832,834,836,839,841,843,845,847,849,851],{"class":122,"line":423},[120,831,443],{"class":130},[120,833,447],{"class":446},[120,835,153],{"class":126},[120,837,838],{"class":166},"6",[120,840,303],{"class":130},[120,842,251],{"class":446},[120,844,153],{"class":126},[120,846,461],{"class":130},[120,848,464],{"class":446},[120,850,153],{"class":126},[120,852,469],{"class":130},[120,854,855],{"class":122,"line":429},[120,856,144],{"emptyLinePlaceholder":143},[120,858,859,861,863],{"class":122,"line":434},[120,860,682],{"class":130},[120,862,153],{"class":126},[120,864,687],{"class":130},[120,866,867],{"class":122,"line":440},[120,868,692],{"class":130},[120,870,872],{"class":122,"line":871},15,[120,873,874],{"class":130},"raster.setRenderer(\n",[120,876,878],{"class":122,"line":877},16,[120,879,880],{"class":130},"    QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)\n",[120,882,884],{"class":122,"line":883},17,[120,885,285],{"class":130},[120,887,889],{"class":122,"line":888},18,[120,890,725],{"class":130},[14,892,893,291,895,898,899,902,903,905,906,910],{},[52,894,290],{},[18,896,897],{},"setClassificationMode(QgsColorRampShader.Quantile)"," switches break placement from ",[18,900,901],{},"Continuous"," (evenly spaced) to equal-count, so ",[18,904,500],{}," computes breaks from the band's value distribution. This is the raster analogue of the natural-breaks and quantile choices you make for vectors in ",[31,907,909],{"href":908},"\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002F","Graduated & Categorized Renderers",". Quantile is the right call for elevation, population density, or any heavy-tailed surface where a linear stretch would crush most of the contrast into one band of colour.",[41,912,914],{"id":913},"recipe-6-discrete-classes-with-explicit-breaks","Recipe 6: Discrete classes with explicit breaks",[14,916,917,918,920],{},"When the audience needs to read distinct categories off the map — elevation bands, risk tiers — a discrete shader with hand-set breaks beats a smooth gradient. You build the ",[18,919,331],{}," list yourself, controlling both the break value and the legend label.",[111,922,924],{"className":113,"code":923,"language":115,"meta":116,"style":116},"from qgis.core import (\n    QgsColorRampShader, QgsRasterShader,\n    QgsSingleBandPseudoColorRenderer,\n)\nfrom qgis.PyQt.QtGui import QColor\n\nitems = [\n    QgsColorRampShader.ColorRampItem(200, QColor(\"#22c55e\"), \"0-200 m\"),\n    QgsColorRampShader.ColorRampItem(500, QColor(\"#b45309\"), \"200-500 m\"),\n    QgsColorRampShader.ColorRampItem(1000, QColor(\"#7c2d12\"), \"500-1000 m\"),\n    QgsColorRampShader.ColorRampItem(3000, QColor(\"#f6f3ea\"), \">1000 m\"),\n]\n\nshader = QgsColorRampShader()\nshader.setColorRampType(QgsColorRampShader.Discrete)\nshader.setColorRampItemList(items)\n\nraster_shader = QgsRasterShader()\nraster_shader.setRasterShaderFunction(shader)\nraster.setRenderer(\n    QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)\n)\nraster.triggerRepaint()\n",[18,925,926,936,941,945,949,959,963,973,996,1014,1033,1052,1056,1060,1069,1074,1079,1083,1091,1096,1101,1106,1111],{"__ignoreMap":116},[120,927,928,930,932,934],{"class":122,"line":123},[120,929,127],{"class":126},[120,931,131],{"class":130},[120,933,134],{"class":126},[120,935,348],{"class":130},[120,937,938],{"class":122,"line":140},[120,939,940],{"class":130},"    QgsColorRampShader, QgsRasterShader,\n",[120,942,943],{"class":122,"line":147},[120,944,784],{"class":130},[120,946,947],{"class":122,"line":173},[120,948,285],{"class":130},[120,950,951,953,955,957],{"class":122,"line":184},[120,952,127],{"class":126},[120,954,364],{"class":130},[120,956,134],{"class":126},[120,958,369],{"class":130},[120,960,961],{"class":122,"line":189},[120,962,144],{"emptyLinePlaceholder":143},[120,964,965,968,970],{"class":122,"line":200},[120,966,967],{"class":130},"items ",[120,969,153],{"class":126},[120,971,972],{"class":130}," [\n",[120,974,975,978,981,984,987,990,993],{"class":122,"line":211},[120,976,977],{"class":130},"    QgsColorRampShader.ColorRampItem(",[120,979,980],{"class":166},"200",[120,982,983],{"class":130},", QColor(",[120,985,986],{"class":159},"\"#22c55e\"",[120,988,989],{"class":130},"), ",[120,991,992],{"class":159},"\"0-200 m\"",[120,994,995],{"class":130},"),\n",[120,997,998,1000,1003,1005,1007,1009,1012],{"class":122,"line":222},[120,999,977],{"class":130},[120,1001,1002],{"class":166},"500",[120,1004,983],{"class":130},[120,1006,398],{"class":159},[120,1008,989],{"class":130},[120,1010,1011],{"class":159},"\"200-500 m\"",[120,1013,995],{"class":130},[120,1015,1016,1018,1021,1023,1026,1028,1031],{"class":122,"line":233},[120,1017,977],{"class":130},[120,1019,1020],{"class":166},"1000",[120,1022,983],{"class":130},[120,1024,1025],{"class":159},"\"#7c2d12\"",[120,1027,989],{"class":130},[120,1029,1030],{"class":159},"\"500-1000 m\"",[120,1032,995],{"class":130},[120,1034,1035,1037,1040,1042,1045,1047,1050],{"class":122,"line":423},[120,1036,977],{"class":130},[120,1038,1039],{"class":166},"3000",[120,1041,983],{"class":130},[120,1043,1044],{"class":159},"\"#f6f3ea\"",[120,1046,989],{"class":130},[120,1048,1049],{"class":159},"\">1000 m\"",[120,1051,995],{"class":130},[120,1053,1054],{"class":122,"line":429},[120,1055,170],{"class":130},[120,1057,1058],{"class":122,"line":434},[120,1059,144],{"emptyLinePlaceholder":143},[120,1061,1062,1064,1066],{"class":122,"line":440},[120,1063,410],{"class":130},[120,1065,153],{"class":126},[120,1067,1068],{"class":130}," QgsColorRampShader()\n",[120,1070,1071],{"class":122,"line":871},[120,1072,1073],{"class":130},"shader.setColorRampType(QgsColorRampShader.Discrete)\n",[120,1075,1076],{"class":122,"line":877},[120,1077,1078],{"class":130},"shader.setColorRampItemList(items)\n",[120,1080,1081],{"class":122,"line":883},[120,1082,144],{"emptyLinePlaceholder":143},[120,1084,1085,1087,1089],{"class":122,"line":888},[120,1086,682],{"class":130},[120,1088,153],{"class":126},[120,1090,687],{"class":130},[120,1092,1094],{"class":122,"line":1093},19,[120,1095,692],{"class":130},[120,1097,1099],{"class":122,"line":1098},20,[120,1100,874],{"class":130},[120,1102,1104],{"class":122,"line":1103},21,[120,1105,880],{"class":130},[120,1107,1109],{"class":122,"line":1108},22,[120,1110,285],{"class":130},[120,1112,1114],{"class":122,"line":1113},23,[120,1115,725],{"class":130},[14,1117,1118,1120,1121,1124,1125,1129,1130,1132,1133,1136,1137,1139],{},[52,1119,290],{}," Each ",[18,1122,1123],{},"ColorRampItem(value, color, label)"," defines the ",[1126,1127,1128],"em",{},"upper bound"," of a class in ",[18,1131,492],{}," mode, plus the legend text. ",[18,1134,1135],{},"setColorRampItemList()"," installs the whole list at once, bypassing ",[18,1138,500],{}," entirely since you are specifying breaks manually. Discrete mode paints a flat colour up to each value, producing a stepped legend that maps cleanly to named bands — ideal when \"is this above 500 m?\" is the question the map must answer.",[41,1141,1143],{"id":1142},"recipe-7-reuse-the-styling-as-a-wrapped-function","Recipe 7: Reuse the styling as a wrapped function",[14,1145,1146],{},"For automation you want the whole pipeline behind one call so it can run over a folder of rasters. The function below classifies and applies a named ramp to any single-band layer.",[111,1148,1150],{"className":113,"code":1149,"language":115,"meta":116,"style":116},"from qgis.core import (\n    QgsRasterBandStats, QgsColorRampShader, QgsStyle,\n    QgsRasterShader, QgsSingleBandPseudoColorRenderer,\n)\n\n\ndef apply_named_ramp(raster, ramp_name=\"Viridis\", classes=7, band=1):\n    \"\"\"Classify a single-band raster with a named color ramp.\"\"\"\n    provider = raster.dataProvider()\n    stats = provider.bandStatistics(band, QgsRasterBandStats.All)\n\n    ramp = QgsStyle.defaultStyle().colorRamp(ramp_name)\n    if ramp is None:\n        raise ValueError(f\"Unknown color ramp: {ramp_name}\")\n\n    shader = QgsColorRampShader(stats.minimumValue, stats.maximumValue)\n    shader.setColorRampType(QgsColorRampShader.Interpolated)\n    shader.setSourceColorRamp(ramp)\n    shader.classifyColorRamp(classes=classes, band=band, input=provider.input())\n\n    raster_shader = QgsRasterShader()\n    raster_shader.setRasterShaderFunction(shader)\n    raster.setRenderer(\n        QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)\n    )\n    raster.triggerRepaint()\n    return raster\n",[18,1151,1152,1162,1167,1172,1176,1180,1184,1218,1223,1232,1241,1245,1255,1272,1298,1302,1312,1317,1322,1346,1350,1359,1364,1369,1375,1381,1387],{"__ignoreMap":116},[120,1153,1154,1156,1158,1160],{"class":122,"line":123},[120,1155,127],{"class":126},[120,1157,131],{"class":130},[120,1159,134],{"class":126},[120,1161,348],{"class":130},[120,1163,1164],{"class":122,"line":140},[120,1165,1166],{"class":130},"    QgsRasterBandStats, QgsColorRampShader, QgsStyle,\n",[120,1168,1169],{"class":122,"line":147},[120,1170,1171],{"class":130},"    QgsRasterShader, QgsSingleBandPseudoColorRenderer,\n",[120,1173,1174],{"class":122,"line":173},[120,1175,285],{"class":130},[120,1177,1178],{"class":122,"line":184},[120,1179,144],{"emptyLinePlaceholder":143},[120,1181,1182],{"class":122,"line":189},[120,1183,144],{"emptyLinePlaceholder":143},[120,1185,1186,1189,1193,1196,1198,1200,1203,1205,1207,1210,1212,1215],{"class":122,"line":200},[120,1187,1188],{"class":126},"def",[120,1190,1192],{"class":1191},"svObZ"," apply_named_ramp",[120,1194,1195],{"class":130},"(raster, ramp_name",[120,1197,153],{"class":126},[120,1199,574],{"class":159},[120,1201,1202],{"class":130},", classes",[120,1204,153],{"class":126},[120,1206,607],{"class":166},[120,1208,1209],{"class":130},", band",[120,1211,153],{"class":126},[120,1213,1214],{"class":166},"1",[120,1216,1217],{"class":130},"):\n",[120,1219,1220],{"class":122,"line":211},[120,1221,1222],{"class":159},"    \"\"\"Classify a single-band raster with a named color ramp.\"\"\"\n",[120,1224,1225,1228,1230],{"class":122,"line":222},[120,1226,1227],{"class":130},"    provider ",[120,1229,153],{"class":126},[120,1231,181],{"class":130},[120,1233,1234,1237,1239],{"class":122,"line":233},[120,1235,1236],{"class":130},"    stats ",[120,1238,153],{"class":126},[120,1240,208],{"class":130},[120,1242,1243],{"class":122,"line":423},[120,1244,144],{"emptyLinePlaceholder":143},[120,1246,1247,1250,1252],{"class":122,"line":429},[120,1248,1249],{"class":130},"    ramp ",[120,1251,153],{"class":126},[120,1253,1254],{"class":130}," QgsStyle.defaultStyle().colorRamp(ramp_name)\n",[120,1256,1257,1260,1263,1266,1269],{"class":122,"line":434},[120,1258,1259],{"class":126},"    if",[120,1261,1262],{"class":130}," ramp ",[120,1264,1265],{"class":126},"is",[120,1267,1268],{"class":166}," None",[120,1270,1271],{"class":130},":\n",[120,1273,1274,1277,1280,1282,1284,1287,1289,1292,1294,1296],{"class":122,"line":440},[120,1275,1276],{"class":126},"        raise",[120,1278,1279],{"class":166}," ValueError",[120,1281,239],{"class":130},[120,1283,242],{"class":126},[120,1285,1286],{"class":159},"\"Unknown color ramp: ",[120,1288,248],{"class":166},[120,1290,1291],{"class":130},"ramp_name",[120,1293,254],{"class":166},[120,1295,282],{"class":159},[120,1297,285],{"class":130},[120,1299,1300],{"class":122,"line":871},[120,1301,144],{"emptyLinePlaceholder":143},[120,1303,1304,1307,1309],{"class":122,"line":877},[120,1305,1306],{"class":130},"    shader ",[120,1308,153],{"class":126},[120,1310,1311],{"class":130}," QgsColorRampShader(stats.minimumValue, stats.maximumValue)\n",[120,1313,1314],{"class":122,"line":883},[120,1315,1316],{"class":130},"    shader.setColorRampType(QgsColorRampShader.Interpolated)\n",[120,1318,1319],{"class":122,"line":888},[120,1320,1321],{"class":130},"    shader.setSourceColorRamp(ramp)\n",[120,1323,1324,1327,1329,1331,1334,1336,1338,1340,1342,1344],{"class":122,"line":1093},[120,1325,1326],{"class":130},"    shader.classifyColorRamp(",[120,1328,447],{"class":446},[120,1330,153],{"class":126},[120,1332,1333],{"class":130},"classes, ",[120,1335,251],{"class":446},[120,1337,153],{"class":126},[120,1339,461],{"class":130},[120,1341,464],{"class":446},[120,1343,153],{"class":126},[120,1345,469],{"class":130},[120,1347,1348],{"class":122,"line":1098},[120,1349,144],{"emptyLinePlaceholder":143},[120,1351,1352,1355,1357],{"class":122,"line":1103},[120,1353,1354],{"class":130},"    raster_shader ",[120,1356,153],{"class":126},[120,1358,687],{"class":130},[120,1360,1361],{"class":122,"line":1108},[120,1362,1363],{"class":130},"    raster_shader.setRasterShaderFunction(shader)\n",[120,1365,1366],{"class":122,"line":1113},[120,1367,1368],{"class":130},"    raster.setRenderer(\n",[120,1370,1372],{"class":122,"line":1371},24,[120,1373,1374],{"class":130},"        QgsSingleBandPseudoColorRenderer(provider, band, raster_shader)\n",[120,1376,1378],{"class":122,"line":1377},25,[120,1379,1380],{"class":130},"    )\n",[120,1382,1384],{"class":122,"line":1383},26,[120,1385,1386],{"class":130},"    raster.triggerRepaint()\n",[120,1388,1390,1393],{"class":122,"line":1389},27,[120,1391,1392],{"class":126},"    return",[120,1394,1395],{"class":130}," raster\n",[14,1397,1398,1400,1401,1404,1405,1407],{},[52,1399,290],{}," The function folds Recipes 1 through 4 into one reusable call, reading the band range fresh each time so it adapts to whatever raster it receives. The ",[18,1402,1403],{},"None"," guard turns a typo'd ramp name into a clear exception rather than a silent failure. Returning the layer lets you chain or log the result. Drop this into a loop over ",[18,1406,61],{}," instances to restyle an entire directory of grids consistently — the styling counterpart to the batch analysis patterns in the raster workflows cluster.",[41,1409,1411],{"id":1410},"qgis-version-compatibility","QGIS Version Compatibility",[14,1413,1414,1415,1418],{},"All snippets target ",[52,1416,1417],{},"QGIS 3.34 LTR with Python 3.12",". The pseudo-color rendering classes have been stable across the 3.x line.",[1420,1421,1422,1438],"table",{},[1423,1424,1425],"thead",{},[1426,1427,1428,1432,1435],"tr",{},[1429,1430,1431],"th",{},"QGIS version",[1429,1433,1434],{},"Python",[1429,1436,1437],{},"Notes",[1439,1440,1441,1456,1467],"tbody",{},[1426,1442,1443,1447,1450],{},[1444,1445,1446],"td",{},"3.28 LTR",[1444,1448,1449],{},"3.9",[1444,1451,1452,1453,1455],{},"All classes present; ",[18,1454,500],{}," signature identical.",[1426,1457,1458,1461,1464],{},[1444,1459,1460],{},"3.34 LTR",[1444,1462,1463],{},"3.12",[1444,1465,1466],{},"Reference version; run as written.",[1426,1468,1469,1472,1474],{},[1444,1470,1471],{},"3.40 \u002F 3.44",[1444,1473,1463],{},[1444,1475,1476,1479,1480,1483,1484,1487],{},[18,1477,1478],{},"QgsColorRampShader.Interpolated"," \u002F ",[18,1481,1482],{},".Quantile"," still resolve; scoped ",[18,1485,1486],{},"QgsColorRampShader.Type.Interpolated"," is the newer spelling.",[14,1489,1490,1492],{},[18,1491,298],{}," and the 1-based band convention apply across all three versions, so a script written for 3.34 runs unchanged on 3.28 and 3.40+.",[41,1494,1496],{"id":1495},"troubleshooting","Troubleshooting",[14,1498,1499,1502,1503,1505,1506,1508,1509,1512,1513,39],{},[52,1500,1501],{},"The raster renders all one color or all black.","\nThe shader's ",[18,1504,262],{},"\u002F",[18,1507,275],{}," do not match the data. Confirm you read them from ",[18,1510,1511],{},"bandStatistics()"," for the correct 1-based band, and that you passed them to ",[18,1514,484],{},[14,1516,1517,1522,1523,1525],{},[52,1518,1519,1521],{},[18,1520,500],{}," produced no items.","\nYou likely called it before ",[18,1524,643],{},", so there was no ramp to sample. Set the source ramp first, then classify.",[14,1527,1528,1535,1536,1539],{},[52,1529,1530,1532,1533,39],{},[18,1531,635],{}," returned ",[18,1534,1403],{},"\nThe name is wrong or that ramp is not installed. Print ",[18,1537,1538],{},"QgsStyle.defaultStyle().colorRampNames()"," and copy an exact name; ramp names are case-sensitive.",[14,1541,1542,1545,1547,1548,1550],{},[52,1543,1544],{},"The legend did not update though the canvas did.",[18,1546,747],{}," only refreshes the canvas. Add ",[18,1549,751],{}," when the GUI is open.",[14,1552,1553,1556,1557,1560],{},[52,1554,1555],{},"NoData pixels show a solid colour.","\nSet a NoData value on the provider or call ",[18,1558,1559],{},"renderer.setNodataColor(QColor(0, 0, 0, 0))"," to render them transparent rather than mapping them onto the ramp.",[41,1562,1564],{"id":1563},"conclusion","Conclusion",[14,1566,1567,1568,1570,1571,1573,1574,1576,1577,1580,1581,1583,1584,1586],{},"Applying a colour ramp to a raster is a fixed three-object pipeline: a ",[18,1569,20],{}," mapping values to colours, wrapped in a ",[18,1572,24],{},", driven by a ",[18,1575,28],{},". The decisions that matter are where the ramp comes from (a hand-built ",[18,1578,1579],{},"QgsGradientColorRamp"," or a named ramp from ",[18,1582,517],{},") and how breaks are placed (linear min–max for evenly distributed data, quantile for skewed surfaces). Anchor the shader to the band's real range via ",[18,1585,38],{},", classify, set the renderer, and repaint.",[41,1588,1590],{"id":1589},"frequently-asked-questions","Frequently Asked Questions",[14,1592,1593,1596,1597,1600,1601,504,1603,1605],{},[52,1594,1595],{},"How do I find the value range of my raster band?","\nCall ",[18,1598,1599],{},"provider.bandStatistics(band, QgsRasterBandStats.All)"," and read ",[18,1602,302],{},[18,1604,306],{},". Band numbers are 1-based, and QGIS may sample large rasters rather than reading every pixel.",[14,1607,1608,1611,1612,1614,1615,1617,1618,1620],{},[52,1609,1610],{},"Where do the named color ramps like Viridis come from?","\nFrom ",[18,1613,517],{},", the application's style database. List them with ",[18,1616,631],{}," and fetch one with ",[18,1619,635],{},". Names are case-sensitive.",[14,1622,1623,1626,1629,1630,1632,1633,1635],{},[52,1624,1625],{},"What is the difference between Interpolated, Discrete, and Exact shader types?",[18,1627,1628],{},"Interpolated"," blends colours smoothly between stops for continuous data. ",[18,1631,492],{}," applies a flat colour up to each break for stepped legends. ",[18,1634,496],{}," matches specific values, which suits categorical rasters such as land-cover codes.",[14,1637,1638,1641],{},[52,1639,1640],{},"When should I use quantile instead of linear classification?","\nUse quantile when the data is skewed or has outliers — elevation, density, rainfall — so each class holds a similar pixel count and contrast is preserved. Linear min–max suits roughly uniform value distributions, while a discrete shader with hand-set breaks is best when the map must communicate named bands rather than a smooth surface.",[41,1643,1645],{"id":1644},"related","Related",[46,1647,1648,1652,1658],{},[49,1649,1650],{},[31,1651,34],{"href":33},[49,1653,1654],{},[31,1655,1657],{"href":1656},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fset-vector-layer-symbol-color-pyqgis\u002F","Set Vector Layer Symbol Color in PyQGIS",[49,1659,1660],{},[31,1661,318],{"href":317},[1663,1664,1665],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":116,"searchDepth":140,"depth":140,"links":1667},[1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681],{"id":43,"depth":140,"text":44},{"id":86,"depth":140,"text":87},{"id":102,"depth":140,"text":103},{"id":321,"depth":140,"text":322},{"id":510,"depth":140,"text":511},{"id":647,"depth":140,"text":648},{"id":755,"depth":140,"text":756},{"id":913,"depth":140,"text":914},{"id":1142,"depth":140,"text":1143},{"id":1410,"depth":140,"text":1411},{"id":1495,"depth":140,"text":1496},{"id":1563,"depth":140,"text":1564},{"id":1589,"depth":140,"text":1590},{"id":1644,"depth":140,"text":1645},"Apply a color ramp to a single-band raster in PyQGIS using QgsColorRampShader, QgsRasterShader, and QgsSingleBandPseudoColorRenderer classified by min\u002Fmax.","md",{},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fapply-color-ramp-to-raster-pyqgis",{"title":5,"description":1682},"pyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fapply-color-ramp-to-raster-pyqgis\u002Findex","A-WrWEQDgpQ26Qd9AX8okOLBxo_MmI6D7ORwgpLGsgg",1781792483473]