[{"data":1,"prerenderedAt":2852},["ShallowReactive",2],{"doc:\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers":3},{"id":4,"title":5,"body":6,"description":2840,"extension":2841,"meta":2842,"navigation":373,"path":2848,"seo":2849,"stem":2850,"__hash__":2851},"docs\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Findex.md","Graduated & Categorized Renderers in PyQGIS",{"type":7,"value":8,"toc":2822},"minimark",[9,14,31,47,64,75,80,131,135,146,296,300,310,533,562,577,580,657,662,666,672,811,833,837,844,1003,1032,1039,1043,1050,1245,1414,1439,1493,1513,1517,1527,1693,1712,1716,1723,1874,1905,1909,1912,2150,2176,2180,2187,2340,2366,2370,2373,2439,2460,2464,2467,2578,2582,2591,2655,2661,2665,2706,2710,2716,2729,2739,2753,2773,2777,2818],[10,11,13],"h1",{"id":12},"graduated-and-categorized-renderers-in-pyqgis","Graduated and Categorized Renderers in PyQGIS",[15,16,17],"p",{},[18,19,20,25,26,30],"em",{},[21,22,24],"a",{"href":23},"\u002F","Home"," → ",[21,27,29],{"href":28},"\u002Fpyqgis-cartography-visualization\u002F","Cartography & Visualization"," → Graduated & Categorized Renderers",[15,32,33,34,38,39,42,43,46],{},"Thematic mapping turns raw attribute tables into maps that communicate patterns at a glance. The two renderers at the heart of this work are ",[35,36,37],"code",{},"QgsCategorizedSymbolRenderer",", which assigns one symbol per distinct attribute value, and ",[35,40,41],{},"QgsGraduatedSymbolRenderer",", which slices a continuous numeric field into classified ranges. Mastering both — along with the classification methods and color ramps that drive them — lets you generate consistent, reproducible cartography entirely from code. This guide sits inside ",[21,44,45],{"href":28},"PyQGIS Cartography & Data Visualization"," and focuses specifically on data-driven symbol assignment: how QGIS decides which feature gets which color or size, and how you control that decision programmatically.",[15,48,49,50,54,55,59,60,63],{},"Where ",[21,51,53],{"href":52},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002F","Programmatic Layer Styling"," deals with single symbols and per-feature properties, and ",[21,56,58],{"href":57},"\u002Fpyqgis-cartography-visualization\u002Flabeling-and-annotations\u002F","Labeling & Annotations"," deals with text, this page is about ",[18,61,62],{},"classification"," — grouping features and mapping each group to a visual variable.",[15,65,66,67,70,71,74],{},"Both renderers share the same underlying model: a layer holds exactly one renderer, and that renderer owns a collection of class definitions plus an optional color ramp. A categorized renderer's collection is a list of ",[35,68,69],{},"QgsRendererCategory"," objects; a graduated renderer's is a list of ",[35,72,73],{},"QgsRendererRange"," objects. Understanding that shared structure is what lets you write generic styling code that branches only where the two genuinely differ — discovering categories versus computing numeric breaks. The sections below build that understanding step by step, from creating each renderer to inspecting, recoloring, and persisting it.",[76,77,79],"h2",{"id":78},"prerequisites","Prerequisites",[81,82,83,91,102,117],"ul",{},[84,85,86,90],"li",{},[87,88,89],"strong",{},"QGIS 3.34 LTR"," (bundles Python 3.12) or a comparable 3.x release with PyQGIS available.",[84,92,93,94,97,98,101],{},"A vector layer loaded in the project with at least one categorical field (e.g. ",[35,95,96],{},"land_use",") and one numeric field (e.g. ",[35,99,100],{},"population",").",[84,103,104,105,108,109,112,113,116],{},"Access to the ",[87,106,107],{},"QGIS Python Console"," (",[35,110,111],{},"Ctrl+Alt+P",") or a standalone script with an initialized ",[35,114,115],{},"QgsApplication",".",[84,118,119,120,123,124,127,128,116],{},"Familiarity with ",[35,121,122],{},"QgsVectorLayer",", ",[35,125,126],{},"QgsSymbol",", and how to retrieve layers via ",[35,129,130],{},"QgsProject.instance()",[76,132,134],{"id":133},"categorized-vs-graduated-at-a-glance","Categorized vs Graduated at a Glance",[15,136,137,138,141,142,145],{},"The single most common mistake is reaching for the wrong renderer. Categorized renderers answer ",[18,139,140],{},"\"what kind is it?\""," (nominal data), while graduated renderers answer ",[18,143,144],{},"\"how much of it is there?\""," (ordinal or ratio data). The diagram below contrasts how each maps source data to symbols.",[147,148,153,154,153,158,153,162,153,169,153,178,153,181,153,189,153,193,153,199,153,202,153,208,153,215,153,219,153,223,153,227,153,231,153,235,153,239,153,244,153,248,153,252,153,255,153,258,153,261,153,264,153,267,153,270,153,273,153,280,153,285,153,289,153,291,153,293],"svg",{"viewBox":149,"role":150,"ariaLabel":151,"xmlns":152},"0 0 640 360","img","Comparison of categorized and graduated renderers in PyQGIS","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[155,156,157],"title",{},"Categorized versus graduated renderer data flow",[159,160,161],"desc",{},"Left panel shows discrete attribute values each mapped to a distinct color; right panel shows a numeric range split into ordered classes mapped to a sequential color ramp.",[163,164],"rect",{"x":165,"y":165,"width":166,"height":167,"fill":168},"0","640","360","#f6f3ea",[163,170],{"x":171,"y":171,"width":172,"height":173,"rx":174,"fill":175,"stroke":176,"style":177},"20","290","320","8","#fffdf7","#17211d","stroke-width:2",[163,179],{"x":180,"y":171,"width":172,"height":173,"rx":174,"fill":175,"stroke":176,"style":177},"330",[182,183,188],"text",{"x":184,"y":185,"fill":176,"style":186,"textAnchor":187},"165","48","text-anchor:middle;font-family:sans-serif;font-size:18px;font-weight:bold","middle","Categorized",[182,190,192],{"x":191,"y":185,"fill":176,"style":186,"textAnchor":187},"475","Graduated",[182,194,198],{"x":184,"y":195,"fill":196,"style":197,"textAnchor":187},"68","#2f3b35","text-anchor:middle;font-family:sans-serif;font-size:12px","one symbol per unique value",[182,200,201],{"x":191,"y":195,"fill":196,"style":197,"textAnchor":187},"numeric ranges into classes",[182,203,207],{"x":204,"y":205,"fill":196,"style":206},"40","100","font-family:monospace;font-size:13px","\"forest\"",[163,209],{"x":210,"y":211,"width":212,"height":213,"fill":214},"200","88","90","18","#15803d",[182,216,218],{"x":204,"y":217,"fill":196,"style":206},"132","\"urban\"",[163,220],{"x":210,"y":221,"width":212,"height":213,"fill":222},"120","#b45309",[182,224,226],{"x":204,"y":225,"fill":196,"style":206},"164","\"water\"",[163,228],{"x":210,"y":229,"width":212,"height":213,"fill":230},"152","#2563eb",[182,232,234],{"x":204,"y":233,"fill":196,"style":206},"196","\"crop\"",[163,236],{"x":210,"y":237,"width":212,"height":213,"fill":238},"184","#22c55e",[182,240,243],{"x":184,"y":241,"fill":242,"style":197,"textAnchor":187},"245","#0f766e","distinct, unordered colors",[182,245,247],{"x":246,"y":205,"fill":196,"style":206},"350","0 – 50",[163,249],{"x":250,"y":211,"width":221,"height":213,"fill":251},"470","#edf8e9",[182,253,254],{"x":246,"y":217,"fill":196,"style":206},"50 – 120",[163,256],{"x":250,"y":221,"width":221,"height":213,"fill":257},"#a1d99b",[182,259,260],{"x":246,"y":225,"fill":196,"style":206},"120 – 300",[163,262],{"x":250,"y":229,"width":221,"height":213,"fill":263},"#41ab5d",[182,265,266],{"x":246,"y":233,"fill":196,"style":206},"300 – 900",[163,268],{"x":250,"y":237,"width":221,"height":213,"fill":269},"#005a32",[182,271,272],{"x":191,"y":241,"fill":242,"style":197,"textAnchor":187},"ordered sequential ramp",[163,274],{"x":204,"y":275,"width":276,"height":277,"rx":278,"fill":279},"270","250","50","6","#26322d",[182,281,37],{"x":184,"y":282,"fill":283,"style":284,"textAnchor":187},"292","#d9f99d","text-anchor:middle;font-family:monospace;font-size:11px",[182,286,288],{"x":184,"y":287,"fill":283,"style":284,"textAnchor":187},"310",".createCategories()",[163,290],{"x":246,"y":275,"width":276,"height":277,"rx":278,"fill":279},[182,292,41],{"x":191,"y":282,"fill":283,"style":284,"textAnchor":187},[182,294,295],{"x":191,"y":287,"fill":283,"style":284,"textAnchor":187},".updateClasses()",[76,297,299],{"id":298},"_1-categorizing-a-layer-by-a-unique-attribute-value","1. Categorizing a Layer by a Unique Attribute Value",[15,301,302,303,305,306,309],{},"A categorized renderer iterates the distinct values of a field and binds each to its own ",[35,304,126],{},". The clean modern path is ",[35,307,308],{},"QgsCategorizedSymbolRenderer.createCategories()",", which collects the unique values, generates symbols from a template, and applies a color ramp in one call.",[311,312,317],"pre",{"className":313,"code":314,"language":315,"meta":316,"style":316},"language-python shiki shiki-themes github-dark","from qgis.core import (\n    QgsProject,\n    QgsCategorizedSymbolRenderer,\n    QgsSymbol,\n    QgsStyle,\n)\n\nlayer = QgsProject.instance().mapLayersByName(\"land_cover\")[0]\nfield_name = \"land_use\"\n\n# Template symbol carries geometry-appropriate defaults (fill, stroke).\ntemplate_symbol = QgsSymbol.defaultSymbol(layer.geometryType())\n\n# Pick a qualitative ramp so unordered categories read as distinct.\ndefault_style = QgsStyle.defaultStyle()\ncolor_ramp = default_style.colorRamp(\"Spectral\")\n\ncategories = QgsCategorizedSymbolRenderer.createCategories(\n    [], template_symbol, layer, field_name\n)\nrenderer = QgsCategorizedSymbolRenderer(field_name, categories)\nrenderer.updateColorRamp(color_ramp)\n\nlayer.setRenderer(renderer)\nlayer.triggerRepaint()\n","python","",[35,318,319,338,344,350,356,362,368,375,400,411,416,423,434,439,445,456,472,477,488,494,499,510,516,521,527],{"__ignoreMap":316},[320,321,324,328,332,335],"span",{"class":322,"line":323},"line",1,[320,325,327],{"class":326},"snl16","from",[320,329,331],{"class":330},"s95oV"," qgis.core ",[320,333,334],{"class":326},"import",[320,336,337],{"class":330}," (\n",[320,339,341],{"class":322,"line":340},2,[320,342,343],{"class":330},"    QgsProject,\n",[320,345,347],{"class":322,"line":346},3,[320,348,349],{"class":330},"    QgsCategorizedSymbolRenderer,\n",[320,351,353],{"class":322,"line":352},4,[320,354,355],{"class":330},"    QgsSymbol,\n",[320,357,359],{"class":322,"line":358},5,[320,360,361],{"class":330},"    QgsStyle,\n",[320,363,365],{"class":322,"line":364},6,[320,366,367],{"class":330},")\n",[320,369,371],{"class":322,"line":370},7,[320,372,374],{"emptyLinePlaceholder":373},true,"\n",[320,376,378,381,384,387,391,394,397],{"class":322,"line":377},8,[320,379,380],{"class":330},"layer ",[320,382,383],{"class":326},"=",[320,385,386],{"class":330}," QgsProject.instance().mapLayersByName(",[320,388,390],{"class":389},"sU2Wk","\"land_cover\"",[320,392,393],{"class":330},")[",[320,395,165],{"class":396},"sDLfK",[320,398,399],{"class":330},"]\n",[320,401,403,406,408],{"class":322,"line":402},9,[320,404,405],{"class":330},"field_name ",[320,407,383],{"class":326},[320,409,410],{"class":389}," \"land_use\"\n",[320,412,414],{"class":322,"line":413},10,[320,415,374],{"emptyLinePlaceholder":373},[320,417,419],{"class":322,"line":418},11,[320,420,422],{"class":421},"sjoCn","# Template symbol carries geometry-appropriate defaults (fill, stroke).\n",[320,424,426,429,431],{"class":322,"line":425},12,[320,427,428],{"class":330},"template_symbol ",[320,430,383],{"class":326},[320,432,433],{"class":330}," QgsSymbol.defaultSymbol(layer.geometryType())\n",[320,435,437],{"class":322,"line":436},13,[320,438,374],{"emptyLinePlaceholder":373},[320,440,442],{"class":322,"line":441},14,[320,443,444],{"class":421},"# Pick a qualitative ramp so unordered categories read as distinct.\n",[320,446,448,451,453],{"class":322,"line":447},15,[320,449,450],{"class":330},"default_style ",[320,452,383],{"class":326},[320,454,455],{"class":330}," QgsStyle.defaultStyle()\n",[320,457,459,462,464,467,470],{"class":322,"line":458},16,[320,460,461],{"class":330},"color_ramp ",[320,463,383],{"class":326},[320,465,466],{"class":330}," default_style.colorRamp(",[320,468,469],{"class":389},"\"Spectral\"",[320,471,367],{"class":330},[320,473,475],{"class":322,"line":474},17,[320,476,374],{"emptyLinePlaceholder":373},[320,478,480,483,485],{"class":322,"line":479},18,[320,481,482],{"class":330},"categories ",[320,484,383],{"class":326},[320,486,487],{"class":330}," QgsCategorizedSymbolRenderer.createCategories(\n",[320,489,491],{"class":322,"line":490},19,[320,492,493],{"class":330},"    [], template_symbol, layer, field_name\n",[320,495,497],{"class":322,"line":496},20,[320,498,367],{"class":330},[320,500,502,505,507],{"class":322,"line":501},21,[320,503,504],{"class":330},"renderer ",[320,506,383],{"class":326},[320,508,509],{"class":330}," QgsCategorizedSymbolRenderer(field_name, categories)\n",[320,511,513],{"class":322,"line":512},22,[320,514,515],{"class":330},"renderer.updateColorRamp(color_ramp)\n",[320,517,519],{"class":322,"line":518},23,[320,520,374],{"emptyLinePlaceholder":373},[320,522,524],{"class":322,"line":523},24,[320,525,526],{"class":330},"layer.setRenderer(renderer)\n",[320,528,530],{"class":322,"line":529},25,[320,531,532],{"class":330},"layer.triggerRepaint()\n",[15,534,535,538,539,542,543,545,546,549,550,553,554,557,558,561],{},[87,536,537],{},"Breakdown:"," ",[35,540,541],{},"createCategories([], ...)"," with an empty value list tells QGIS to scan the layer and discover every distinct value of ",[35,544,96],{},". ",[35,547,548],{},"QgsSymbol.defaultSymbol()"," returns a fill, line, or marker symbol matching the layer geometry, so the same code works for polygons or points. ",[35,551,552],{},"updateColorRamp()"," recolors all categories from the ramp in evenly spaced steps. Always call ",[35,555,556],{},"triggerRepaint()"," (or ",[35,559,560],{},"iface.mapCanvas().refresh()",") so the change is visible.",[15,563,564,565,568,569,572,573,576],{},"For nominal data, prefer a ",[18,566,567],{},"qualitative"," ramp such as ",[35,570,571],{},"Spectral"," or ",[35,574,575],{},"Set1"," rather than a sequential one — sequential ramps imply an order that categories do not have.",[15,578,579],{},"If you need to constrain the categories to a known set rather than discovering every value, pass that list explicitly instead of an empty one. This is useful when a field contains noise values you want to exclude, or when you want categories to appear in a deliberate order in the legend:",[311,581,583],{"className":313,"code":582,"language":315,"meta":316,"style":316},"# Only build categories for the three classes you care about,\n# in the order they should appear in the legend.\nwanted = [\"forest\", \"urban\", \"water\"]\ncategories = QgsCategorizedSymbolRenderer.createCategories(\n    wanted, template_symbol, layer, field_name\n)\nrenderer = QgsCategorizedSymbolRenderer(field_name, categories)\nrenderer.updateColorRamp(QgsStyle.defaultStyle().colorRamp(\"Set1\"))\nlayer.setRenderer(renderer)\n",[35,584,585,590,595,617,625,630,634,642,653],{"__ignoreMap":316},[320,586,587],{"class":322,"line":323},[320,588,589],{"class":421},"# Only build categories for the three classes you care about,\n",[320,591,592],{"class":322,"line":340},[320,593,594],{"class":421},"# in the order they should appear in the legend.\n",[320,596,597,600,602,605,607,609,611,613,615],{"class":322,"line":346},[320,598,599],{"class":330},"wanted ",[320,601,383],{"class":326},[320,603,604],{"class":330}," [",[320,606,207],{"class":389},[320,608,123],{"class":330},[320,610,218],{"class":389},[320,612,123],{"class":330},[320,614,226],{"class":389},[320,616,399],{"class":330},[320,618,619,621,623],{"class":322,"line":352},[320,620,482],{"class":330},[320,622,383],{"class":326},[320,624,487],{"class":330},[320,626,627],{"class":322,"line":358},[320,628,629],{"class":330},"    wanted, template_symbol, layer, field_name\n",[320,631,632],{"class":322,"line":364},[320,633,367],{"class":330},[320,635,636,638,640],{"class":322,"line":370},[320,637,504],{"class":330},[320,639,383],{"class":326},[320,641,509],{"class":330},[320,643,644,647,650],{"class":322,"line":377},[320,645,646],{"class":330},"renderer.updateColorRamp(QgsStyle.defaultStyle().colorRamp(",[320,648,649],{"class":389},"\"Set1\"",[320,651,652],{"class":330},"))\n",[320,654,655],{"class":322,"line":402},[320,656,526],{"class":330},[15,658,659,661],{},[87,660,537],{}," Supplying a non-empty value list short-circuits discovery, so QGIS builds one category per item you named and skips everything else. Any feature whose value is not in the list falls through to the renderer's \"all other values\" entry, which you can enable, hide, or restyle separately. This gives you full control over both membership and legend order, which automatic discovery (alphabetical by default) does not guarantee.",[76,663,665],{"id":664},"_2-adjusting-individual-categories","2. Adjusting Individual Categories",[15,667,668,669,671],{},"After building a categorized renderer you frequently need to recolor one class, rename a label, or hide a value. Each entry is a ",[35,670,69],{}," you can read and rewrite in place.",[311,673,675],{"className":313,"code":674,"language":315,"meta":316,"style":316},"from qgis.PyQt.QtGui import QColor\n\nrenderer = layer.renderer()  # QgsCategorizedSymbolRenderer\n\nfor i, category in enumerate(renderer.categories()):\n    value = category.value()\n    label = category.label()\n    if value == \"water\":\n        # Override the auto-generated color for a specific class.\n        symbol = category.symbol().clone()\n        symbol.setColor(QColor(\"#2563eb\"))\n        renderer.updateCategorySymbol(i, symbol)\n        renderer.updateCategoryLabel(i, \"Open Water\")\n\nlayer.triggerRepaint()\n",[35,676,677,689,693,705,709,726,736,746,763,768,778,788,793,803,807],{"__ignoreMap":316},[320,678,679,681,684,686],{"class":322,"line":323},[320,680,327],{"class":326},[320,682,683],{"class":330}," qgis.PyQt.QtGui ",[320,685,334],{"class":326},[320,687,688],{"class":330}," QColor\n",[320,690,691],{"class":322,"line":340},[320,692,374],{"emptyLinePlaceholder":373},[320,694,695,697,699,702],{"class":322,"line":346},[320,696,504],{"class":330},[320,698,383],{"class":326},[320,700,701],{"class":330}," layer.renderer()  ",[320,703,704],{"class":421},"# QgsCategorizedSymbolRenderer\n",[320,706,707],{"class":322,"line":352},[320,708,374],{"emptyLinePlaceholder":373},[320,710,711,714,717,720,723],{"class":322,"line":358},[320,712,713],{"class":326},"for",[320,715,716],{"class":330}," i, category ",[320,718,719],{"class":326},"in",[320,721,722],{"class":396}," enumerate",[320,724,725],{"class":330},"(renderer.categories()):\n",[320,727,728,731,733],{"class":322,"line":364},[320,729,730],{"class":330},"    value ",[320,732,383],{"class":326},[320,734,735],{"class":330}," category.value()\n",[320,737,738,741,743],{"class":322,"line":370},[320,739,740],{"class":330},"    label ",[320,742,383],{"class":326},[320,744,745],{"class":330}," category.label()\n",[320,747,748,751,754,757,760],{"class":322,"line":377},[320,749,750],{"class":326},"    if",[320,752,753],{"class":330}," value ",[320,755,756],{"class":326},"==",[320,758,759],{"class":389}," \"water\"",[320,761,762],{"class":330},":\n",[320,764,765],{"class":322,"line":402},[320,766,767],{"class":421},"        # Override the auto-generated color for a specific class.\n",[320,769,770,773,775],{"class":322,"line":413},[320,771,772],{"class":330},"        symbol ",[320,774,383],{"class":326},[320,776,777],{"class":330}," category.symbol().clone()\n",[320,779,780,783,786],{"class":322,"line":418},[320,781,782],{"class":330},"        symbol.setColor(QColor(",[320,784,785],{"class":389},"\"#2563eb\"",[320,787,652],{"class":330},[320,789,790],{"class":322,"line":425},[320,791,792],{"class":330},"        renderer.updateCategorySymbol(i, symbol)\n",[320,794,795,798,801],{"class":322,"line":436},[320,796,797],{"class":330},"        renderer.updateCategoryLabel(i, ",[320,799,800],{"class":389},"\"Open Water\"",[320,802,367],{"class":330},[320,804,805],{"class":322,"line":441},[320,806,374],{"emptyLinePlaceholder":373},[320,808,809],{"class":322,"line":447},[320,810,532],{"class":330},[15,812,813,538,815,818,819,822,823,826,827,830,831,116],{},[87,814,537],{},[35,816,817],{},"renderer.categories()"," returns the ordered list; the index ",[35,820,821],{},"i"," is what ",[35,824,825],{},"updateCategorySymbol()"," and ",[35,828,829],{},"updateCategoryLabel()"," expect. Cloning the symbol before mutating it avoids aliasing surprises where two categories share the same object. To control colors at the per-feature or per-symbol level rather than per-class, see ",[21,832,53],{"href":52},[76,834,836],{"id":835},"_3-graduating-a-numeric-field-into-classes","3. Graduating a Numeric Field into Classes",[15,838,839,840,843],{},"A graduated renderer maps a continuous field onto a small number of ordered classes. The workflow is: instantiate the renderer on the field, choose a classification method, set a class count and color ramp, then call ",[35,841,842],{},"updateClasses()"," to compute the break values.",[311,845,847],{"className":313,"code":846,"language":315,"meta":316,"style":316},"from qgis.core import (\n    QgsGraduatedSymbolRenderer,\n    QgsClassificationQuantile,\n    QgsStyle,\n    QgsSymbol,\n)\n\nlayer = QgsProject.instance().mapLayersByName(\"counties\")[0]\nfield_name = \"population\"\n\nrenderer = QgsGraduatedSymbolRenderer(field_name)\nrenderer.setSourceSymbol(QgsSymbol.defaultSymbol(layer.geometryType()))\n\n# Classification method drives where the class breaks fall.\nrenderer.setClassificationMethod(QgsClassificationQuantile())\n\n# Compute 5 quantile classes from the layer's population values.\nrenderer.updateClasses(layer, 5)\n\n# Apply a sequential ramp suited to ordered magnitude data.\nramp = QgsStyle.defaultStyle().colorRamp(\"Greens\")\nrenderer.updateColorRamp(ramp)\n\nlayer.setRenderer(renderer)\nlayer.triggerRepaint()\n",[35,848,849,859,864,869,873,877,881,885,902,911,915,924,929,933,938,943,947,952,962,966,971,986,991,995,999],{"__ignoreMap":316},[320,850,851,853,855,857],{"class":322,"line":323},[320,852,327],{"class":326},[320,854,331],{"class":330},[320,856,334],{"class":326},[320,858,337],{"class":330},[320,860,861],{"class":322,"line":340},[320,862,863],{"class":330},"    QgsGraduatedSymbolRenderer,\n",[320,865,866],{"class":322,"line":346},[320,867,868],{"class":330},"    QgsClassificationQuantile,\n",[320,870,871],{"class":322,"line":352},[320,872,361],{"class":330},[320,874,875],{"class":322,"line":358},[320,876,355],{"class":330},[320,878,879],{"class":322,"line":364},[320,880,367],{"class":330},[320,882,883],{"class":322,"line":370},[320,884,374],{"emptyLinePlaceholder":373},[320,886,887,889,891,893,896,898,900],{"class":322,"line":377},[320,888,380],{"class":330},[320,890,383],{"class":326},[320,892,386],{"class":330},[320,894,895],{"class":389},"\"counties\"",[320,897,393],{"class":330},[320,899,165],{"class":396},[320,901,399],{"class":330},[320,903,904,906,908],{"class":322,"line":402},[320,905,405],{"class":330},[320,907,383],{"class":326},[320,909,910],{"class":389}," \"population\"\n",[320,912,913],{"class":322,"line":413},[320,914,374],{"emptyLinePlaceholder":373},[320,916,917,919,921],{"class":322,"line":418},[320,918,504],{"class":330},[320,920,383],{"class":326},[320,922,923],{"class":330}," QgsGraduatedSymbolRenderer(field_name)\n",[320,925,926],{"class":322,"line":425},[320,927,928],{"class":330},"renderer.setSourceSymbol(QgsSymbol.defaultSymbol(layer.geometryType()))\n",[320,930,931],{"class":322,"line":436},[320,932,374],{"emptyLinePlaceholder":373},[320,934,935],{"class":322,"line":441},[320,936,937],{"class":421},"# Classification method drives where the class breaks fall.\n",[320,939,940],{"class":322,"line":447},[320,941,942],{"class":330},"renderer.setClassificationMethod(QgsClassificationQuantile())\n",[320,944,945],{"class":322,"line":458},[320,946,374],{"emptyLinePlaceholder":373},[320,948,949],{"class":322,"line":474},[320,950,951],{"class":421},"# Compute 5 quantile classes from the layer's population values.\n",[320,953,954,957,960],{"class":322,"line":479},[320,955,956],{"class":330},"renderer.updateClasses(layer, ",[320,958,959],{"class":396},"5",[320,961,367],{"class":330},[320,963,964],{"class":322,"line":490},[320,965,374],{"emptyLinePlaceholder":373},[320,967,968],{"class":322,"line":496},[320,969,970],{"class":421},"# Apply a sequential ramp suited to ordered magnitude data.\n",[320,972,973,976,978,981,984],{"class":322,"line":501},[320,974,975],{"class":330},"ramp ",[320,977,383],{"class":326},[320,979,980],{"class":330}," QgsStyle.defaultStyle().colorRamp(",[320,982,983],{"class":389},"\"Greens\"",[320,985,367],{"class":330},[320,987,988],{"class":322,"line":512},[320,989,990],{"class":330},"renderer.updateColorRamp(ramp)\n",[320,992,993],{"class":322,"line":518},[320,994,374],{"emptyLinePlaceholder":373},[320,996,997],{"class":322,"line":523},[320,998,526],{"class":330},[320,1000,1001],{"class":322,"line":529},[320,1002,532],{"class":330},[15,1004,1005,538,1007,1010,1011,1014,1015,1018,1019,1021,1022,123,1025,123,1028,1031],{},[87,1006,537],{},[35,1008,1009],{},"setSourceSymbol()"," defines the base symbol that every class clones before recoloring. ",[35,1012,1013],{},"setClassificationMethod()"," plugs in the algorithm that decides break positions — swapping it changes the map dramatically. ",[35,1016,1017],{},"updateClasses(layer, 5)"," runs that method against the field and creates five ",[35,1020,73],{}," objects. Because magnitude has a natural order, a sequential ramp (",[35,1023,1024],{},"Greens",[35,1026,1027],{},"Blues",[35,1029,1030],{},"Viridis",") is correct here, unlike the qualitative ramp used for categories.",[15,1033,1034,1035,116],{},"This exact sequence — graduated renderer, classification method, sequential ramp — is the backbone of a shaded-polygon map. For an end-to-end recipe that adds the crucial area-normalization step, follow ",[21,1036,1038],{"href":1037},"\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Fcreate-choropleth-map-pyqgis\u002F","Create a Choropleth Map in PyQGIS",[76,1040,1042],{"id":1041},"_4-choosing-a-classification-method","4. Choosing a Classification Method",[15,1044,1045,1046,1049],{},"QGIS 3.x exposes classification as pluggable ",[35,1047,1048],{},"QgsClassificationMethod"," subclasses. The three you will reach for most are equal interval, quantile, and natural breaks. They produce different maps from identical data, so the choice is cartographic, not cosmetic. The diagram below feeds one right-skewed field into all three methods and shows where each drops its four class breaks.",[147,1051,153,1054,153,1057,153,1060,153,1064,153,1070,153,1073,153,1080,153,1086,153,1089,153,1092,153,1095,153,1098,153,1101,153,1104,153,1107,153,1110,153,1113,153,1116,153,1119,153,1122,153,1125,153,1128,153,1134,153,1137,153,1140,153,1142,153,1145,153,1147,153,1151,153,1153,153,1156,153,1159,153,1162,153,1167,153,1172,153,1176,153,1180,153,1184,153,1188,153,1193,153,1197,153,1201,153,1205,153,1208,153,1212,153,1215,153,1219,153,1223,153,1226,153,1229,153,1231,153,1234,153,1237,153,1241],{"viewBox":1052,"role":150,"ariaLabel":1053,"xmlns":152},"0 0 680 356","How equal interval, quantile, and Jenks place class breaks on the same right-skewed data",[155,1055,1056],{},"Three classification methods, one distribution",[159,1058,1059],{},"A right-skewed set of values from 0 to 1000 is classified into five classes three ways: equal interval produces equal-width bins that leave the high classes nearly empty; quantile crowds its breaks into the dense low end to balance feature counts; Jenks natural breaks snap to the gaps between clusters.",[163,1061],{"x":165,"y":165,"width":1062,"height":1063,"fill":168},"680","356",[182,1065,1069],{"x":1066,"y":1067,"fill":176,"style":1068,"textAnchor":187},"340","30","text-anchor:middle;font-family:sans-serif;font-size:16px;font-weight:bold","Same right-skewed data, three sets of class breaks",[182,1071,1072],{"x":1066,"y":277,"fill":196,"style":197,"textAnchor":187},"five classes; markers show where each method places its four breaks",[182,1074,1079],{"x":1075,"y":1076,"fill":196,"style":1077,"textAnchor":1078},"130","84","text-anchor:end;font-family:sans-serif;font-size:12px","end","values",[1081,1082],"circle",{"cx":1083,"cy":1084,"r":1085,"fill":242},"150.2","80","4",[1081,1087],{"cx":1088,"cy":1084,"r":1085,"fill":242},"160.4",[1081,1090],{"cx":1091,"cy":1084,"r":1085,"fill":242},"165.5",[1081,1093],{"cx":1094,"cy":1084,"r":1085,"fill":242},"170.6",[1081,1096],{"cx":1097,"cy":1084,"r":1085,"fill":242},"175.7",[1081,1099],{"cx":1100,"cy":1084,"r":1085,"fill":242},"180.8",[1081,1102],{"cx":1103,"cy":1084,"r":1085,"fill":242},"185.9",[1081,1105],{"cx":1106,"cy":1084,"r":1085,"fill":242},"196.1",[1081,1108],{"cx":1109,"cy":1084,"r":1085,"fill":242},"206.3",[1081,1111],{"cx":1112,"cy":1084,"r":1085,"fill":242},"216.5",[1081,1114],{"cx":1115,"cy":1084,"r":1085,"fill":242},"231.8",[1081,1117],{"cx":1118,"cy":1084,"r":1085,"fill":242},"252.2",[1081,1120],{"cx":1121,"cy":1084,"r":1085,"fill":242},"293",[1081,1123],{"cx":1124,"cy":1084,"r":1085,"fill":242},"395",[1081,1126],{"cx":1127,"cy":1084,"r":1085,"fill":242},"624.5",[322,1129],{"x1":1130,"y1":1131,"x2":1132,"y2":1131,"stroke":196,"style":1133},"140","94","650","stroke-width:1.5",[322,1135],{"x1":1130,"y1":1131,"x2":1130,"y2":1136,"stroke":196,"style":1133},"99",[322,1138],{"x1":1139,"y1":1131,"x2":1139,"y2":1136,"stroke":196,"style":1133},"267.5",[322,1141],{"x1":1124,"y1":1131,"x2":1124,"y2":1136,"stroke":196,"style":1133},[322,1143],{"x1":1144,"y1":1131,"x2":1144,"y2":1136,"stroke":196,"style":1133},"522.5",[322,1146],{"x1":1132,"y1":1131,"x2":1132,"y2":1136,"stroke":196,"style":1133},[182,1148,165],{"x":1130,"y":1149,"fill":196,"style":1150,"textAnchor":187},"112","text-anchor:middle;font-family:sans-serif;font-size:11px",[182,1152,276],{"x":1139,"y":1149,"fill":196,"style":1150,"textAnchor":187},[182,1154,1155],{"x":1124,"y":1149,"fill":196,"style":1150,"textAnchor":187},"500",[182,1157,1158],{"x":1144,"y":1149,"fill":196,"style":1150,"textAnchor":187},"750",[182,1160,1161],{"x":1132,"y":1149,"fill":196,"style":1150,"textAnchor":187},"1000",[182,1163,1166],{"x":1075,"y":1164,"fill":176,"style":1165,"textAnchor":1078},"155","text-anchor:end;font-family:sans-serif;font-size:13px;font-weight:bold","Equal interval",[163,1168],{"x":1130,"y":1130,"width":1169,"height":1170,"fill":251,"stroke":176,"style":1171},"102","22","stroke-width:1",[163,1173],{"x":1174,"y":1130,"width":1169,"height":1170,"fill":1175,"stroke":176,"style":1171},"242","#bae4b3",[163,1177],{"x":1178,"y":1130,"width":1169,"height":1170,"fill":1179,"stroke":176,"style":1171},"344","#74c476",[163,1181],{"x":1182,"y":1130,"width":1169,"height":1170,"fill":1183,"stroke":176,"style":1171},"446","#31a354",[163,1185],{"x":1186,"y":1130,"width":1169,"height":1170,"fill":1187,"stroke":176,"style":1171},"548","#006d2c",[182,1189,1192],{"x":1130,"y":1190,"fill":196,"style":1191},"178","font-family:sans-serif;font-size:12px","Equal-width bins; the sparse high end leaves classes 4 and 5 nearly empty.",[182,1194,1196],{"x":1075,"y":1195,"fill":176,"style":1165,"textAnchor":1078},"220","Quantile",[163,1198],{"x":1130,"y":1199,"width":1200,"height":1170,"fill":251,"stroke":176,"style":1171},"205","28",[163,1202],{"x":1203,"y":1199,"width":1204,"height":1170,"fill":1175,"stroke":176,"style":1171},"168","15",[163,1206],{"x":1207,"y":1199,"width":213,"height":1170,"fill":1179,"stroke":176,"style":1171},"183",[163,1209],{"x":1210,"y":1199,"width":1211,"height":1170,"fill":1183,"stroke":176,"style":1171},"201","41",[163,1213],{"x":1174,"y":1199,"width":1214,"height":1170,"fill":1187,"stroke":176,"style":1171},"408",[182,1216,1218],{"x":1130,"y":1217,"fill":196,"style":1191},"243","Equal feature count per class; breaks crowd into the dense low values.",[182,1220,1222],{"x":1075,"y":1221,"fill":176,"style":1165,"textAnchor":1078},"285","Jenks",[163,1224],{"x":1130,"y":275,"width":1225,"height":1170,"fill":251,"stroke":176,"style":1171},"51",[163,1227],{"x":1228,"y":275,"width":1225,"height":1170,"fill":1175,"stroke":176,"style":1171},"191",[163,1230],{"x":1174,"y":275,"width":1169,"height":1170,"fill":1179,"stroke":176,"style":1171},[163,1232],{"x":1178,"y":275,"width":1233,"height":1170,"fill":1183,"stroke":176,"style":1171},"153",[163,1235],{"x":1236,"y":275,"width":1233,"height":1170,"fill":1187,"stroke":176,"style":1171},"497",[182,1238,1240],{"x":1130,"y":1239,"fill":196,"style":1191},"308","Breaks snap to the natural gaps, hugging the real clusters in the data.",[182,1242,1244],{"x":1066,"y":1066,"fill":196,"style":1243,"textAnchor":187},"text-anchor:middle;font-family:sans-serif;font-size:12px;font-style:italic","Identical values, identical class count — only the method changes the map.",[311,1246,1248],{"className":313,"code":1247,"language":315,"meta":316,"style":316},"from qgis.core import (\n    QgsClassificationEqualInterval,\n    QgsClassificationQuantile,\n    QgsClassificationJenks,\n)\n\nmethods = {\n    \"equal\": QgsClassificationEqualInterval(),\n    \"quantile\": QgsClassificationQuantile(),\n    \"jenks\": QgsClassificationJenks(),\n}\n\nfor name, method in methods.items():\n    renderer.setClassificationMethod(method)\n    renderer.updateClasses(layer, 5)\n    breaks = [f\"{r.lowerValue():.0f}-{r.upperValue():.0f}\"\n              for r in renderer.ranges()]\n    print(name, breaks)\n",[35,1249,1250,1260,1265,1269,1274,1278,1282,1292,1300,1308,1316,1321,1325,1337,1342,1351,1393,1406],{"__ignoreMap":316},[320,1251,1252,1254,1256,1258],{"class":322,"line":323},[320,1253,327],{"class":326},[320,1255,331],{"class":330},[320,1257,334],{"class":326},[320,1259,337],{"class":330},[320,1261,1262],{"class":322,"line":340},[320,1263,1264],{"class":330},"    QgsClassificationEqualInterval,\n",[320,1266,1267],{"class":322,"line":346},[320,1268,868],{"class":330},[320,1270,1271],{"class":322,"line":352},[320,1272,1273],{"class":330},"    QgsClassificationJenks,\n",[320,1275,1276],{"class":322,"line":358},[320,1277,367],{"class":330},[320,1279,1280],{"class":322,"line":364},[320,1281,374],{"emptyLinePlaceholder":373},[320,1283,1284,1287,1289],{"class":322,"line":370},[320,1285,1286],{"class":330},"methods ",[320,1288,383],{"class":326},[320,1290,1291],{"class":330}," {\n",[320,1293,1294,1297],{"class":322,"line":377},[320,1295,1296],{"class":389},"    \"equal\"",[320,1298,1299],{"class":330},": QgsClassificationEqualInterval(),\n",[320,1301,1302,1305],{"class":322,"line":402},[320,1303,1304],{"class":389},"    \"quantile\"",[320,1306,1307],{"class":330},": QgsClassificationQuantile(),\n",[320,1309,1310,1313],{"class":322,"line":413},[320,1311,1312],{"class":389},"    \"jenks\"",[320,1314,1315],{"class":330},": QgsClassificationJenks(),\n",[320,1317,1318],{"class":322,"line":418},[320,1319,1320],{"class":330},"}\n",[320,1322,1323],{"class":322,"line":425},[320,1324,374],{"emptyLinePlaceholder":373},[320,1326,1327,1329,1332,1334],{"class":322,"line":436},[320,1328,713],{"class":326},[320,1330,1331],{"class":330}," name, method ",[320,1333,719],{"class":326},[320,1335,1336],{"class":330}," methods.items():\n",[320,1338,1339],{"class":322,"line":441},[320,1340,1341],{"class":330},"    renderer.setClassificationMethod(method)\n",[320,1343,1344,1347,1349],{"class":322,"line":447},[320,1345,1346],{"class":330},"    renderer.updateClasses(layer, ",[320,1348,959],{"class":396},[320,1350,367],{"class":330},[320,1352,1353,1356,1358,1360,1363,1366,1369,1372,1375,1378,1381,1383,1386,1388,1390],{"class":322,"line":458},[320,1354,1355],{"class":330},"    breaks ",[320,1357,383],{"class":326},[320,1359,604],{"class":330},[320,1361,1362],{"class":326},"f",[320,1364,1365],{"class":389},"\"",[320,1367,1368],{"class":396},"{",[320,1370,1371],{"class":330},"r.lowerValue()",[320,1373,1374],{"class":326},":.0f",[320,1376,1377],{"class":396},"}",[320,1379,1380],{"class":389},"-",[320,1382,1368],{"class":396},[320,1384,1385],{"class":330},"r.upperValue()",[320,1387,1374],{"class":326},[320,1389,1377],{"class":396},[320,1391,1392],{"class":389},"\"\n",[320,1394,1395,1398,1401,1403],{"class":322,"line":474},[320,1396,1397],{"class":326},"              for",[320,1399,1400],{"class":330}," r ",[320,1402,719],{"class":326},[320,1404,1405],{"class":330}," renderer.ranges()]\n",[320,1407,1408,1411],{"class":322,"line":479},[320,1409,1410],{"class":396},"    print",[320,1412,1413],{"class":330},"(name, breaks)\n",[15,1415,1416,1418,1419,1422,1423,1426,1427,1430,1431,1434,1435,116],{},[87,1417,537],{}," Each method computes break points differently. ",[35,1420,1421],{},"QgsClassificationEqualInterval"," divides the value range into equal-width bins — fast and intuitive, but a few outliers can leave most classes empty. ",[35,1424,1425],{},"QgsClassificationQuantile"," puts an equal ",[18,1428,1429],{},"count"," of features in each class — great for ranked maps, but break values look arbitrary. ",[35,1432,1433],{},"QgsClassificationJenks"," (natural breaks) minimizes within-class variance and maximizes between-class variance, hugging natural clusters in the data. For a deep treatment of Jenks and when to prefer it, see ",[21,1436,1438],{"href":1437},"\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Fclassify-layer-natural-breaks-jenks-pyqgis\u002F","Classify a Layer with Natural Breaks (Jenks) in PyQGIS",[1440,1441,1442,1458],"table",{},[1443,1444,1445],"thead",{},[1446,1447,1448,1452,1455],"tr",{},[1449,1450,1451],"th",{},"Method",[1449,1453,1454],{},"Best for",[1449,1456,1457],{},"Watch out for",[1459,1460,1461,1472,1482],"tbody",{},[1446,1462,1463,1466,1469],{},[1464,1465,1166],"td",{},[1464,1467,1468],{},"Evenly spread data, intuitive legends",[1464,1470,1471],{},"Skewed data leaves classes empty",[1446,1473,1474,1476,1479],{},[1464,1475,1196],{},[1464,1477,1478],{},"Ranked maps, even map ink balance",[1464,1480,1481],{},"Adjacent similar values split across classes",[1446,1483,1484,1487,1490],{},[1464,1485,1486],{},"Jenks (natural breaks)",[1464,1488,1489],{},"Clustered, real-world distributions",[1464,1491,1492],{},"Slower on very large layers; breaks vary with N",[15,1494,1495,1496,1499,1500,1503,1504,1506,1507,1509,1510,1512],{},"Two further methods are worth knowing. ",[35,1497,1498],{},"QgsClassificationLogarithmic"," spaces breaks on a log scale, which tames heavily right-skewed data such as population or income where a handful of huge values would otherwise compress everyone else into the bottom class. ",[35,1501,1502],{},"QgsClassificationPrettyBreaks"," rounds break values to human-friendly numbers (10, 25, 50) at the cost of slightly uneven class membership — ideal when a clean legend matters more than statistical precision. All of them are interchangeable: every method is a ",[35,1505,1048],{}," subclass, so ",[35,1508,1013],{}," accepts any of them and ",[35,1511,842],{}," does the rest. That uniform interface is what makes it cheap to offer users a method dropdown in a plugin and apply their choice with one line.",[76,1514,1516],{"id":1515},"_5-color-ramps-and-updatecolorramp","5. Color Ramps and updateColorRamp()",[15,1518,1519,1520,1522,1523,1526],{},"Both renderers store classes (or categories) plus a color ramp, and ",[35,1521,552],{}," recolors every class without recomputing the breaks. Ramps come from ",[35,1524,1525],{},"QgsStyle.defaultStyle()",", which exposes every ramp in the user's QGIS style library by name.",[311,1528,1530],{"className":313,"code":1529,"language":315,"meta":316,"style":316},"from qgis.core import QgsStyle, QgsGradientColorRamp\nfrom qgis.PyQt.QtGui import QColor\n\nstyle = QgsStyle.defaultStyle()\n\n# Discover available ramp names.\nprint(style.colorRampNames()[:10])\n\n# Built-in ramp by name.\nviridis = style.colorRamp(\"Viridis\")\nrenderer.updateColorRamp(viridis)\n\n# Or build a custom two-color gradient on the fly.\ncustom = QgsGradientColorRamp(QColor(\"#edf8e9\"), QColor(\"#005a32\"))\nrenderer.updateColorRamp(custom)\n\n# Reverse a ramp so high values map to dark colors.\nviridis_inv = style.colorRamp(\"Viridis\")\nviridis_inv.invert()\nrenderer.updateColorRamp(viridis_inv)\n\nlayer.triggerRepaint()\n",[35,1531,1532,1543,1553,1557,1566,1570,1575,1589,1593,1598,1613,1618,1622,1627,1648,1653,1657,1662,1675,1680,1685,1689],{"__ignoreMap":316},[320,1533,1534,1536,1538,1540],{"class":322,"line":323},[320,1535,327],{"class":326},[320,1537,331],{"class":330},[320,1539,334],{"class":326},[320,1541,1542],{"class":330}," QgsStyle, QgsGradientColorRamp\n",[320,1544,1545,1547,1549,1551],{"class":322,"line":340},[320,1546,327],{"class":326},[320,1548,683],{"class":330},[320,1550,334],{"class":326},[320,1552,688],{"class":330},[320,1554,1555],{"class":322,"line":346},[320,1556,374],{"emptyLinePlaceholder":373},[320,1558,1559,1562,1564],{"class":322,"line":352},[320,1560,1561],{"class":330},"style ",[320,1563,383],{"class":326},[320,1565,455],{"class":330},[320,1567,1568],{"class":322,"line":358},[320,1569,374],{"emptyLinePlaceholder":373},[320,1571,1572],{"class":322,"line":364},[320,1573,1574],{"class":421},"# Discover available ramp names.\n",[320,1576,1577,1580,1583,1586],{"class":322,"line":370},[320,1578,1579],{"class":396},"print",[320,1581,1582],{"class":330},"(style.colorRampNames()[:",[320,1584,1585],{"class":396},"10",[320,1587,1588],{"class":330},"])\n",[320,1590,1591],{"class":322,"line":377},[320,1592,374],{"emptyLinePlaceholder":373},[320,1594,1595],{"class":322,"line":402},[320,1596,1597],{"class":421},"# Built-in ramp by name.\n",[320,1599,1600,1603,1605,1608,1611],{"class":322,"line":413},[320,1601,1602],{"class":330},"viridis ",[320,1604,383],{"class":326},[320,1606,1607],{"class":330}," style.colorRamp(",[320,1609,1610],{"class":389},"\"Viridis\"",[320,1612,367],{"class":330},[320,1614,1615],{"class":322,"line":418},[320,1616,1617],{"class":330},"renderer.updateColorRamp(viridis)\n",[320,1619,1620],{"class":322,"line":425},[320,1621,374],{"emptyLinePlaceholder":373},[320,1623,1624],{"class":322,"line":436},[320,1625,1626],{"class":421},"# Or build a custom two-color gradient on the fly.\n",[320,1628,1629,1632,1634,1637,1640,1643,1646],{"class":322,"line":441},[320,1630,1631],{"class":330},"custom ",[320,1633,383],{"class":326},[320,1635,1636],{"class":330}," QgsGradientColorRamp(QColor(",[320,1638,1639],{"class":389},"\"#edf8e9\"",[320,1641,1642],{"class":330},"), QColor(",[320,1644,1645],{"class":389},"\"#005a32\"",[320,1647,652],{"class":330},[320,1649,1650],{"class":322,"line":447},[320,1651,1652],{"class":330},"renderer.updateColorRamp(custom)\n",[320,1654,1655],{"class":322,"line":458},[320,1656,374],{"emptyLinePlaceholder":373},[320,1658,1659],{"class":322,"line":474},[320,1660,1661],{"class":421},"# Reverse a ramp so high values map to dark colors.\n",[320,1663,1664,1667,1669,1671,1673],{"class":322,"line":479},[320,1665,1666],{"class":330},"viridis_inv ",[320,1668,383],{"class":326},[320,1670,1607],{"class":330},[320,1672,1610],{"class":389},[320,1674,367],{"class":330},[320,1676,1677],{"class":322,"line":490},[320,1678,1679],{"class":330},"viridis_inv.invert()\n",[320,1681,1682],{"class":322,"line":496},[320,1683,1684],{"class":330},"renderer.updateColorRamp(viridis_inv)\n",[320,1686,1687],{"class":322,"line":501},[320,1688,374],{"emptyLinePlaceholder":373},[320,1690,1691],{"class":322,"line":512},[320,1692,532],{"class":330},[15,1694,1695,538,1697,1700,1701,1703,1704,1707,1708,1711],{},[87,1696,537],{},[35,1698,1699],{},"colorRampNames()"," lists everything available, including cpt-city ramps the user installed. ",[35,1702,552],{}," is non-destructive to your class breaks — it only restyles, so you can preview several ramps quickly. ",[35,1705,1706],{},"QgsGradientColorRamp"," lets you bypass the library entirely when you need brand-specific colors. ",[35,1709,1710],{},"invert()"," flips the direction, which matters when convention expects darker symbols for larger magnitudes.",[76,1713,1715],{"id":1714},"_6-graduating-by-size-instead-of-color","6. Graduating by Size Instead of Color",[15,1717,1718,1719,1722],{},"Color is the default visual variable for a graduated renderer, but magnitude reads just as clearly — sometimes better on point and line layers — when it drives ",[18,1720,1721],{},"symbol size",". A proportional-symbol map keeps a single hue and grows the marker as the value rises, which avoids the \"is this class darker or just smaller?\" ambiguity of a busy choropleth. The switch is one method call plus a size range; the classes and breaks you already computed stay intact.",[311,1724,1726],{"className":313,"code":1725,"language":315,"meta":316,"style":316},"from qgis.core import (\n    QgsGraduatedSymbolRenderer,\n    QgsClassificationQuantile,\n    QgsStyle,\n    QgsSymbol,\n)\n\nlayer = QgsProject.instance().mapLayersByName(\"cities\")[0]\nfield_name = \"population\"\n\nrenderer = QgsGraduatedSymbolRenderer(field_name)\nrenderer.setSourceSymbol(QgsSymbol.defaultSymbol(layer.geometryType()))\nrenderer.setClassificationMethod(QgsClassificationQuantile())\nrenderer.updateClasses(layer, 5)\n\n# Drive marker size (in mm) instead of color across the classes.\nrenderer.setGraduatedMethod(QgsGraduatedSymbolRenderer.GraduatedSize)\nrenderer.setSymbolSizes(2.0, 10.0)\n\n# Keep one flat fill so size alone carries the message.\nrenderer.updateColorRamp(QgsStyle.defaultStyle().colorRamp(\"Greys\"))\n\nlayer.setRenderer(renderer)\nlayer.triggerRepaint()\n",[35,1727,1728,1738,1742,1746,1750,1754,1758,1762,1779,1787,1791,1799,1803,1807,1815,1819,1824,1829,1844,1848,1853,1862,1866,1870],{"__ignoreMap":316},[320,1729,1730,1732,1734,1736],{"class":322,"line":323},[320,1731,327],{"class":326},[320,1733,331],{"class":330},[320,1735,334],{"class":326},[320,1737,337],{"class":330},[320,1739,1740],{"class":322,"line":340},[320,1741,863],{"class":330},[320,1743,1744],{"class":322,"line":346},[320,1745,868],{"class":330},[320,1747,1748],{"class":322,"line":352},[320,1749,361],{"class":330},[320,1751,1752],{"class":322,"line":358},[320,1753,355],{"class":330},[320,1755,1756],{"class":322,"line":364},[320,1757,367],{"class":330},[320,1759,1760],{"class":322,"line":370},[320,1761,374],{"emptyLinePlaceholder":373},[320,1763,1764,1766,1768,1770,1773,1775,1777],{"class":322,"line":377},[320,1765,380],{"class":330},[320,1767,383],{"class":326},[320,1769,386],{"class":330},[320,1771,1772],{"class":389},"\"cities\"",[320,1774,393],{"class":330},[320,1776,165],{"class":396},[320,1778,399],{"class":330},[320,1780,1781,1783,1785],{"class":322,"line":402},[320,1782,405],{"class":330},[320,1784,383],{"class":326},[320,1786,910],{"class":389},[320,1788,1789],{"class":322,"line":413},[320,1790,374],{"emptyLinePlaceholder":373},[320,1792,1793,1795,1797],{"class":322,"line":418},[320,1794,504],{"class":330},[320,1796,383],{"class":326},[320,1798,923],{"class":330},[320,1800,1801],{"class":322,"line":425},[320,1802,928],{"class":330},[320,1804,1805],{"class":322,"line":436},[320,1806,942],{"class":330},[320,1808,1809,1811,1813],{"class":322,"line":441},[320,1810,956],{"class":330},[320,1812,959],{"class":396},[320,1814,367],{"class":330},[320,1816,1817],{"class":322,"line":447},[320,1818,374],{"emptyLinePlaceholder":373},[320,1820,1821],{"class":322,"line":458},[320,1822,1823],{"class":421},"# Drive marker size (in mm) instead of color across the classes.\n",[320,1825,1826],{"class":322,"line":474},[320,1827,1828],{"class":330},"renderer.setGraduatedMethod(QgsGraduatedSymbolRenderer.GraduatedSize)\n",[320,1830,1831,1834,1837,1839,1842],{"class":322,"line":479},[320,1832,1833],{"class":330},"renderer.setSymbolSizes(",[320,1835,1836],{"class":396},"2.0",[320,1838,123],{"class":330},[320,1840,1841],{"class":396},"10.0",[320,1843,367],{"class":330},[320,1845,1846],{"class":322,"line":490},[320,1847,374],{"emptyLinePlaceholder":373},[320,1849,1850],{"class":322,"line":496},[320,1851,1852],{"class":421},"# Keep one flat fill so size alone carries the message.\n",[320,1854,1855,1857,1860],{"class":322,"line":501},[320,1856,646],{"class":330},[320,1858,1859],{"class":389},"\"Greys\"",[320,1861,652],{"class":330},[320,1863,1864],{"class":322,"line":512},[320,1865,374],{"emptyLinePlaceholder":373},[320,1867,1868],{"class":322,"line":518},[320,1869,526],{"class":330},[320,1871,1872],{"class":322,"line":523},[320,1873,532],{"class":330},[15,1875,1876,538,1878,1881,1882,1885,1886,1889,1890,1892,1893,1896,1897,1900,1901,1904],{},[87,1877,537],{},[35,1879,1880],{},"setGraduatedMethod(GraduatedSize)"," tells the renderer to interpolate the source symbol's ",[18,1883,1884],{},"size"," between the bounds you pass to ",[35,1887,1888],{},"setSymbolSizes(min, max)"," rather than pulling colors from the ramp. The class breaks from ",[35,1891,842],{}," are unchanged — only the visual variable they map to is different. Because size is now doing the work, a near-neutral ramp such as ",[35,1894,1895],{},"Greys"," keeps every marker legible without a competing color signal. ",[35,1898,1899],{},"GraduatedSize"," applies to marker and line symbols; for polygons, color (",[35,1902,1903],{},"GraduatedColor",", the default) remains the right choice since you cannot resize a fill.",[76,1906,1908],{"id":1907},"_7-reading-and-reusing-an-existing-renderer","7. Reading and Reusing an Existing Renderer",[15,1910,1911],{},"Production scripts often inherit a layer that is already styled and need to inspect or extend that styling rather than rebuild it from scratch. Renderers are introspectable: you can read the type, the field, the breaks, and the symbols, then make targeted changes. Guarding on the renderer class keeps the same routine safe whether the layer arrives categorized, graduated, or with a plain single-symbol renderer.",[311,1913,1915],{"className":313,"code":1914,"language":315,"meta":316,"style":316},"from qgis.core import (\n    QgsGraduatedSymbolRenderer,\n    QgsCategorizedSymbolRenderer,\n)\n\nlayer = QgsProject.instance().mapLayersByName(\"counties\")[0]\nrenderer = layer.renderer()\n\nif isinstance(renderer, QgsGraduatedSymbolRenderer):\n    print(f\"Graduated on '{renderer.classAttribute()}' \"\n          f\"with {len(renderer.ranges())} classes\")\n    # Clone so we never mutate the live renderer in place.\n    new_renderer = renderer.clone()\n    new_renderer.updateColorRamp(QgsStyle.defaultStyle().colorRamp(\"Magma\"))\n    layer.setRenderer(new_renderer)\n\nelif isinstance(renderer, QgsCategorizedSymbolRenderer):\n    print(f\"Categorized on '{renderer.classAttribute()}' \"\n          f\"with {len(renderer.categories())} categories\")\n\nelse:\n    print(f\"Single-symbol or unsupported renderer: {type(renderer).__name__}\")\n\nlayer.triggerRepaint()\n",[35,1916,1917,1927,1931,1935,1939,1943,1959,1968,1972,1983,2005,2026,2031,2041,2051,2056,2060,2070,2089,2107,2111,2118,2142,2146],{"__ignoreMap":316},[320,1918,1919,1921,1923,1925],{"class":322,"line":323},[320,1920,327],{"class":326},[320,1922,331],{"class":330},[320,1924,334],{"class":326},[320,1926,337],{"class":330},[320,1928,1929],{"class":322,"line":340},[320,1930,863],{"class":330},[320,1932,1933],{"class":322,"line":346},[320,1934,349],{"class":330},[320,1936,1937],{"class":322,"line":352},[320,1938,367],{"class":330},[320,1940,1941],{"class":322,"line":358},[320,1942,374],{"emptyLinePlaceholder":373},[320,1944,1945,1947,1949,1951,1953,1955,1957],{"class":322,"line":364},[320,1946,380],{"class":330},[320,1948,383],{"class":326},[320,1950,386],{"class":330},[320,1952,895],{"class":389},[320,1954,393],{"class":330},[320,1956,165],{"class":396},[320,1958,399],{"class":330},[320,1960,1961,1963,1965],{"class":322,"line":370},[320,1962,504],{"class":330},[320,1964,383],{"class":326},[320,1966,1967],{"class":330}," layer.renderer()\n",[320,1969,1970],{"class":322,"line":377},[320,1971,374],{"emptyLinePlaceholder":373},[320,1973,1974,1977,1980],{"class":322,"line":402},[320,1975,1976],{"class":326},"if",[320,1978,1979],{"class":396}," isinstance",[320,1981,1982],{"class":330},"(renderer, QgsGraduatedSymbolRenderer):\n",[320,1984,1985,1987,1990,1992,1995,1997,2000,2002],{"class":322,"line":413},[320,1986,1410],{"class":396},[320,1988,1989],{"class":330},"(",[320,1991,1362],{"class":326},[320,1993,1994],{"class":389},"\"Graduated on '",[320,1996,1368],{"class":396},[320,1998,1999],{"class":330},"renderer.classAttribute()",[320,2001,1377],{"class":396},[320,2003,2004],{"class":389},"' \"\n",[320,2006,2007,2010,2013,2016,2019,2021,2024],{"class":322,"line":418},[320,2008,2009],{"class":326},"          f",[320,2011,2012],{"class":389},"\"with ",[320,2014,2015],{"class":396},"{len",[320,2017,2018],{"class":330},"(renderer.ranges())",[320,2020,1377],{"class":396},[320,2022,2023],{"class":389}," classes\"",[320,2025,367],{"class":330},[320,2027,2028],{"class":322,"line":425},[320,2029,2030],{"class":421},"    # Clone so we never mutate the live renderer in place.\n",[320,2032,2033,2036,2038],{"class":322,"line":436},[320,2034,2035],{"class":330},"    new_renderer ",[320,2037,383],{"class":326},[320,2039,2040],{"class":330}," renderer.clone()\n",[320,2042,2043,2046,2049],{"class":322,"line":441},[320,2044,2045],{"class":330},"    new_renderer.updateColorRamp(QgsStyle.defaultStyle().colorRamp(",[320,2047,2048],{"class":389},"\"Magma\"",[320,2050,652],{"class":330},[320,2052,2053],{"class":322,"line":447},[320,2054,2055],{"class":330},"    layer.setRenderer(new_renderer)\n",[320,2057,2058],{"class":322,"line":458},[320,2059,374],{"emptyLinePlaceholder":373},[320,2061,2062,2065,2067],{"class":322,"line":474},[320,2063,2064],{"class":326},"elif",[320,2066,1979],{"class":396},[320,2068,2069],{"class":330},"(renderer, QgsCategorizedSymbolRenderer):\n",[320,2071,2072,2074,2076,2078,2081,2083,2085,2087],{"class":322,"line":479},[320,2073,1410],{"class":396},[320,2075,1989],{"class":330},[320,2077,1362],{"class":326},[320,2079,2080],{"class":389},"\"Categorized on '",[320,2082,1368],{"class":396},[320,2084,1999],{"class":330},[320,2086,1377],{"class":396},[320,2088,2004],{"class":389},[320,2090,2091,2093,2095,2097,2100,2102,2105],{"class":322,"line":490},[320,2092,2009],{"class":326},[320,2094,2012],{"class":389},[320,2096,2015],{"class":396},[320,2098,2099],{"class":330},"(renderer.categories())",[320,2101,1377],{"class":396},[320,2103,2104],{"class":389}," categories\"",[320,2106,367],{"class":330},[320,2108,2109],{"class":322,"line":496},[320,2110,374],{"emptyLinePlaceholder":373},[320,2112,2113,2116],{"class":322,"line":501},[320,2114,2115],{"class":326},"else",[320,2117,762],{"class":330},[320,2119,2120,2122,2124,2126,2129,2132,2135,2138,2140],{"class":322,"line":512},[320,2121,1410],{"class":396},[320,2123,1989],{"class":330},[320,2125,1362],{"class":326},[320,2127,2128],{"class":389},"\"Single-symbol or unsupported renderer: ",[320,2130,2131],{"class":396},"{type",[320,2133,2134],{"class":330},"(renderer).",[320,2136,2137],{"class":396},"__name__}",[320,2139,1365],{"class":389},[320,2141,367],{"class":330},[320,2143,2144],{"class":322,"line":518},[320,2145,374],{"emptyLinePlaceholder":373},[320,2147,2148],{"class":322,"line":523},[320,2149,532],{"class":330},[15,2151,2152,538,2154,2157,2158,2161,2162,572,2165,545,2168,2171,2172,2175],{},[87,2153,537],{},[35,2155,2156],{},"layer.renderer()"," returns the live renderer object; ",[35,2159,2160],{},"isinstance()"," checks let you branch on its concrete type before calling type-specific methods such as ",[35,2163,2164],{},"ranges()",[35,2166,2167],{},"categories()",[35,2169,2170],{},"classAttribute()"," reports the field the renderer is bound to, which is invaluable in batch jobs where the field name is not known ahead of time. Calling ",[35,2173,2174],{},"clone()"," before mutating is the safe habit: it produces an independent copy so an exception mid-edit cannot leave the displayed renderer half-modified. This pattern is the backbone of any tool that restyles many layers consistently — for example, applying a house color ramp across an atlas.",[76,2177,2179],{"id":2178},"_8-saving-loading-and-sharing-styles","8. Saving, Loading, and Sharing Styles",[15,2181,2182,2183,2186],{},"Once a renderer looks right, capture it so the same classification and colors apply to other layers or projects without re-running the classification logic. QGIS serializes styling to ",[35,2184,2185],{},".qml"," (QML) files and can also embed it in the data source via a sidecar or database table.",[311,2188,2190],{"className":313,"code":2189,"language":315,"meta":316,"style":316},"# Export the full symbology (renderer + labels) to a QML file.\nresult, message = layer.saveNamedStyle(\"\u002Ftmp\u002Fcounties.qml\")\nprint(\"saved\" if result else f\"failed: {message}\")\n\n# Apply that style to a second, similarly-structured layer.\nother = QgsProject.instance().mapLayersByName(\"counties_2020\")[0]\nok, msg = other.loadNamedStyle(\"\u002Ftmp\u002Fcounties.qml\")\nother.triggerRepaint()\n\n# Export only the symbology category (omit labels, diagrams) if needed.\nfrom qgis.core import QgsMapLayer\nlayer.saveNamedStyle(\n    \"\u002Ftmp\u002Fcounties_symbology.qml\",\n    categories=QgsMapLayer.Symbology,\n)\n",[35,2191,2192,2197,2212,2246,2250,2255,2273,2287,2292,2296,2301,2312,2317,2325,2336],{"__ignoreMap":316},[320,2193,2194],{"class":322,"line":323},[320,2195,2196],{"class":421},"# Export the full symbology (renderer + labels) to a QML file.\n",[320,2198,2199,2202,2204,2207,2210],{"class":322,"line":340},[320,2200,2201],{"class":330},"result, message ",[320,2203,383],{"class":326},[320,2205,2206],{"class":330}," layer.saveNamedStyle(",[320,2208,2209],{"class":389},"\"\u002Ftmp\u002Fcounties.qml\"",[320,2211,367],{"class":330},[320,2213,2214,2216,2218,2221,2224,2227,2229,2232,2235,2237,2240,2242,2244],{"class":322,"line":346},[320,2215,1579],{"class":396},[320,2217,1989],{"class":330},[320,2219,2220],{"class":389},"\"saved\"",[320,2222,2223],{"class":326}," if",[320,2225,2226],{"class":330}," result ",[320,2228,2115],{"class":326},[320,2230,2231],{"class":326}," f",[320,2233,2234],{"class":389},"\"failed: ",[320,2236,1368],{"class":396},[320,2238,2239],{"class":330},"message",[320,2241,1377],{"class":396},[320,2243,1365],{"class":389},[320,2245,367],{"class":330},[320,2247,2248],{"class":322,"line":352},[320,2249,374],{"emptyLinePlaceholder":373},[320,2251,2252],{"class":322,"line":358},[320,2253,2254],{"class":421},"# Apply that style to a second, similarly-structured layer.\n",[320,2256,2257,2260,2262,2264,2267,2269,2271],{"class":322,"line":364},[320,2258,2259],{"class":330},"other ",[320,2261,383],{"class":326},[320,2263,386],{"class":330},[320,2265,2266],{"class":389},"\"counties_2020\"",[320,2268,393],{"class":330},[320,2270,165],{"class":396},[320,2272,399],{"class":330},[320,2274,2275,2278,2280,2283,2285],{"class":322,"line":370},[320,2276,2277],{"class":330},"ok, msg ",[320,2279,383],{"class":326},[320,2281,2282],{"class":330}," other.loadNamedStyle(",[320,2284,2209],{"class":389},[320,2286,367],{"class":330},[320,2288,2289],{"class":322,"line":377},[320,2290,2291],{"class":330},"other.triggerRepaint()\n",[320,2293,2294],{"class":322,"line":402},[320,2295,374],{"emptyLinePlaceholder":373},[320,2297,2298],{"class":322,"line":413},[320,2299,2300],{"class":421},"# Export only the symbology category (omit labels, diagrams) if needed.\n",[320,2302,2303,2305,2307,2309],{"class":322,"line":418},[320,2304,327],{"class":326},[320,2306,331],{"class":330},[320,2308,334],{"class":326},[320,2310,2311],{"class":330}," QgsMapLayer\n",[320,2313,2314],{"class":322,"line":425},[320,2315,2316],{"class":330},"layer.saveNamedStyle(\n",[320,2318,2319,2322],{"class":322,"line":436},[320,2320,2321],{"class":389},"    \"\u002Ftmp\u002Fcounties_symbology.qml\"",[320,2323,2324],{"class":330},",\n",[320,2326,2327,2331,2333],{"class":322,"line":441},[320,2328,2330],{"class":2329},"s9osk","    categories",[320,2332,383],{"class":326},[320,2334,2335],{"class":330},"QgsMapLayer.Symbology,\n",[320,2337,2338],{"class":322,"line":447},[320,2339,367],{"class":330},[15,2341,2342,538,2344,2347,2348,2351,2352,2355,2356,2359,2360,2362,2363,2365],{},[87,2343,537],{},[35,2345,2346],{},"saveNamedStyle()"," returns a ",[35,2349,2350],{},"(bool, str)"," tuple — always check it, since a read-only path is a common silent failure. ",[35,2353,2354],{},"loadNamedStyle()"," applies a saved style to any compatible layer; the field referenced by the renderer must exist in the target or the classes render empty. The ",[35,2357,2358],{},"categories="," argument lets you export a subset (symbology only, labels only, or all), which is useful when you want to share class colors without overwriting a layer's existing labels configured in ",[21,2361,58],{"href":57},". For team workflows, commit the ",[35,2364,2185],{}," alongside the data so every analyst renders the layer identically.",[76,2367,2369],{"id":2368},"_9-refreshing-the-legend-and-canvas","9. Refreshing the Legend and Canvas",[15,2371,2372],{},"A renderer change does not automatically propagate to the Layers panel legend until you tell QGIS to rebuild it. In scripts, refresh both the symbology cache and the layer tree view.",[311,2374,2376],{"className":313,"code":2375,"language":315,"meta":316,"style":316},"from qgis.utils import iface\n\nlayer.setRenderer(renderer)\n\n# Rebuild the legend nodes for this layer in the tree.\nlayer.triggerRepaint()\nif iface is not None:\n    iface.layerTreeView().refreshLayerSymbology(layer.id())\n    iface.mapCanvas().refresh()\n",[35,2377,2378,2390,2394,2398,2402,2407,2411,2429,2434],{"__ignoreMap":316},[320,2379,2380,2382,2385,2387],{"class":322,"line":323},[320,2381,327],{"class":326},[320,2383,2384],{"class":330}," qgis.utils ",[320,2386,334],{"class":326},[320,2388,2389],{"class":330}," iface\n",[320,2391,2392],{"class":322,"line":340},[320,2393,374],{"emptyLinePlaceholder":373},[320,2395,2396],{"class":322,"line":346},[320,2397,526],{"class":330},[320,2399,2400],{"class":322,"line":352},[320,2401,374],{"emptyLinePlaceholder":373},[320,2403,2404],{"class":322,"line":358},[320,2405,2406],{"class":421},"# Rebuild the legend nodes for this layer in the tree.\n",[320,2408,2409],{"class":322,"line":364},[320,2410,532],{"class":330},[320,2412,2413,2415,2418,2421,2424,2427],{"class":322,"line":370},[320,2414,1976],{"class":326},[320,2416,2417],{"class":330}," iface ",[320,2419,2420],{"class":326},"is",[320,2422,2423],{"class":326}," not",[320,2425,2426],{"class":396}," None",[320,2428,762],{"class":330},[320,2430,2431],{"class":322,"line":377},[320,2432,2433],{"class":330},"    iface.layerTreeView().refreshLayerSymbology(layer.id())\n",[320,2435,2436],{"class":322,"line":402},[320,2437,2438],{"class":330},"    iface.mapCanvas().refresh()\n",[15,2440,2441,538,2443,2445,2446,2449,2450,2452,2453,2456,2457,116],{},[87,2442,537],{},[35,2444,556],{}," invalidates the rendered image. ",[35,2447,2448],{},"refreshLayerSymbology()"," regenerates the expandable legend entries (the swatches under the layer name). ",[35,2451,560],{}," forces an immediate redraw. The ",[35,2454,2455],{},"iface is not None"," guard keeps the same code safe in standalone scripts where there is no GUI. To save the styling for reuse, call ",[35,2458,2459],{},"layer.saveNamedStyle(\"\u002Fpath\u002Fto\u002Fstyle.qml\")",[76,2461,2463],{"id":2462},"choosing-between-the-two-renderers","Choosing between the two renderers",[15,2465,2466],{},"The decision is not about the field's storage type but about whether its values have a meaningful order.",[15,2468,2469],{},[147,2470,2473,2476,2479,2483,2497,2503,2508,2513,2519,2524,2528,2531,2534,2537,2540,2544,2547,2553,2555,2559,2563,2568,2570,2573,2575],{"viewBox":2471,"role":150,"ariaLabel":2472,"xmlns":152},"0 0 760 244","A decision tree choosing between categorized and graduated renderers based on whether values are ordered, how many distinct values exist, and whether they are counts",[155,2474,2475],{},"Categorized or graduated?",[159,2477,2478],{},"Starting from a field, ask whether its values have a meaningful order. Unordered values such as zoning codes go to a categorized renderer with one class per value. Ordered numeric values go to a graduated renderer, which needs a classification method and a class count. A numeric field with only a handful of distinct codes is really categorical despite being stored as a number.",[163,2480],{"x":165,"y":165,"width":2481,"height":2482,"fill":168},"760","244",[2484,2485,2486],"defs",{},[2487,2488,2493],"marker",{"id":2489,"viewBox":2490,"refX":174,"refY":959,"markerWidth":2491,"markerHeight":2491,"orient":2492},"rendPickArrow","0 0 10 10","7","auto-start-reverse",[2494,2495],"path",{"d":2496,"fill":196},"M0 0 L10 5 L0 10 z",[182,2498,2502],{"x":2499,"y":2500,"style":2501,"fill":176,"textAnchor":187},"380","26","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","Ask about order, not about the column type",[163,2504],{"x":172,"y":2505,"width":2506,"height":2505,"rx":174,"fill":279,"stroke":242,"style":2507},"46","180","stroke-width:2.5",[182,2509,2512],{"x":2499,"y":2510,"style":2511,"fill":283,"textAnchor":187},"74","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","the field",[163,2514],{"x":2515,"y":2516,"width":2517,"height":2518,"rx":174,"fill":175,"stroke":230,"style":2507},"16","122","228","66",[182,2520,2523],{"x":1075,"y":2521,"style":2522,"fill":230,"textAnchor":187},"146","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","no meaningful order",[182,2525,2527],{"x":1075,"y":1203,"style":2526,"fill":196,"textAnchor":187},"text-anchor:middle;font-size:11px;font-family:sans-serif","zoning, land use, owner",[163,2529],{"x":2530,"y":2516,"width":2517,"height":2518,"rx":174,"fill":175,"stroke":214,"style":2507},"266",[182,2532,2533],{"x":2499,"y":2521,"style":2522,"fill":214,"textAnchor":187},"ordered quantity",[182,2535,2536],{"x":2499,"y":1203,"style":2526,"fill":196,"textAnchor":187},"population, value, depth",[163,2538],{"x":2539,"y":2516,"width":2517,"height":2518,"rx":174,"fill":175,"stroke":222,"style":2507},"516",[182,2541,2543],{"x":2542,"y":2521,"style":2522,"fill":222,"textAnchor":187},"630","numeric codes",[182,2545,2546],{"x":2542,"y":1203,"style":2526,"fill":196,"textAnchor":187},"class 1, 2, 5 — not a quantity",[322,2548],{"x1":180,"y1":2549,"x2":2550,"y2":2551,"stroke":196,"style":2552},"92","160","118","stroke-width:2;marker-end:url(#rendPickArrow)",[322,2554],{"x1":2499,"y1":2549,"x2":2499,"y2":2551,"stroke":196,"style":2552},[322,2556],{"x1":2557,"y1":2549,"x2":2558,"y2":2551,"stroke":196,"style":2552},"430","600",[163,2560],{"x":2515,"y":210,"width":2517,"height":2561,"rx":278,"fill":230,"fillOpacity":2562,"stroke":230,"style":177},"34",0.14,[182,2564,2567],{"x":1075,"y":2565,"style":2566,"fill":230,"textAnchor":187},"222","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","categorized",[163,2569],{"x":2530,"y":210,"width":2517,"height":2561,"rx":278,"fill":214,"fillOpacity":2562,"stroke":214,"style":177},[182,2571,2572],{"x":2499,"y":2565,"style":2566,"fill":214,"textAnchor":187},"graduated",[163,2574],{"x":2539,"y":210,"width":2517,"height":2561,"rx":278,"fill":230,"fillOpacity":2562,"stroke":230,"style":177},[182,2576,2577],{"x":2542,"y":2565,"style":2566,"fill":230,"textAnchor":187},"categorized, despite the type",[76,2579,2581],{"id":2580},"version-compatibility","Version Compatibility",[15,2583,2584,2585,2587,2588,2590],{},"The classification-method API used here — ",[35,2586,1013],{}," plus ",[35,2589,842],{}," — has been stable since QGIS 3.10 and is the recommended path on the 3.34 LTR baseline.",[1440,2592,2593,2603],{},[1443,2594,2595],{},[1446,2596,2597,2600],{},[1449,2598,2599],{},"QGIS \u002F Python",[1449,2601,2602],{},"Notes",[1459,2604,2605,2615,2626,2634],{},[1446,2606,2607,2612],{},[1464,2608,2609],{},[87,2610,2611],{},"3.34 LTR (Python 3.12)",[1464,2613,2614],{},"Baseline for this guide. All APIs above work as written.",[1446,2616,2617,2620],{},[1464,2618,2619],{},"3.28 LTR (Python 3.9)",[1464,2621,2622,2623,2625],{},"Fully supported. ",[35,2624,1433],{}," and friends available.",[1446,2627,2628,2631],{},[1464,2629,2630],{},"3.40 \u002F 3.44",[1464,2632,2633],{},"Same API; additional built-in ramps and refined Jenks performance.",[1446,2635,2636,2639],{},[1464,2637,2638],{},"Pre-3.10",[1464,2640,2641,2642,2645,2646,2649,2650,123,2652,2654],{},"Avoid: older code used ",[35,2643,2644],{},"QgsGraduatedSymbolRenderer.createRenderer(...)"," with a ",[35,2647,2648],{},"mode"," enum (",[35,2651,1222],{},[35,2653,1196],{},") instead of method objects.",[15,2656,2657,2658,2660],{},"If you maintain code targeting older releases, the legacy ",[35,2659,2648],{},"-enum constructor still exists but is deprecated; migrate to method objects for forward compatibility.",[76,2662,2664],{"id":2663},"key-takeaways","Key Takeaways",[81,2666,2667,2676,2690,2693,2698],{},[84,2668,2669,2670,2672,2673,2675],{},"Use ",[35,2671,37],{}," for nominal data (one symbol per value) and ",[35,2674,41],{}," for numeric magnitude (ordered classes).",[84,2677,2678,2679,2682,2683,2686,2687,116],{},"Build categories with ",[35,2680,2681],{},"createCategories([], template, layer, field)","; build classes with ",[35,2684,2685],{},"setClassificationMethod(...)"," then ",[35,2688,2689],{},"updateClasses(layer, n)",[84,2691,2692],{},"Pick the classification method deliberately: equal interval, quantile, and Jenks produce visibly different maps.",[84,2694,2695,2697],{},[35,2696,552],{}," restyles classes without recomputing breaks — use qualitative ramps for categories, sequential ramps for graduated values.",[84,2699,2700,2701,826,2703,2705],{},"Always ",[35,2702,556],{},[35,2704,2448],{}," so the canvas and legend reflect the new renderer.",[76,2707,2709],{"id":2708},"frequently-asked-questions","Frequently Asked Questions",[15,2711,2712,2715],{},[87,2713,2714],{},"When should I use a categorized renderer instead of a graduated one?","\nUse categorized for discrete, unordered values such as land-use class, administrative name, or zoning code. Use graduated when the field is numeric and the magnitude matters — population, income, elevation. If you graduate a code field, the legend will imply an order that does not exist.",[15,2717,2718,2721,2722,2724,2725,2728],{},[87,2719,2720],{},"Why is my map all one color after setting a graduated renderer?","\nAlmost always you set the renderer but never called ",[35,2723,2689],{},", so there are zero ranges, or the chosen field contains nulls\u002Fstrings that the method skipped. Confirm ",[35,2726,2727],{},"renderer.ranges()"," is non-empty and the field is numeric.",[15,2730,2731,2734,2735,2738],{},[87,2732,2733],{},"How do I keep the same class breaks but change colors?","\nCall ",[35,2736,2737],{},"renderer.updateColorRamp(new_ramp)",". It recolors every existing class or category in place and leaves your computed break values untouched, which makes ramp previewing fast.",[15,2740,2741,2744,2745,2748,2749,2752],{},[87,2742,2743],{},"Can I assign symbol size instead of color to graduated classes?","\nYes. Set ",[35,2746,2747],{},"renderer.setGraduatedMethod(QgsGraduatedSymbolRenderer.GraduatedSize)"," and provide a min\u002Fmax size with ",[35,2750,2751],{},"setSymbolSizes()"," (point\u002Fline layers). Graduated color is the default; graduated size produces proportional-symbol maps.",[15,2754,2755,2758,2759,23,2762,2765,2766,2769,2770,116],{},[87,2756,2757],{},"Do renderer changes persist when I save the project?","\nYes — renderers are serialized into the ",[35,2760,2761],{},".qgz",[35,2763,2764],{},".qgs"," project file. To reuse styling across projects, export it with ",[35,2767,2768],{},"layer.saveNamedStyle(\"style.qml\")"," and load it later with ",[35,2771,2772],{},"layer.loadNamedStyle()",[76,2774,2776],{"id":2775},"related","Related",[81,2778,2779,2783,2787,2791,2795,2799,2805,2811],{},[84,2780,2781],{},[21,2782,45],{"href":28},[84,2784,2785],{},[21,2786,53],{"href":52},[84,2788,2789],{},[21,2790,58],{"href":57},[84,2792,2793],{},[21,2794,1038],{"href":1037},[84,2796,2797],{},[21,2798,1438],{"href":1437},[84,2800,2801],{},[21,2802,2804],{"href":2803},"\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Frule-based-renderer-pyqgis\u002F","Create a Rule-Based Renderer in PyQGIS",[84,2806,2807],{},[21,2808,2810],{"href":2809},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fsave-and-load-qml-style-pyqgis\u002F","Save and Load a QML Style in PyQGIS",[84,2812,2813,2817],{},[21,2814,2816],{"href":2815},"\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Fcreate-categorized-renderer-pyqgis\u002F","Create a Categorized Renderer in PyQGIS"," — colour a layer by a field, with stable colours and a catch-all category.",[2819,2820,2821],"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 pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}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 .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":316,"searchDepth":340,"depth":340,"links":2823},[2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839],{"id":78,"depth":340,"text":79},{"id":133,"depth":340,"text":134},{"id":298,"depth":340,"text":299},{"id":664,"depth":340,"text":665},{"id":835,"depth":340,"text":836},{"id":1041,"depth":340,"text":1042},{"id":1515,"depth":340,"text":1516},{"id":1714,"depth":340,"text":1715},{"id":1907,"depth":340,"text":1908},{"id":2178,"depth":340,"text":2179},{"id":2368,"depth":340,"text":2369},{"id":2462,"depth":340,"text":2463},{"id":2580,"depth":340,"text":2581},{"id":2663,"depth":340,"text":2664},{"id":2708,"depth":340,"text":2709},{"id":2775,"depth":340,"text":2776},"Build thematic maps in PyQGIS with QgsCategorizedSymbolRenderer and QgsGraduatedSymbolRenderer, classification methods, color ramps, and legends.","md",{"slug":2843,"type":2844,"breadcrumb":2845,"datePublished":2846,"dateModified":2847},"graduated-categorized-renderers","guide","Graduated & Categorized Renderers","2025-02-11","2026-07-18","\u002Fpyqgis-cartography-visualization\u002Fgraduated-categorized-renderers",{"title":5,"description":2840},"pyqgis-cartography-visualization\u002Fgraduated-categorized-renderers\u002Findex","0YU5SjdL2ddIJljzXZBdEAme04BlHTo4CdE_IMxwKTg",1787823360556]