[{"data":1,"prerenderedAt":2097},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet":2064,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet":2073,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet":2078,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet":2079},{"id":4,"title":5,"body":6,"dateModified":2029,"datePublished":2029,"description":2030,"extension":2031,"faq":2032,"keyword":2041,"kind":2042,"meta":2043,"navigation":105,"path":2053,"seo":2054,"slug":2057,"stem":2058,"topics":2059,"type":2062,"__hash__":2063},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet\u002Findex.md","Use Conditional Formatting Rules That Reference Another Sheet",{"type":7,"value":8,"toc":2017},"minimark",[9,19,24,50,57,61,64,488,491,495,502,701,732,911,915,918,1001,1015,1019,1034,1230,1242,1327,1331,1334,1752,1758,1765,1890,1894,1934,1938,1952,1956,1962,1968,1974,1980,1984,2013],[10,11,12,13,18],"p",{},"The most useful highlighting rules depend on information kept somewhere else. Orders should turn red when the customer is on the credit-hold list maintained on another tab; amounts should turn amber when they exceed a threshold that finance changes on a Settings sheet; a stock level should be flagged when it falls below the reorder point in a lookup table. Putting those lists and thresholds on their own sheets means people can update them without touching the rules — and the highlighting follows immediately. Conditional formatting formulas can reference other sheets directly in Excel 2010 and later, or through defined names, which also work in older versions and make the rules easier to read. This page writes such rules with openpyxl, explains the anchoring that makes them work on every row, and checks their logic by recalculating the same formulas in helper cells. It belongs to ",[14,15,17],"a",{"href":16},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002F","Applying Conditional Formatting with openpyxl",".",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," openpyxl\n",[10,51,52,53,56],{},"The examples build a workbook with an Orders sheet, a Blocked sheet listing customers on credit hold, and a Settings sheet holding a review threshold. LibreOffice (",[32,54,55],{},"soffice",") is used in Step 5 to recalculate helper formulas and confirm which rows the rules will highlight; it is optional.",[20,58,60],{"id":59},"step-1-the-workbook-data-a-list-and-a-setting","Step 1 — The workbook: data, a list and a setting",[10,62,63],{},"Put the reference data on its own sheets, each in a simple, labelled range:",[25,65,69],{"className":66,"code":67,"language":68,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.styles import Font\n\nwb = Workbook()\norders = wb.active\norders.title = \"Orders\"\norders.append([\"Order\", \"Customer\", \"Amount\"])\nrows = [(\"SO-1001\", \"Oakridge Farms\", 1240), (\"SO-1002\", \"Café Señor\", 380), (\"SO-1003\", \"Zenith Logistics\", 5600),\n        (\"SO-1004\", \"Haddad & Sons\", 920), (\"SO-1005\", \"Café Señor\", 2150), (\"SO-1006\", \"Lindqvist AB\", 7400),\n        (\"SO-1007\", \"Greenway Garden\", 610)]\nfor r in rows:\n    orders.append(list(r))\n\nblocked = wb.create_sheet(\"Blocked\")\nblocked.append([\"Customer on credit hold\"])\nfor name in [\"Café Señor\", \"Lindqvist AB\"]:\n    blocked.append([name])\n\nsettings = wb.create_sheet(\"Settings\")\nsettings[\"A1\"], settings[\"B1\"] = \"Review orders above\", 5000\nfor ws in wb.worksheets:\n    ws[\"A1\"].font = Font(bold=True)\nprint([ws.title for ws in wb.worksheets])\n","python",[32,70,71,87,100,107,119,130,141,164,223,273,294,309,321,326,343,354,376,382,387,402,430,443,470],{"__ignoreMap":30},[35,72,73,77,81,84],{"class":37,"line":38},[35,74,76],{"class":75},"s-kum","from",[35,78,80],{"class":79},"skGVy"," openpyxl ",[35,82,83],{"class":75},"import",[35,85,86],{"class":79}," Workbook\n",[35,88,90,92,95,97],{"class":37,"line":89},2,[35,91,76],{"class":75},[35,93,94],{"class":79}," openpyxl.styles ",[35,96,83],{"class":75},[35,98,99],{"class":79}," Font\n",[35,101,103],{"class":37,"line":102},3,[35,104,106],{"emptyLinePlaceholder":105},true,"\n",[35,108,110,113,116],{"class":37,"line":109},4,[35,111,112],{"class":79},"wb ",[35,114,115],{"class":75},"=",[35,117,118],{"class":79}," Workbook()\n",[35,120,122,125,127],{"class":37,"line":121},5,[35,123,124],{"class":79},"orders ",[35,126,115],{"class":75},[35,128,129],{"class":79}," wb.active\n",[35,131,133,136,138],{"class":37,"line":132},6,[35,134,135],{"class":79},"orders.title ",[35,137,115],{"class":75},[35,139,140],{"class":45}," \"Orders\"\n",[35,142,144,147,150,153,156,158,161],{"class":37,"line":143},7,[35,145,146],{"class":79},"orders.append([",[35,148,149],{"class":45},"\"Order\"",[35,151,152],{"class":79},", ",[35,154,155],{"class":45},"\"Customer\"",[35,157,152],{"class":79},[35,159,160],{"class":45},"\"Amount\"",[35,162,163],{"class":79},"])\n",[35,165,167,170,172,175,178,180,183,185,189,192,195,197,200,202,205,207,210,212,215,217,220],{"class":37,"line":166},8,[35,168,169],{"class":79},"rows ",[35,171,115],{"class":75},[35,173,174],{"class":79}," [(",[35,176,177],{"class":45},"\"SO-1001\"",[35,179,152],{"class":79},[35,181,182],{"class":45},"\"Oakridge Farms\"",[35,184,152],{"class":79},[35,186,188],{"class":187},"sP0c6","1240",[35,190,191],{"class":79},"), (",[35,193,194],{"class":45},"\"SO-1002\"",[35,196,152],{"class":79},[35,198,199],{"class":45},"\"Café Señor\"",[35,201,152],{"class":79},[35,203,204],{"class":187},"380",[35,206,191],{"class":79},[35,208,209],{"class":45},"\"SO-1003\"",[35,211,152],{"class":79},[35,213,214],{"class":45},"\"Zenith Logistics\"",[35,216,152],{"class":79},[35,218,219],{"class":187},"5600",[35,221,222],{"class":79},"),\n",[35,224,226,229,232,234,237,239,242,244,247,249,251,253,256,258,261,263,266,268,271],{"class":37,"line":225},9,[35,227,228],{"class":79},"        (",[35,230,231],{"class":45},"\"SO-1004\"",[35,233,152],{"class":79},[35,235,236],{"class":45},"\"Haddad & Sons\"",[35,238,152],{"class":79},[35,240,241],{"class":187},"920",[35,243,191],{"class":79},[35,245,246],{"class":45},"\"SO-1005\"",[35,248,152],{"class":79},[35,250,199],{"class":45},[35,252,152],{"class":79},[35,254,255],{"class":187},"2150",[35,257,191],{"class":79},[35,259,260],{"class":45},"\"SO-1006\"",[35,262,152],{"class":79},[35,264,265],{"class":45},"\"Lindqvist AB\"",[35,267,152],{"class":79},[35,269,270],{"class":187},"7400",[35,272,222],{"class":79},[35,274,276,278,281,283,286,288,291],{"class":37,"line":275},10,[35,277,228],{"class":79},[35,279,280],{"class":45},"\"SO-1007\"",[35,282,152],{"class":79},[35,284,285],{"class":45},"\"Greenway Garden\"",[35,287,152],{"class":79},[35,289,290],{"class":187},"610",[35,292,293],{"class":79},")]\n",[35,295,297,300,303,306],{"class":37,"line":296},11,[35,298,299],{"class":75},"for",[35,301,302],{"class":79}," r ",[35,304,305],{"class":75},"in",[35,307,308],{"class":79}," rows:\n",[35,310,312,315,318],{"class":37,"line":311},12,[35,313,314],{"class":79},"    orders.append(",[35,316,317],{"class":187},"list",[35,319,320],{"class":79},"(r))\n",[35,322,324],{"class":37,"line":323},13,[35,325,106],{"emptyLinePlaceholder":105},[35,327,329,332,334,337,340],{"class":37,"line":328},14,[35,330,331],{"class":79},"blocked ",[35,333,115],{"class":75},[35,335,336],{"class":79}," wb.create_sheet(",[35,338,339],{"class":45},"\"Blocked\"",[35,341,342],{"class":79},")\n",[35,344,346,349,352],{"class":37,"line":345},15,[35,347,348],{"class":79},"blocked.append([",[35,350,351],{"class":45},"\"Customer on credit hold\"",[35,353,163],{"class":79},[35,355,357,359,362,364,367,369,371,373],{"class":37,"line":356},16,[35,358,299],{"class":75},[35,360,361],{"class":79}," name ",[35,363,305],{"class":75},[35,365,366],{"class":79}," [",[35,368,199],{"class":45},[35,370,152],{"class":79},[35,372,265],{"class":45},[35,374,375],{"class":79},"]:\n",[35,377,379],{"class":37,"line":378},17,[35,380,381],{"class":79},"    blocked.append([name])\n",[35,383,385],{"class":37,"line":384},18,[35,386,106],{"emptyLinePlaceholder":105},[35,388,390,393,395,397,400],{"class":37,"line":389},19,[35,391,392],{"class":79},"settings ",[35,394,115],{"class":75},[35,396,336],{"class":79},[35,398,399],{"class":45},"\"Settings\"",[35,401,342],{"class":79},[35,403,405,408,411,414,417,420,422,425,427],{"class":37,"line":404},20,[35,406,407],{"class":79},"settings[",[35,409,410],{"class":45},"\"A1\"",[35,412,413],{"class":79},"], settings[",[35,415,416],{"class":45},"\"B1\"",[35,418,419],{"class":79},"] ",[35,421,115],{"class":75},[35,423,424],{"class":45}," \"Review orders above\"",[35,426,152],{"class":79},[35,428,429],{"class":187},"5000\n",[35,431,433,435,438,440],{"class":37,"line":432},21,[35,434,299],{"class":75},[35,436,437],{"class":79}," ws ",[35,439,305],{"class":75},[35,441,442],{"class":79}," wb.worksheets:\n",[35,444,446,449,451,454,456,459,463,465,468],{"class":37,"line":445},22,[35,447,448],{"class":79},"    ws[",[35,450,410],{"class":45},[35,452,453],{"class":79},"].font ",[35,455,115],{"class":75},[35,457,458],{"class":79}," Font(",[35,460,462],{"class":461},"sa561","bold",[35,464,115],{"class":75},[35,466,467],{"class":187},"True",[35,469,342],{"class":79},[35,471,473,476,479,481,483,485],{"class":37,"line":472},23,[35,474,475],{"class":187},"print",[35,477,478],{"class":79},"([ws.title ",[35,480,299],{"class":75},[35,482,437],{"class":79},[35,484,305],{"class":75},[35,486,487],{"class":79}," wb.worksheets])\n",[10,489,490],{},"The blocked list is a single column with a header, so it can grow downwards without changing any rule; the threshold is one labelled cell. Keeping reference data this simple is what makes it safe for other people to maintain.",[20,492,494],{"id":493},"step-2-highlight-rows-whose-customer-is-on-another-sheets-list","Step 2 — Highlight rows whose customer is on another sheet's list",[10,496,497,498,501],{},"A formula rule is evaluated for each cell in its range, relative to the range's top-left cell. Write the formula for the first data row, with ",[32,499,500],{},"$"," on the parts that must not move:",[25,503,505],{"className":66,"code":504,"language":68,"meta":30,"style":30},"from openpyxl.formatting.rule import FormulaRule\nfrom openpyxl.styles import PatternFill\n\nred = PatternFill(\"solid\", fgColor=\"FFC7CE\")\namber = PatternFill(\"solid\", fgColor=\"FFEB9C\")\nlast = orders.max_row\n\norders.conditional_formatting.add(\n    f\"A2:C{last}\",\n    FormulaRule(formula=[\"COUNTIF(Blocked!$A$2:$A$500,$B2)>0\"], fill=red, font=Font(color=\"9C0006\")),\n)\nprint(\"rule range:\", f\"A2:C{last}\")\n",[32,506,507,519,530,534,559,581,591,595,600,624,670,674],{"__ignoreMap":30},[35,508,509,511,514,516],{"class":37,"line":38},[35,510,76],{"class":75},[35,512,513],{"class":79}," openpyxl.formatting.rule ",[35,515,83],{"class":75},[35,517,518],{"class":79}," FormulaRule\n",[35,520,521,523,525,527],{"class":37,"line":89},[35,522,76],{"class":75},[35,524,94],{"class":79},[35,526,83],{"class":75},[35,528,529],{"class":79}," PatternFill\n",[35,531,532],{"class":37,"line":102},[35,533,106],{"emptyLinePlaceholder":105},[35,535,536,539,541,544,547,549,552,554,557],{"class":37,"line":109},[35,537,538],{"class":79},"red ",[35,540,115],{"class":75},[35,542,543],{"class":79}," PatternFill(",[35,545,546],{"class":45},"\"solid\"",[35,548,152],{"class":79},[35,550,551],{"class":461},"fgColor",[35,553,115],{"class":75},[35,555,556],{"class":45},"\"FFC7CE\"",[35,558,342],{"class":79},[35,560,561,564,566,568,570,572,574,576,579],{"class":37,"line":121},[35,562,563],{"class":79},"amber ",[35,565,115],{"class":75},[35,567,543],{"class":79},[35,569,546],{"class":45},[35,571,152],{"class":79},[35,573,551],{"class":461},[35,575,115],{"class":75},[35,577,578],{"class":45},"\"FFEB9C\"",[35,580,342],{"class":79},[35,582,583,586,588],{"class":37,"line":132},[35,584,585],{"class":79},"last ",[35,587,115],{"class":75},[35,589,590],{"class":79}," orders.max_row\n",[35,592,593],{"class":37,"line":143},[35,594,106],{"emptyLinePlaceholder":105},[35,596,597],{"class":37,"line":166},[35,598,599],{"class":79},"orders.conditional_formatting.add(\n",[35,601,602,605,608,612,615,618,621],{"class":37,"line":225},[35,603,604],{"class":75},"    f",[35,606,607],{"class":45},"\"A2:C",[35,609,611],{"class":610},"sSjpA","{",[35,613,614],{"class":79},"last",[35,616,617],{"class":610},"}",[35,619,620],{"class":45},"\"",[35,622,623],{"class":79},",\n",[35,625,626,629,632,634,637,640,643,646,648,651,654,656,659,662,664,667],{"class":37,"line":275},[35,627,628],{"class":79},"    FormulaRule(",[35,630,631],{"class":461},"formula",[35,633,115],{"class":75},[35,635,636],{"class":79},"[",[35,638,639],{"class":45},"\"COUNTIF(Blocked!$A$2:$A$500,$B2)>0\"",[35,641,642],{"class":79},"], ",[35,644,645],{"class":461},"fill",[35,647,115],{"class":75},[35,649,650],{"class":79},"red, ",[35,652,653],{"class":461},"font",[35,655,115],{"class":75},[35,657,658],{"class":79},"Font(",[35,660,661],{"class":461},"color",[35,663,115],{"class":75},[35,665,666],{"class":45},"\"9C0006\"",[35,668,669],{"class":79},")),\n",[35,671,672],{"class":37,"line":296},[35,673,342],{"class":79},[35,675,676,678,681,684,686,689,691,693,695,697,699],{"class":37,"line":311},[35,677,475],{"class":187},[35,679,680],{"class":79},"(",[35,682,683],{"class":45},"\"rule range:\"",[35,685,152],{"class":79},[35,687,688],{"class":75},"f",[35,690,607],{"class":45},[35,692,611],{"class":610},[35,694,614],{"class":79},[35,696,617],{"class":610},[35,698,620],{"class":45},[35,700,342],{"class":79},[10,702,703,704,707,708,711,712,715,716,719,720,723,724,727,728,18],{},"For each cell in ",[32,705,706],{},"A2:C8",", Excel evaluates the formula as if it were written in that cell, shifting relative references. ",[32,709,710],{},"$B2"," has a fixed column and a relative row, so on row 5 it becomes ",[32,713,714],{},"$B5"," — every cell of a row looks at that row's customer, and the whole row is highlighted. ",[32,717,718],{},"Blocked!$A$2:$A$500"," is fully anchored, so every row checks the same list; making it larger than the current list lets the list grow. The sheet name goes before the ",[32,721,722],{},"!","; a name containing spaces must be quoted, as in ",[32,725,726],{},"'Credit hold'!$A$2:$A$500",". Row-highlighting rules in general are covered in ",[14,729,731],{"href":730},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-an-entire-row-based-on-a-cell-value-with-openpyxl\u002F","Highlight an Entire Row Based on a Cell Value with openpyxl",[733,734,742,743,742,747,742,751,742,759,742,768,742,772,742,779,742,783,742,787,742,791,742,796,742,798,742,802,742,804,742,807,742,810,742,814,742,816,742,819,742,821,742,823,742,826,742,830,742,832,742,835,742,837,742,839,742,842,742,846,742,849,742,852,742,855,742,858,742,860,742,862,742,865,742,868,742,873,742,876,742,882,742,886,742,893,742,898,742,906],"svg",{"viewBox":735,"role":736,"ariaLabelledBy":737,"xmlns":740,"style":741},"27 0 705 164","img",[738,739],"xs-anchor-t","xs-anchor-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:705px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[744,745,746],"title",{"id":738},"How the formula shifts from row to row",[748,749,750],"desc",{"id":739},"The rule is written for row 2 as COUNTIF of the Blocked list with $B2. On row 5 Excel evaluates it with $B5, because the row of B2 is relative, while the Blocked range is anchored and stays the same for every row.",[752,753],"rect",{"x":754,"y":755,"width":756,"height":757,"fill":758},"27","0","705","164","#ffffff",[752,760],{"x":761,"y":762,"width":763,"height":764,"rx":755,"fill":765,"stroke":766,"style":767},"43.6","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[752,769],{"x":770,"y":762,"width":771,"height":764,"rx":755,"fill":765,"stroke":766,"style":767},"75.6","75.4",[773,774,778],"text",{"x":775,"y":776,"style":777},"113.3","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[752,780],{"x":781,"y":762,"width":782,"height":764,"rx":755,"fill":765,"stroke":766,"style":767},"151.0","148.9",[773,784,786],{"x":785,"y":776,"style":777},"225.5","B",[752,788],{"x":761,"y":789,"width":763,"height":790,"rx":755,"fill":765,"stroke":766,"style":767},"64.0","28.0",[773,792,795],{"x":793,"y":794,"style":777},"59.6","83.0","1",[752,797],{"x":770,"y":789,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,799,801],{"x":775,"y":794,"style":800},"font-size:10.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","part",[752,803],{"x":781,"y":789,"width":782,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,805,806],{"x":785,"y":794,"style":800},"reference",[752,808],{"x":761,"y":809,"width":763,"height":790,"rx":755,"fill":765,"stroke":766,"style":767},"92.0",[773,811,813],{"x":793,"y":812,"style":777},"111.0","2",[752,815],{"x":770,"y":809,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,817,317],{"x":775,"y":812,"style":818},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[752,820],{"x":781,"y":809,"width":782,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,822,718],{"x":785,"y":812,"style":818},[752,824],{"x":761,"y":825,"width":763,"height":790,"rx":755,"fill":765,"stroke":766,"style":767},"120.0",[773,827,829],{"x":793,"y":828,"style":777},"139.0","3",[752,831],{"x":770,"y":825,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,833,834],{"x":775,"y":828,"style":818},"customer",[752,836],{"x":781,"y":825,"width":782,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,838,710],{"x":785,"y":828,"style":818},[752,840],{"x":841,"y":762,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},"492.1",[773,843,801],{"x":844,"y":845,"style":800},"529.8","59.0",[752,847],{"x":848,"y":762,"width":782,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},"567.5",[773,850,806],{"x":851,"y":845,"style":800},"642.0",[752,853],{"x":841,"y":854,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},"68.0",[773,856,317],{"x":844,"y":857,"style":818},"87.0",[752,859],{"x":848,"y":854,"width":782,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},[773,861,718],{"x":851,"y":857,"style":818},[752,863],{"x":841,"y":864,"width":771,"height":790,"rx":755,"fill":758,"stroke":766,"style":767},"96.0",[773,866,834],{"x":844,"y":867,"style":818},"115.0",[752,869],{"x":848,"y":864,"width":782,"height":790,"rx":755,"fill":870,"stroke":871,"style":872},"#d9f4f1","var(--teal,#0f9488)","stroke-width:1.5px",[773,874,714],{"x":851,"y":867,"style":875},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[773,877,881],{"x":878,"y":879,"style":880},"171.7","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","written for row 2",[773,883,885],{"x":884,"y":879,"style":880},"604.3","evaluated on row 5",[37,887],{"x1":888,"y1":889,"x2":890,"y2":889,"stroke":891,"style":892},"309.9","82.0","478.1","var(--brand,#5b5cf0)","stroke-width:2px",[894,895],"polygon",{"points":896,"fill":897},"482.1,82.0 473.1,87.0 473.1,77.0","#5b5cf0",[752,899],{"x":900,"y":901,"width":902,"height":903,"rx":904,"fill":758,"stroke":766,"style":905},"335.1","49.0","121.8","22.0","11","stroke-width:1.2px",[773,907,910],{"x":908,"y":789,"style":909},"396.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","relative to A2",[20,912,914],{"id":913},"step-3-a-threshold-kept-on-a-settings-sheet","Step 3 — A threshold kept on a Settings sheet",[10,916,917],{},"The same idea makes a rule's threshold editable. Compare each amount with the Settings cell, fully anchored:",[25,919,921],{"className":66,"code":920,"language":68,"meta":30,"style":30},"orders.conditional_formatting.add(\n    f\"C2:C{last}\",\n    FormulaRule(formula=[\"$C2>Settings!$B$1\"], fill=amber, font=Font(bold=True)),\n)\nprint(\"amount rule added; threshold cell Settings!B1 =\", settings[\"B1\"].value)\n",[32,922,923,927,944,980,984],{"__ignoreMap":30},[35,924,925],{"class":37,"line":38},[35,926,599],{"class":79},[35,928,929,931,934,936,938,940,942],{"class":37,"line":89},[35,930,604],{"class":75},[35,932,933],{"class":45},"\"C2:C",[35,935,611],{"class":610},[35,937,614],{"class":79},[35,939,617],{"class":610},[35,941,620],{"class":45},[35,943,623],{"class":79},[35,945,946,948,950,952,954,957,959,961,963,966,968,970,972,974,976,978],{"class":37,"line":102},[35,947,628],{"class":79},[35,949,631],{"class":461},[35,951,115],{"class":75},[35,953,636],{"class":79},[35,955,956],{"class":45},"\"$C2>Settings!$B$1\"",[35,958,642],{"class":79},[35,960,645],{"class":461},[35,962,115],{"class":75},[35,964,965],{"class":79},"amber, ",[35,967,653],{"class":461},[35,969,115],{"class":75},[35,971,658],{"class":79},[35,973,462],{"class":461},[35,975,115],{"class":75},[35,977,467],{"class":187},[35,979,669],{"class":79},[35,981,982],{"class":37,"line":109},[35,983,342],{"class":79},[35,985,986,988,990,993,996,998],{"class":37,"line":121},[35,987,475],{"class":187},[35,989,680],{"class":79},[35,991,992],{"class":45},"\"amount rule added; threshold cell Settings!B1 =\"",[35,994,995],{"class":79},", settings[",[35,997,416],{"class":45},[35,999,1000],{"class":79},"].value)\n",[10,1002,1003,1006,1007,1010,1011,18],{},[32,1004,1005],{},"$C2"," moves with the row; ",[32,1008,1009],{},"Settings!$B$1"," never moves. When finance changes the threshold from 5,000 to 2,000, every amount above 2,000 is highlighted the next time the sheet recalculates — no one edits the rule. Rules apply in order, and a cell that matches both — a blocked customer with a large order — gets both formats where they do not conflict (red fill from the first rule, bold from the second). Controlling which rule wins is covered in ",[14,1012,1014],{"href":1013},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true\u002F","Control Conditional Formatting Rule Order and Stop If True",[20,1016,1018],{"id":1017},"step-4-defined-names-for-readable-portable-rules","Step 4 — Defined names for readable, portable rules",[10,1020,1021,1022,1026,1027,1030,1031,1033],{},"Cross-sheet references inside conditional formatting have worked since Excel 2010. Older versions — and some other spreadsheet programs — only accept them through ",[1023,1024,1025],"em",{},"defined names",". Names are worth using anyway, because ",[32,1028,1029],{},"BlockedCustomers"," explains itself where ",[32,1032,718],{}," does not:",[25,1035,1037],{"className":66,"code":1036,"language":68,"meta":30,"style":30},"from openpyxl.workbook.defined_name import DefinedName\n\nwb.defined_names[\"BlockedCustomers\"] = DefinedName(\"BlockedCustomers\", attr_text=\"Blocked!$A$2:$A$500\")\nwb.defined_names[\"ReviewThreshold\"] = DefinedName(\"ReviewThreshold\", attr_text=\"Settings!$B$1\")\n\nnamed = wb.copy_worksheet(orders)\nnamed.title = \"Orders (named)\"\nnamed.conditional_formatting.add(f\"A2:C{last}\", FormulaRule(formula=[\"COUNTIF(BlockedCustomers,$B2)>0\"], fill=red))\nnamed.conditional_formatting.add(f\"C2:C{last}\", FormulaRule(formula=[\"$C2>ReviewThreshold\"], fill=amber))\nwb.save(\"orders_flags.xlsx\")\nprint(sorted(wb.defined_names.keys()))\n",[32,1038,1039,1051,1055,1084,1110,1114,1124,1134,1172,1208,1218],{"__ignoreMap":30},[35,1040,1041,1043,1046,1048],{"class":37,"line":38},[35,1042,76],{"class":75},[35,1044,1045],{"class":79}," openpyxl.workbook.defined_name ",[35,1047,83],{"class":75},[35,1049,1050],{"class":79}," DefinedName\n",[35,1052,1053],{"class":37,"line":89},[35,1054,106],{"emptyLinePlaceholder":105},[35,1056,1057,1060,1063,1065,1067,1070,1072,1074,1077,1079,1082],{"class":37,"line":102},[35,1058,1059],{"class":79},"wb.defined_names[",[35,1061,1062],{"class":45},"\"BlockedCustomers\"",[35,1064,419],{"class":79},[35,1066,115],{"class":75},[35,1068,1069],{"class":79}," DefinedName(",[35,1071,1062],{"class":45},[35,1073,152],{"class":79},[35,1075,1076],{"class":461},"attr_text",[35,1078,115],{"class":75},[35,1080,1081],{"class":45},"\"Blocked!$A$2:$A$500\"",[35,1083,342],{"class":79},[35,1085,1086,1088,1091,1093,1095,1097,1099,1101,1103,1105,1108],{"class":37,"line":109},[35,1087,1059],{"class":79},[35,1089,1090],{"class":45},"\"ReviewThreshold\"",[35,1092,419],{"class":79},[35,1094,115],{"class":75},[35,1096,1069],{"class":79},[35,1098,1090],{"class":45},[35,1100,152],{"class":79},[35,1102,1076],{"class":461},[35,1104,115],{"class":75},[35,1106,1107],{"class":45},"\"Settings!$B$1\"",[35,1109,342],{"class":79},[35,1111,1112],{"class":37,"line":121},[35,1113,106],{"emptyLinePlaceholder":105},[35,1115,1116,1119,1121],{"class":37,"line":132},[35,1117,1118],{"class":79},"named ",[35,1120,115],{"class":75},[35,1122,1123],{"class":79}," wb.copy_worksheet(orders)\n",[35,1125,1126,1129,1131],{"class":37,"line":143},[35,1127,1128],{"class":79},"named.title ",[35,1130,115],{"class":75},[35,1132,1133],{"class":45}," \"Orders (named)\"\n",[35,1135,1136,1139,1141,1143,1145,1147,1149,1151,1154,1156,1158,1160,1163,1165,1167,1169],{"class":37,"line":166},[35,1137,1138],{"class":79},"named.conditional_formatting.add(",[35,1140,688],{"class":75},[35,1142,607],{"class":45},[35,1144,611],{"class":610},[35,1146,614],{"class":79},[35,1148,617],{"class":610},[35,1150,620],{"class":45},[35,1152,1153],{"class":79},", FormulaRule(",[35,1155,631],{"class":461},[35,1157,115],{"class":75},[35,1159,636],{"class":79},[35,1161,1162],{"class":45},"\"COUNTIF(BlockedCustomers,$B2)>0\"",[35,1164,642],{"class":79},[35,1166,645],{"class":461},[35,1168,115],{"class":75},[35,1170,1171],{"class":79},"red))\n",[35,1173,1174,1176,1178,1180,1182,1184,1186,1188,1190,1192,1194,1196,1199,1201,1203,1205],{"class":37,"line":225},[35,1175,1138],{"class":79},[35,1177,688],{"class":75},[35,1179,933],{"class":45},[35,1181,611],{"class":610},[35,1183,614],{"class":79},[35,1185,617],{"class":610},[35,1187,620],{"class":45},[35,1189,1153],{"class":79},[35,1191,631],{"class":461},[35,1193,115],{"class":75},[35,1195,636],{"class":79},[35,1197,1198],{"class":45},"\"$C2>ReviewThreshold\"",[35,1200,642],{"class":79},[35,1202,645],{"class":461},[35,1204,115],{"class":75},[35,1206,1207],{"class":79},"amber))\n",[35,1209,1210,1213,1216],{"class":37,"line":275},[35,1211,1212],{"class":79},"wb.save(",[35,1214,1215],{"class":45},"\"orders_flags.xlsx\"",[35,1217,342],{"class":79},[35,1219,1220,1222,1224,1227],{"class":37,"line":296},[35,1221,475],{"class":187},[35,1223,680],{"class":79},[35,1225,1226],{"class":187},"sorted",[35,1228,1229],{"class":79},"(wb.defined_names.keys()))\n",[10,1231,1232,1233,1237,1238,1241],{},"The two names are workbook-level, so any sheet's rules can use them. If the blocked list moves to another sheet, only the name's definition changes and every rule using it keeps working. Creating names is covered in more depth in ",[14,1234,1236],{"href":1235},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl\u002F","Create a Named Range in Excel with openpyxl",". (Note that ",[32,1239,1240],{},"copy_worksheet"," copies cell values and styles but not conditional formatting, which is why the rules are added to the copy again.)",[733,1243,742,1249,742,1252,742,1255,742,1260,742,1267,742,1278,742,1283,742,1288,742,1292,742,1296,742,1300,742,1303,742,1310,742,1314,742,1318,742,1321,742,1324],{"viewBox":1244,"role":736,"ariaLabelledBy":1245,"xmlns":740,"style":1248},"4 0 752 207",[1246,1247],"xs-names-t","xs-names-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[744,1250,1251],{"id":1246},"Direct references or defined names",[748,1253,1254],{"id":1247},"A direct cross-sheet reference such as Blocked!$A$2:$A$500 works in Excel 2010 and later but is hard to read and must be updated in every rule if the list moves. A defined name such as BlockedCustomers reads clearly, works in older versions, and is updated in one place.",[752,1256],{"x":1257,"y":755,"width":1258,"height":1259,"fill":758},"4","752","207",[752,1261],{"x":1262,"y":1263,"width":1264,"height":1265,"rx":1266,"fill":765,"stroke":766,"style":892},"20.0","16.0","351.0","175.0","14",[1268,1269,1271],"g",{"transform":1270},"translate(182.5,29.0) scale(1.083)",[1272,1273],"path",{"d":1274,"fill":1275,"stroke":1276,"style":1277},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1","none","var(--text,#172033)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[773,1279,718],{"x":1280,"y":1281,"style":1282},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[37,1284],{"x1":1285,"y1":1286,"x2":1287,"y2":1286,"stroke":766,"style":767},"36.0","91.0","355.0",[773,1289,1291],{"x":1280,"y":812,"style":1290},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Excel 2010 and later",[773,1293,1295],{"x":1280,"y":1294,"style":1290},"137.0","hard to read in the rule",[773,1297,1299],{"x":1280,"y":1298,"style":1290},"163.0","edit every rule if the list moves",[752,1301],{"x":1302,"y":1263,"width":1264,"height":1265,"rx":1266,"fill":870,"stroke":871,"style":892},"389.0",[1268,1304,1306],{"transform":1305},"translate(551.5,29.0) scale(1.083)",[1272,1307],{"d":1308,"fill":1275,"stroke":1309,"style":1277},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[773,1311,1029],{"x":1312,"y":1281,"style":1313},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[37,1315],{"x1":1316,"y1":1286,"x2":1317,"y2":1286,"stroke":871,"style":767},"405.0","724.0",[773,1319,1320],{"x":1312,"y":812,"style":1290},"works in older versions too",[773,1322,1323],{"x":1312,"y":1294,"style":1290},"rule explains itself",[773,1325,1326],{"x":1312,"y":1298,"style":1290},"change the definition once",[20,1328,1330],{"id":1329},"step-5-check-the-rule-logic-by-recalculating-it","Step 5 — Check the rule logic by recalculating it",[10,1332,1333],{},"Conditional formatting is evaluated when the file is opened, so Python cannot see which cells are highlighted. But the rule formulas are ordinary formulas: write the same expressions into helper cells, recalculate the workbook, and read the results:",[25,1335,1337],{"className":66,"code":1336,"language":68,"meta":30,"style":30},"import subprocess\nfrom openpyxl import load_workbook\n\ncheck = load_workbook(\"orders_flags.xlsx\")\nws = check[\"Orders\"]\nws[\"E1\"], ws[\"F1\"] = \"Blocked?\", \"Review?\"\nfor r in range(2, last + 1):\n    ws[f\"E{r}\"] = f\"=COUNTIF(BlockedCustomers,$B{r})>0\"\n    ws[f\"F{r}\"] = f\"=$C{r}>ReviewThreshold\"\ncheck.save(\"orders_check.xlsx\")\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"calc\", \"orders_check.xlsx\"],\n               check=True, capture_output=True)\ncalc = load_workbook(\"calc\u002Forders_check.xlsx\", data_only=True)[\"Orders\"]\nfor r in range(2, last + 1):\n    print(calc[f\"A{r}\"].value, calc[f\"B{r}\"].value, calc[f\"C{r}\"].value,\n          \"| red\" if calc[f\"E{r}\"].value else \"\", \"| amber\" if calc[f\"F{r}\"].value else \"\")\n",[32,1338,1339,1346,1357,1361,1375,1391,1417,1444,1481,1516,1526,1566,1586,1614,1636,1691],{"__ignoreMap":30},[35,1340,1341,1343],{"class":37,"line":38},[35,1342,83],{"class":75},[35,1344,1345],{"class":79}," subprocess\n",[35,1347,1348,1350,1352,1354],{"class":37,"line":89},[35,1349,76],{"class":75},[35,1351,80],{"class":79},[35,1353,83],{"class":75},[35,1355,1356],{"class":79}," load_workbook\n",[35,1358,1359],{"class":37,"line":102},[35,1360,106],{"emptyLinePlaceholder":105},[35,1362,1363,1366,1368,1371,1373],{"class":37,"line":109},[35,1364,1365],{"class":79},"check ",[35,1367,115],{"class":75},[35,1369,1370],{"class":79}," load_workbook(",[35,1372,1215],{"class":45},[35,1374,342],{"class":79},[35,1376,1377,1380,1382,1385,1388],{"class":37,"line":121},[35,1378,1379],{"class":79},"ws ",[35,1381,115],{"class":75},[35,1383,1384],{"class":79}," check[",[35,1386,1387],{"class":45},"\"Orders\"",[35,1389,1390],{"class":79},"]\n",[35,1392,1393,1396,1399,1402,1405,1407,1409,1412,1414],{"class":37,"line":132},[35,1394,1395],{"class":79},"ws[",[35,1397,1398],{"class":45},"\"E1\"",[35,1400,1401],{"class":79},"], ws[",[35,1403,1404],{"class":45},"\"F1\"",[35,1406,419],{"class":79},[35,1408,115],{"class":75},[35,1410,1411],{"class":45}," \"Blocked?\"",[35,1413,152],{"class":79},[35,1415,1416],{"class":45},"\"Review?\"\n",[35,1418,1419,1421,1423,1425,1428,1430,1432,1435,1438,1441],{"class":37,"line":143},[35,1420,299],{"class":75},[35,1422,302],{"class":79},[35,1424,305],{"class":75},[35,1426,1427],{"class":187}," range",[35,1429,680],{"class":79},[35,1431,813],{"class":187},[35,1433,1434],{"class":79},", last ",[35,1436,1437],{"class":75},"+",[35,1439,1440],{"class":187}," 1",[35,1442,1443],{"class":79},"):\n",[35,1445,1446,1448,1450,1453,1455,1458,1460,1462,1464,1466,1469,1472,1474,1476,1478],{"class":37,"line":166},[35,1447,448],{"class":79},[35,1449,688],{"class":75},[35,1451,1452],{"class":45},"\"E",[35,1454,611],{"class":610},[35,1456,1457],{"class":79},"r",[35,1459,617],{"class":610},[35,1461,620],{"class":45},[35,1463,419],{"class":79},[35,1465,115],{"class":75},[35,1467,1468],{"class":75}," f",[35,1470,1471],{"class":45},"\"=COUNTIF(BlockedCustomers,$B",[35,1473,611],{"class":610},[35,1475,1457],{"class":79},[35,1477,617],{"class":610},[35,1479,1480],{"class":45},")>0\"\n",[35,1482,1483,1485,1487,1490,1492,1494,1496,1498,1500,1502,1504,1507,1509,1511,1513],{"class":37,"line":225},[35,1484,448],{"class":79},[35,1486,688],{"class":75},[35,1488,1489],{"class":45},"\"F",[35,1491,611],{"class":610},[35,1493,1457],{"class":79},[35,1495,617],{"class":610},[35,1497,620],{"class":45},[35,1499,419],{"class":79},[35,1501,115],{"class":75},[35,1503,1468],{"class":75},[35,1505,1506],{"class":45},"\"=$C",[35,1508,611],{"class":610},[35,1510,1457],{"class":79},[35,1512,617],{"class":610},[35,1514,1515],{"class":45},">ReviewThreshold\"\n",[35,1517,1518,1521,1524],{"class":37,"line":275},[35,1519,1520],{"class":79},"check.save(",[35,1522,1523],{"class":45},"\"orders_check.xlsx\"",[35,1525,342],{"class":79},[35,1527,1528,1531,1534,1536,1539,1541,1544,1546,1549,1551,1554,1556,1559,1561,1563],{"class":37,"line":296},[35,1529,1530],{"class":79},"subprocess.run([",[35,1532,1533],{"class":45},"\"soffice\"",[35,1535,152],{"class":79},[35,1537,1538],{"class":45},"\"--headless\"",[35,1540,152],{"class":79},[35,1542,1543],{"class":45},"\"--convert-to\"",[35,1545,152],{"class":79},[35,1547,1548],{"class":45},"\"xlsx\"",[35,1550,152],{"class":79},[35,1552,1553],{"class":45},"\"--outdir\"",[35,1555,152],{"class":79},[35,1557,1558],{"class":45},"\"calc\"",[35,1560,152],{"class":79},[35,1562,1523],{"class":45},[35,1564,1565],{"class":79},"],\n",[35,1567,1568,1571,1573,1575,1577,1580,1582,1584],{"class":37,"line":311},[35,1569,1570],{"class":461},"               check",[35,1572,115],{"class":75},[35,1574,467],{"class":187},[35,1576,152],{"class":79},[35,1578,1579],{"class":461},"capture_output",[35,1581,115],{"class":75},[35,1583,467],{"class":187},[35,1585,342],{"class":79},[35,1587,1588,1591,1593,1595,1598,1600,1603,1605,1607,1610,1612],{"class":37,"line":323},[35,1589,1590],{"class":79},"calc ",[35,1592,115],{"class":75},[35,1594,1370],{"class":79},[35,1596,1597],{"class":45},"\"calc\u002Forders_check.xlsx\"",[35,1599,152],{"class":79},[35,1601,1602],{"class":461},"data_only",[35,1604,115],{"class":75},[35,1606,467],{"class":187},[35,1608,1609],{"class":79},")[",[35,1611,1387],{"class":45},[35,1613,1390],{"class":79},[35,1615,1616,1618,1620,1622,1624,1626,1628,1630,1632,1634],{"class":37,"line":328},[35,1617,299],{"class":75},[35,1619,302],{"class":79},[35,1621,305],{"class":75},[35,1623,1427],{"class":187},[35,1625,680],{"class":79},[35,1627,813],{"class":187},[35,1629,1434],{"class":79},[35,1631,1437],{"class":75},[35,1633,1440],{"class":187},[35,1635,1443],{"class":79},[35,1637,1638,1641,1644,1646,1649,1651,1653,1655,1657,1660,1662,1665,1667,1669,1671,1673,1675,1677,1680,1682,1684,1686,1688],{"class":37,"line":345},[35,1639,1640],{"class":187},"    print",[35,1642,1643],{"class":79},"(calc[",[35,1645,688],{"class":75},[35,1647,1648],{"class":45},"\"A",[35,1650,611],{"class":610},[35,1652,1457],{"class":79},[35,1654,617],{"class":610},[35,1656,620],{"class":45},[35,1658,1659],{"class":79},"].value, calc[",[35,1661,688],{"class":75},[35,1663,1664],{"class":45},"\"B",[35,1666,611],{"class":610},[35,1668,1457],{"class":79},[35,1670,617],{"class":610},[35,1672,620],{"class":45},[35,1674,1659],{"class":79},[35,1676,688],{"class":75},[35,1678,1679],{"class":45},"\"C",[35,1681,611],{"class":610},[35,1683,1457],{"class":79},[35,1685,617],{"class":610},[35,1687,620],{"class":45},[35,1689,1690],{"class":79},"].value,\n",[35,1692,1693,1696,1699,1702,1704,1706,1708,1710,1712,1714,1717,1720,1723,1725,1728,1730,1732,1734,1736,1738,1740,1742,1744,1746,1748,1750],{"class":37,"line":356},[35,1694,1695],{"class":45},"          \"| red\"",[35,1697,1698],{"class":75}," if",[35,1700,1701],{"class":79}," calc[",[35,1703,688],{"class":75},[35,1705,1452],{"class":45},[35,1707,611],{"class":610},[35,1709,1457],{"class":79},[35,1711,617],{"class":610},[35,1713,620],{"class":45},[35,1715,1716],{"class":79},"].value ",[35,1718,1719],{"class":75},"else",[35,1721,1722],{"class":45}," \"\"",[35,1724,152],{"class":79},[35,1726,1727],{"class":45},"\"| amber\"",[35,1729,1698],{"class":75},[35,1731,1701],{"class":79},[35,1733,688],{"class":75},[35,1735,1489],{"class":45},[35,1737,611],{"class":610},[35,1739,1457],{"class":79},[35,1741,617],{"class":610},[35,1743,620],{"class":45},[35,1745,1716],{"class":79},[35,1747,1719],{"class":75},[35,1749,1722],{"class":45},[35,1751,342],{"class":79},[10,1753,1754,1755,1757],{},"The recalculated helper cells show exactly which rows each rule will highlight: Café Señor's two orders and Lindqvist's order in red, and the two orders above 5,000 — Zenith and Lindqvist — in amber, with Lindqvist matching both. Checking against an independent expectation (the blocked names, the threshold) catches the classic mistakes: a missing ",[32,1756,500],{}," that makes every row look at row 2, an unanchored list range that slides down, a misspelt sheet name. Delete the helper columns, or do this on a copy as here, before delivering the workbook.",[10,1759,1760,1761,1764],{},"Rendering the workbook itself confirms the rules are applied, not just that their logic is right: converted to PDF with LibreOffice, the Orders sheet showed the three red rows and the amber cell for Zenith. Lindqvist's amount cell was red rather than amber, because when two rules set a fill on the same cell, the first rule's fill wins — Excel then still applies the second rule's bold font, while LibreOffice applies only the first matching rule. If the combination matters, write a dedicated third rule for \"blocked ",[1023,1762,1763],{},"and"," above threshold\" and put it first.",[733,1766,742,1771,742,1774,742,1777,742,1780,742,1785,742,1792,742,1798,742,1803,742,1808,742,1811,742,1815,742,1821,742,1827,742,1831,742,1835,742,1838,742,1841,742,1844,742,1850,742,1855,742,1858,742,1861,742,1865,742,1868,742,1873,742,1879,742,1884,742,1887],{"viewBox":1767,"role":736,"ariaLabelledBy":1768,"xmlns":740,"style":1248},"4 0 752 142",[1769,1770],"xs-flow-t","xs-flow-d",[744,1772,1773],{"id":1769},"Rules driven by reference sheets",[748,1775,1776],{"id":1770},"Lists and thresholds live on their own sheets, defined names give them readable labels, formula rules compare each row with them using correct anchoring, and helper formulas recalculated outside Excel confirm which rows each rule highlights.",[752,1778],{"x":1257,"y":755,"width":1258,"height":1779,"fill":758},"142",[752,1781],{"x":1262,"y":1263,"width":1782,"height":1783,"rx":1784,"fill":765,"stroke":766,"style":892},"153.0","110.5","12",[1268,1786,1788],{"transform":1787},"translate(84.5,37.8) scale(1.000)",[1272,1789],{"d":1790,"fill":1275,"stroke":1276,"style":1791},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[773,1793,1797],{"x":1794,"y":1795,"style":1796},"96.5","84.2","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Reference sheets",[773,1799,1802],{"x":1794,"y":1800,"style":1801},"103.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Blocked list, Settings",[37,1804],{"x1":1805,"y1":1806,"x2":1807,"y2":1806,"stroke":891,"style":892},"178.0","71.2","200.0",[894,1809],{"points":1810,"fill":897},"204.0,71.2 195.0,76.2 195.0,66.2",[752,1812],{"x":1813,"y":1263,"width":1782,"height":1783,"rx":1784,"fill":1814,"stroke":891,"style":892},"209.0","#f0f4ff",[1268,1816,1818],{"transform":1817},"translate(273.5,29.0) scale(1.000)",[1272,1819],{"d":1274,"fill":1275,"stroke":1820,"style":1791},"var(--brand-strong,#4338ca)",[773,1822,1826],{"x":1823,"y":1824,"style":1825},"285.5","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Defined names",[773,1828,1830],{"x":1823,"y":1829,"style":1801},"95.0","BlockedCustomers,",[773,1832,1834],{"x":1823,"y":1833,"style":1801},"112.5","ReviewThreshold",[37,1836],{"x1":1837,"y1":1806,"x2":1302,"y2":1806,"stroke":891,"style":892},"367.0",[894,1839],{"points":1840,"fill":897},"393.0,71.2 384.0,76.2 384.0,66.2",[752,1842],{"x":1843,"y":1263,"width":1782,"height":1783,"rx":1784,"fill":870,"stroke":871,"style":892},"398.0",[1268,1845,1847],{"transform":1846},"translate(462.5,29.0) scale(1.000)",[1272,1848],{"d":1849,"fill":1275,"stroke":1309,"style":1791},"M3 5h18l-7 8v6l-4 2v-8z",[773,1851,1854],{"x":1852,"y":1824,"style":1853},"474.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Formula rules",[773,1856,1857],{"x":1852,"y":1829,"style":1801},"$B2 relative, list",[773,1859,1860],{"x":1852,"y":1833,"style":1801},"anchored",[37,1862],{"x1":1863,"y1":1806,"x2":1864,"y2":1806,"stroke":891,"style":892},"556.0","578.0",[894,1866],{"points":1867,"fill":897},"582.0,71.2 573.0,76.2 573.0,66.2",[752,1869],{"x":1870,"y":1263,"width":1782,"height":1783,"rx":1784,"fill":1871,"stroke":1872,"style":892},"587.0","#fdefd8","var(--gold,#b4740a)",[1268,1874,1876],{"transform":1875},"translate(651.5,29.0) scale(1.000)",[1272,1877],{"d":1308,"fill":1275,"stroke":1878,"style":1791},"var(--gold-ink,#7a4e06)",[773,1880,1883],{"x":1881,"y":1824,"style":1882},"663.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Verify",[773,1885,1886],{"x":1881,"y":1829,"style":1801},"helper formulas,",[773,1888,1889],{"x":1881,"y":1833,"style":1801},"recalc",[20,1891,1893],{"id":1892},"common-pitfalls","Common pitfalls",[1895,1896,1897,1908,1916,1922,1928],"ul",{},[1898,1899,1900,1904,1905,1907],"li",{},[1901,1902,1903],"strong",{},"Anchoring the wrong parts."," The row of the data cell must be relative (",[32,1906,710],{},"), the list and setting fully anchored.",[1898,1909,1910,1913,1914,18],{},[1901,1911,1912],{},"Unquoted sheet names with spaces."," Use ",[32,1915,726],{},[1898,1917,1918,1921],{},[1901,1919,1920],{},"List ranges that stop at the current last row."," Make them larger, or use a table column, so the list can grow.",[1898,1923,1924,1927],{},[1901,1925,1926],{},"Older Excel versions."," Use defined names for cross-sheet references.",[1898,1929,1930,1933],{},[1901,1931,1932],{},"Assuming the rule works because it was written."," Recalculate the same formula in helper cells and check.",[20,1935,1937],{"id":1936},"conclusion","Conclusion",[10,1939,1940,1941,1944,1945,1948,1949,1951],{},"Conditional formatting rules can depend on other sheets: a ",[32,1942,1943],{},"COUNTIF"," against the list on the Blocked sheet highlights rows whose customer is on a list kept elsewhere, and ",[32,1946,1947],{},"$C2>Settings!$B$1"," compares each value with an editable threshold. Anchor the shared references fully and keep the data row relative, quote sheet names with spaces, and prefer defined names such as ",[32,1950,1029],{}," for readability and compatibility. Verify the logic by writing the same formulas into helper cells and recalculating, since Python cannot see the highlighting itself.",[20,1953,1955],{"id":1954},"frequently-asked-questions","Frequently asked questions",[10,1957,1958,1961],{},[1901,1959,1960],{},"Can conditional formatting refer to another sheet in Excel?","\nYes, in Excel 2010 and later a conditional formatting formula can reference another sheet directly. In older versions, refer to the other sheet through a defined name.",[10,1963,1964,1967],{},[1901,1965,1966],{},"How do I highlight rows if a value appears in a list on another sheet?","\nUse a formula rule that counts the row's customer in the list on the other sheet, such as COUNTIF(BlockedCustomers,$B2)>0, applied to the whole data range, with the list range fully anchored and the row of the lookup cell relative.",[10,1969,1970,1973],{},[1901,1971,1972],{},"How do I make a conditional formatting threshold editable?","\nPut the threshold in a cell on a Settings sheet and compare against it with an absolute reference, such as $C2>Settings!$B$1.",[10,1975,1976,1979],{},[1901,1977,1978],{},"How can I check which cells a conditional formatting rule will highlight?","\nWrite the same formula into helper cells for each row, recalculate the workbook, for example with LibreOffice, and read the TRUE or FALSE results.",[20,1981,1983],{"id":1982},"related","Related",[1895,1985,1986,1992,1999,2006],{},[1898,1987,1988,1989,1991],{},"Up one level: ",[14,1990,17],{"href":16}," — rule-based formatting.",[1898,1993,1994,1998],{},[14,1995,1997],{"href":1996},"\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"," — thresholds within one sheet.",[1898,2000,2001,2005],{},[14,2002,2004],{"href":2003},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcheck-references-between-excel-sheets\u002F","Check References Between Excel Sheets"," — validating the same lists in Python.",[1898,2007,2008,2012],{},[14,2009,2011],{"href":2010},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formulas-that-reference-other-sheets-with-openpyxl\u002F","Write Formulas That Reference Other Sheets with openpyxl"," — cross-sheet references in cells.",[2014,2015,2016],"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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":30,"searchDepth":89,"depth":89,"links":2018},[2019,2020,2021,2022,2023,2024,2025,2026,2027,2028],{"id":22,"depth":89,"text":23},{"id":59,"depth":89,"text":60},{"id":493,"depth":89,"text":494},{"id":913,"depth":89,"text":914},{"id":1017,"depth":89,"text":1018},{"id":1329,"depth":89,"text":1330},{"id":1892,"depth":89,"text":1893},{"id":1936,"depth":89,"text":1937},{"id":1954,"depth":89,"text":1955},{"id":1982,"depth":89,"text":1983},"2026-10-02","Highlight cells based on lists and settings kept on other sheets with openpyxl: flag orders from customers on a blocked list with COUNTIF across sheets, colour values above a threshold stored on a Settings sheet, use defined names so rules read clearly and work in older Excel versions, anchor references correctly, and verify the rule logic by recalculating a helper formula.","md",[2033,2035,2037,2039],{"q":1960,"a":2034},"Yes, in Excel 2010 and later a conditional formatting formula can reference another sheet directly. In older versions, refer to the other sheet through a defined name.",{"q":1966,"a":2036},"Use a formula rule that counts the row's customer in the list on the other sheet, such as COUNTIF(BlockedCustomers,$B2)>0, applied to the whole data range, with the list range fully anchored and the row of the lookup cell relative.",{"q":1972,"a":2038},"Put the threshold in a cell on a Settings sheet and compare against it with an absolute reference, such as $C2>Settings!$B$1.",{"q":1978,"a":2040},"Write the same formula into helper cells for each row, recalculate the workbook, for example with LibreOffice, and read the TRUE or FALSE results.","use conditional formatting rules that reference another sheet",null,{"breadcrumb":2044},[2045,2048,2051],{"name":2046,"item":2047},"Home","\u002F",{"name":2049,"item":2050},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2052,"item":16},"Applying Conditional Formatting With openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet",{"title":2055,"description":2056},"Conditional Formatting That References Another Sheet (openpyxl)","Write openpyxl FormulaRule conditional formatting that looks up other sheets: COUNTIF against a list on another tab, thresholds from a Settings sheet, defined names, $ anchoring and a recalculated helper check.","use-conditional-formatting-rules-that-reference-another-sheet","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fuse-conditional-formatting-rules-that-reference-another-sheet\u002Findex",[2060,2061],"conditional-formatting","openpyxl","how-to","Kwgac_8IrqV50YKhyTwoJoZ9KsZUGxisYfs_wE3B04U",[2065,2069],{"title":2066,"path":2067,"stem":2068,"children":-1},"Apply Conditional Formatting to a Range in openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fopenpyxl-apply-conditional-formatting-to-range","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fopenpyxl-apply-conditional-formatting-to-range\u002Findex",{"title":2070,"path":2071,"stem":2072,"children":-1},"Cleaning Excel Data With Pandas: A Production Workflow","\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas","advanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Findex",[2074,2076],{"path":2075,"title":2052},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl",{"path":2077,"title":2049},"\u002Fadvanced-data-transformation-and-cleaning",[],[2080,2083,2086,2089,2092,2095],{"path":2081,"title":2082,"kind":2062},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter","Apply Conditional Formatting with xlsxwriter",{"path":2084,"title":2085,"kind":2062},"\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":2087,"title":2088,"kind":2062},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","Add Icon Sets to Excel Cells with openpyxl",{"path":2090,"title":2091,"kind":2062},"\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":2093,"title":2094,"kind":2062},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-conditional-formatting-to-an-excel-table-that-grows","Apply Conditional Formatting to an Excel Table That Grows",{"path":2096,"title":1014,"kind":2062},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true",1790972080474]