[{"data":1,"prerenderedAt":1588},["ShallowReactive",2],{"doc:\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fuse-style-manager-and-symbol-library-pyqgis":3},{"id":4,"title":5,"body":6,"description":1577,"extension":1578,"meta":1579,"navigation":263,"path":1584,"seo":1585,"stem":1586,"__hash__":1587},"docs\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fuse-style-manager-and-symbol-library-pyqgis\u002Findex.md","Use the Style Manager and Symbol Library in PyQGIS",{"type":7,"value":8,"toc":1564},"minimark",[9,13,22,31,196,201,223,227,230,349,367,371,374,496,524,527,609,626,630,633,681,696,812,816,819,1178,1190,1204,1208,1211,1280,1298,1305,1309,1315,1395,1399,1465,1469,1475,1479,1492,1502,1513,1528,1532,1561],[10,11,5],"h1",{"id":12},"use-the-style-manager-and-symbol-library-in-pyqgis",[14,15,16,17,21],"p",{},"QGIS keeps a database of reusable symbols, colour ramps, text formats and label settings — the thing behind ",[18,19,20],"em",{},"Settings → Style Manager",". Most people treat it as somewhere symbols happen to live. Treated deliberately, it is how an organisation ships one house style to forty analysts and how a plugin stops hard-coding colours in twelve places.",[14,23,24,25,30],{},"This recipe belongs to ",[26,27,29],"a",{"href":28},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002F","Programmatic Layer Styling in PyQGIS",". It covers reading and writing the default style database, saving symbols and ramps with tags, searching by tag, building a distributable XML style file, and loading one at plugin start-up.",[14,32,33],{},[34,35,40,44,48,55,72,81,90,96,105,111,116,121,125,128,133,137,141,144,147,150,157,164,170,175,178,182,186,190],"svg",{"viewBox":36,"role":37,"ariaLabel":38,"xmlns":39},"0 0 760 304","img","The QGIS style database holding symbols, colour ramps, text formats and label settings, each addressable by name and by tag, and importable from or exportable to an XML style file","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[41,42,43],"title",{},"What the style database holds",[45,46,47],"desc",{},"The default style database stores four kinds of entity: symbols, colour ramps, text formats and label settings. Each is addressable by name and can carry any number of tags. The whole database, or a tagged subset of it, can be written to an XML style file and imported on another machine.",[49,50],"rect",{"x":51,"y":51,"width":52,"height":53,"fill":54},"0","760","304","#f6f3ea",[56,57,58],"defs",{},[59,60,67],"marker",{"id":61,"viewBox":62,"refX":63,"refY":64,"markerWidth":65,"markerHeight":65,"orient":66},"smArrow","0 0 10 10","8","5","7","auto-start-reverse",[68,69],"path",{"d":70,"fill":71},"M0 0 L10 5 L0 10 z","#2f3b35",[73,74,80],"text",{"x":75,"y":76,"style":77,"fill":78,"textAnchor":79},"380","28","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","One database, four entity types, one portable file",[49,82],{"x":83,"y":84,"width":75,"height":85,"rx":86,"fill":87,"stroke":88,"style":89},"30","54","200","10","#fffdf7","#0f766e","stroke-width:2.5",[73,91,95],{"x":92,"y":93,"style":94,"fill":88,"textAnchor":79},"220","80","text-anchor:middle;font-size:12px;font-weight:bold;font-family:monospace","QgsStyle.defaultStyle()",[49,97],{"x":84,"y":98,"width":99,"height":100,"rx":101,"fill":102,"stroke":103,"style":104},"96","164","60","6","#eff3ff","#2563eb","stroke-width:1.8",[73,106,110],{"x":107,"y":108,"style":109,"fill":103,"textAnchor":79},"136","120","text-anchor:middle;font-size:10.5px;font-weight:bold;font-family:sans-serif","symbols",[73,112,115],{"x":107,"y":113,"style":114,"fill":71,"textAnchor":79},"140","text-anchor:middle;font-size:10px;font-family:monospace","symbolNames()",[49,117],{"x":118,"y":98,"width":99,"height":100,"rx":101,"fill":119,"stroke":120,"style":104},"228","#fdf2e2","#b45309",[73,122,124],{"x":123,"y":108,"style":109,"fill":120,"textAnchor":79},"310","colour ramps",[73,126,127],{"x":123,"y":113,"style":114,"fill":71,"textAnchor":79},"colorRampNames()",[49,129],{"x":84,"y":130,"width":99,"height":100,"rx":101,"fill":131,"stroke":132,"style":104},"166","#edf8e9","#15803d",[73,134,136],{"x":107,"y":135,"style":109,"fill":132,"textAnchor":79},"190","text formats",[73,138,140],{"x":107,"y":139,"style":114,"fill":71,"textAnchor":79},"210","textFormatNames()",[49,142],{"x":118,"y":130,"width":99,"height":100,"rx":101,"fill":143,"stroke":88,"style":104},"#eef7f4",[73,145,146],{"x":123,"y":135,"style":109,"fill":88,"textAnchor":79},"label settings",[73,148,149],{"x":123,"y":139,"style":114,"fill":71,"textAnchor":79},"labelSettingsNames()",[151,152],"line",{"x1":153,"y1":154,"x2":155,"y2":154,"stroke":71,"style":156},"414","154","452","stroke-width:2;marker-end:url(#smArrow)",[49,158],{"x":159,"y":93,"width":160,"height":161,"rx":86,"fill":162,"stroke":78,"style":163},"460","270","70","#e7e2d4","stroke-width:2",[73,165,169],{"x":166,"y":167,"style":168,"fill":78,"textAnchor":79},"595","106","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","tags",[73,171,174],{"x":166,"y":172,"style":173,"fill":71,"textAnchor":79},"130","text-anchor:middle;font-size:10.5px;font-family:sans-serif","\"house style\" · \"hydrology\" · \"draft\"",[49,176],{"x":159,"y":130,"width":160,"height":177,"rx":86,"fill":131,"stroke":132,"style":89},"88",[73,179,181],{"x":166,"y":180,"style":168,"fill":132,"textAnchor":79},"194","exportXml()",[73,183,185],{"x":166,"y":184,"style":173,"fill":71,"textAnchor":79},"218","one file, version-controllable",[73,187,189],{"x":166,"y":188,"style":173,"fill":71,"textAnchor":79},"240","importXml() on every machine",[73,191,195],{"x":75,"y":192,"style":193,"fill":194,"textAnchor":79},"288","text-anchor:middle;font-size:11px;font-family:sans-serif","#59645f","tags are the only practical way to find anything once the database is large",[197,198,200],"h2",{"id":199},"prerequisites","Prerequisites",[202,203,204,212,220],"ul",{},[205,206,207,211],"li",{},[208,209,210],"strong",{},"QGIS 3.34 LTR"," (bundled Python 3.12) or newer.",[205,213,214,215,219],{},"A symbol you want to save; anything from ",[26,216,218],{"href":217},"\u002Fpyqgis-cartography-visualization\u002Fsymbol-layers-and-advanced-symbology\u002Fstack-symbol-layers-pyqgis\u002F","a stacked symbol"," to a plain fill will do.",[205,221,222],{},"Write access to the user profile directory if you intend to modify the default database, which is where it lives.",[197,224,226],{"id":225},"read-what-is-already-there","Read what is already there",[14,228,229],{},"The default style is a singleton, and enumerating it is the fastest way to learn what QGIS ships with.",[231,232,237],"pre",{"className":233,"code":234,"language":235,"meta":236,"style":236},"language-python shiki shiki-themes github-dark","from qgis.core import QgsStyle\n\nstyle = QgsStyle.defaultStyle()\nprint(len(style.symbolNames()), \"symbols\")\nprint(len(style.colorRampNames()), \"colour ramps\")\nprint([n for n in style.colorRampNames() if \"Blues\" in n])\n","python","",[238,239,240,258,265,277,300,317],"code",{"__ignoreMap":236},[241,242,244,248,252,255],"span",{"class":151,"line":243},1,[241,245,247],{"class":246},"snl16","from",[241,249,251],{"class":250},"s95oV"," qgis.core ",[241,253,254],{"class":246},"import",[241,256,257],{"class":250}," QgsStyle\n",[241,259,261],{"class":151,"line":260},2,[241,262,264],{"emptyLinePlaceholder":263},true,"\n",[241,266,268,271,274],{"class":151,"line":267},3,[241,269,270],{"class":250},"style ",[241,272,273],{"class":246},"=",[241,275,276],{"class":250}," QgsStyle.defaultStyle()\n",[241,278,280,284,287,290,293,297],{"class":151,"line":279},4,[241,281,283],{"class":282},"sDLfK","print",[241,285,286],{"class":250},"(",[241,288,289],{"class":282},"len",[241,291,292],{"class":250},"(style.symbolNames()), ",[241,294,296],{"class":295},"sU2Wk","\"symbols\"",[241,298,299],{"class":250},")\n",[241,301,303,305,307,309,312,315],{"class":151,"line":302},5,[241,304,283],{"class":282},[241,306,286],{"class":250},[241,308,289],{"class":282},[241,310,311],{"class":250},"(style.colorRampNames()), ",[241,313,314],{"class":295},"\"colour ramps\"",[241,316,299],{"class":250},[241,318,320,322,325,328,331,334,337,340,343,346],{"class":151,"line":319},6,[241,321,283],{"class":282},[241,323,324],{"class":250},"([n ",[241,326,327],{"class":246},"for",[241,329,330],{"class":250}," n ",[241,332,333],{"class":246},"in",[241,335,336],{"class":250}," style.colorRampNames() ",[241,338,339],{"class":246},"if",[241,341,342],{"class":295}," \"Blues\"",[241,344,345],{"class":246}," in",[241,347,348],{"class":250}," n])\n",[14,350,351,354,355,358,359,362,363,366],{},[208,352,353],{},"Breakdown:"," ",[238,356,357],{},"defaultStyle()"," returns the user's own database, merged with the ones QGIS ships, so the counts differ between installations. Every getter that takes a name returns ",[238,360,361],{},"None"," for a name that is not present rather than raising, which is why so much styling code fails silently — ",[238,364,365],{},"setColorRamp(style.colorRamp(\"Blues \"))"," with a stray space produces a black layer and no message. Filtering the name list, as above, is a two-second way to confirm the spelling before hard-coding it.",[197,368,370],{"id":369},"save-a-symbol-with-tags","Save a symbol with tags",[14,372,373],{},"Adding an entity takes a name; making it findable later takes tags.",[231,375,377],{"className":233,"code":376,"language":235,"meta":236,"style":236},"from qgis.core import QgsStyle, QgsFillSymbol\n\nsymbol = QgsFillSymbol.createSimple({\n    \"color\": \"#2a6f97\", \"outline_color\": \"#123f5a\", \"outline_width\": \"0.4\",\n})\n\nstyle = QgsStyle.defaultStyle()\nstyle.addSymbol(\"Water body — house\", symbol.clone(), True)\nstyle.tagSymbol(QgsStyle.SymbolEntity, \"Water body — house\", [\"house style\", \"hydrology\"])\n",[238,378,379,390,394,404,439,444,448,457,474],{"__ignoreMap":236},[241,380,381,383,385,387],{"class":151,"line":243},[241,382,247],{"class":246},[241,384,251],{"class":250},[241,386,254],{"class":246},[241,388,389],{"class":250}," QgsStyle, QgsFillSymbol\n",[241,391,392],{"class":151,"line":260},[241,393,264],{"emptyLinePlaceholder":263},[241,395,396,399,401],{"class":151,"line":267},[241,397,398],{"class":250},"symbol ",[241,400,273],{"class":246},[241,402,403],{"class":250}," QgsFillSymbol.createSimple({\n",[241,405,406,409,412,415,418,421,423,426,428,431,433,436],{"class":151,"line":279},[241,407,408],{"class":295},"    \"color\"",[241,410,411],{"class":250},": ",[241,413,414],{"class":295},"\"#2a6f97\"",[241,416,417],{"class":250},", ",[241,419,420],{"class":295},"\"outline_color\"",[241,422,411],{"class":250},[241,424,425],{"class":295},"\"#123f5a\"",[241,427,417],{"class":250},[241,429,430],{"class":295},"\"outline_width\"",[241,432,411],{"class":250},[241,434,435],{"class":295},"\"0.4\"",[241,437,438],{"class":250},",\n",[241,440,441],{"class":151,"line":302},[241,442,443],{"class":250},"})\n",[241,445,446],{"class":151,"line":319},[241,447,264],{"emptyLinePlaceholder":263},[241,449,451,453,455],{"class":151,"line":450},7,[241,452,270],{"class":250},[241,454,273],{"class":246},[241,456,276],{"class":250},[241,458,460,463,466,469,472],{"class":151,"line":459},8,[241,461,462],{"class":250},"style.addSymbol(",[241,464,465],{"class":295},"\"Water body — house\"",[241,467,468],{"class":250},", symbol.clone(), ",[241,470,471],{"class":282},"True",[241,473,299],{"class":250},[241,475,477,480,482,485,488,490,493],{"class":151,"line":476},9,[241,478,479],{"class":250},"style.tagSymbol(QgsStyle.SymbolEntity, ",[241,481,465],{"class":295},[241,483,484],{"class":250},", [",[241,486,487],{"class":295},"\"house style\"",[241,489,417],{"class":250},[241,491,492],{"class":295},"\"hydrology\"",[241,494,495],{"class":250},"])\n",[14,497,498,500,501,504,505,508,509,511,512,515,516,519,520,523],{},[208,499,353],{}," The third argument to ",[238,502,503],{},"addSymbol()"," is ",[238,506,507],{},"update",", and passing ",[238,510,471],{}," writes the change to the database immediately rather than only into the in-memory copy — omit it and the symbol vanishes when QGIS closes. ",[238,513,514],{},"symbol.clone()"," matters because the database takes ownership: passing the live symbol and then continuing to use it leads to a symbol whose lifetime is managed twice, which crashes rather than misbehaving. ",[238,517,518],{},"tagSymbol()"," takes the entity type as its first argument because the same call handles ramps and text formats through ",[238,521,522],{},"QgsStyle.ColorrampEntity"," and friends.",[14,525,526],{},"Colour ramps follow the same pattern, and are worth saving whenever a project uses a non-default one:",[231,528,530],{"className":233,"code":529,"language":235,"meta":236,"style":236},"from qgis.core import QgsGradientColorRamp\nfrom qgis.PyQt.QtGui import QColor\n\nramp = QgsGradientColorRamp(QColor(\"#f7fbff\"), QColor(\"#08306b\"))\nstyle.addColorRamp(\"House blues\", ramp, True)\nstyle.tagSymbol(QgsStyle.ColorrampEntity, \"House blues\", [\"house style\"])\n",[238,531,532,543,555,559,581,596],{"__ignoreMap":236},[241,533,534,536,538,540],{"class":151,"line":243},[241,535,247],{"class":246},[241,537,251],{"class":250},[241,539,254],{"class":246},[241,541,542],{"class":250}," QgsGradientColorRamp\n",[241,544,545,547,550,552],{"class":151,"line":260},[241,546,247],{"class":246},[241,548,549],{"class":250}," qgis.PyQt.QtGui ",[241,551,254],{"class":246},[241,553,554],{"class":250}," QColor\n",[241,556,557],{"class":151,"line":267},[241,558,264],{"emptyLinePlaceholder":263},[241,560,561,564,566,569,572,575,578],{"class":151,"line":279},[241,562,563],{"class":250},"ramp ",[241,565,273],{"class":246},[241,567,568],{"class":250}," QgsGradientColorRamp(QColor(",[241,570,571],{"class":295},"\"#f7fbff\"",[241,573,574],{"class":250},"), QColor(",[241,576,577],{"class":295},"\"#08306b\"",[241,579,580],{"class":250},"))\n",[241,582,583,586,589,592,594],{"class":151,"line":302},[241,584,585],{"class":250},"style.addColorRamp(",[241,587,588],{"class":295},"\"House blues\"",[241,590,591],{"class":250},", ramp, ",[241,593,471],{"class":282},[241,595,299],{"class":250},[241,597,598,601,603,605,607],{"class":151,"line":319},[241,599,600],{"class":250},"style.tagSymbol(QgsStyle.ColorrampEntity, ",[241,602,588],{"class":295},[241,604,484],{"class":250},[241,606,487],{"class":295},[241,608,495],{"class":250},[14,610,611,613,614,617,618,621,622,625],{},[208,612,353],{}," A two-stop gradient is the simplest ramp; ",[238,615,616],{},"QgsGradientColorRamp"," also accepts intermediate stops through ",[238,619,620],{},"setStops()",", and ",[238,623,624],{},"QgsColorBrewerColorRamp"," wraps the standard cartographic schemes if you would rather use one of those than invent a scale. Tagging the ramp with the same tag as the symbols is what makes the export below select the whole house style in one query.",[197,627,629],{"id":628},"find-things-by-tag","Find things by tag",[14,631,632],{},"Once a database has a few hundred entries, names stop being a way to find anything.",[231,634,636],{"className":233,"code":635,"language":235,"meta":236,"style":236},"names = style.symbolsWithTag(\n    QgsStyle.SymbolEntity, style.tagId(\"house style\")\n)\nfor symbol_id in names:\n    print(style.symbolName(symbol_id))\n",[238,637,638,648,657,661,673],{"__ignoreMap":236},[241,639,640,643,645],{"class":151,"line":243},[241,641,642],{"class":250},"names ",[241,644,273],{"class":246},[241,646,647],{"class":250}," style.symbolsWithTag(\n",[241,649,650,653,655],{"class":151,"line":260},[241,651,652],{"class":250},"    QgsStyle.SymbolEntity, style.tagId(",[241,654,487],{"class":295},[241,656,299],{"class":250},[241,658,659],{"class":151,"line":267},[241,660,299],{"class":250},[241,662,663,665,668,670],{"class":151,"line":279},[241,664,327],{"class":246},[241,666,667],{"class":250}," symbol_id ",[241,669,333],{"class":246},[241,671,672],{"class":250}," names:\n",[241,674,675,678],{"class":151,"line":302},[241,676,677],{"class":282},"    print",[241,679,680],{"class":250},"(style.symbolName(symbol_id))\n",[14,682,683,354,685,688,689,692,693,695],{},[208,684,353],{},[238,686,687],{},"symbolsWithTag()"," takes a numeric tag id rather than the string, and ",[238,690,691],{},"tagId()"," resolves it — returning ",[238,694,51],{}," for a tag that does not exist, which then matches nothing and looks like an empty result rather than a mistake. The function returns entity ids, so a second lookup converts them to names. It is more indirection than it should be, and wrapping it in a small helper is worth doing once per codebase.",[14,697,698],{},[34,699,702,705,708,711,718,721,727,732,738,744,747,751,754,758,760,763,766,771,775,780,786,792,796,800,804,808],{"viewBox":700,"role":37,"ariaLabel":701,"xmlns":39},"0 0 760 276","A tagged symbol library where one tag selects a coherent set of symbols and ramps across different geometry types, which is then exported as a single house style file",[41,703,704],{},"A tag is a house style",[45,706,707],{},"Symbols for water, vegetation, buildings and roads, together with two colour ramps, all carry the tag house style. Querying that tag returns the whole set regardless of geometry type or entity type, and exporting the query result produces one distributable file.",[49,709],{"x":51,"y":51,"width":52,"height":710,"fill":54},"276",[56,712,713],{},[59,714,716],{"id":715,"viewBox":62,"refX":63,"refY":64,"markerWidth":65,"markerHeight":65,"orient":66},"tagArrow",[68,717],{"d":70,"fill":71},[73,719,720],{"x":75,"y":76,"style":77,"fill":78,"textAnchor":79},"One query, one coherent set, one file",[49,722],{"x":723,"y":724,"width":725,"height":726,"rx":86,"fill":87,"stroke":194,"style":163},"26","52","330","182",[73,728,731],{"x":729,"y":730,"style":168,"fill":78,"textAnchor":79},"191","76","the database",[49,733],{"x":734,"y":735,"width":172,"height":83,"rx":736,"fill":102,"stroke":103,"style":737},"50","92","4","stroke-width:1.5",[73,739,743],{"x":740,"y":741,"style":742,"fill":71,"textAnchor":79},"115","112","text-anchor:middle;font-size:9.5px;font-family:sans-serif","Water body",[49,745],{"x":746,"y":735,"width":172,"height":83,"rx":736,"fill":131,"stroke":132,"style":737},"196",[73,748,750],{"x":749,"y":741,"style":742,"fill":71,"textAnchor":79},"261","Woodland",[49,752],{"x":734,"y":753,"width":172,"height":83,"rx":736,"fill":162,"stroke":78,"style":737},"128",[73,755,757],{"x":740,"y":756,"style":742,"fill":71,"textAnchor":79},"148","Building",[49,759],{"x":746,"y":753,"width":172,"height":83,"rx":736,"fill":119,"stroke":120,"style":737},[73,761,762],{"x":749,"y":756,"style":742,"fill":71,"textAnchor":79},"Road casing",[49,764],{"x":734,"y":99,"width":710,"height":83,"rx":736,"fill":765,"stroke":194,"style":737},"#efeadd",[73,767,770],{"x":768,"y":769,"style":742,"fill":194,"textAnchor":79},"188","184","Sample symbol (untagged) — not selected",[73,772,774],{"x":729,"y":184,"style":773,"fill":194,"textAnchor":79},"text-anchor:middle;font-size:10px;font-family:sans-serif","tag: \"house style\" on the top four",[151,776],{"x1":777,"y1":113,"x2":778,"y2":113,"stroke":71,"style":779},"362","398","stroke-width:2;marker-end:url(#tagArrow)",[49,781],{"x":782,"y":783,"width":784,"height":785,"rx":86,"fill":143,"stroke":88,"style":89},"408","66","326","72",[73,787,791],{"x":788,"y":789,"style":790,"fill":88,"textAnchor":79},"571","94","text-anchor:middle;font-size:11px;font-weight:bold;font-family:monospace","symbolsWithTag(...)",[73,793,795],{"x":788,"y":794,"style":173,"fill":71,"textAnchor":79},"118","four symbols and two ramps",[49,797],{"x":782,"y":798,"width":784,"height":799,"rx":86,"fill":131,"stroke":132,"style":89},"152","82",[73,801,803],{"x":788,"y":802,"style":790,"fill":132,"textAnchor":79},"180","exportXml(\"house.xml\")",[73,805,807],{"x":788,"y":806,"style":173,"fill":71,"textAnchor":79},"204","one file for the whole team",[73,809,811],{"x":788,"y":810,"style":173,"fill":71,"textAnchor":79},"224","and for version control",[197,813,815],{"id":814},"a-house-style-as-code","A house style as code",[14,817,818],{},"The version of this that survives contact with a team keeps the style definition in a Python module rather than in anybody's profile directory, and installs it from there.",[231,820,822],{"className":233,"code":821,"language":235,"meta":236,"style":236},"from qgis.core import QgsStyle, QgsFillSymbol, QgsLineSymbol, QgsGradientColorRamp\nfrom qgis.PyQt.QtGui import QColor\n\nPREFIX = \"ACME\"\n\nFILLS = {\n    \"Water\": {\"color\": \"#2a6f97\", \"outline_color\": \"#123f5a\", \"outline_width\": \"0.4\"},\n    \"Woodland\": {\"color\": \"#4b7f52\", \"outline_color\": \"#2f5335\", \"outline_width\": \"0.3\"},\n    \"Building\": {\"color\": \"#8a7f6d\", \"outline_color\": \"#3f3a32\", \"outline_width\": \"0.25\"},\n}\n\n\ndef install(style=None, tag=\"ACME house style\"):\n    style = style or QgsStyle.defaultStyle()\n    for name, props in FILLS.items():\n        full = f\"{PREFIX} · {name}\"\n        symbol = QgsFillSymbol.createSimple(props)\n        style.addSymbol(full, symbol.clone(), True)\n        style.tagSymbol(QgsStyle.SymbolEntity, full, [tag])\n    ramp = QgsGradientColorRamp(QColor(\"#f7fbff\"), QColor(\"#08306b\"))\n    style.addColorRamp(f\"{PREFIX} · Blues\", ramp, True)\n    style.tagSymbol(QgsStyle.ColorrampEntity, f\"{PREFIX} · Blues\", [tag])\n    return style\n",[238,823,824,835,845,849,860,864,874,908,942,976,982,987,992,1020,1036,1053,1085,1096,1106,1112,1130,1152,1169],{"__ignoreMap":236},[241,825,826,828,830,832],{"class":151,"line":243},[241,827,247],{"class":246},[241,829,251],{"class":250},[241,831,254],{"class":246},[241,833,834],{"class":250}," QgsStyle, QgsFillSymbol, QgsLineSymbol, QgsGradientColorRamp\n",[241,836,837,839,841,843],{"class":151,"line":260},[241,838,247],{"class":246},[241,840,549],{"class":250},[241,842,254],{"class":246},[241,844,554],{"class":250},[241,846,847],{"class":151,"line":267},[241,848,264],{"emptyLinePlaceholder":263},[241,850,851,854,857],{"class":151,"line":279},[241,852,853],{"class":282},"PREFIX",[241,855,856],{"class":246}," =",[241,858,859],{"class":295}," \"ACME\"\n",[241,861,862],{"class":151,"line":302},[241,863,264],{"emptyLinePlaceholder":263},[241,865,866,869,871],{"class":151,"line":319},[241,867,868],{"class":282},"FILLS",[241,870,856],{"class":246},[241,872,873],{"class":250}," {\n",[241,875,876,879,882,885,887,889,891,893,895,897,899,901,903,905],{"class":151,"line":450},[241,877,878],{"class":295},"    \"Water\"",[241,880,881],{"class":250},": {",[241,883,884],{"class":295},"\"color\"",[241,886,411],{"class":250},[241,888,414],{"class":295},[241,890,417],{"class":250},[241,892,420],{"class":295},[241,894,411],{"class":250},[241,896,425],{"class":295},[241,898,417],{"class":250},[241,900,430],{"class":295},[241,902,411],{"class":250},[241,904,435],{"class":295},[241,906,907],{"class":250},"},\n",[241,909,910,913,915,917,919,922,924,926,928,931,933,935,937,940],{"class":151,"line":459},[241,911,912],{"class":295},"    \"Woodland\"",[241,914,881],{"class":250},[241,916,884],{"class":295},[241,918,411],{"class":250},[241,920,921],{"class":295},"\"#4b7f52\"",[241,923,417],{"class":250},[241,925,420],{"class":295},[241,927,411],{"class":250},[241,929,930],{"class":295},"\"#2f5335\"",[241,932,417],{"class":250},[241,934,430],{"class":295},[241,936,411],{"class":250},[241,938,939],{"class":295},"\"0.3\"",[241,941,907],{"class":250},[241,943,944,947,949,951,953,956,958,960,962,965,967,969,971,974],{"class":151,"line":476},[241,945,946],{"class":295},"    \"Building\"",[241,948,881],{"class":250},[241,950,884],{"class":295},[241,952,411],{"class":250},[241,954,955],{"class":295},"\"#8a7f6d\"",[241,957,417],{"class":250},[241,959,420],{"class":295},[241,961,411],{"class":250},[241,963,964],{"class":295},"\"#3f3a32\"",[241,966,417],{"class":250},[241,968,430],{"class":295},[241,970,411],{"class":250},[241,972,973],{"class":295},"\"0.25\"",[241,975,907],{"class":250},[241,977,979],{"class":151,"line":978},10,[241,980,981],{"class":250},"}\n",[241,983,985],{"class":151,"line":984},11,[241,986,264],{"emptyLinePlaceholder":263},[241,988,990],{"class":151,"line":989},12,[241,991,264],{"emptyLinePlaceholder":263},[241,993,995,998,1002,1005,1007,1009,1012,1014,1017],{"class":151,"line":994},13,[241,996,997],{"class":246},"def",[241,999,1001],{"class":1000},"svObZ"," install",[241,1003,1004],{"class":250},"(style",[241,1006,273],{"class":246},[241,1008,361],{"class":282},[241,1010,1011],{"class":250},", tag",[241,1013,273],{"class":246},[241,1015,1016],{"class":295},"\"ACME house style\"",[241,1018,1019],{"class":250},"):\n",[241,1021,1023,1026,1028,1031,1034],{"class":151,"line":1022},14,[241,1024,1025],{"class":250},"    style ",[241,1027,273],{"class":246},[241,1029,1030],{"class":250}," style ",[241,1032,1033],{"class":246},"or",[241,1035,276],{"class":250},[241,1037,1039,1042,1045,1047,1050],{"class":151,"line":1038},15,[241,1040,1041],{"class":246},"    for",[241,1043,1044],{"class":250}," name, props ",[241,1046,333],{"class":246},[241,1048,1049],{"class":282}," FILLS",[241,1051,1052],{"class":250},".items():\n",[241,1054,1056,1059,1061,1064,1067,1070,1073,1076,1079,1082],{"class":151,"line":1055},16,[241,1057,1058],{"class":250},"        full ",[241,1060,273],{"class":246},[241,1062,1063],{"class":246}," f",[241,1065,1066],{"class":295},"\"",[241,1068,1069],{"class":282},"{PREFIX}",[241,1071,1072],{"class":295}," · ",[241,1074,1075],{"class":282},"{",[241,1077,1078],{"class":250},"name",[241,1080,1081],{"class":282},"}",[241,1083,1084],{"class":295},"\"\n",[241,1086,1088,1091,1093],{"class":151,"line":1087},17,[241,1089,1090],{"class":250},"        symbol ",[241,1092,273],{"class":246},[241,1094,1095],{"class":250}," QgsFillSymbol.createSimple(props)\n",[241,1097,1099,1102,1104],{"class":151,"line":1098},18,[241,1100,1101],{"class":250},"        style.addSymbol(full, symbol.clone(), ",[241,1103,471],{"class":282},[241,1105,299],{"class":250},[241,1107,1109],{"class":151,"line":1108},19,[241,1110,1111],{"class":250},"        style.tagSymbol(QgsStyle.SymbolEntity, full, [tag])\n",[241,1113,1115,1118,1120,1122,1124,1126,1128],{"class":151,"line":1114},20,[241,1116,1117],{"class":250},"    ramp ",[241,1119,273],{"class":246},[241,1121,568],{"class":250},[241,1123,571],{"class":295},[241,1125,574],{"class":250},[241,1127,577],{"class":295},[241,1129,580],{"class":250},[241,1131,1133,1136,1139,1141,1143,1146,1148,1150],{"class":151,"line":1132},21,[241,1134,1135],{"class":250},"    style.addColorRamp(",[241,1137,1138],{"class":246},"f",[241,1140,1066],{"class":295},[241,1142,1069],{"class":282},[241,1144,1145],{"class":295}," · Blues\"",[241,1147,591],{"class":250},[241,1149,471],{"class":282},[241,1151,299],{"class":250},[241,1153,1155,1158,1160,1162,1164,1166],{"class":151,"line":1154},22,[241,1156,1157],{"class":250},"    style.tagSymbol(QgsStyle.ColorrampEntity, ",[241,1159,1138],{"class":246},[241,1161,1066],{"class":295},[241,1163,1069],{"class":282},[241,1165,1145],{"class":295},[241,1167,1168],{"class":250},", [tag])\n",[241,1170,1172,1175],{"class":151,"line":1171},23,[241,1173,1174],{"class":246},"    return",[241,1176,1177],{"class":250}," style\n",[14,1179,1180,1182,1183,1186,1187,1189],{},[208,1181,353],{}," Keeping the colours in a plain dictionary rather than scattered through constructor calls means a brand change is one edit and a review is one diff. The prefix in every name is what makes a later uninstall or upgrade possible — deleting everything matching a prefix is safe in a way that deleting by tag is not, because a user may have added their own symbols to the same tag. Defaulting ",[238,1184,1185],{},"style"," to ",[238,1188,361],{}," and resolving inside lets the same function install into the user's library or into a private in-memory style, which is exactly the flexibility a plugin needs between \"set up my workspace\" and \"load my own symbols quietly\".",[14,1191,1192,1193,1196,1197,1200,1201,1203],{},"Calling ",[238,1194,1195],{},"install()"," from a plugin's ",[238,1198,1199],{},"initGui()"," is cheap enough to do on every start, since ",[238,1202,503],{}," with an existing name replaces rather than duplicating. That idempotence is what lets the house style be updated by shipping a new plugin version rather than by asking forty people to import a file.",[197,1205,1207],{"id":1206},"export-and-import-a-house-style","Export and import a house style",[14,1209,1210],{},"The database is SQLite in the user profile; the portable form is XML.",[231,1212,1214],{"className":233,"code":1213,"language":235,"meta":236,"style":236},"style.exportXml(\"\u002Fdata\u002Fstyles\u002Fhouse_style.xml\")\n\n# on another machine, or at plugin start-up\nincoming = QgsStyle()\nincoming.createMemoryDatabase()\nif not incoming.importXml(\"\u002Fdata\u002Fstyles\u002Fhouse_style.xml\"):\n    raise RuntimeError(\"house style file could not be read\")\n",[238,1215,1216,1226,1230,1236,1246,1251,1265],{"__ignoreMap":236},[241,1217,1218,1221,1224],{"class":151,"line":243},[241,1219,1220],{"class":250},"style.exportXml(",[241,1222,1223],{"class":295},"\"\u002Fdata\u002Fstyles\u002Fhouse_style.xml\"",[241,1225,299],{"class":250},[241,1227,1228],{"class":151,"line":260},[241,1229,264],{"emptyLinePlaceholder":263},[241,1231,1232],{"class":151,"line":267},[241,1233,1235],{"class":1234},"sjoCn","# on another machine, or at plugin start-up\n",[241,1237,1238,1241,1243],{"class":151,"line":279},[241,1239,1240],{"class":250},"incoming ",[241,1242,273],{"class":246},[241,1244,1245],{"class":250}," QgsStyle()\n",[241,1247,1248],{"class":151,"line":302},[241,1249,1250],{"class":250},"incoming.createMemoryDatabase()\n",[241,1252,1253,1255,1258,1261,1263],{"class":151,"line":319},[241,1254,339],{"class":246},[241,1256,1257],{"class":246}," not",[241,1259,1260],{"class":250}," incoming.importXml(",[241,1262,1223],{"class":295},[241,1264,1019],{"class":250},[241,1266,1267,1270,1273,1275,1278],{"class":151,"line":450},[241,1268,1269],{"class":246},"    raise",[241,1271,1272],{"class":282}," RuntimeError",[241,1274,286],{"class":250},[241,1276,1277],{"class":295},"\"house style file could not be read\"",[241,1279,299],{"class":250},[14,1281,1282,354,1284,1286,1287,1290,1291,1294,1295,1297],{},[208,1283,353],{},[238,1285,181],{}," writes the whole database, not a tagged subset — to distribute only part of it, build a second ",[238,1288,1289],{},"QgsStyle"," in memory, add the tagged entities to it, and export that. ",[238,1292,1293],{},"createMemoryDatabase()"," is what makes a ",[238,1296,1289],{}," usable without touching the user's own file, which is the right approach in a plugin: read your symbols into a private style object rather than mutating the analyst's library behind their back.",[14,1299,1300,1301,1304],{},"Where the intent genuinely is to install into the user's library, ",[238,1302,1303],{},"QgsStyle.defaultStyle().importXml()"," merges the file in. Name collisions overwrite silently, so prefixing every entity with the organisation's name is worth the verbosity.",[197,1306,1308],{"id":1307},"qgis-version-compatibility","QGIS version compatibility",[14,1310,1311,1312,1314],{},"The examples target ",[208,1313,210],{}," (Python 3.12).",[1316,1317,1318,1334],"table",{},[1319,1320,1321],"thead",{},[1322,1323,1324,1328,1331],"tr",{},[1325,1326,1327],"th",{},"QGIS version",[1325,1329,1330],{},"Python",[1325,1332,1333],{},"Notes",[1335,1336,1337,1351,1362,1374,1385],"tbody",{},[1322,1338,1339,1343,1346],{},[1340,1341,1342],"td",{},"3.16 LTR",[1340,1344,1345],{},"3.7",[1340,1347,1348,1350],{},[238,1349,1289],{},", tagging and XML import\u002Fexport present.",[1322,1352,1353,1356,1359],{},[1340,1354,1355],{},"3.22 LTR",[1340,1357,1358],{},"3.9",[1340,1360,1361],{},"Text formats and label settings storable alongside symbols.",[1322,1363,1364,1367,1369],{},[1340,1365,1366],{},"3.28 LTR",[1340,1368,1358],{},[1340,1370,1371,1373],{},[238,1372,1293],{}," for private in-plugin style objects.",[1322,1375,1376,1379,1382],{},[1340,1377,1378],{},"3.34 LTR",[1340,1380,1381],{},"3.12",[1340,1383,1384],{},"Baseline for this page.",[1322,1386,1387,1390,1392],{},[1340,1388,1389],{},"3.40+",[1340,1391,1381],{},[1340,1393,1394],{},"Legend patch shapes and 3D symbols added as entity types.",[197,1396,1398],{"id":1397},"troubleshooting","Troubleshooting",[202,1400,1401,1413,1422,1434,1451,1457],{},[205,1402,1403,354,1406,1408,1409,1412],{},[208,1404,1405],{},"The symbol disappeared after restarting QGIS.",[238,1407,503],{}," was called without ",[238,1410,1411],{},"update=True",", so it never reached the database.",[205,1414,1415,1418,1419,1421],{},[208,1416,1417],{},"QGIS crashed after saving a symbol."," The live symbol object was passed rather than a clone, so ownership is shared. Always pass ",[238,1420,514],{},".",[205,1423,1424,1430,1431,1433],{},[208,1425,1426,1429],{},[238,1427,1428],{},"colorRamp()"," returned None."," The name does not match exactly. Filter ",[238,1432,127],{}," rather than trusting a remembered spelling.",[205,1435,1436,354,1441,1443,1444,1446,1447,1450],{},[208,1437,1438,1440],{},[238,1439,687],{}," returns nothing.",[238,1442,691],{}," gave ",[238,1445,51],{}," for a tag that does not exist. Check ",[238,1448,1449],{},"style.tags()"," first.",[205,1452,1453,1456],{},[208,1454,1455],{},"Importing overwrote a colleague's symbols."," Names collide silently on import. Prefix distributed entities.",[205,1458,1459,354,1462,1464],{},[208,1460,1461],{},"The exported file is enormous.",[238,1463,181],{}," writes the entire database including everything QGIS ships. Build a memory style with only your entities.",[197,1466,1468],{"id":1467},"conclusion","Conclusion",[14,1470,1471,1472,1474],{},"Treat the style database as a shared asset rather than a scratchpad: name entities predictably, tag them so they can be found, clone before handing symbols over, and pass ",[238,1473,1411],{}," so changes persist. For distribution, build a private in-memory style and export that, which keeps the file small and leaves the user's own library alone.",[197,1476,1478],{"id":1477},"frequently-asked-questions","Frequently Asked Questions",[14,1480,1481,1484,1487,1488,1491],{},[208,1482,1483],{},"Where is the style database on disk?",[238,1485,1486],{},"symbology-style.db"," in the active user profile directory, which ",[238,1489,1490],{},"QgsApplication.qgisSettingsDirPath()"," reports. It is SQLite, so it can be inspected directly — but write to it through the API rather than with SQL.",[14,1493,1494,1497,1498,1421],{},[208,1495,1496],{},"Can a project carry its own style database?","\nA project stores the styles its layers use, but not a library. To ship a library with a project, distribute the XML alongside it and import at load time from a ",[26,1499,1501],{"href":1500},"\u002Fpyqgis-fundamentals-environment-setup\u002Fworking-with-qgis-projects\u002Fsave-and-load-qgis-project-pyqgis\u002F","project-read hook",[14,1503,1504,1507,1508,1512],{},[208,1505,1506],{},"How do I save a whole layer style rather than one symbol?","\nThat is a ",[26,1509,1511],{"href":1510},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fsave-and-load-qml-style-pyqgis\u002F","QML style"," rather than a library entry. The library holds reusable pieces; QML holds a complete layer style including renderer and labelling.",[14,1514,1515,1518,1519,1522,1523,1527],{},[208,1516,1517],{},"Can I store a colour ramp used by a heatmap?","\nYes — ramps are entity type ",[238,1520,1521],{},"ColorrampEntity"," regardless of what consumes them, so a ramp saved here is available to ",[26,1524,1526],{"href":1525},"\u002Fpyqgis-cartography-visualization\u002Fsymbol-layers-and-advanced-symbology\u002Fcreate-heatmap-renderer-pyqgis\u002F","a heatmap renderer",", a graduated renderer or a raster.",[197,1529,1531],{"id":1530},"related","Related",[202,1533,1534,1539,1544,1550,1555],{},[205,1535,1536,1538],{},[26,1537,29],{"href":28}," — the guide this recipe belongs to",[205,1540,1541],{},[26,1542,1543],{"href":1510},"Save and Load a QML Style in PyQGIS",[205,1545,1546],{},[26,1547,1549],{"href":1548},"\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fapply-sld-style-to-layer-pyqgis\u002F","Apply an SLD Style to a Layer in PyQGIS",[205,1551,1552],{},[26,1553,1554],{"href":217},"Stack Symbol Layers in PyQGIS",[205,1556,1557],{},[26,1558,1560],{"href":1559},"\u002Fqgis-plugin-development\u002Fplugin-settings-and-localization\u002Fstore-plugin-settings-with-qgssettings\u002F","Store Plugin Settings with QgsSettings",[1185,1562,1563],{},"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 .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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 .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}",{"title":236,"searchDepth":260,"depth":260,"links":1565},[1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576],{"id":199,"depth":260,"text":200},{"id":225,"depth":260,"text":226},{"id":369,"depth":260,"text":370},{"id":628,"depth":260,"text":629},{"id":814,"depth":260,"text":815},{"id":1206,"depth":260,"text":1207},{"id":1307,"depth":260,"text":1308},{"id":1397,"depth":260,"text":1398},{"id":1467,"depth":260,"text":1468},{"id":1477,"depth":260,"text":1478},{"id":1530,"depth":260,"text":1531},"Read and write the QGIS symbol library from Python with QgsStyle — save symbols and colour ramps, tag and search them, build an XML style file, and ship a house style with a plugin.","md",{"slug":1580,"type":1581,"breadcrumb":1582,"datePublished":1583,"dateModified":1583},"use-style-manager-and-symbol-library-pyqgis","article","Style Manager & Symbol Library","2026-08-27","\u002Fpyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fuse-style-manager-and-symbol-library-pyqgis",{"title":5,"description":1577},"pyqgis-cartography-visualization\u002Fprogrammatic-layer-styling\u002Fuse-style-manager-and-symbol-library-pyqgis\u002Findex","ui8vFihJjk7A0KiDAJmMdVH9ZCmivrkz4Wm4Pbbj4oA",1787823360560]