[{"data":1,"prerenderedAt":2418},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting":2385,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting":2394,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting":2399,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting":2400},{"id":4,"title":5,"body":6,"dateModified":2350,"datePublished":2350,"description":2351,"extension":2352,"faq":2353,"keyword":2362,"kind":2363,"meta":2364,"navigation":115,"path":2374,"seo":2375,"slug":2378,"stem":2379,"topics":2380,"type":2383,"__hash__":2384},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting\u002Findex.md","Highlight Cells with Formula Errors Using Conditional Formatting",{"type":7,"value":8,"toc":2338},"minimark",[9,39,44,72,83,87,654,660,664,899,932,1095,1099,1107,1172,1186,1190,1816,1841,2085,2195,2199,2211,2215,2250,2254,2273,2277,2283,2289,2295,2301,2305,2334],[10,11,12,13,17,18,21,22,25,26,29,30,32,33,38],"p",{},"A workbook full of formulas will eventually show an error: a division by a zero quantity gives ",[14,15,16],"code",{},"#DIV\u002F0!",", a lookup for a code that is not in the table gives ",[14,19,20],{},"#N\u002FA",", text where a number should be gives ",[14,23,24],{},"#VALUE!",", and a deleted column leaves ",[14,27,28],{},"#REF!"," behind. In a long sheet these are easy to miss, and a total that includes one becomes an error itself, so the problem spreads. Conditional formatting can make every error cell stand out the moment it appears — including errors that appear later, when someone edits the workbook — and a short Python check can list them before the file is sent. This page adds a rule that colours any error, a gentler rule for ",[14,31,20],{}," results that are expected, a rule that highlights a whole row when one of its formulas fails, and a scan that finds every error after recalculation. It belongs to ",[34,35,37],"a",{"href":36},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002F","Applying Conditional Formatting with openpyxl",".",[40,41,43],"h2",{"id":42},"prerequisites","Prerequisites",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pillow\n","bash","",[14,52,53],{"__ignoreMap":50},[54,55,58,62,66,69],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sMTad","pip",[54,63,65],{"class":64},"srMev"," install",[54,67,68],{"class":64}," openpyxl",[54,70,71],{"class":64}," pillow\n",[10,73,74,75,78,79,82],{},"LibreOffice (",[14,76,77],{},"soffice",") recalculates the workbook so the formulas produce real errors, and ",[14,80,81],{},"pdftoppm"," renders it so the highlighting can be checked. The example is an order sheet with a price lookup and a margin calculation — the two places errors usually come from.",[40,84,86],{"id":85},"step-1-a-sheet-that-produces-errors","Step 1 — A sheet that produces errors",[45,88,92],{"className":89,"code":90,"language":91,"meta":50,"style":50},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.title = \"Orders\"\nprices = wb.create_sheet(\"Prices\")\nprices.append([\"SKU\", \"Price\"])\nfor sku, price in [(\"B-100\", 0.45), (\"N-200\", 0.12), (\"W-300\", 0.05)]:\n    prices.append([sku, price])\n\nws.append([\"Order\", \"SKU\", \"Qty\", \"Revenue\", \"Cost\", \"Unit price\", \"Margin %\"])\norders = [(\"SO-1\", \"B-100\", 120, 54.0, 25.2), (\"SO-2\", \"N-200\", 0, 0, 0), (\"SO-3\", \"X-999\", 10, 30.0, 12.0),\n          (\"SO-4\", \"W-300\", 300, \"TBC\", 6.0), (\"SO-5\", \"B-100\", 80, 36.0, 16.8)]\nfor r, (order, sku, qty, revenue, cost) in enumerate(orders, start=2):\n    ws.append([order, sku, qty, revenue, cost,\n               f\"=VLOOKUP(B{r},Prices!$A$2:$B$4,2,FALSE)\",\n               f\"=(D{r}-E{r})\u002FD{r}\"])\n    ws[f\"G{r}\"].number_format = \"0.0%\"\nws[\"D8\"], ws[\"F8\"] = \"=SUM(D2:D6)\", \"Total check\"\nws[\"G8\"] = \"=SUM(G2:G6)\"\nfor col, width in zip(\"ABCDEFG\", (8, 8, 7, 10, 8, 11, 10)):\n    ws.column_dimensions[col].width = width\n","python",[14,93,94,110,117,129,140,151,168,186,234,240,245,285,367,422,450,456,481,518,546,574,589,643],{"__ignoreMap":50},[54,95,96,100,104,107],{"class":56,"line":57},[54,97,99],{"class":98},"s-kum","from",[54,101,103],{"class":102},"skGVy"," openpyxl ",[54,105,106],{"class":98},"import",[54,108,109],{"class":102}," Workbook\n",[54,111,113],{"class":56,"line":112},2,[54,114,116],{"emptyLinePlaceholder":115},true,"\n",[54,118,120,123,126],{"class":56,"line":119},3,[54,121,122],{"class":102},"wb ",[54,124,125],{"class":98},"=",[54,127,128],{"class":102}," Workbook()\n",[54,130,132,135,137],{"class":56,"line":131},4,[54,133,134],{"class":102},"ws ",[54,136,125],{"class":98},[54,138,139],{"class":102}," wb.active\n",[54,141,143,146,148],{"class":56,"line":142},5,[54,144,145],{"class":102},"ws.title ",[54,147,125],{"class":98},[54,149,150],{"class":64}," \"Orders\"\n",[54,152,154,157,159,162,165],{"class":56,"line":153},6,[54,155,156],{"class":102},"prices ",[54,158,125],{"class":98},[54,160,161],{"class":102}," wb.create_sheet(",[54,163,164],{"class":64},"\"Prices\"",[54,166,167],{"class":102},")\n",[54,169,171,174,177,180,183],{"class":56,"line":170},7,[54,172,173],{"class":102},"prices.append([",[54,175,176],{"class":64},"\"SKU\"",[54,178,179],{"class":102},", ",[54,181,182],{"class":64},"\"Price\"",[54,184,185],{"class":102},"])\n",[54,187,189,192,195,198,201,204,206,210,213,216,218,221,223,226,228,231],{"class":56,"line":188},8,[54,190,191],{"class":98},"for",[54,193,194],{"class":102}," sku, price ",[54,196,197],{"class":98},"in",[54,199,200],{"class":102}," [(",[54,202,203],{"class":64},"\"B-100\"",[54,205,179],{"class":102},[54,207,209],{"class":208},"sP0c6","0.45",[54,211,212],{"class":102},"), (",[54,214,215],{"class":64},"\"N-200\"",[54,217,179],{"class":102},[54,219,220],{"class":208},"0.12",[54,222,212],{"class":102},[54,224,225],{"class":64},"\"W-300\"",[54,227,179],{"class":102},[54,229,230],{"class":208},"0.05",[54,232,233],{"class":102},")]:\n",[54,235,237],{"class":56,"line":236},9,[54,238,239],{"class":102},"    prices.append([sku, price])\n",[54,241,243],{"class":56,"line":242},10,[54,244,116],{"emptyLinePlaceholder":115},[54,246,248,251,254,256,258,260,263,265,268,270,273,275,278,280,283],{"class":56,"line":247},11,[54,249,250],{"class":102},"ws.append([",[54,252,253],{"class":64},"\"Order\"",[54,255,179],{"class":102},[54,257,176],{"class":64},[54,259,179],{"class":102},[54,261,262],{"class":64},"\"Qty\"",[54,264,179],{"class":102},[54,266,267],{"class":64},"\"Revenue\"",[54,269,179],{"class":102},[54,271,272],{"class":64},"\"Cost\"",[54,274,179],{"class":102},[54,276,277],{"class":64},"\"Unit price\"",[54,279,179],{"class":102},[54,281,282],{"class":64},"\"Margin %\"",[54,284,185],{"class":102},[54,286,288,291,293,295,298,300,302,304,307,309,312,314,317,319,322,324,326,328,331,333,335,337,339,341,344,346,349,351,354,356,359,361,364],{"class":56,"line":287},12,[54,289,290],{"class":102},"orders ",[54,292,125],{"class":98},[54,294,200],{"class":102},[54,296,297],{"class":64},"\"SO-1\"",[54,299,179],{"class":102},[54,301,203],{"class":64},[54,303,179],{"class":102},[54,305,306],{"class":208},"120",[54,308,179],{"class":102},[54,310,311],{"class":208},"54.0",[54,313,179],{"class":102},[54,315,316],{"class":208},"25.2",[54,318,212],{"class":102},[54,320,321],{"class":64},"\"SO-2\"",[54,323,179],{"class":102},[54,325,215],{"class":64},[54,327,179],{"class":102},[54,329,330],{"class":208},"0",[54,332,179],{"class":102},[54,334,330],{"class":208},[54,336,179],{"class":102},[54,338,330],{"class":208},[54,340,212],{"class":102},[54,342,343],{"class":64},"\"SO-3\"",[54,345,179],{"class":102},[54,347,348],{"class":64},"\"X-999\"",[54,350,179],{"class":102},[54,352,353],{"class":208},"10",[54,355,179],{"class":102},[54,357,358],{"class":208},"30.0",[54,360,179],{"class":102},[54,362,363],{"class":208},"12.0",[54,365,366],{"class":102},"),\n",[54,368,370,373,376,378,380,382,385,387,390,392,395,397,400,402,404,406,409,411,414,416,419],{"class":56,"line":369},13,[54,371,372],{"class":102},"          (",[54,374,375],{"class":64},"\"SO-4\"",[54,377,179],{"class":102},[54,379,225],{"class":64},[54,381,179],{"class":102},[54,383,384],{"class":208},"300",[54,386,179],{"class":102},[54,388,389],{"class":64},"\"TBC\"",[54,391,179],{"class":102},[54,393,394],{"class":208},"6.0",[54,396,212],{"class":102},[54,398,399],{"class":64},"\"SO-5\"",[54,401,179],{"class":102},[54,403,203],{"class":64},[54,405,179],{"class":102},[54,407,408],{"class":208},"80",[54,410,179],{"class":102},[54,412,413],{"class":208},"36.0",[54,415,179],{"class":102},[54,417,418],{"class":208},"16.8",[54,420,421],{"class":102},")]\n",[54,423,425,427,430,432,435,438,442,444,447],{"class":56,"line":424},14,[54,426,191],{"class":98},[54,428,429],{"class":102}," r, (order, sku, qty, revenue, cost) ",[54,431,197],{"class":98},[54,433,434],{"class":208}," enumerate",[54,436,437],{"class":102},"(orders, ",[54,439,441],{"class":440},"sa561","start",[54,443,125],{"class":98},[54,445,446],{"class":208},"2",[54,448,449],{"class":102},"):\n",[54,451,453],{"class":56,"line":452},15,[54,454,455],{"class":102},"    ws.append([order, sku, qty, revenue, cost,\n",[54,457,459,462,465,469,472,475,478],{"class":56,"line":458},16,[54,460,461],{"class":98},"               f",[54,463,464],{"class":64},"\"=VLOOKUP(B",[54,466,468],{"class":467},"sSjpA","{",[54,470,471],{"class":102},"r",[54,473,474],{"class":467},"}",[54,476,477],{"class":64},",Prices!$A$2:$B$4,2,FALSE)\"",[54,479,480],{"class":102},",\n",[54,482,484,486,489,491,493,495,498,500,502,504,507,509,511,513,516],{"class":56,"line":483},17,[54,485,461],{"class":98},[54,487,488],{"class":64},"\"=(D",[54,490,468],{"class":467},[54,492,471],{"class":102},[54,494,474],{"class":467},[54,496,497],{"class":64},"-E",[54,499,468],{"class":467},[54,501,471],{"class":102},[54,503,474],{"class":467},[54,505,506],{"class":64},")\u002FD",[54,508,468],{"class":467},[54,510,471],{"class":102},[54,512,474],{"class":467},[54,514,515],{"class":64},"\"",[54,517,185],{"class":102},[54,519,521,524,527,530,532,534,536,538,541,543],{"class":56,"line":520},18,[54,522,523],{"class":102},"    ws[",[54,525,526],{"class":98},"f",[54,528,529],{"class":64},"\"G",[54,531,468],{"class":467},[54,533,471],{"class":102},[54,535,474],{"class":467},[54,537,515],{"class":64},[54,539,540],{"class":102},"].number_format ",[54,542,125],{"class":98},[54,544,545],{"class":64}," \"0.0%\"\n",[54,547,549,552,555,558,561,564,566,569,571],{"class":56,"line":548},19,[54,550,551],{"class":102},"ws[",[54,553,554],{"class":64},"\"D8\"",[54,556,557],{"class":102},"], ws[",[54,559,560],{"class":64},"\"F8\"",[54,562,563],{"class":102},"] ",[54,565,125],{"class":98},[54,567,568],{"class":64}," \"=SUM(D2:D6)\"",[54,570,179],{"class":102},[54,572,573],{"class":64},"\"Total check\"\n",[54,575,577,579,582,584,586],{"class":56,"line":576},20,[54,578,551],{"class":102},[54,580,581],{"class":64},"\"G8\"",[54,583,563],{"class":102},[54,585,125],{"class":98},[54,587,588],{"class":64}," \"=SUM(G2:G6)\"\n",[54,590,592,594,597,599,602,605,608,611,614,616,618,620,623,625,627,629,631,633,636,638,640],{"class":56,"line":591},21,[54,593,191],{"class":98},[54,595,596],{"class":102}," col, width ",[54,598,197],{"class":98},[54,600,601],{"class":208}," zip",[54,603,604],{"class":102},"(",[54,606,607],{"class":64},"\"ABCDEFG\"",[54,609,610],{"class":102},", (",[54,612,613],{"class":208},"8",[54,615,179],{"class":102},[54,617,613],{"class":208},[54,619,179],{"class":102},[54,621,622],{"class":208},"7",[54,624,179],{"class":102},[54,626,353],{"class":208},[54,628,179],{"class":102},[54,630,613],{"class":208},[54,632,179],{"class":102},[54,634,635],{"class":208},"11",[54,637,179],{"class":102},[54,639,353],{"class":208},[54,641,642],{"class":102},")):\n",[54,644,646,649,651],{"class":56,"line":645},22,[54,647,648],{"class":102},"    ws.column_dimensions[col].width ",[54,650,125],{"class":98},[54,652,653],{"class":102}," width\n",[10,655,656,657,659],{},"Order SO-2 has zero revenue, so its margin divides by zero; SO-3 uses a SKU missing from the price list, so the lookup returns ",[14,658,20],{},"; SO-4 has \"TBC\" typed where its revenue should be. The sum in G8 then inherits an error from the margins above it — the way errors spread through a sheet. In a real report the data would come from pandas or a database, but the shapes are the same: zero denominators, codes missing from reference tables and text that slipped into numeric columns account for most formula errors in generated workbooks.",[40,661,663],{"id":662},"step-2-colour-errors-with-na-treated-separately","Step 2 — Colour errors, with #N\u002FA treated separately",[45,665,667],{"className":89,"code":666,"language":91,"meta":50,"style":50},"from openpyxl.formatting.rule import FormulaRule\nfrom openpyxl.styles import Font, PatternFill\n\nERROR_FILL = PatternFill(\"solid\", fgColor=\"FFC7CE\")\nNA_FILL = PatternFill(\"solid\", fgColor=\"FFF2CC\")\narea = \"D2:G8\"\nws.conditional_formatting.add(area, FormulaRule(formula=[\"ISNA(D2)\"], fill=NA_FILL, font=Font(color=\"7F6000\"), stopIfTrue=True))\nws.conditional_formatting.add(area, FormulaRule(formula=[\"ISERROR(D2)\"], fill=ERROR_FILL, font=Font(color=\"9C0006\", bold=True)))\nwb.save(\"orders_errors.xlsx\")\nprint([(r.formula, r.priority) for cf in ws.conditional_formatting for r in cf.rules])\n",[14,668,669,681,693,697,723,745,755,813,861,871],{"__ignoreMap":50},[54,670,671,673,676,678],{"class":56,"line":57},[54,672,99],{"class":98},[54,674,675],{"class":102}," openpyxl.formatting.rule ",[54,677,106],{"class":98},[54,679,680],{"class":102}," FormulaRule\n",[54,682,683,685,688,690],{"class":56,"line":112},[54,684,99],{"class":98},[54,686,687],{"class":102}," openpyxl.styles ",[54,689,106],{"class":98},[54,691,692],{"class":102}," Font, PatternFill\n",[54,694,695],{"class":56,"line":119},[54,696,116],{"emptyLinePlaceholder":115},[54,698,699,702,705,708,711,713,716,718,721],{"class":56,"line":131},[54,700,701],{"class":208},"ERROR_FILL",[54,703,704],{"class":98}," =",[54,706,707],{"class":102}," PatternFill(",[54,709,710],{"class":64},"\"solid\"",[54,712,179],{"class":102},[54,714,715],{"class":440},"fgColor",[54,717,125],{"class":98},[54,719,720],{"class":64},"\"FFC7CE\"",[54,722,167],{"class":102},[54,724,725,728,730,732,734,736,738,740,743],{"class":56,"line":142},[54,726,727],{"class":208},"NA_FILL",[54,729,704],{"class":98},[54,731,707],{"class":102},[54,733,710],{"class":64},[54,735,179],{"class":102},[54,737,715],{"class":440},[54,739,125],{"class":98},[54,741,742],{"class":64},"\"FFF2CC\"",[54,744,167],{"class":102},[54,746,747,750,752],{"class":56,"line":153},[54,748,749],{"class":102},"area ",[54,751,125],{"class":98},[54,753,754],{"class":64}," \"D2:G8\"\n",[54,756,757,760,763,765,768,771,774,777,779,781,783,786,788,791,794,796,799,802,805,807,810],{"class":56,"line":170},[54,758,759],{"class":102},"ws.conditional_formatting.add(area, FormulaRule(",[54,761,762],{"class":440},"formula",[54,764,125],{"class":98},[54,766,767],{"class":102},"[",[54,769,770],{"class":64},"\"ISNA(D2)\"",[54,772,773],{"class":102},"], ",[54,775,776],{"class":440},"fill",[54,778,125],{"class":98},[54,780,727],{"class":208},[54,782,179],{"class":102},[54,784,785],{"class":440},"font",[54,787,125],{"class":98},[54,789,790],{"class":102},"Font(",[54,792,793],{"class":440},"color",[54,795,125],{"class":98},[54,797,798],{"class":64},"\"7F6000\"",[54,800,801],{"class":102},"), ",[54,803,804],{"class":440},"stopIfTrue",[54,806,125],{"class":98},[54,808,809],{"class":208},"True",[54,811,812],{"class":102},"))\n",[54,814,815,817,819,821,823,826,828,830,832,834,836,838,840,842,844,846,849,851,854,856,858],{"class":56,"line":188},[54,816,759],{"class":102},[54,818,762],{"class":440},[54,820,125],{"class":98},[54,822,767],{"class":102},[54,824,825],{"class":64},"\"ISERROR(D2)\"",[54,827,773],{"class":102},[54,829,776],{"class":440},[54,831,125],{"class":98},[54,833,701],{"class":208},[54,835,179],{"class":102},[54,837,785],{"class":440},[54,839,125],{"class":98},[54,841,790],{"class":102},[54,843,793],{"class":440},[54,845,125],{"class":98},[54,847,848],{"class":64},"\"9C0006\"",[54,850,179],{"class":102},[54,852,853],{"class":440},"bold",[54,855,125],{"class":98},[54,857,809],{"class":208},[54,859,860],{"class":102},")))\n",[54,862,863,866,869],{"class":56,"line":236},[54,864,865],{"class":102},"wb.save(",[54,867,868],{"class":64},"\"orders_errors.xlsx\"",[54,870,167],{"class":102},[54,872,873,876,879,881,884,886,889,891,894,896],{"class":56,"line":242},[54,874,875],{"class":208},"print",[54,877,878],{"class":102},"([(r.formula, r.priority) ",[54,880,191],{"class":98},[54,882,883],{"class":102}," cf ",[54,885,197],{"class":98},[54,887,888],{"class":102}," ws.conditional_formatting ",[54,890,191],{"class":98},[54,892,893],{"class":102}," r ",[54,895,197],{"class":98},[54,897,898],{"class":102}," cf.rules])\n",[10,900,901,902,905,906,909,910,913,914,916,917,919,920,924,925,928,929,931],{},"Each rule is a formula written for the top-left cell of the range, ",[14,903,904],{},"D2","; Excel adjusts the relative reference for every other cell, exactly as when copying a formula. ",[14,907,908],{},"ISERROR"," is true for every error type; ",[14,911,912],{},"ISNA"," only for ",[14,915,20],{},". A missing price is often an expected situation — a new product not yet priced — so it gets a pale yellow warning rather than the red used for genuine faults, and ",[14,918,804],{}," stops the red rule from being applied on top of it. The order in which rules are added sets their priority, as explained in ",[34,921,923],{"href":922},"\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",". openpyxl also offers a dedicated ",[14,926,927],{},"Rule(type=\"containsErrors\")",", which Excel lists as \"Format only cells that contain errors\"; the formula form shown here does the same and makes the ",[14,930,20],{}," distinction possible.",[933,934,942,943,942,947,942,951,942,958,942,968,942,979,942,985,942,989,942,993,942,996,942,1001,942,1009,942,1013,942,1021,942,1028,942,1033,942,1038,942,1040,942,1043,942,1047,942,1050,942,1053,942,1059,942,1062,942,1064,942,1066,942,1069,942,1073,942,1076,942,1081,942,1088,942,1092],"svg",{"viewBox":935,"role":936,"ariaLabelledBy":937,"xmlns":940,"style":941},"4 0 752 272","img",[938,939],"fe-rules-t","fe-rules-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  ",[944,945,946],"title",{"id":938},"Which colour an error cell gets",[948,949,950],"desc",{"id":939},"Cells whose value is",[952,953],"rect",{"x":954,"y":330,"width":955,"height":956,"fill":957},"4","752","272","#ffffff",[952,959],{"x":960,"y":961,"width":962,"height":963,"rx":964,"fill":965,"stroke":966,"style":967},"240.0","16.0","280.0","75.5","12","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[969,970,972],"g",{"transform":971},"translate(368.0,29.0) scale(1.000)",[973,974],"path",{"d":975,"fill":976,"stroke":977,"style":978},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[980,981,984],"text",{"x":982,"y":963,"style":983},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Formula result",[56,986],{"x1":982,"y1":987,"x2":982,"y2":988,"stroke":966,"style":967},"91.5","111.5",[56,990],{"x1":991,"y1":988,"x2":992,"y2":988,"stroke":966,"style":967},"134.7","625.3",[56,994],{"x1":991,"y1":988,"x2":991,"y2":995,"stroke":966,"style":967},"157.5",[997,998],"polygon",{"points":999,"fill":1000},"134.7,161.5 129.7,152.5 139.7,152.5","#5b5cf0",[952,1002],{"x":1003,"y":1004,"width":1005,"height":1006,"rx":353,"fill":957,"stroke":1007,"style":1008},"110.3","121.5","48.7","21.0","var(--line,#cdd5e6)","stroke-width:1.2px",[980,1010,20],{"x":991,"y":1011,"style":1012},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle",[952,1014],{"x":1015,"y":1016,"width":1017,"height":1018,"rx":964,"fill":1019,"stroke":1020,"style":967},"20.0","163.5","229.3","93.0","#fdefd8","var(--gold,#b4740a)",[969,1022,1024],{"transform":1023},"translate(122.7,176.5) scale(1.000)",[973,1025],{"d":1026,"fill":976,"stroke":1027,"style":978},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--gold-ink,#7a4e06)",[980,1029,1032],{"x":991,"y":1030,"style":1031},"223.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","yellow warning",[980,1034,1037],{"x":991,"y":1035,"style":1036},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","ISNA, stop if true",[56,1039],{"x1":982,"y1":988,"x2":982,"y2":995,"stroke":966,"style":967},[997,1041],{"points":1042,"fill":1000},"380.0,161.5 375.0,152.5 385.0,152.5",[952,1044],{"x":1045,"y":1004,"width":1046,"height":1006,"rx":353,"fill":957,"stroke":1007,"style":1008},"339.2","81.7",[980,1048,1049],{"x":982,"y":1011,"style":1012},"other error",[952,1051],{"x":1052,"y":1016,"width":1017,"height":1018,"rx":964,"fill":965,"stroke":966,"style":967},"265.3",[969,1054,1056],{"transform":1055},"translate(368.0,176.5) scale(1.000)",[973,1057],{"d":1058,"fill":976,"stroke":977,"style":978},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[980,1060,1061],{"x":982,"y":1030,"style":983},"red highlight",[980,1063,908],{"x":982,"y":1035,"style":1036},[56,1065],{"x1":992,"y1":988,"x2":992,"y2":995,"stroke":966,"style":967},[997,1067],{"points":1068,"fill":1000},"625.3,161.5 620.3,152.5 630.3,152.5",[952,1070],{"x":1071,"y":1004,"width":1072,"height":1006,"rx":353,"fill":957,"stroke":1007,"style":1008},"592.8","65.1",[980,1074,1075],{"x":992,"y":1011,"style":1012},"no error",[952,1077],{"x":1078,"y":1016,"width":1017,"height":1018,"rx":964,"fill":1079,"stroke":1080,"style":967},"510.7","#d9f4f1","var(--teal,#0f9488)",[969,1082,1084],{"transform":1083},"translate(613.3,176.5) scale(1.000)",[973,1085],{"d":1086,"fill":976,"stroke":1087,"style":978},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[980,1089,1091],{"x":992,"y":1030,"style":1090},"font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","unchanged",[980,1093,1094],{"x":992,"y":1035,"style":1036},"normal format",[40,1096,1098],{"id":1097},"step-3-highlight-the-whole-row","Step 3 — Highlight the whole row",[10,1100,1101,1102,1106],{},"A red margin cell is easy to see; knowing which ",[1103,1104,1105],"em",{},"order"," it belongs to is easier still if the whole row is marked. A rule over the full row width with an absolute column reference does that:",[45,1108,1110],{"className":89,"code":1109,"language":91,"meta":50,"style":50},"row_rule = FormulaRule(formula=[\"OR(ISERROR($F2),ISERROR($G2))\"], fill=PatternFill(\"solid\", fgColor=\"FBE9EB\"))\nws.conditional_formatting.add(\"A2:C6\", row_rule)\nwb.save(\"orders_errors.xlsx\")\n",[14,1111,1112,1153,1164],{"__ignoreMap":50},[54,1113,1114,1117,1119,1122,1124,1126,1128,1131,1133,1135,1137,1140,1142,1144,1146,1148,1151],{"class":56,"line":57},[54,1115,1116],{"class":102},"row_rule ",[54,1118,125],{"class":98},[54,1120,1121],{"class":102}," FormulaRule(",[54,1123,762],{"class":440},[54,1125,125],{"class":98},[54,1127,767],{"class":102},[54,1129,1130],{"class":64},"\"OR(ISERROR($F2),ISERROR($G2))\"",[54,1132,773],{"class":102},[54,1134,776],{"class":440},[54,1136,125],{"class":98},[54,1138,1139],{"class":102},"PatternFill(",[54,1141,710],{"class":64},[54,1143,179],{"class":102},[54,1145,715],{"class":440},[54,1147,125],{"class":98},[54,1149,1150],{"class":64},"\"FBE9EB\"",[54,1152,812],{"class":102},[54,1154,1155,1158,1161],{"class":56,"line":112},[54,1156,1157],{"class":102},"ws.conditional_formatting.add(",[54,1159,1160],{"class":64},"\"A2:C6\"",[54,1162,1163],{"class":102},", row_rule)\n",[54,1165,1166,1168,1170],{"class":56,"line":119},[54,1167,865],{"class":102},[54,1169,868],{"class":64},[54,1171,167],{"class":102},[10,1173,1174,1177,1178,1181,1182,38],{},[14,1175,1176],{},"$F2"," and ",[14,1179,1180],{},"$G2"," lock the columns but leave the row relative, so each row checks its own unit price and margin. The rule is applied only to the descriptive columns A to C, which receive a light tint, while the error cells themselves keep the stronger colours from Step 2. Whole-row highlighting in general is covered in ",[34,1183,1185],{"href":1184},"\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",[40,1187,1189],{"id":1188},"step-4-recalculate-check-the-colours-and-list-the-errors","Step 4 — Recalculate, check the colours, and list the errors",[45,1191,1193],{"className":89,"code":1192,"language":91,"meta":50,"style":50},"import subprocess\nfrom openpyxl import load_workbook\nfrom PIL import Image\n\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"calc\", \"orders_errors.xlsx\"], check=True, capture_output=True)\ncalc = load_workbook(\"calc\u002Forders_errors.xlsx\", data_only=True)[\"Orders\"]\nERRORS = (\"#DIV\u002F0!\", \"#N\u002FA\", \"#VALUE!\", \"#REF!\", \"#NAME?\", \"#NUM!\", \"#NULL!\")\nfound = [(c.coordinate, c.value) for row in calc.iter_rows() for c in row if isinstance(c.value, str) and c.value in ERRORS]\nfor coord, err in found:\n    print(f\"{coord:\u003C4} {err:\u003C8} row {coord[1:]}: {calc[f'A{coord[1:]}'].value or 'total'}\")\n\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"pdf\", \"orders_errors.xlsx\"], check=True, capture_output=True)\nsubprocess.run([\"pdftoppm\", \"-png\", \"-r\", \"80\", \"-f\", \"1\", \"-l\", \"1\", \"orders_errors.pdf\", \"errors\"], check=True)\ncolours = {c for n, c in Image.open(\"errors-1.png\").convert(\"RGB\").getcolors(maxcolors=10**6) if n > 50}\nfor name, hexval in [(\"red error fill\", \"FFC7CE\"), (\"yellow #N\u002FA fill\", \"FFF2CC\"), (\"row tint\", \"FBE9EB\")]:\n    print(f\"{name:\u003C17} {'rendered' if tuple(int(hexval[i:i + 2], 16) for i in (0, 2, 4)) in colours else 'missing'}\")\n",[14,1194,1195,1202,1213,1226,1230,1287,1318,1363,1420,1432,1520,1524,1565,1626,1687,1725],{"__ignoreMap":50},[54,1196,1197,1199],{"class":56,"line":57},[54,1198,106],{"class":98},[54,1200,1201],{"class":102}," subprocess\n",[54,1203,1204,1206,1208,1210],{"class":56,"line":112},[54,1205,99],{"class":98},[54,1207,103],{"class":102},[54,1209,106],{"class":98},[54,1211,1212],{"class":102}," load_workbook\n",[54,1214,1215,1217,1220,1223],{"class":56,"line":119},[54,1216,99],{"class":98},[54,1218,1219],{"class":208}," PIL",[54,1221,1222],{"class":98}," import",[54,1224,1225],{"class":102}," Image\n",[54,1227,1228],{"class":56,"line":131},[54,1229,116],{"emptyLinePlaceholder":115},[54,1231,1232,1235,1238,1240,1243,1245,1248,1250,1253,1255,1258,1260,1263,1265,1267,1269,1272,1274,1276,1278,1281,1283,1285],{"class":56,"line":142},[54,1233,1234],{"class":102},"subprocess.run([",[54,1236,1237],{"class":64},"\"soffice\"",[54,1239,179],{"class":102},[54,1241,1242],{"class":64},"\"--headless\"",[54,1244,179],{"class":102},[54,1246,1247],{"class":64},"\"--convert-to\"",[54,1249,179],{"class":102},[54,1251,1252],{"class":64},"\"xlsx\"",[54,1254,179],{"class":102},[54,1256,1257],{"class":64},"\"--outdir\"",[54,1259,179],{"class":102},[54,1261,1262],{"class":64},"\"calc\"",[54,1264,179],{"class":102},[54,1266,868],{"class":64},[54,1268,773],{"class":102},[54,1270,1271],{"class":440},"check",[54,1273,125],{"class":98},[54,1275,809],{"class":208},[54,1277,179],{"class":102},[54,1279,1280],{"class":440},"capture_output",[54,1282,125],{"class":98},[54,1284,809],{"class":208},[54,1286,167],{"class":102},[54,1288,1289,1292,1294,1297,1300,1302,1305,1307,1309,1312,1315],{"class":56,"line":153},[54,1290,1291],{"class":102},"calc ",[54,1293,125],{"class":98},[54,1295,1296],{"class":102}," load_workbook(",[54,1298,1299],{"class":64},"\"calc\u002Forders_errors.xlsx\"",[54,1301,179],{"class":102},[54,1303,1304],{"class":440},"data_only",[54,1306,125],{"class":98},[54,1308,809],{"class":208},[54,1310,1311],{"class":102},")[",[54,1313,1314],{"class":64},"\"Orders\"",[54,1316,1317],{"class":102},"]\n",[54,1319,1320,1323,1325,1328,1331,1333,1336,1338,1341,1343,1346,1348,1351,1353,1356,1358,1361],{"class":56,"line":170},[54,1321,1322],{"class":208},"ERRORS",[54,1324,704],{"class":98},[54,1326,1327],{"class":102}," (",[54,1329,1330],{"class":64},"\"#DIV\u002F0!\"",[54,1332,179],{"class":102},[54,1334,1335],{"class":64},"\"#N\u002FA\"",[54,1337,179],{"class":102},[54,1339,1340],{"class":64},"\"#VALUE!\"",[54,1342,179],{"class":102},[54,1344,1345],{"class":64},"\"#REF!\"",[54,1347,179],{"class":102},[54,1349,1350],{"class":64},"\"#NAME?\"",[54,1352,179],{"class":102},[54,1354,1355],{"class":64},"\"#NUM!\"",[54,1357,179],{"class":102},[54,1359,1360],{"class":64},"\"#NULL!\"",[54,1362,167],{"class":102},[54,1364,1365,1368,1370,1373,1375,1378,1380,1383,1385,1388,1390,1392,1395,1398,1401,1404,1407,1410,1413,1415,1418],{"class":56,"line":188},[54,1366,1367],{"class":102},"found ",[54,1369,125],{"class":98},[54,1371,1372],{"class":102}," [(c.coordinate, c.value) ",[54,1374,191],{"class":98},[54,1376,1377],{"class":102}," row ",[54,1379,197],{"class":98},[54,1381,1382],{"class":102}," calc.iter_rows() ",[54,1384,191],{"class":98},[54,1386,1387],{"class":102}," c ",[54,1389,197],{"class":98},[54,1391,1377],{"class":102},[54,1393,1394],{"class":98},"if",[54,1396,1397],{"class":208}," isinstance",[54,1399,1400],{"class":102},"(c.value, ",[54,1402,1403],{"class":208},"str",[54,1405,1406],{"class":102},") ",[54,1408,1409],{"class":98},"and",[54,1411,1412],{"class":102}," c.value ",[54,1414,197],{"class":98},[54,1416,1417],{"class":208}," ERRORS",[54,1419,1317],{"class":102},[54,1421,1422,1424,1427,1429],{"class":56,"line":236},[54,1423,191],{"class":98},[54,1425,1426],{"class":102}," coord, err ",[54,1428,197],{"class":98},[54,1430,1431],{"class":102}," found:\n",[54,1433,1434,1437,1439,1441,1443,1445,1448,1451,1453,1456,1459,1462,1464,1466,1468,1471,1474,1477,1479,1482,1484,1487,1489,1492,1494,1496,1498,1500,1502,1505,1508,1511,1514,1516,1518],{"class":56,"line":242},[54,1435,1436],{"class":208},"    print",[54,1438,604],{"class":102},[54,1440,526],{"class":98},[54,1442,515],{"class":64},[54,1444,468],{"class":467},[54,1446,1447],{"class":102},"coord",[54,1449,1450],{"class":98},":\u003C4",[54,1452,474],{"class":467},[54,1454,1455],{"class":467}," {",[54,1457,1458],{"class":102},"err",[54,1460,1461],{"class":98},":\u003C8",[54,1463,474],{"class":467},[54,1465,1377],{"class":64},[54,1467,468],{"class":467},[54,1469,1470],{"class":102},"coord[",[54,1472,1473],{"class":208},"1",[54,1475,1476],{"class":102},":]",[54,1478,474],{"class":467},[54,1480,1481],{"class":64},": ",[54,1483,468],{"class":467},[54,1485,1486],{"class":102},"calc[",[54,1488,526],{"class":98},[54,1490,1491],{"class":64},"'A",[54,1493,468],{"class":467},[54,1495,1470],{"class":102},[54,1497,1473],{"class":208},[54,1499,1476],{"class":102},[54,1501,474],{"class":467},[54,1503,1504],{"class":64},"'",[54,1506,1507],{"class":102},"].value ",[54,1509,1510],{"class":98},"or",[54,1512,1513],{"class":64}," 'total'",[54,1515,474],{"class":467},[54,1517,515],{"class":64},[54,1519,167],{"class":102},[54,1521,1522],{"class":56,"line":247},[54,1523,116],{"emptyLinePlaceholder":115},[54,1525,1526,1528,1530,1532,1534,1536,1538,1540,1543,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563],{"class":56,"line":287},[54,1527,1234],{"class":102},[54,1529,1237],{"class":64},[54,1531,179],{"class":102},[54,1533,1242],{"class":64},[54,1535,179],{"class":102},[54,1537,1247],{"class":64},[54,1539,179],{"class":102},[54,1541,1542],{"class":64},"\"pdf\"",[54,1544,179],{"class":102},[54,1546,868],{"class":64},[54,1548,773],{"class":102},[54,1550,1271],{"class":440},[54,1552,125],{"class":98},[54,1554,809],{"class":208},[54,1556,179],{"class":102},[54,1558,1280],{"class":440},[54,1560,125],{"class":98},[54,1562,809],{"class":208},[54,1564,167],{"class":102},[54,1566,1567,1569,1572,1574,1577,1579,1582,1584,1587,1589,1592,1594,1597,1599,1602,1604,1606,1608,1611,1613,1616,1618,1620,1622,1624],{"class":56,"line":369},[54,1568,1234],{"class":102},[54,1570,1571],{"class":64},"\"pdftoppm\"",[54,1573,179],{"class":102},[54,1575,1576],{"class":64},"\"-png\"",[54,1578,179],{"class":102},[54,1580,1581],{"class":64},"\"-r\"",[54,1583,179],{"class":102},[54,1585,1586],{"class":64},"\"80\"",[54,1588,179],{"class":102},[54,1590,1591],{"class":64},"\"-f\"",[54,1593,179],{"class":102},[54,1595,1596],{"class":64},"\"1\"",[54,1598,179],{"class":102},[54,1600,1601],{"class":64},"\"-l\"",[54,1603,179],{"class":102},[54,1605,1596],{"class":64},[54,1607,179],{"class":102},[54,1609,1610],{"class":64},"\"orders_errors.pdf\"",[54,1612,179],{"class":102},[54,1614,1615],{"class":64},"\"errors\"",[54,1617,773],{"class":102},[54,1619,1271],{"class":440},[54,1621,125],{"class":98},[54,1623,809],{"class":208},[54,1625,167],{"class":102},[54,1627,1628,1631,1633,1636,1638,1641,1643,1646,1649,1652,1655,1658,1661,1663,1665,1668,1671,1673,1675,1678,1681,1684],{"class":56,"line":424},[54,1629,1630],{"class":102},"colours ",[54,1632,125],{"class":98},[54,1634,1635],{"class":102}," {c ",[54,1637,191],{"class":98},[54,1639,1640],{"class":102}," n, c ",[54,1642,197],{"class":98},[54,1644,1645],{"class":102}," Image.open(",[54,1647,1648],{"class":64},"\"errors-1.png\"",[54,1650,1651],{"class":102},").convert(",[54,1653,1654],{"class":64},"\"RGB\"",[54,1656,1657],{"class":102},").getcolors(",[54,1659,1660],{"class":440},"maxcolors",[54,1662,125],{"class":98},[54,1664,353],{"class":208},[54,1666,1667],{"class":98},"**",[54,1669,1670],{"class":208},"6",[54,1672,1406],{"class":102},[54,1674,1394],{"class":98},[54,1676,1677],{"class":102}," n ",[54,1679,1680],{"class":98},">",[54,1682,1683],{"class":208}," 50",[54,1685,1686],{"class":102},"}\n",[54,1688,1689,1691,1694,1696,1698,1701,1703,1705,1707,1710,1712,1714,1716,1719,1721,1723],{"class":56,"line":452},[54,1690,191],{"class":98},[54,1692,1693],{"class":102}," name, hexval ",[54,1695,197],{"class":98},[54,1697,200],{"class":102},[54,1699,1700],{"class":64},"\"red error fill\"",[54,1702,179],{"class":102},[54,1704,720],{"class":64},[54,1706,212],{"class":102},[54,1708,1709],{"class":64},"\"yellow #N\u002FA fill\"",[54,1711,179],{"class":102},[54,1713,742],{"class":64},[54,1715,212],{"class":102},[54,1717,1718],{"class":64},"\"row tint\"",[54,1720,179],{"class":102},[54,1722,1150],{"class":64},[54,1724,233],{"class":102},[54,1726,1727,1729,1731,1733,1735,1737,1740,1743,1745,1747,1750,1753,1756,1758,1761,1764,1767,1770,1772,1775,1777,1779,1782,1784,1786,1788,1790,1792,1794,1796,1799,1801,1804,1807,1810,1812,1814],{"class":56,"line":458},[54,1728,1436],{"class":208},[54,1730,604],{"class":102},[54,1732,526],{"class":98},[54,1734,515],{"class":64},[54,1736,468],{"class":467},[54,1738,1739],{"class":102},"name",[54,1741,1742],{"class":98},":\u003C17",[54,1744,474],{"class":467},[54,1746,1455],{"class":467},[54,1748,1749],{"class":64},"'rendered'",[54,1751,1752],{"class":98}," if",[54,1754,1755],{"class":208}," tuple",[54,1757,604],{"class":102},[54,1759,1760],{"class":208},"int",[54,1762,1763],{"class":102},"(hexval[i:i ",[54,1765,1766],{"class":98},"+",[54,1768,1769],{"class":208}," 2",[54,1771,773],{"class":102},[54,1773,1774],{"class":208},"16",[54,1776,1406],{"class":102},[54,1778,191],{"class":98},[54,1780,1781],{"class":102}," i ",[54,1783,197],{"class":98},[54,1785,1327],{"class":102},[54,1787,330],{"class":208},[54,1789,179],{"class":102},[54,1791,446],{"class":208},[54,1793,179],{"class":102},[54,1795,954],{"class":208},[54,1797,1798],{"class":102},")) ",[54,1800,197],{"class":98},[54,1802,1803],{"class":102}," colours ",[54,1805,1806],{"class":98},"else",[54,1808,1809],{"class":64}," 'missing'",[54,1811,474],{"class":467},[54,1813,515],{"class":64},[54,1815,167],{"class":102},[10,1817,1818,1819,1822,1823,1825,1826,1828,1829,1832,1833,1836,1837,38],{},"After recalculation, openpyxl's ",[14,1820,1821],{},"data_only=True"," view returns error results as their text, ",[14,1824,16],{}," and so on, which makes them easy to find with a scan. The list shows exactly where the problems are: the division by zero for SO-2, the missing price for SO-3 and the ",[14,1827,24],{}," from SO-4's text revenue, plus the margin total in G8 that inherited an error. The revenue total in D8 does ",[1103,1830,1831],{},"not"," show an error: ",[14,1834,1835],{},"SUM"," silently skips the text, so the total is simply too low — a reminder that some data problems produce no error at all and need a check of their own. All three fills appear in the rendered page. A job that builds reports can run this scan and refuse to send a workbook with unexpected errors, as described in ",[34,1838,1840],{"href":1839},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fvalidate-an-excel-report-before-sending-it\u002F","Validate an Excel Report Before Sending It",[933,1842,942,1848,942,1851,942,1854,942,1859,942,1866,942,1870,942,1876,942,1880,942,1884,942,1888,942,1892,942,1896,942,1900,942,1904,942,1908,942,1912,942,1916,942,1919,942,1923,942,1925,942,1928,942,1930,942,1933,942,1935,942,1938,942,1940,942,1943,942,1946,942,1949,942,1951,942,1955,942,1957,942,1960,942,1962,942,1964,942,1966,942,1968,942,1970,942,1973,942,1976,942,1980,942,1982,942,1985,942,1987,942,1990,942,1992,942,1994,942,1996,942,1998,942,2002,942,2005,942,2008,942,2011,942,2013,942,2016,942,2018,942,2021,942,2023,942,2025,942,2027,942,2030,942,2032,942,2035,942,2038,942,2042,942,2044,942,2047,942,2049,942,2052,942,2054,942,2056,942,2058,942,2060,942,2062,942,2064,942,2067,942,2070,942,2072,942,2075,942,2077,942,2079,942,2081,942,2083],{"viewBox":1843,"role":936,"ariaLabelledBy":1844,"xmlns":940,"style":1847},"158 0 444 224",[1845,1846],"fe-sheet-t","fe-sheet-d","width:100%;max-width:444px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[944,1849,1850],{"id":1845},"The order sheet after recalculation",[948,1852,1853],{"id":1846},"SO-2 shows a division by zero in the margin column, SO-3 shows",[952,1855],{"x":1856,"y":330,"width":1857,"height":1858,"fill":957},"158","444","224",[952,1860],{"x":1861,"y":961,"width":1862,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"174.1","32.0","24.0","#e7ebef","stroke-width:1px",[952,1867],{"x":1868,"y":961,"width":1869,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"206.1","95.9",[980,1871,1875],{"x":1872,"y":1873,"style":1874},"254.0","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[952,1877],{"x":1878,"y":961,"width":1879,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"302.0","68.1",[980,1881,1883],{"x":1882,"y":1873,"style":1874},"336.1","B",[952,1885],{"x":1886,"y":961,"width":1887,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"370.1","49.1",[980,1889,1891],{"x":1890,"y":1873,"style":1874},"394.7","C",[952,1893],{"x":1894,"y":961,"width":1895,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"419.2","83.5",[980,1897,1899],{"x":1898,"y":1873,"style":1874},"461.0","D",[952,1901],{"x":1902,"y":961,"width":1903,"height":1863,"rx":330,"fill":1864,"stroke":1007,"style":1865},"502.7","83.2",[980,1905,1907],{"x":1906,"y":1873,"style":1874},"544.3","E",[952,1909],{"x":1861,"y":1910,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"40.0","28.0",[980,1913,1473],{"x":1914,"y":1915,"style":1874},"190.1","59.0",[952,1917],{"x":1868,"y":1910,"width":1869,"height":1911,"rx":330,"fill":965,"stroke":966,"style":1918},"stroke-width:1.5px",[980,1920,1922],{"x":1872,"y":1915,"style":1921},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Order",[952,1924],{"x":1878,"y":1910,"width":1879,"height":1911,"rx":330,"fill":965,"stroke":966,"style":1918},[980,1926,1927],{"x":1882,"y":1915,"style":1921},"SKU",[952,1929],{"x":1886,"y":1910,"width":1887,"height":1911,"rx":330,"fill":965,"stroke":966,"style":1918},[980,1931,1932],{"x":1890,"y":1915,"style":1921},"Qty",[952,1934],{"x":1894,"y":1910,"width":1895,"height":1911,"rx":330,"fill":965,"stroke":966,"style":1918},[980,1936,1937],{"x":1898,"y":1915,"style":1921},"Unit price",[952,1939],{"x":1902,"y":1910,"width":1903,"height":1911,"rx":330,"fill":965,"stroke":966,"style":1918},[980,1941,1942],{"x":1906,"y":1915,"style":1921},"Margin %",[952,1944],{"x":1861,"y":1945,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"68.0",[980,1947,446],{"x":1914,"y":1948,"style":1874},"87.0",[952,1950],{"x":1868,"y":1945,"width":1869,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1952,1954],{"x":1872,"y":1948,"style":1953},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","SO-1",[952,1956],{"x":1878,"y":1945,"width":1879,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1958,1959],{"x":1882,"y":1948,"style":1953},"B-100",[952,1961],{"x":1886,"y":1945,"width":1887,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1963,306],{"x":1890,"y":1948,"style":1953},[952,1965],{"x":1894,"y":1945,"width":1895,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1967,209],{"x":1898,"y":1948,"style":1953},[952,1969],{"x":1902,"y":1945,"width":1903,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1971,1972],{"x":1906,"y":1948,"style":1953},"53.3%",[952,1974],{"x":1861,"y":1975,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"96.0",[980,1977,1979],{"x":1914,"y":1978,"style":1874},"115.0","3",[952,1981],{"x":1868,"y":1975,"width":1869,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1983,1984],{"x":1872,"y":1978,"style":1953},"SO-2",[952,1986],{"x":1878,"y":1975,"width":1879,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1988,1989],{"x":1882,"y":1978,"style":1953},"N-200",[952,1991],{"x":1886,"y":1975,"width":1887,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1993,330],{"x":1890,"y":1978,"style":1953},[952,1995],{"x":1894,"y":1975,"width":1895,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,1997,220],{"x":1898,"y":1978,"style":1953},[952,1999],{"x":1902,"y":1975,"width":1903,"height":1911,"rx":330,"fill":2000,"stroke":2001,"style":1918},"#fce9e9","var(--danger,#dc2626)",[980,2003,16],{"x":1906,"y":1978,"style":2004},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle",[952,2006],{"x":1861,"y":2007,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"124.0",[980,2009,954],{"x":1914,"y":2010,"style":1874},"143.0",[952,2012],{"x":1868,"y":2007,"width":1869,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2014,2015],{"x":1872,"y":2010,"style":1953},"SO-3",[952,2017],{"x":1878,"y":2007,"width":1879,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2019,2020],{"x":1882,"y":2010,"style":1953},"X-999",[952,2022],{"x":1886,"y":2007,"width":1887,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2024,353],{"x":1890,"y":2010,"style":1953},[952,2026],{"x":1894,"y":2007,"width":1895,"height":1911,"rx":330,"fill":1019,"stroke":1020,"style":1918},[980,2028,20],{"x":1898,"y":2010,"style":2029},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[952,2031],{"x":1902,"y":2007,"width":1903,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2033,2034],{"x":1906,"y":2010,"style":1953},"60.0%",[952,2036],{"x":1861,"y":2037,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"152.0",[980,2039,2041],{"x":1914,"y":2040,"style":1874},"171.0","5",[952,2043],{"x":1868,"y":2037,"width":1869,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2045,2046],{"x":1872,"y":2040,"style":1953},"SO-4",[952,2048],{"x":1878,"y":2037,"width":1879,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2050,2051],{"x":1882,"y":2040,"style":1953},"W-300",[952,2053],{"x":1886,"y":2037,"width":1887,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2055,384],{"x":1890,"y":2040,"style":1953},[952,2057],{"x":1894,"y":2037,"width":1895,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2059,230],{"x":1898,"y":2040,"style":1953},[952,2061],{"x":1902,"y":2037,"width":1903,"height":1911,"rx":330,"fill":2000,"stroke":2001,"style":1918},[980,2063,24],{"x":1906,"y":2040,"style":2004},[952,2065],{"x":1861,"y":2066,"width":1862,"height":1911,"rx":330,"fill":1864,"stroke":1007,"style":1865},"180.0",[980,2068,1670],{"x":1914,"y":2069,"style":1874},"199.0",[952,2071],{"x":1868,"y":2066,"width":1869,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[980,2073,2074],{"x":1872,"y":2069,"style":1953},"Total check",[952,2076],{"x":1878,"y":2066,"width":1879,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[952,2078],{"x":1886,"y":2066,"width":1887,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[952,2080],{"x":1894,"y":2066,"width":1895,"height":1911,"rx":330,"fill":957,"stroke":1007,"style":1865},[952,2082],{"x":1902,"y":2066,"width":1903,"height":1911,"rx":330,"fill":2000,"stroke":2001,"style":1918},[980,2084,16],{"x":1906,"y":2069,"style":2004},[933,2086,942,2091,942,2094,942,2097,942,2100,942,2104,942,2111,942,2116,942,2119,942,2123,942,2127,942,2132,942,2135,942,2138,942,2144,942,2148,942,2151,942,2155,942,2158,942,2161,942,2166,942,2170,942,2173,942,2177,942,2180,942,2183,942,2188,942,2192],{"viewBox":2087,"role":936,"ariaLabelledBy":2088,"xmlns":940,"style":941},"4 0 752 160",[2089,2090],"fe-check-t","fe-check-d",[944,2092,2093],{"id":2089},"Catching errors before a report goes out",[948,2095,2096],{"id":2090},"Conditional formatting rules mark errors for people reading the workbook. Before sending, the job recalculates the workbook, scans the data-only values for error strings, lists them with their rows, and stops if any unexpected error remains.",[952,2098],{"x":954,"y":330,"width":955,"height":2099,"fill":957},"160",[952,2101],{"x":1015,"y":961,"width":2102,"height":2103,"rx":964,"fill":1864,"stroke":1007,"style":967},"153.0","128.0",[969,2105,2107],{"transform":2106},"translate(84.5,29.0) scale(1.000)",[973,2108],{"d":2109,"fill":976,"stroke":2110,"style":978},"M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z M12 9a3 3 0 1 0 .01 0z","var(--text,#172033)",[980,2112,2115],{"x":2113,"y":963,"style":2114},"96.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Rules in the",[980,2117,2118],{"x":2113,"y":1018,"style":2114},"workbook",[980,2120,2122],{"x":2113,"y":2121,"style":1036},"112.5","errors visible to",[980,2124,2126],{"x":2113,"y":2125,"style":1036},"130.0","readers",[56,2128],{"x1":2129,"y1":2130,"x2":2131,"y2":2130,"stroke":966,"style":967},"178.0","80.0","200.0",[997,2133],{"points":2134,"fill":1000},"204.0,80.0 195.0,85.0 195.0,75.0",[952,2136],{"x":2137,"y":961,"width":2102,"height":2103,"rx":964,"fill":965,"stroke":966,"style":967},"209.0",[969,2139,2141],{"transform":2140},"translate(273.5,46.5) scale(1.000)",[973,2142],{"d":2143,"fill":976,"stroke":977,"style":978},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7",[980,2145,2147],{"x":2146,"y":1018,"style":983},"285.5","Recalculate",[980,2149,2150],{"x":2146,"y":2121,"style":1036},"LibreOffice or Excel",[56,2152],{"x1":2153,"y1":2130,"x2":2154,"y2":2130,"stroke":966,"style":967},"367.0","389.0",[997,2156],{"points":2157,"fill":1000},"393.0,80.0 384.0,85.0 384.0,75.0",[952,2159],{"x":2160,"y":961,"width":2102,"height":2103,"rx":964,"fill":1019,"stroke":1020,"style":967},"398.0",[969,2162,2164],{"transform":2163},"translate(462.5,46.5) scale(1.000)",[973,2165],{"d":1026,"fill":976,"stroke":1027,"style":978},[980,2167,2169],{"x":2168,"y":1018,"style":1031},"474.5","Scan values",[980,2171,2172],{"x":2168,"y":2121,"style":1036},"#DIV\u002F0!, #N\u002FA, …",[56,2174],{"x1":2175,"y1":2130,"x2":2176,"y2":2130,"stroke":966,"style":967},"556.0","578.0",[997,2178],{"points":2179,"fill":1000},"582.0,80.0 573.0,85.0 573.0,75.0",[952,2181],{"x":2182,"y":961,"width":2102,"height":2103,"rx":964,"fill":1079,"stroke":1080,"style":967},"587.0",[969,2184,2186],{"transform":2185},"translate(651.5,46.5) scale(1.000)",[973,2187],{"d":1086,"fill":976,"stroke":1087,"style":978},[980,2189,2191],{"x":2190,"y":1018,"style":1090},"663.5","Report or stop",[980,2193,2194],{"x":2190,"y":2121,"style":1036},"before sending",[40,2196,2198],{"id":2197},"when-errors-are-acceptable","When errors are acceptable",[10,2200,2201,2202,2204,2205,2207,2208,2210],{},"Not every error in a finished report is a fault. A ",[14,2203,20],{}," in a lookup column can be the honest answer — \"no price agreed yet\" — and replacing it with zero would be worse, because zero is a valid price. Decide, column by column, which errors are allowed: lookups against reference data that is known to be incomplete may show ",[14,2206,20],{},", while divisions, type errors and broken references never should. The scan in Step 4 can then compare what it finds against that list — allow ",[14,2209,20],{}," in column F, fail on anything else — so the check is strict where it matters and quiet where an error carries information. Recording the decision in the workbook, on a notes sheet, tells readers what the yellow cells mean.",[40,2212,2214],{"id":2213},"common-pitfalls","Common pitfalls",[2216,2217,2218,2226,2232,2238,2244],"ul",{},[2219,2220,2221,2225],"li",{},[2222,2223,2224],"strong",{},"A rule written for the wrong anchor cell."," The formula refers to the range's top-left cell.",[2219,2227,2228,2231],{},[2222,2229,2230],{},"Treating every #N\u002FA as a fault."," Give expected lookup misses their own, softer rule.",[2219,2233,2234,2237],{},[2222,2235,2236],{},"Hiding errors with white text."," It hides the total that inherited them too; fix or flag them.",[2219,2239,2240,2243],{},[2222,2241,2242],{},"Checking an uncalculated file."," Errors only exist after Excel or LibreOffice has calculated it.",[2219,2245,2246,2249],{},[2222,2247,2248],{},"Forgetting totals."," Errors spread upwards; check summary cells as well.",[40,2251,2253],{"id":2252},"conclusion","Conclusion",[10,2255,2256,2257,2260,2261,2263,2264,2266,2267,2269,2270,2272],{},"Add a ",[14,2258,2259],{},"FormulaRule"," with ",[14,2262,908],{}," to colour every error cell, preceded by an ",[14,2265,912],{}," rule with ",[14,2268,804],{}," when missing lookups deserve a gentler warning, and a row rule with locked columns to mark the records that contain them. Because the rules live in the workbook, errors that appear later are highlighted too. Before sending, recalculate and scan the ",[14,2271,1304],{}," values for error strings, so every error is accounted for.",[40,2274,2276],{"id":2275},"frequently-asked-questions","Frequently asked questions",[10,2278,2279,2282],{},[2222,2280,2281],{},"How do I highlight error cells in Excel with Python?","\nAdd a conditional formatting rule with openpyxl's FormulaRule and the formula ISERROR on the top-left cell of the range, with a fill and font for the highlight.",[10,2284,2285,2288],{},[2222,2286,2287],{},"How can I highlight #N\u002FA differently from other errors?","\nAdd an ISNA rule before the ISERROR rule and set stopIfTrue on it, so #N\u002FA cells get their own format and the general error rule is skipped.",[10,2290,2291,2294],{},[2222,2292,2293],{},"How do I find all error cells in a workbook with Python?","\nRecalculate the workbook, load it with openpyxl using data_only=True, and look for cells whose values are error strings such as #DIV\u002F0! or #N\u002FA.",[10,2296,2297,2300],{},[2222,2298,2299],{},"Should I use IFERROR to hide errors instead?","\nOnly where an error has an agreed meaning; hiding them everywhere also hides genuine data problems.",[40,2302,2304],{"id":2303},"related","Related",[2216,2306,2307,2313,2320,2327],{},[2219,2308,2309,2310,2312],{},"Up one level: ",[34,2311,37],{"href":36}," — rules from Python.",[2219,2314,2315,2319],{},[34,2316,2318],{"href":2317},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Ffind-formula-errors-in-a-workbook-with-python\u002F","Find Formula Errors in a Workbook with Python"," — finding errors without formatting.",[2219,2321,2322,2326],{},[34,2323,2325],{"href":2324},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fiferror-and-isna-equivalents-in-pandas\u002F","IFERROR, IFNA, ISNA and ISNUMBER Equivalents in pandas"," — the same logic in pandas.",[2219,2328,2329,2333],{},[34,2330,2332],{"href":2331},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-blank-cells-with-openpyxl\u002F","Highlight Blank Cells with openpyxl"," — another data-quality rule.",[2335,2336,2337],"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":50,"searchDepth":112,"depth":112,"links":2339},[2340,2341,2342,2343,2344,2345,2346,2347,2348,2349],{"id":42,"depth":112,"text":43},{"id":85,"depth":112,"text":86},{"id":662,"depth":112,"text":663},{"id":1097,"depth":112,"text":1098},{"id":1188,"depth":112,"text":1189},{"id":2197,"depth":112,"text":2198},{"id":2213,"depth":112,"text":2214},{"id":2252,"depth":112,"text":2253},{"id":2275,"depth":112,"text":2276},{"id":2303,"depth":112,"text":2304},"2026-10-02","Make #DIV\u002F0!, #N\u002FA, #VALUE! and #REF! results stand out in a generated workbook with openpyxl conditional formatting: a rule that colours any error, a separate softer rule for expected #N\u002FA lookups, a whole-row highlight driven by an error in one column, and a Python check that lists every error cell after recalculation so problems are found before the report is sent.","md",[2354,2356,2358,2360],{"q":2281,"a":2355},"Add a conditional formatting rule with openpyxl's FormulaRule and the formula ISERROR on the top-left cell of the range, with a fill and font for the highlight.",{"q":2287,"a":2357},"Add an ISNA rule before the ISERROR rule and set stopIfTrue on it, so #N\u002FA cells get their own format and the general error rule is skipped.",{"q":2293,"a":2359},"Recalculate the workbook, load it with openpyxl using data_only=True, and look for cells whose values are error strings such as #DIV\u002F0! or #N\u002FA.",{"q":2299,"a":2361},"Only where an error has an agreed meaning; hiding them everywhere also hides genuine data problems.","highlight formula errors conditional formatting openpyxl",null,{"breadcrumb":2365},[2366,2369,2372],{"name":2367,"item":2368},"Home","\u002F",{"name":2370,"item":2371},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":2373,"item":36},"Applying Conditional Formatting With openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting",{"title":2376,"description":2377},"Highlight Formula Errors with Conditional Formatting in Python","openpyxl conditional formatting for formula errors: ISERROR and ISNA rules, the containsErrors rule type, rule order, whole-row highlights, and listing every error cell with Python after a LibreOffice recalculation.","highlight-cells-with-formula-errors-using-conditional-formatting","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting\u002Findex",[2381,2382],"conditional-formatting","excel-formulas","how-to","fTUlBF-mWvmUEkUcl8f_AgzaYQ28pMFfhIkxmxG51P4",[2386,2390],{"title":2387,"path":2388,"stem":2389,"children":-1},"Highlight Cells Containing Specific Text with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-containing-text-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-containing-text-with-openpyxl\u002Findex",{"title":2391,"path":2392,"stem":2393,"children":-1},"Highlight Differences Between Two Columns with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-differences-between-two-columns-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-differences-between-two-columns-with-openpyxl\u002Findex",[2395,2397],{"path":2396,"title":2373},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl",{"path":2398,"title":2370},"\u002Fadvanced-data-transformation-and-cleaning",[],[2401,2404,2407,2410,2413,2416],{"path":2402,"title":2403,"kind":2383},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fapply-conditional-formatting-with-xlsxwriter","Apply Conditional Formatting with xlsxwriter",{"path":2405,"title":2406,"kind":2383},"\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":2408,"title":2409,"kind":2383},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","Add Icon Sets to Excel Cells with openpyxl",{"path":2411,"title":2412,"kind":2383},"\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":2414,"title":2415,"kind":2383},"\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":2417,"title":923,"kind":2383},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true",1790972078230]