[{"data":1,"prerenderedAt":2418},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true":2388,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true":2397,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true":2402,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true":2403},{"id":4,"title":5,"body":6,"dateModified":2353,"datePublished":2353,"description":2354,"extension":2355,"faq":2356,"keyword":2365,"kind":2366,"meta":2367,"navigation":131,"path":2377,"seo":2378,"slug":2381,"stem":2382,"topics":2383,"type":2386,"__hash__":2387},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true\u002Findex.md","Control Conditional Formatting Rule Order and Stop If True",{"type":7,"value":8,"toc":2340},"minimark",[9,28,33,62,73,77,533,540,544,547,572,575,721,725,732,1087,1101,1281,1285,1288,1527,1534,1538,1541,2077,2080,2205,2209,2220,2224,2262,2266,2275,2279,2285,2291,2297,2303,2307,2336],[10,11,12,13,17,18,21,22,27],"p",{},"A margin column has three rules: blue bold text for anything positive, a red fill for anything above 100, an amber fill for anything above 50. A value of 150 matches all three. What the reader sees depends on the rules' ",[14,15,16],"em",{},"priority"," — and, surprisingly, on which application opens the file: Excel layers the formats of every matching rule as long as they do not conflict, while LibreOffice applies only the first matching rule. A report that looks right in one can look wrong in the other. openpyxl numbers rules in the order you add them, lets you set priorities explicitly, and supports Excel's ",[14,19,20],{},"Stop If True"," flag, which together make the result predictable everywhere. This page belongs to ",[23,24,26],"a",{"href":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002F","Applying Conditional Formatting with openpyxl",".",[29,30,32],"h2",{"id":31},"prerequisites","Prerequisites",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pillow\n","bash","",[41,42,43],"code",{"__ignoreMap":39},[44,45,48,52,56,59],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sMTad","pip",[44,53,55],{"class":54},"srMev"," install",[44,57,58],{"class":54}," openpyxl",[44,60,61],{"class":54}," pillow\n",[10,63,64,65,68,69,72],{},"LibreOffice (",[41,66,67],{},"soffice",") and ",[41,70,71],{},"pdftoppm"," are used in Step 5 to render the sheet and check which rule won; they are optional.",[29,74,76],{"id":75},"step-1-openpyxl-numbers-rules-in-the-order-you-add-them","Step 1 — openpyxl numbers rules in the order you add them",[34,78,82],{"className":79,"code":80,"language":81,"meta":39,"style":39},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.styles import PatternFill, Font\nfrom openpyxl.formatting.rule import CellIsRule\n\ndef fill(hex_colour):\n    return PatternFill(\"solid\", start_color=hex_colour, end_color=hex_colour)\n\nwb = Workbook()\nws = wb.active\nws.title = \"Margins\"\nfor i, v in enumerate([150, 75, 20, -10], start=1):\n    ws.cell(i, 1, v)\n    ws.row_dimensions[i].height = 28\nws.column_dimensions[\"A\"].width = 18\n\npositive = CellIsRule(operator=\"greaterThan\", formula=[\"0\"], font=Font(bold=True, color=\"1D4ED8\"))\nhigh = CellIsRule(operator=\"greaterThan\", formula=[\"100\"], fill=fill(\"FCA5A5\"))\nmedium = CellIsRule(operator=\"greaterThan\", formula=[\"50\"], fill=fill(\"FCD34D\"))\nfor rule in (positive, high, medium):\n    ws.conditional_formatting.add(\"A1:A4\", rule)\nfor cf in ws.conditional_formatting:\n    for r in cf.rules:\n        print(cf.sqref, r.operator, r.formula, \"priority\", r.priority, \"stopIfTrue\", r.stopIfTrue)\n","python",[41,83,84,100,113,126,133,146,179,184,195,206,217,271,282,293,310,315,378,420,460,473,485,498,512],{"__ignoreMap":39},[44,85,86,90,94,97],{"class":46,"line":47},[44,87,89],{"class":88},"s-kum","from",[44,91,93],{"class":92},"skGVy"," openpyxl ",[44,95,96],{"class":88},"import",[44,98,99],{"class":92}," Workbook\n",[44,101,103,105,108,110],{"class":46,"line":102},2,[44,104,89],{"class":88},[44,106,107],{"class":92}," openpyxl.styles ",[44,109,96],{"class":88},[44,111,112],{"class":92}," PatternFill, Font\n",[44,114,116,118,121,123],{"class":46,"line":115},3,[44,117,89],{"class":88},[44,119,120],{"class":92}," openpyxl.formatting.rule ",[44,122,96],{"class":88},[44,124,125],{"class":92}," CellIsRule\n",[44,127,129],{"class":46,"line":128},4,[44,130,132],{"emptyLinePlaceholder":131},true,"\n",[44,134,136,139,143],{"class":46,"line":135},5,[44,137,138],{"class":88},"def",[44,140,142],{"class":141},"s_Opv"," fill",[44,144,145],{"class":92},"(hex_colour):\n",[44,147,149,152,155,158,161,165,168,171,174,176],{"class":46,"line":148},6,[44,150,151],{"class":88},"    return",[44,153,154],{"class":92}," PatternFill(",[44,156,157],{"class":54},"\"solid\"",[44,159,160],{"class":92},", ",[44,162,164],{"class":163},"sa561","start_color",[44,166,167],{"class":88},"=",[44,169,170],{"class":92},"hex_colour, ",[44,172,173],{"class":163},"end_color",[44,175,167],{"class":88},[44,177,178],{"class":92},"hex_colour)\n",[44,180,182],{"class":46,"line":181},7,[44,183,132],{"emptyLinePlaceholder":131},[44,185,187,190,192],{"class":46,"line":186},8,[44,188,189],{"class":92},"wb ",[44,191,167],{"class":88},[44,193,194],{"class":92}," Workbook()\n",[44,196,198,201,203],{"class":46,"line":197},9,[44,199,200],{"class":92},"ws ",[44,202,167],{"class":88},[44,204,205],{"class":92}," wb.active\n",[44,207,209,212,214],{"class":46,"line":208},10,[44,210,211],{"class":92},"ws.title ",[44,213,167],{"class":88},[44,215,216],{"class":54}," \"Margins\"\n",[44,218,220,223,226,229,233,236,239,241,244,246,249,251,254,257,260,263,265,268],{"class":46,"line":219},11,[44,221,222],{"class":88},"for",[44,224,225],{"class":92}," i, v ",[44,227,228],{"class":88},"in",[44,230,232],{"class":231},"sP0c6"," enumerate",[44,234,235],{"class":92},"([",[44,237,238],{"class":231},"150",[44,240,160],{"class":92},[44,242,243],{"class":231},"75",[44,245,160],{"class":92},[44,247,248],{"class":231},"20",[44,250,160],{"class":92},[44,252,253],{"class":88},"-",[44,255,256],{"class":231},"10",[44,258,259],{"class":92},"], ",[44,261,262],{"class":163},"start",[44,264,167],{"class":88},[44,266,267],{"class":231},"1",[44,269,270],{"class":92},"):\n",[44,272,274,277,279],{"class":46,"line":273},12,[44,275,276],{"class":92},"    ws.cell(i, ",[44,278,267],{"class":231},[44,280,281],{"class":92},", v)\n",[44,283,285,288,290],{"class":46,"line":284},13,[44,286,287],{"class":92},"    ws.row_dimensions[i].height ",[44,289,167],{"class":88},[44,291,292],{"class":231}," 28\n",[44,294,296,299,302,305,307],{"class":46,"line":295},14,[44,297,298],{"class":92},"ws.column_dimensions[",[44,300,301],{"class":54},"\"A\"",[44,303,304],{"class":92},"].width ",[44,306,167],{"class":88},[44,308,309],{"class":231}," 18\n",[44,311,313],{"class":46,"line":312},15,[44,314,132],{"emptyLinePlaceholder":131},[44,316,318,321,323,326,329,331,334,336,339,341,344,347,349,352,354,357,360,362,365,367,370,372,375],{"class":46,"line":317},16,[44,319,320],{"class":92},"positive ",[44,322,167],{"class":88},[44,324,325],{"class":92}," CellIsRule(",[44,327,328],{"class":163},"operator",[44,330,167],{"class":88},[44,332,333],{"class":54},"\"greaterThan\"",[44,335,160],{"class":92},[44,337,338],{"class":163},"formula",[44,340,167],{"class":88},[44,342,343],{"class":92},"[",[44,345,346],{"class":54},"\"0\"",[44,348,259],{"class":92},[44,350,351],{"class":163},"font",[44,353,167],{"class":88},[44,355,356],{"class":92},"Font(",[44,358,359],{"class":163},"bold",[44,361,167],{"class":88},[44,363,364],{"class":231},"True",[44,366,160],{"class":92},[44,368,369],{"class":163},"color",[44,371,167],{"class":88},[44,373,374],{"class":54},"\"1D4ED8\"",[44,376,377],{"class":92},"))\n",[44,379,381,384,386,388,390,392,394,396,398,400,402,405,407,410,412,415,418],{"class":46,"line":380},17,[44,382,383],{"class":92},"high ",[44,385,167],{"class":88},[44,387,325],{"class":92},[44,389,328],{"class":163},[44,391,167],{"class":88},[44,393,333],{"class":54},[44,395,160],{"class":92},[44,397,338],{"class":163},[44,399,167],{"class":88},[44,401,343],{"class":92},[44,403,404],{"class":54},"\"100\"",[44,406,259],{"class":92},[44,408,409],{"class":163},"fill",[44,411,167],{"class":88},[44,413,414],{"class":92},"fill(",[44,416,417],{"class":54},"\"FCA5A5\"",[44,419,377],{"class":92},[44,421,423,426,428,430,432,434,436,438,440,442,444,447,449,451,453,455,458],{"class":46,"line":422},18,[44,424,425],{"class":92},"medium ",[44,427,167],{"class":88},[44,429,325],{"class":92},[44,431,328],{"class":163},[44,433,167],{"class":88},[44,435,333],{"class":54},[44,437,160],{"class":92},[44,439,338],{"class":163},[44,441,167],{"class":88},[44,443,343],{"class":92},[44,445,446],{"class":54},"\"50\"",[44,448,259],{"class":92},[44,450,409],{"class":163},[44,452,167],{"class":88},[44,454,414],{"class":92},[44,456,457],{"class":54},"\"FCD34D\"",[44,459,377],{"class":92},[44,461,463,465,468,470],{"class":46,"line":462},19,[44,464,222],{"class":88},[44,466,467],{"class":92}," rule ",[44,469,228],{"class":88},[44,471,472],{"class":92}," (positive, high, medium):\n",[44,474,476,479,482],{"class":46,"line":475},20,[44,477,478],{"class":92},"    ws.conditional_formatting.add(",[44,480,481],{"class":54},"\"A1:A4\"",[44,483,484],{"class":92},", rule)\n",[44,486,488,490,493,495],{"class":46,"line":487},21,[44,489,222],{"class":88},[44,491,492],{"class":92}," cf ",[44,494,228],{"class":88},[44,496,497],{"class":92}," ws.conditional_formatting:\n",[44,499,501,504,507,509],{"class":46,"line":500},22,[44,502,503],{"class":88},"    for",[44,505,506],{"class":92}," r ",[44,508,228],{"class":88},[44,510,511],{"class":92}," cf.rules:\n",[44,513,515,518,521,524,527,530],{"class":46,"line":514},23,[44,516,517],{"class":231},"        print",[44,519,520],{"class":92},"(cf.sqref, r.operator, r.formula, ",[44,522,523],{"class":54},"\"priority\"",[44,525,526],{"class":92},", r.priority, ",[44,528,529],{"class":54},"\"stopIfTrue\"",[44,531,532],{"class":92},", r.stopIfTrue)\n",[10,534,535,536,539],{},"Each ",[41,537,538],{},"add"," call gives the rule the next priority number unless it already has one: here 1 for \"positive\", 2 for \"above 100\", 3 for \"above 50\". Priority 1 is evaluated first. The numbers are unique across the whole sheet, not per range, which matters when rules on different ranges overlap. In this order, a value of 150 matches all three rules, starting with the blue-bold rule.",[29,541,543],{"id":542},"step-2-how-excel-and-libreoffice-resolve-overlaps","Step 2 — How Excel and LibreOffice resolve overlaps",[10,545,546],{},"The order produces different results in the two applications:",[548,549,550,562],"ul",{},[551,552,553,557,558,561],"li",{},[554,555,556],"strong",{},"Excel"," evaluates every rule in priority order and applies ",[14,559,560],{},"all"," matching formats that do not conflict. For 150: blue bold text from rule 1, red fill from rule 2; rule 3's amber fill conflicts with the red fill already chosen, so the higher-priority red wins. The cell shows blue bold on red.",[551,563,564,567,568,571],{},[554,565,566],{},"LibreOffice"," applies only the ",[14,569,570],{},"first"," rule that matches. For 150: rule 1 matches, so the cell is blue bold with no fill at all — the red and amber rules are never applied.",[10,573,574],{},"Same file, two different pictures: a reviewer in LibreOffice sees no warning colour on the highest values. The general cure is to make the outcome independent of the merging behaviour, which the next two steps do.",[576,577,585,586,585,590,585,594,585,602,585,612,585,623,585,629,585,635,585,641,585,649,585,653,585,658,585,662,585,669,585,673,585,677,585,684,585,688,585,692,585,695,585,700,585,703,585,710,585,713,585,718],"svg",{"viewBox":578,"role":579,"ariaLabelledBy":580,"xmlns":583,"style":584},"4 0 752 233","img",[581,582],"cf-apps-t","cf-apps-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[587,588,589],"title",{"id":581},"The same three rules on the value 150",[591,592,593],"desc",{"id":582},"In Excel, every matching rule contributes non-conflicting formats, so 150 is blue bold on a red fill, with the higher-priority red fill beating the amber one. In LibreOffice only the first matching rule applies, so 150 is blue bold with no fill.",[595,596],"rect",{"x":597,"y":598,"width":599,"height":600,"fill":601},"4","0","752","233","#ffffff",[595,603],{"x":604,"y":605,"width":606,"height":607,"rx":608,"fill":609,"stroke":610,"style":611},"20.0","16.0","351.0","201.0","14","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[613,614,616],"g",{"transform":615},"translate(182.5,29.0) scale(1.083)",[617,618],"path",{"d":619,"fill":620,"stroke":621,"style":622},"M3 5.5l8-1.2v7.2H3z M13 4l8-1.2v8.7h-8z M3 13.5h8v7.2l-8-1.2z M13 13.5h8v8.7l-8-1.2z","none","var(--brand-strong,#4338ca)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[624,625,556],"text",{"x":626,"y":627,"style":628},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[46,630],{"x1":631,"y1":632,"x2":633,"y2":632,"stroke":610,"style":634},"36.0","91.0","355.0","stroke-width:1px",[624,636,640],{"x":637,"y":638,"style":639},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","rule 1: blue bold text",[613,642,644],{"transform":643},"translate(38.5,99.5) scale(0.625)",[617,645],{"d":646,"fill":620,"stroke":647,"style":648},"M5 12.5l4.5 4.5L19 7","var(--teal,#0f9488)","stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[624,650,652],{"x":637,"y":651,"style":639},"137.0","rule 2: red fill",[613,654,656],{"transform":655},"translate(38.5,125.5) scale(0.625)",[617,657],{"d":646,"fill":620,"stroke":647,"style":648},[624,659,661],{"x":637,"y":660,"style":639},"163.0","rule 3: amber fill loses to red",[613,663,665],{"transform":664},"translate(38.5,151.5) scale(0.625)",[617,666],{"d":667,"fill":620,"stroke":668,"style":648},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)",[624,670,672],{"x":637,"y":671,"style":639},"189.0","result: blue bold on red",[595,674],{"x":675,"y":605,"width":606,"height":607,"rx":608,"fill":676,"stroke":668,"style":611},"389.0","#fdefd8",[613,678,680],{"transform":679},"translate(551.5,29.0) scale(1.083)",[617,681],{"d":682,"fill":620,"stroke":683,"style":622},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","var(--gold-ink,#7a4e06)",[624,685,566],{"x":686,"y":627,"style":687},"564.5","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[46,689],{"x1":690,"y1":632,"x2":691,"y2":632,"stroke":668,"style":634},"405.0","724.0",[624,693,640],{"x":694,"y":638,"style":639},"429.0",[613,696,698],{"transform":697},"translate(407.5,99.5) scale(0.625)",[617,699],{"d":646,"fill":620,"stroke":647,"style":648},[624,701,702],{"x":694,"y":651,"style":639},"rule 2 never applied",[613,704,706],{"transform":705},"translate(407.5,125.5) scale(0.625)",[617,707],{"d":708,"fill":620,"stroke":709,"style":648},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[624,711,712],{"x":694,"y":660,"style":639},"rule 3 never applied",[613,714,716],{"transform":715},"translate(407.5,151.5) scale(0.625)",[617,717],{"d":708,"fill":620,"stroke":709,"style":648},[624,719,720],{"x":694,"y":671,"style":639},"result: blue bold, no fill",[29,722,724],{"id":723},"step-3-put-the-most-specific-rule-first-and-make-it-complete","Step 3 — Put the most specific rule first and make it complete",[10,726,727,728,731],{},"Order rules from most specific to most general, and give each rule ",[14,729,730],{},"every"," format it needs instead of relying on another rule to add the rest:",[34,733,735],{"className":79,"code":734,"language":81,"meta":39,"style":39},"wb = Workbook()\nws = wb.active\nws.title = \"Margins\"\nfor i, v in enumerate([150, 75, 20, -10], start=1):\n    ws.cell(i, 1, v)\n    ws.row_dimensions[i].height = 28\nws.column_dimensions[\"A\"].width = 18\n\nbold_blue = Font(bold=True, color=\"1D4ED8\")\nrules = [\n    CellIsRule(operator=\"greaterThan\", formula=[\"100\"], fill=fill(\"FCA5A5\"), font=bold_blue, stopIfTrue=True),\n    CellIsRule(operator=\"greaterThan\", formula=[\"50\"], fill=fill(\"FCD34D\"), font=bold_blue, stopIfTrue=True),\n    CellIsRule(operator=\"greaterThan\", formula=[\"0\"], font=bold_blue, stopIfTrue=True),\n]\nfor priority, rule in enumerate(rules, start=1):\n    rule.priority = priority\n    ws.conditional_formatting.add(\"A1:A4\", rule)\nwb.save(\"margins_ordered.xlsx\")\nprint([(r.formula[0], r.priority, r.stopIfTrue) for cf in ws.conditional_formatting for r in cf.rules])\n",[41,736,737,745,753,761,799,807,815,827,831,858,868,919,965,1001,1006,1028,1038,1046,1056],{"__ignoreMap":39},[44,738,739,741,743],{"class":46,"line":47},[44,740,189],{"class":92},[44,742,167],{"class":88},[44,744,194],{"class":92},[44,746,747,749,751],{"class":46,"line":102},[44,748,200],{"class":92},[44,750,167],{"class":88},[44,752,205],{"class":92},[44,754,755,757,759],{"class":46,"line":115},[44,756,211],{"class":92},[44,758,167],{"class":88},[44,760,216],{"class":54},[44,762,763,765,767,769,771,773,775,777,779,781,783,785,787,789,791,793,795,797],{"class":46,"line":128},[44,764,222],{"class":88},[44,766,225],{"class":92},[44,768,228],{"class":88},[44,770,232],{"class":231},[44,772,235],{"class":92},[44,774,238],{"class":231},[44,776,160],{"class":92},[44,778,243],{"class":231},[44,780,160],{"class":92},[44,782,248],{"class":231},[44,784,160],{"class":92},[44,786,253],{"class":88},[44,788,256],{"class":231},[44,790,259],{"class":92},[44,792,262],{"class":163},[44,794,167],{"class":88},[44,796,267],{"class":231},[44,798,270],{"class":92},[44,800,801,803,805],{"class":46,"line":135},[44,802,276],{"class":92},[44,804,267],{"class":231},[44,806,281],{"class":92},[44,808,809,811,813],{"class":46,"line":148},[44,810,287],{"class":92},[44,812,167],{"class":88},[44,814,292],{"class":231},[44,816,817,819,821,823,825],{"class":46,"line":181},[44,818,298],{"class":92},[44,820,301],{"class":54},[44,822,304],{"class":92},[44,824,167],{"class":88},[44,826,309],{"class":231},[44,828,829],{"class":46,"line":186},[44,830,132],{"emptyLinePlaceholder":131},[44,832,833,836,838,841,843,845,847,849,851,853,855],{"class":46,"line":197},[44,834,835],{"class":92},"bold_blue ",[44,837,167],{"class":88},[44,839,840],{"class":92}," Font(",[44,842,359],{"class":163},[44,844,167],{"class":88},[44,846,364],{"class":231},[44,848,160],{"class":92},[44,850,369],{"class":163},[44,852,167],{"class":88},[44,854,374],{"class":54},[44,856,857],{"class":92},")\n",[44,859,860,863,865],{"class":46,"line":208},[44,861,862],{"class":92},"rules ",[44,864,167],{"class":88},[44,866,867],{"class":92}," [\n",[44,869,870,873,875,877,879,881,883,885,887,889,891,893,895,897,899,902,904,906,909,912,914,916],{"class":46,"line":219},[44,871,872],{"class":92},"    CellIsRule(",[44,874,328],{"class":163},[44,876,167],{"class":88},[44,878,333],{"class":54},[44,880,160],{"class":92},[44,882,338],{"class":163},[44,884,167],{"class":88},[44,886,343],{"class":92},[44,888,404],{"class":54},[44,890,259],{"class":92},[44,892,409],{"class":163},[44,894,167],{"class":88},[44,896,414],{"class":92},[44,898,417],{"class":54},[44,900,901],{"class":92},"), ",[44,903,351],{"class":163},[44,905,167],{"class":88},[44,907,908],{"class":92},"bold_blue, ",[44,910,911],{"class":163},"stopIfTrue",[44,913,167],{"class":88},[44,915,364],{"class":231},[44,917,918],{"class":92},"),\n",[44,920,921,923,925,927,929,931,933,935,937,939,941,943,945,947,949,951,953,955,957,959,961,963],{"class":46,"line":273},[44,922,872],{"class":92},[44,924,328],{"class":163},[44,926,167],{"class":88},[44,928,333],{"class":54},[44,930,160],{"class":92},[44,932,338],{"class":163},[44,934,167],{"class":88},[44,936,343],{"class":92},[44,938,446],{"class":54},[44,940,259],{"class":92},[44,942,409],{"class":163},[44,944,167],{"class":88},[44,946,414],{"class":92},[44,948,457],{"class":54},[44,950,901],{"class":92},[44,952,351],{"class":163},[44,954,167],{"class":88},[44,956,908],{"class":92},[44,958,911],{"class":163},[44,960,167],{"class":88},[44,962,364],{"class":231},[44,964,918],{"class":92},[44,966,967,969,971,973,975,977,979,981,983,985,987,989,991,993,995,997,999],{"class":46,"line":284},[44,968,872],{"class":92},[44,970,328],{"class":163},[44,972,167],{"class":88},[44,974,333],{"class":54},[44,976,160],{"class":92},[44,978,338],{"class":163},[44,980,167],{"class":88},[44,982,343],{"class":92},[44,984,346],{"class":54},[44,986,259],{"class":92},[44,988,351],{"class":163},[44,990,167],{"class":88},[44,992,908],{"class":92},[44,994,911],{"class":163},[44,996,167],{"class":88},[44,998,364],{"class":231},[44,1000,918],{"class":92},[44,1002,1003],{"class":46,"line":295},[44,1004,1005],{"class":92},"]\n",[44,1007,1008,1010,1013,1015,1017,1020,1022,1024,1026],{"class":46,"line":312},[44,1009,222],{"class":88},[44,1011,1012],{"class":92}," priority, rule ",[44,1014,228],{"class":88},[44,1016,232],{"class":231},[44,1018,1019],{"class":92},"(rules, ",[44,1021,262],{"class":163},[44,1023,167],{"class":88},[44,1025,267],{"class":231},[44,1027,270],{"class":92},[44,1029,1030,1033,1035],{"class":46,"line":317},[44,1031,1032],{"class":92},"    rule.priority ",[44,1034,167],{"class":88},[44,1036,1037],{"class":92}," priority\n",[44,1039,1040,1042,1044],{"class":46,"line":380},[44,1041,478],{"class":92},[44,1043,481],{"class":54},[44,1045,484],{"class":92},[44,1047,1048,1051,1054],{"class":46,"line":422},[44,1049,1050],{"class":92},"wb.save(",[44,1052,1053],{"class":54},"\"margins_ordered.xlsx\"",[44,1055,857],{"class":92},[44,1057,1058,1061,1064,1066,1069,1071,1073,1075,1078,1080,1082,1084],{"class":46,"line":462},[44,1059,1060],{"class":231},"print",[44,1062,1063],{"class":92},"([(r.formula[",[44,1065,598],{"class":231},[44,1067,1068],{"class":92},"], r.priority, r.stopIfTrue) ",[44,1070,222],{"class":88},[44,1072,492],{"class":92},[44,1074,228],{"class":88},[44,1076,1077],{"class":92}," ws.conditional_formatting ",[44,1079,222],{"class":88},[44,1081,506],{"class":92},[44,1083,228],{"class":88},[44,1085,1086],{"class":92}," cf.rules])\n",[10,1088,1089,1090,1093,1094,1097,1098,1100],{},"Now the \"above 100\" rule comes first and carries both the red fill and the blue bold font, so it no longer needs to be combined with anything. ",[41,1091,1092],{},"stopIfTrue=True"," tells Excel not to evaluate further rules once this one matches — the behaviour LibreOffice has anyway — so both applications show the same thing: 150 red, 75 amber, 20 blue bold, −10 unformatted. Setting ",[41,1095,1096],{},"rule.priority"," before ",[41,1099,538],{}," keeps the numbers you chose, because openpyxl only assigns one when the rule has none.",[576,1102,585,1107,585,1110,585,1113,585,1116,585,1122,585,1129,585,1135,585,1140,585,1144,585,1148,585,1151,585,1156,585,1164,585,1169,585,1176,585,1182,585,1187,585,1191,585,1194,585,1197,585,1201,585,1204,585,1207,585,1212,585,1217,585,1221,585,1225,585,1228,585,1231,585,1235,585,1238,585,1241,585,1246,585,1249,585,1252,585,1254,585,1257,585,1261,585,1264,585,1268,585,1274,585,1278],{"viewBox":1103,"role":579,"ariaLabelledBy":1104,"xmlns":583,"style":584},"4 0 752 308",[1105,1106],"cf-flow-t","cf-flow-d",[587,1108,1109],{"id":1105},"How a cell is formatted with ordered, stop-if-true rules",[591,1111,1112],{"id":1106},"The value is tested against the rule with priority 1, above 100. If it matches, red fill and blue bold apply and evaluation stops. Otherwise it is tested against priority 2, above 50, which applies amber and stops, then priority 3, above 0, which applies blue bold. A value matching none stays unformatted.",[595,1114],{"x":597,"y":598,"width":599,"height":1115,"fill":601},"308",[595,1117],{"x":1118,"y":605,"width":1119,"height":1120,"rx":1121,"fill":609,"stroke":610,"style":611},"240.0","280.0","93.0","12",[613,1123,1125],{"transform":1124},"translate(368.0,29.0) scale(1.000)",[617,1126],{"d":1127,"fill":620,"stroke":621,"style":1128},"M3 5h18l-7 8v6l-4 2v-8z","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[624,1130,1134],{"x":1131,"y":1132,"style":1133},"380.0","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Test rules in priority order",[624,1136,1139],{"x":1131,"y":1137,"style":1138},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","first match wins (stopIfTrue)",[46,1141],{"x1":1131,"y1":1142,"x2":1131,"y2":1143,"stroke":610,"style":611},"109.0","129.0",[46,1145],{"x1":1146,"y1":1143,"x2":1147,"y2":1143,"stroke":610,"style":611},"104.0","656.0",[46,1149],{"x1":1146,"y1":1143,"x2":1146,"y2":1150,"stroke":610,"style":611},"175.0",[1152,1153],"polygon",{"points":1154,"fill":1155},"104.0,179.0 99.0,170.0 109.0,170.0","#5b5cf0",[595,1157],{"x":1158,"y":1159,"width":1160,"height":1161,"rx":256,"fill":601,"stroke":1162,"style":1163},"78.7","139.0","50.5","21.0","var(--line,#cdd5e6)","stroke-width:1.2px",[624,1165,1168],{"x":1146,"y":1166,"style":1167},"153.5","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","> 100",[595,1170],{"x":604,"y":1171,"width":1172,"height":1173,"rx":1121,"fill":1174,"stroke":1175,"style":611},"181.0","168.0","110.5","#fce9e9","var(--danger,#dc2626)",[613,1177,1179],{"transform":1178},"translate(92.0,202.8) scale(1.000)",[617,1180],{"d":667,"fill":620,"stroke":1181,"style":1128},"var(--accent-ink,#be185d)",[624,1183,1186],{"x":1146,"y":1184,"style":1185},"249.2","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Priority 1",[624,1188,1190],{"x":1146,"y":1189,"style":1138},"268.8","red fill, blue bold — stop",[46,1192],{"x1":1193,"y1":1143,"x2":1193,"y2":1150,"stroke":610,"style":611},"288.0",[1152,1195],{"points":1196,"fill":1155},"288.0,179.0 283.0,170.0 293.0,170.0",[595,1198],{"x":1199,"y":1159,"width":1200,"height":1161,"rx":256,"fill":601,"stroke":1162,"style":1163},"265.6","44.7",[624,1202,1203],{"x":1193,"y":1166,"style":1167},"> 50",[595,1205],{"x":1206,"y":1171,"width":1172,"height":1173,"rx":1121,"fill":676,"stroke":668,"style":611},"204.0",[613,1208,1210],{"transform":1209},"translate(276.0,194.0) scale(1.000)",[617,1211],{"d":667,"fill":620,"stroke":683,"style":1128},[624,1213,1216],{"x":1193,"y":1214,"style":1215},"240.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Priority 2",[624,1218,1220],{"x":1193,"y":1219,"style":1138},"260.0","amber fill, blue bold —",[624,1222,1224],{"x":1193,"y":1223,"style":1138},"277.5","stop",[46,1226],{"x1":1227,"y1":1143,"x2":1227,"y2":1150,"stroke":610,"style":611},"472.0",[1152,1229],{"points":1230,"fill":1155},"472.0,179.0 467.0,170.0 477.0,170.0",[595,1232],{"x":1233,"y":1159,"width":1234,"height":1161,"rx":256,"fill":601,"stroke":1162,"style":1163},"453.4","37.2",[624,1236,1237],{"x":1227,"y":1166,"style":1167},"> 0",[595,1239],{"x":1240,"y":1171,"width":1172,"height":1173,"rx":1121,"fill":609,"stroke":610,"style":611},"388.0",[613,1242,1244],{"transform":1243},"translate(460.0,202.8) scale(1.000)",[617,1245],{"d":646,"fill":620,"stroke":621,"style":1128},[624,1247,1248],{"x":1227,"y":1184,"style":1133},"Priority 3",[624,1250,1251],{"x":1227,"y":1189,"style":1138},"blue bold — stop",[46,1253],{"x1":1147,"y1":1143,"x2":1147,"y2":1150,"stroke":610,"style":611},[1152,1255],{"points":1256,"fill":1155},"656.0,179.0 651.0,170.0 661.0,170.0",[595,1258],{"x":1259,"y":1159,"width":1260,"height":1161,"rx":256,"fill":601,"stroke":1162,"style":1163},"619.6","72.9",[624,1262,1263],{"x":1147,"y":1166,"style":1167},"no match",[595,1265],{"x":1266,"y":1171,"width":1172,"height":1173,"rx":1121,"fill":1267,"stroke":1162,"style":611},"572.0","#e7ebef",[613,1269,1271],{"transform":1270},"translate(644.0,202.8) scale(1.000)",[617,1272],{"d":682,"fill":620,"stroke":1273,"style":1128},"var(--text,#172033)",[624,1275,1277],{"x":1147,"y":1184,"style":1276},"font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Unformatted",[624,1279,1280],{"x":1147,"y":1189,"style":1138},"e.g. −10",[29,1282,1284],{"id":1283},"step-4-inspect-and-reorder-rules-in-an-existing-workbook","Step 4 — Inspect and reorder rules in an existing workbook",[10,1286,1287],{},"Templates often arrive with rules in the wrong order. Load them, list them with their priorities, and renumber:",[34,1289,1291],{"className":79,"code":1290,"language":81,"meta":39,"style":39},"from openpyxl import load_workbook\n\nwb = load_workbook(\"margins_ordered.xlsx\")\nws = wb[\"Margins\"]\nall_rules = [(str(cf.sqref), r) for cf in ws.conditional_formatting for r in cf.rules]\nfor rng, r in sorted(all_rules, key=lambda t: t[1].priority):\n    print(rng, r.priority, r.operator, r.formula, \"stop\" if r.stopIfTrue else \"\")\n\norder = [\"0\", \"50\", \"100\"]                       # e.g. a template that wants the general rule first\nfor rng, r in all_rules:\n    r.priority = order.index(r.formula[0]) + 1\nwb.save(\"margins_reordered.xlsx\")\nprint([(r.formula[0], r.priority) for _, r in sorted(all_rules, key=lambda t: t[1].priority)])\n",[41,1292,1293,1304,1308,1321,1335,1368,1397,1422,1426,1453,1464,1485,1494],{"__ignoreMap":39},[44,1294,1295,1297,1299,1301],{"class":46,"line":47},[44,1296,89],{"class":88},[44,1298,93],{"class":92},[44,1300,96],{"class":88},[44,1302,1303],{"class":92}," load_workbook\n",[44,1305,1306],{"class":46,"line":102},[44,1307,132],{"emptyLinePlaceholder":131},[44,1309,1310,1312,1314,1317,1319],{"class":46,"line":115},[44,1311,189],{"class":92},[44,1313,167],{"class":88},[44,1315,1316],{"class":92}," load_workbook(",[44,1318,1053],{"class":54},[44,1320,857],{"class":92},[44,1322,1323,1325,1327,1330,1333],{"class":46,"line":128},[44,1324,200],{"class":92},[44,1326,167],{"class":88},[44,1328,1329],{"class":92}," wb[",[44,1331,1332],{"class":54},"\"Margins\"",[44,1334,1005],{"class":92},[44,1336,1337,1340,1342,1345,1348,1351,1353,1355,1357,1359,1361,1363,1365],{"class":46,"line":135},[44,1338,1339],{"class":92},"all_rules ",[44,1341,167],{"class":88},[44,1343,1344],{"class":92}," [(",[44,1346,1347],{"class":231},"str",[44,1349,1350],{"class":92},"(cf.sqref), r) ",[44,1352,222],{"class":88},[44,1354,492],{"class":92},[44,1356,228],{"class":88},[44,1358,1077],{"class":92},[44,1360,222],{"class":88},[44,1362,506],{"class":92},[44,1364,228],{"class":88},[44,1366,1367],{"class":92}," cf.rules]\n",[44,1369,1370,1372,1375,1377,1380,1383,1386,1389,1392,1394],{"class":46,"line":148},[44,1371,222],{"class":88},[44,1373,1374],{"class":92}," rng, r ",[44,1376,228],{"class":88},[44,1378,1379],{"class":231}," sorted",[44,1381,1382],{"class":92},"(all_rules, ",[44,1384,1385],{"class":163},"key",[44,1387,1388],{"class":88},"=lambda",[44,1390,1391],{"class":92}," t: t[",[44,1393,267],{"class":231},[44,1395,1396],{"class":92},"].priority):\n",[44,1398,1399,1402,1405,1408,1411,1414,1417,1420],{"class":46,"line":181},[44,1400,1401],{"class":231},"    print",[44,1403,1404],{"class":92},"(rng, r.priority, r.operator, r.formula, ",[44,1406,1407],{"class":54},"\"stop\"",[44,1409,1410],{"class":88}," if",[44,1412,1413],{"class":92}," r.stopIfTrue ",[44,1415,1416],{"class":88},"else",[44,1418,1419],{"class":54}," \"\"",[44,1421,857],{"class":92},[44,1423,1424],{"class":46,"line":186},[44,1425,132],{"emptyLinePlaceholder":131},[44,1427,1428,1431,1433,1436,1438,1440,1442,1444,1446,1449],{"class":46,"line":197},[44,1429,1430],{"class":92},"order ",[44,1432,167],{"class":88},[44,1434,1435],{"class":92}," [",[44,1437,346],{"class":54},[44,1439,160],{"class":92},[44,1441,446],{"class":54},[44,1443,160],{"class":92},[44,1445,404],{"class":54},[44,1447,1448],{"class":92},"]                       ",[44,1450,1452],{"class":1451},"s-wDw","# e.g. a template that wants the general rule first\n",[44,1454,1455,1457,1459,1461],{"class":46,"line":208},[44,1456,222],{"class":88},[44,1458,1374],{"class":92},[44,1460,228],{"class":88},[44,1462,1463],{"class":92}," all_rules:\n",[44,1465,1466,1469,1471,1474,1476,1479,1482],{"class":46,"line":219},[44,1467,1468],{"class":92},"    r.priority ",[44,1470,167],{"class":88},[44,1472,1473],{"class":92}," order.index(r.formula[",[44,1475,598],{"class":231},[44,1477,1478],{"class":92},"]) ",[44,1480,1481],{"class":88},"+",[44,1483,1484],{"class":231}," 1\n",[44,1486,1487,1489,1492],{"class":46,"line":273},[44,1488,1050],{"class":92},[44,1490,1491],{"class":54},"\"margins_reordered.xlsx\"",[44,1493,857],{"class":92},[44,1495,1496,1498,1500,1502,1505,1507,1510,1512,1514,1516,1518,1520,1522,1524],{"class":46,"line":284},[44,1497,1060],{"class":231},[44,1499,1063],{"class":92},[44,1501,598],{"class":231},[44,1503,1504],{"class":92},"], r.priority) ",[44,1506,222],{"class":88},[44,1508,1509],{"class":92}," _, r ",[44,1511,228],{"class":88},[44,1513,1379],{"class":231},[44,1515,1382],{"class":92},[44,1517,1385],{"class":163},[44,1519,1388],{"class":88},[44,1521,1391],{"class":92},[44,1523,267],{"class":231},[44,1525,1526],{"class":92},"].priority)])\n",[10,1528,1529,1530,27],{},"Priorities are plain attributes on the loaded rules, so renumbering them and saving changes the evaluation order. Keep the numbers unique across the sheet; two rules with the same priority are evaluated in an application-defined order. Listing and removing rules is covered in ",[23,1531,1533],{"href":1532},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Flist-and-remove-conditional-formatting-with-openpyxl\u002F","List and Remove Conditional Formatting with openpyxl",[29,1535,1537],{"id":1536},"step-5-check-what-the-reader-sees","Step 5 — Check what the reader sees",[10,1539,1540],{},"Rule order is easy to get subtly wrong, and the file alone does not show the outcome. Render the sheet and check whether the warning colours appear:",[34,1542,1544],{"className":79,"code":1543,"language":81,"meta":39,"style":39},"import subprocess\nfrom PIL import Image\n\ndef colours_on_page(xlsx):\n    pdf = xlsx.replace(\".xlsx\", \".pdf\")\n    subprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pdf\", xlsx], check=True, capture_output=True)\n    subprocess.run([\"pdftoppm\", \"-png\", \"-r\", \"60\", \"-f\", \"1\", \"-l\", \"1\", pdf, pdf[:-4]], check=True)\n    img = Image.open(pdf[:-4] + \"-1.png\").convert(\"RGB\")\n    found = {colour for _, colour in img.getcolors(maxcolors=1_000_000)}\n    return {\"red fill\": (0xFC, 0xA5, 0xA5) in found, \"amber fill\": (0xFC, 0xD3, 0x4D) in found}\n\nfirst_unordered = Workbook()\nws0 = first_unordered.active\nfor i, v in enumerate([150, 75, 20, -10], start=1):\n    ws0.cell(i, 1, v)\nfor rule in (CellIsRule(operator=\"greaterThan\", formula=[\"0\"], font=Font(bold=True, color=\"1D4ED8\")),\n             CellIsRule(operator=\"greaterThan\", formula=[\"100\"], fill=fill(\"FCA5A5\")),\n             CellIsRule(operator=\"greaterThan\", formula=[\"50\"], fill=fill(\"FCD34D\"))):\n    ws0.conditional_formatting.add(\"A1:A4\", rule)\nfirst_unordered.save(\"margins_general_first.xlsx\")\n\nprint(\"general rule first:\", colours_on_page(\"margins_general_first.xlsx\"))\nprint(\"specific rules first:\", colours_on_page(\"margins_ordered.xlsx\"))\n",[41,1545,1546,1553,1566,1570,1580,1600,1644,1703,1733,1764,1834,1838,1847,1857,1895,1904,1956,1989,2022,2031,2041,2045,2062],{"__ignoreMap":39},[44,1547,1548,1550],{"class":46,"line":47},[44,1549,96],{"class":88},[44,1551,1552],{"class":92}," subprocess\n",[44,1554,1555,1557,1560,1563],{"class":46,"line":102},[44,1556,89],{"class":88},[44,1558,1559],{"class":231}," PIL",[44,1561,1562],{"class":88}," import",[44,1564,1565],{"class":92}," Image\n",[44,1567,1568],{"class":46,"line":115},[44,1569,132],{"emptyLinePlaceholder":131},[44,1571,1572,1574,1577],{"class":46,"line":128},[44,1573,138],{"class":88},[44,1575,1576],{"class":141}," colours_on_page",[44,1578,1579],{"class":92},"(xlsx):\n",[44,1581,1582,1585,1587,1590,1593,1595,1598],{"class":46,"line":135},[44,1583,1584],{"class":92},"    pdf ",[44,1586,167],{"class":88},[44,1588,1589],{"class":92}," xlsx.replace(",[44,1591,1592],{"class":54},"\".xlsx\"",[44,1594,160],{"class":92},[44,1596,1597],{"class":54},"\".pdf\"",[44,1599,857],{"class":92},[44,1601,1602,1605,1608,1610,1613,1615,1618,1620,1623,1626,1629,1631,1633,1635,1638,1640,1642],{"class":46,"line":148},[44,1603,1604],{"class":92},"    subprocess.run([",[44,1606,1607],{"class":54},"\"soffice\"",[44,1609,160],{"class":92},[44,1611,1612],{"class":54},"\"--headless\"",[44,1614,160],{"class":92},[44,1616,1617],{"class":54},"\"--convert-to\"",[44,1619,160],{"class":92},[44,1621,1622],{"class":54},"\"pdf\"",[44,1624,1625],{"class":92},", xlsx], ",[44,1627,1628],{"class":163},"check",[44,1630,167],{"class":88},[44,1632,364],{"class":231},[44,1634,160],{"class":92},[44,1636,1637],{"class":163},"capture_output",[44,1639,167],{"class":88},[44,1641,364],{"class":231},[44,1643,857],{"class":92},[44,1645,1646,1648,1651,1653,1656,1658,1661,1663,1666,1668,1671,1673,1676,1678,1681,1683,1685,1688,1690,1692,1695,1697,1699,1701],{"class":46,"line":181},[44,1647,1604],{"class":92},[44,1649,1650],{"class":54},"\"pdftoppm\"",[44,1652,160],{"class":92},[44,1654,1655],{"class":54},"\"-png\"",[44,1657,160],{"class":92},[44,1659,1660],{"class":54},"\"-r\"",[44,1662,160],{"class":92},[44,1664,1665],{"class":54},"\"60\"",[44,1667,160],{"class":92},[44,1669,1670],{"class":54},"\"-f\"",[44,1672,160],{"class":92},[44,1674,1675],{"class":54},"\"1\"",[44,1677,160],{"class":92},[44,1679,1680],{"class":54},"\"-l\"",[44,1682,160],{"class":92},[44,1684,1675],{"class":54},[44,1686,1687],{"class":92},", pdf, pdf[:",[44,1689,253],{"class":88},[44,1691,597],{"class":231},[44,1693,1694],{"class":92},"]], ",[44,1696,1628],{"class":163},[44,1698,167],{"class":88},[44,1700,364],{"class":231},[44,1702,857],{"class":92},[44,1704,1705,1708,1710,1713,1715,1717,1720,1722,1725,1728,1731],{"class":46,"line":186},[44,1706,1707],{"class":92},"    img ",[44,1709,167],{"class":88},[44,1711,1712],{"class":92}," Image.open(pdf[:",[44,1714,253],{"class":88},[44,1716,597],{"class":231},[44,1718,1719],{"class":92},"] ",[44,1721,1481],{"class":88},[44,1723,1724],{"class":54}," \"-1.png\"",[44,1726,1727],{"class":92},").convert(",[44,1729,1730],{"class":54},"\"RGB\"",[44,1732,857],{"class":92},[44,1734,1735,1738,1740,1743,1745,1748,1750,1753,1756,1758,1761],{"class":46,"line":197},[44,1736,1737],{"class":92},"    found ",[44,1739,167],{"class":88},[44,1741,1742],{"class":92}," {colour ",[44,1744,222],{"class":88},[44,1746,1747],{"class":92}," _, colour ",[44,1749,228],{"class":88},[44,1751,1752],{"class":92}," img.getcolors(",[44,1754,1755],{"class":163},"maxcolors",[44,1757,167],{"class":88},[44,1759,1760],{"class":231},"1_000_000",[44,1762,1763],{"class":92},")}\n",[44,1765,1766,1768,1771,1774,1777,1780,1783,1785,1787,1790,1792,1794,1796,1799,1801,1804,1807,1809,1811,1813,1815,1817,1820,1822,1824,1827,1829,1831],{"class":46,"line":208},[44,1767,151],{"class":88},[44,1769,1770],{"class":92}," {",[44,1772,1773],{"class":54},"\"red fill\"",[44,1775,1776],{"class":92},": (",[44,1778,1779],{"class":88},"0x",[44,1781,1782],{"class":231},"FC",[44,1784,160],{"class":92},[44,1786,1779],{"class":88},[44,1788,1789],{"class":231},"A5",[44,1791,160],{"class":92},[44,1793,1779],{"class":88},[44,1795,1789],{"class":231},[44,1797,1798],{"class":92},") ",[44,1800,228],{"class":88},[44,1802,1803],{"class":92}," found, ",[44,1805,1806],{"class":54},"\"amber fill\"",[44,1808,1776],{"class":92},[44,1810,1779],{"class":88},[44,1812,1782],{"class":231},[44,1814,160],{"class":92},[44,1816,1779],{"class":88},[44,1818,1819],{"class":231},"D3",[44,1821,160],{"class":92},[44,1823,1779],{"class":88},[44,1825,1826],{"class":231},"4D",[44,1828,1798],{"class":92},[44,1830,228],{"class":88},[44,1832,1833],{"class":92}," found}\n",[44,1835,1836],{"class":46,"line":219},[44,1837,132],{"emptyLinePlaceholder":131},[44,1839,1840,1843,1845],{"class":46,"line":273},[44,1841,1842],{"class":92},"first_unordered ",[44,1844,167],{"class":88},[44,1846,194],{"class":92},[44,1848,1849,1852,1854],{"class":46,"line":284},[44,1850,1851],{"class":92},"ws0 ",[44,1853,167],{"class":88},[44,1855,1856],{"class":92}," first_unordered.active\n",[44,1858,1859,1861,1863,1865,1867,1869,1871,1873,1875,1877,1879,1881,1883,1885,1887,1889,1891,1893],{"class":46,"line":295},[44,1860,222],{"class":88},[44,1862,225],{"class":92},[44,1864,228],{"class":88},[44,1866,232],{"class":231},[44,1868,235],{"class":92},[44,1870,238],{"class":231},[44,1872,160],{"class":92},[44,1874,243],{"class":231},[44,1876,160],{"class":92},[44,1878,248],{"class":231},[44,1880,160],{"class":92},[44,1882,253],{"class":88},[44,1884,256],{"class":231},[44,1886,259],{"class":92},[44,1888,262],{"class":163},[44,1890,167],{"class":88},[44,1892,267],{"class":231},[44,1894,270],{"class":92},[44,1896,1897,1900,1902],{"class":46,"line":312},[44,1898,1899],{"class":92},"    ws0.cell(i, ",[44,1901,267],{"class":231},[44,1903,281],{"class":92},[44,1905,1906,1908,1910,1912,1915,1917,1919,1921,1923,1925,1927,1929,1931,1933,1935,1937,1939,1941,1943,1945,1947,1949,1951,1953],{"class":46,"line":317},[44,1907,222],{"class":88},[44,1909,467],{"class":92},[44,1911,228],{"class":88},[44,1913,1914],{"class":92}," (CellIsRule(",[44,1916,328],{"class":163},[44,1918,167],{"class":88},[44,1920,333],{"class":54},[44,1922,160],{"class":92},[44,1924,338],{"class":163},[44,1926,167],{"class":88},[44,1928,343],{"class":92},[44,1930,346],{"class":54},[44,1932,259],{"class":92},[44,1934,351],{"class":163},[44,1936,167],{"class":88},[44,1938,356],{"class":92},[44,1940,359],{"class":163},[44,1942,167],{"class":88},[44,1944,364],{"class":231},[44,1946,160],{"class":92},[44,1948,369],{"class":163},[44,1950,167],{"class":88},[44,1952,374],{"class":54},[44,1954,1955],{"class":92},")),\n",[44,1957,1958,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987],{"class":46,"line":380},[44,1959,1960],{"class":92},"             CellIsRule(",[44,1962,328],{"class":163},[44,1964,167],{"class":88},[44,1966,333],{"class":54},[44,1968,160],{"class":92},[44,1970,338],{"class":163},[44,1972,167],{"class":88},[44,1974,343],{"class":92},[44,1976,404],{"class":54},[44,1978,259],{"class":92},[44,1980,409],{"class":163},[44,1982,167],{"class":88},[44,1984,414],{"class":92},[44,1986,417],{"class":54},[44,1988,1955],{"class":92},[44,1990,1991,1993,1995,1997,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017,2019],{"class":46,"line":422},[44,1992,1960],{"class":92},[44,1994,328],{"class":163},[44,1996,167],{"class":88},[44,1998,333],{"class":54},[44,2000,160],{"class":92},[44,2002,338],{"class":163},[44,2004,167],{"class":88},[44,2006,343],{"class":92},[44,2008,446],{"class":54},[44,2010,259],{"class":92},[44,2012,409],{"class":163},[44,2014,167],{"class":88},[44,2016,414],{"class":92},[44,2018,457],{"class":54},[44,2020,2021],{"class":92},"))):\n",[44,2023,2024,2027,2029],{"class":46,"line":462},[44,2025,2026],{"class":92},"    ws0.conditional_formatting.add(",[44,2028,481],{"class":54},[44,2030,484],{"class":92},[44,2032,2033,2036,2039],{"class":46,"line":475},[44,2034,2035],{"class":92},"first_unordered.save(",[44,2037,2038],{"class":54},"\"margins_general_first.xlsx\"",[44,2040,857],{"class":92},[44,2042,2043],{"class":46,"line":487},[44,2044,132],{"emptyLinePlaceholder":131},[44,2046,2047,2049,2052,2055,2058,2060],{"class":46,"line":500},[44,2048,1060],{"class":231},[44,2050,2051],{"class":92},"(",[44,2053,2054],{"class":54},"\"general rule first:\"",[44,2056,2057],{"class":92},", colours_on_page(",[44,2059,2038],{"class":54},[44,2061,377],{"class":92},[44,2063,2064,2066,2068,2071,2073,2075],{"class":46,"line":514},[44,2065,1060],{"class":231},[44,2067,2051],{"class":92},[44,2069,2070],{"class":54},"\"specific rules first:\"",[44,2072,2057],{"class":92},[44,2074,1053],{"class":54},[44,2076,377],{"class":92},[10,2078,2079],{},"In LibreOffice's rendering, the file with the general rule first shows neither warning colour — every positive value stopped at the blue-bold rule — while the ordered file shows both. A test like this, which checks that the colours that matter actually appear, catches a template edit that reorders the rules before anyone notices on a printed report.",[576,2081,585,2087,585,2090,585,2093,585,2098,585,2103,585,2107,585,2113,585,2117,585,2121,585,2125,585,2129,585,2132,585,2136,585,2138,585,2141,585,2144,585,2148,585,2150,585,2152,585,2154,585,2158,585,2161,585,2165,585,2167,585,2169,585,2171,585,2174,585,2177,585,2180,585,2182,585,2184,585,2186,585,2189,585,2192,585,2196,585,2198,585,2201,585,2203],{"viewBox":2082,"role":579,"ariaLabelledBy":2083,"xmlns":583,"style":2086},"227 0 305 196",[2084,2085],"cf-result-t","cf-result-d","width:100%;max-width:305px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[587,2088,2089],{"id":2084},"The ordered rules in the rendered sheet",[591,2091,2092],{"id":2085},"The margins column after applying the ordered rules. 150 has a red fill and blue bold text, 75 an amber fill and blue bold text, 20 blue bold text only, and -10 no formatting.",[595,2094],{"x":2095,"y":598,"width":2096,"height":2097,"fill":601},"227","305","196",[595,2099],{"x":2100,"y":605,"width":2101,"height":2102,"rx":598,"fill":1267,"stroke":1162,"style":634},"243.8","32.0","24.0",[595,2104],{"x":2105,"y":605,"width":2106,"height":2102,"rx":598,"fill":1267,"stroke":1162,"style":634},"275.8","63.8",[624,2108,2112],{"x":2109,"y":2110,"style":2111},"307.7","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[595,2114],{"x":2115,"y":605,"width":2116,"height":2102,"rx":598,"fill":1267,"stroke":1162,"style":634},"339.6","176.5",[624,2118,2120],{"x":2119,"y":2110,"style":2111},"427.9","B",[595,2122],{"x":2100,"y":2123,"width":2101,"height":2124,"rx":598,"fill":1267,"stroke":1162,"style":634},"40.0","28.0",[624,2126,267],{"x":2127,"y":2128,"style":2111},"259.8","59.0",[595,2130],{"x":2105,"y":2123,"width":2106,"height":2124,"rx":598,"fill":609,"stroke":610,"style":2131},"stroke-width:1.5px",[624,2133,2135],{"x":2109,"y":2128,"style":2134},"font-size:11px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Margin",[595,2137],{"x":2115,"y":2123,"width":2116,"height":2124,"rx":598,"fill":609,"stroke":610,"style":2131},[624,2139,2140],{"x":2119,"y":2128,"style":2134},"Rule applied",[595,2142],{"x":2100,"y":2143,"width":2101,"height":2124,"rx":598,"fill":1267,"stroke":1162,"style":634},"68.0",[624,2145,2147],{"x":2127,"y":2146,"style":2111},"87.0","2",[595,2149],{"x":2105,"y":2143,"width":2106,"height":2124,"rx":598,"fill":1174,"stroke":1175,"style":2131},[624,2151,238],{"x":2109,"y":2146,"style":2134},[595,2153],{"x":2115,"y":2143,"width":2116,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2155,2157],{"x":2119,"y":2146,"style":2156},"font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","priority 1: red, blue bold",[595,2159],{"x":2100,"y":2160,"width":2101,"height":2124,"rx":598,"fill":1267,"stroke":1162,"style":634},"96.0",[624,2162,2164],{"x":2127,"y":2163,"style":2111},"115.0","3",[595,2166],{"x":2105,"y":2160,"width":2106,"height":2124,"rx":598,"fill":676,"stroke":668,"style":2131},[624,2168,243],{"x":2109,"y":2163,"style":2134},[595,2170],{"x":2115,"y":2160,"width":2116,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2172,2173],{"x":2119,"y":2163,"style":2156},"priority 2: amber, blue bold",[595,2175],{"x":2100,"y":2176,"width":2101,"height":2124,"rx":598,"fill":1267,"stroke":1162,"style":634},"124.0",[624,2178,597],{"x":2127,"y":2179,"style":2111},"143.0",[595,2181],{"x":2105,"y":2176,"width":2106,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2183,248],{"x":2109,"y":2179,"style":2134},[595,2185],{"x":2115,"y":2176,"width":2116,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2187,2188],{"x":2119,"y":2179,"style":2156},"priority 3: blue bold",[595,2190],{"x":2100,"y":2191,"width":2101,"height":2124,"rx":598,"fill":1267,"stroke":1162,"style":634},"152.0",[624,2193,2195],{"x":2127,"y":2194,"style":2111},"171.0","5",[595,2197],{"x":2105,"y":2191,"width":2106,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2199,2200],{"x":2109,"y":2194,"style":2156},"-10",[595,2202],{"x":2115,"y":2191,"width":2116,"height":2124,"rx":598,"fill":601,"stroke":1162,"style":634},[624,2204,620],{"x":2119,"y":2194,"style":2156},[29,2206,2208],{"id":2207},"performance-notes","Performance notes",[10,2210,2211,2212,2215,2216,2219],{},"Rule order also affects how fast a sheet feels. Each rule is evaluated for every cell in its range whenever the sheet recalculates, so a long list of overlapping rules over whole columns slows scrolling and editing in Excel. Stop-if-true helps here too: once a cell matches an early rule, later ones are skipped. Keep ranges to the data (",[41,2213,2214],{},"A2:A5000",", not ",[41,2217,2218],{},"A:A","), merge rules that differ only in colour into an ordered set like the one above, and remove rules that duplicate others — templates edited by many hands often accumulate several identical copies, which Step 4's listing makes easy to spot.",[29,2221,2223],{"id":2222},"common-pitfalls","Common pitfalls",[548,2225,2226,2232,2238,2244,2250,2256],{},[551,2227,2228,2231],{},[554,2229,2230],{},"Relying on rules combining."," Excel merges non-conflicting formats; LibreOffice does not. Make each rule complete.",[551,2233,2234,2237],{},[554,2235,2236],{},"General rules first."," A broad rule at priority 1 hides specific ones in LibreOffice; order from specific to general.",[551,2239,2240,2243],{},[554,2241,2242],{},"Forgetting stopIfTrue."," Without it, Excel keeps adding formats from lower-priority rules.",[551,2245,2246,2249],{},[554,2247,2248],{},"Duplicate priorities."," Keep numbers unique across the sheet; renumber after editing.",[551,2251,2252,2255],{},[554,2253,2254],{},"Overlapping ranges."," Priority applies across ranges too; a rule on A1:D100 can outrank one on A1:A10.",[551,2257,2258,2261],{},[554,2259,2260],{},"Colour scales, data bars and icon sets."," Excel does not offer stop-if-true on these rule types themselves; place them deliberately in the priority order and test how they combine with your other rules.",[29,2263,2265],{"id":2264},"conclusion","Conclusion",[10,2267,2268,2269,2271,2272,2274],{},"Conditional-formatting rules are evaluated by priority, and openpyxl assigns 1, 2, 3… in the order you add them unless you set ",[41,2270,1096],{}," yourself. Excel layers all matching, non-conflicting formats while LibreOffice applies only the first match, so order rules from most specific to most general, give each rule every format it needs, and set ",[41,2273,1092],{}," so the first match wins in both. Renumber priorities in existing templates when needed, and render the sheet in a test to confirm the warning colours appear.",[29,2276,2278],{"id":2277},"frequently-asked-questions","Frequently asked questions",[10,2280,2281,2284],{},[554,2282,2283],{},"How do I set the priority of a conditional formatting rule in openpyxl?","\nSet rule.priority to the number you want before calling ws.conditional_formatting.add. openpyxl only assigns a priority automatically when the rule has none, numbering rules in the order they are added.",[10,2286,2287,2290],{},[554,2288,2289],{},"What does stopIfTrue do in conditional formatting?","\nWhen a rule with stopIfTrue matches a cell, Excel stops evaluating lower-priority rules for that cell. It makes the first matching rule the only one applied.",[10,2292,2293,2296],{},[554,2294,2295],{},"Why do my conditional formats look different in LibreOffice and Excel?","\nExcel applies all matching rules whose formats do not conflict, while LibreOffice applies only the first matching rule. Put specific rules first, include every format in each rule, and use stopIfTrue for consistent results.",[10,2298,2299,2302],{},[554,2300,2301],{},"How do I change the order of existing conditional formatting rules?","\nLoad the workbook, iterate over ws.conditional_formatting and its rules, assign new unique priority numbers, and save. Lower numbers are evaluated first.",[29,2304,2306],{"id":2305},"related","Related",[548,2308,2309,2315,2322,2329],{},[551,2310,2311,2312,2314],{},"Up one level: ",[23,2313,26],{"href":25}," — rules for highlighting data.",[551,2316,2317,2321],{},[23,2318,2320],{"href":2319},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-above-a-threshold-with-openpyxl\u002F","Highlight Cells Above a Threshold with openpyxl"," — single-threshold rules.",[551,2323,2324,2328],{},[23,2325,2327],{"href":2326},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl\u002F","Add Icon Sets with openpyxl"," — another rule type that interacts with priority.",[551,2330,2331,2335],{},[23,2332,2334],{"href":2333},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fapply-gradient-and-pattern-fills-with-openpyxl\u002F","Apply Gradient and Pattern Fills with openpyxl"," — fill colours in rules.",[2337,2338,2339],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":39,"searchDepth":102,"depth":102,"links":2341},[2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352],{"id":31,"depth":102,"text":32},{"id":75,"depth":102,"text":76},{"id":542,"depth":102,"text":543},{"id":723,"depth":102,"text":724},{"id":1283,"depth":102,"text":1284},{"id":1536,"depth":102,"text":1537},{"id":2207,"depth":102,"text":2208},{"id":2222,"depth":102,"text":2223},{"id":2264,"depth":102,"text":2265},{"id":2277,"depth":102,"text":2278},{"id":2305,"depth":102,"text":2306},"2026-10-02","When several conditional-formatting rules match the same cell, their priority decides what the reader sees — and Excel and LibreOffice resolve overlaps differently. See how openpyxl numbers rules, set priority explicitly, use stopIfTrue so the first matching rule wins everywhere, design self-contained rules, and check the order in a saved file and a rendered page.","md",[2357,2359,2361,2363],{"q":2283,"a":2358},"Set rule.priority to the number you want before calling ws.conditional_formatting.add. openpyxl only assigns a priority automatically when the rule has none, numbering rules in the order they are added.",{"q":2289,"a":2360},"When a rule with stopIfTrue matches a cell, Excel stops evaluating lower-priority rules for that cell. It makes the first matching rule the only one applied.",{"q":2295,"a":2362},"Excel applies all matching rules whose formats do not conflict, while LibreOffice applies only the first matching rule. Put specific rules first, include every format in each rule, and use stopIfTrue for consistent results.",{"q":2301,"a":2364},"Load the workbook, iterate over ws.conditional_formatting and its rules, assign new unique priority numbers, and save. Lower numbers are evaluated first.","control conditional formatting rule order and stop if true",null,{"breadcrumb":2368},[2369,2372,2375],{"name":2370,"item":2371},"Home","\u002F",{"name":2373,"item":2374},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2376,"item":25},"Applying Conditional Formatting With openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true",{"title":2379,"description":2380},"Conditional Formatting Rule Priority and stopIfTrue in openpyxl","Order conditional formatting rules with openpyxl: automatic priorities in add order, setting rule.priority, stopIfTrue, how Excel combines non-conflicting rules while LibreOffice applies only the first match, and verifying rule order and rendering.","control-conditional-formatting-rule-order-and-stop-if-true","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true\u002Findex",[2384,2385],"conditional-formatting","openpyxl","how-to","xnfq-FGtIM1iLMnZ-XbkSg8UTNq7S-BcxStBkKz_luU",[2389,2393],{"title":2390,"path":2391,"stem":2392,"children":-1},"Apply Conditional Formatting to an Excel Table That Grows","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-conditional-formatting-to-an-excel-table-that-grows","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-conditional-formatting-to-an-excel-table-that-grows\u002Findex",{"title":2394,"path":2395,"stem":2396,"children":-1},"Highlight an Entire Row Based on a Cell Value with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-an-entire-row-based-on-a-cell-value-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-an-entire-row-based-on-a-cell-value-with-openpyxl\u002Findex",[2398,2400],{"path":2399,"title":2376},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl",{"path":2401,"title":2373},"\u002Fadvanced-data-transformation-and-cleaning",[],[2404,2407,2410,2413,2416,2417],{"path":2405,"title":2406,"kind":2386},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter","Apply Conditional Formatting with xlsxwriter",{"path":2408,"title":2409,"kind":2386},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-data-bars-and-colour-scales-with-openpyxl","Add Data Bars and Colour Scales with openpyxl",{"path":2411,"title":2412,"kind":2386},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","Add Icon Sets to Excel Cells with openpyxl",{"path":2414,"title":2415,"kind":2386},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl","Apply a Colour Scale per Row or per Column with openpyxl",{"path":2391,"title":2390,"kind":2386},{"path":2395,"title":2394,"kind":2386},1790972078109]