[{"data":1,"prerenderedAt":1725},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl":1716},{"id":4,"title":5,"body":6,"dateModified":1693,"datePublished":1693,"description":1694,"extension":1695,"faq":1696,"meta":1707,"navigation":227,"path":1708,"seo":1709,"slug":1712,"stem":1713,"type":1714,"__hash__":1715},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl\u002Findex.md","Highlight Duplicate Values in Excel with openpyxl",{"type":7,"value":8,"toc":1678},"minimark",[9,19,114,119,147,151,154,446,452,456,463,539,555,559,562,674,679,794,798,805,924,930,934,937,1208,1221,1225,1228,1308,1315,1319,1322,1419,1426,1436,1484,1491,1495,1560,1564,1570,1574,1583,1587,1599,1605,1619,1625,1634,1638,1674],[10,11,12,13,18],"p",{},"Duplicate rows are the quietest data problem: nothing errors, totals are simply wrong. Excel's conditional formatting can make them visible in the delivered workbook, so the person who owns the data sees the problem in the file rather than in a message about the file. openpyxl writes those rules directly. This guide covers the built-in duplicate rule, formula rules for the cases it cannot express, and when to skip conditional formatting and paint the cells yourself. 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,29,30,29,34,29,38,29,45,29,52,29,57,29,65,29,73,29,78,29,81,29,85,29,89,29,94,29,98,29,103,29,105,29,108,29,110],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"0 0 760 232","img",[25,26],"dup-t","dup-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"A rule travels with the file; a fill is baked in",[35,36,37],"desc",{"id":26},"A conditional formatting rule is stored as an instruction that Excel evaluates on open and re-evaluates after edits, while a static fill records the decision the script made at write time.",[39,40],"rect",{"x":41,"y":41,"width":42,"height":43,"fill":44},"0","760","232","#ffffff",[46,47,51],"text",{"x":48,"y":49,"style":50},"196","28","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","conditional rule",[46,53,56],{"x":54,"y":49,"style":55},"566","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","static fill",[58,59],"line",{"x1":60,"y1":61,"x2":60,"y2":62,"stroke":63,"style":64},"380","40","212","var(--line,#cdd5e6)","stroke-width:1px",[39,66],{"x":67,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":63},"30","46","332","44","9","#ebebfd",[46,74,77],{"x":48,"y":75,"style":76},"74","font-size:12px;fill:var(--text,#172033);text-anchor:middle","Excel evaluates it on open",[39,79],{"x":67,"y":80,"width":69,"height":70,"rx":71,"fill":72,"stroke":63},"98",[46,82,84],{"x":48,"y":83,"style":76},"126","updates when the reader edits",[39,86],{"x":67,"y":87,"width":69,"height":70,"rx":71,"fill":88,"stroke":63},"150","#fdefd8",[46,90,93],{"x":48,"y":91,"style":92},"178","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","invisible to a PDF export",[39,95],{"x":96,"y":68,"width":69,"height":70,"rx":71,"fill":97,"stroke":63},"398","#d9f4f1",[46,99,102],{"x":100,"y":75,"style":101},"564","font-size:12px;fill:var(--teal-ink,#0b6157);text-anchor:middle","Python decided at write time",[39,104],{"x":96,"y":80,"width":69,"height":70,"rx":71,"fill":97,"stroke":63},[46,106,107],{"x":100,"y":83,"style":101},"fixed — an edit does not change it",[39,109],{"x":96,"y":87,"width":69,"height":70,"rx":71,"fill":97,"stroke":63},[46,111,113],{"x":100,"y":91,"style":112},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","survives PDF and screenshots",[115,116,118],"h2",{"id":117},"prerequisites","Prerequisites",[120,121,126],"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas\n","bash","",[127,128,129],"code",{"__ignoreMap":125},[130,131,133,137,141,144],"span",{"class":58,"line":132},1,[130,134,136],{"class":135},"sMTad","pip",[130,138,140],{"class":139},"srMev"," install",[130,142,143],{"class":139}," openpyxl",[130,145,146],{"class":139}," pandas\n",[115,148,150],{"id":149},"the-built-in-duplicate-rule","The built-in duplicate rule",[10,152,153],{},"openpyxl exposes Excel's own duplicate rule, which needs no formula:",[120,155,159],{"className":156,"code":157,"language":158,"meta":125,"style":125},"language-python shiki shiki-themes github-light github-dark-high-contrast","\"\"\"Highlight every value that appears more than once in a column.\"\"\"\nfrom openpyxl import load_workbook\nfrom openpyxl.formatting.rule import Rule\nfrom openpyxl.styles import Font, PatternFill\nfrom openpyxl.styles.differential import DifferentialStyle\n\nwb = load_workbook(\"orders.xlsx\")\nws = wb[\"Orders\"]\n\npink = PatternFill(start_color=\"FFC7CE\", end_color=\"FFC7CE\", fill_type=\"solid\")\nred_text = Font(color=\"9C0006\")\nstyle = DifferentialStyle(fill=pink, font=red_text)\n\nws.conditional_formatting.add(\n    f\"A2:A{ws.max_row}\",\n    Rule(type=\"duplicateValues\", dxf=style, stopIfTrue=False),\n)\nwb.save(\"orders.xlsx\")\n","python",[127,160,161,166,183,196,209,222,229,247,264,269,311,332,359,364,370,395,431,436],{"__ignoreMap":125},[130,162,163],{"class":58,"line":132},[130,164,165],{"class":139},"\"\"\"Highlight every value that appears more than once in a column.\"\"\"\n",[130,167,169,173,177,180],{"class":58,"line":168},2,[130,170,172],{"class":171},"s-kum","from",[130,174,176],{"class":175},"skGVy"," openpyxl ",[130,178,179],{"class":171},"import",[130,181,182],{"class":175}," load_workbook\n",[130,184,186,188,191,193],{"class":58,"line":185},3,[130,187,172],{"class":171},[130,189,190],{"class":175}," openpyxl.formatting.rule ",[130,192,179],{"class":171},[130,194,195],{"class":175}," Rule\n",[130,197,199,201,204,206],{"class":58,"line":198},4,[130,200,172],{"class":171},[130,202,203],{"class":175}," openpyxl.styles ",[130,205,179],{"class":171},[130,207,208],{"class":175}," Font, PatternFill\n",[130,210,212,214,217,219],{"class":58,"line":211},5,[130,213,172],{"class":171},[130,215,216],{"class":175}," openpyxl.styles.differential ",[130,218,179],{"class":171},[130,220,221],{"class":175}," DifferentialStyle\n",[130,223,225],{"class":58,"line":224},6,[130,226,228],{"emptyLinePlaceholder":227},true,"\n",[130,230,232,235,238,241,244],{"class":58,"line":231},7,[130,233,234],{"class":175},"wb ",[130,236,237],{"class":171},"=",[130,239,240],{"class":175}," load_workbook(",[130,242,243],{"class":139},"\"orders.xlsx\"",[130,245,246],{"class":175},")\n",[130,248,250,253,255,258,261],{"class":58,"line":249},8,[130,251,252],{"class":175},"ws ",[130,254,237],{"class":171},[130,256,257],{"class":175}," wb[",[130,259,260],{"class":139},"\"Orders\"",[130,262,263],{"class":175},"]\n",[130,265,267],{"class":58,"line":266},9,[130,268,228],{"emptyLinePlaceholder":227},[130,270,272,275,277,280,284,286,289,292,295,297,299,301,304,306,309],{"class":58,"line":271},10,[130,273,274],{"class":175},"pink ",[130,276,237],{"class":171},[130,278,279],{"class":175}," PatternFill(",[130,281,283],{"class":282},"sa561","start_color",[130,285,237],{"class":171},[130,287,288],{"class":139},"\"FFC7CE\"",[130,290,291],{"class":175},", ",[130,293,294],{"class":282},"end_color",[130,296,237],{"class":171},[130,298,288],{"class":139},[130,300,291],{"class":175},[130,302,303],{"class":282},"fill_type",[130,305,237],{"class":171},[130,307,308],{"class":139},"\"solid\"",[130,310,246],{"class":175},[130,312,314,317,319,322,325,327,330],{"class":58,"line":313},11,[130,315,316],{"class":175},"red_text ",[130,318,237],{"class":171},[130,320,321],{"class":175}," Font(",[130,323,324],{"class":282},"color",[130,326,237],{"class":171},[130,328,329],{"class":139},"\"9C0006\"",[130,331,246],{"class":175},[130,333,335,338,340,343,346,348,351,354,356],{"class":58,"line":334},12,[130,336,337],{"class":175},"style ",[130,339,237],{"class":171},[130,341,342],{"class":175}," DifferentialStyle(",[130,344,345],{"class":282},"fill",[130,347,237],{"class":171},[130,349,350],{"class":175},"pink, ",[130,352,353],{"class":282},"font",[130,355,237],{"class":171},[130,357,358],{"class":175},"red_text)\n",[130,360,362],{"class":58,"line":361},13,[130,363,228],{"emptyLinePlaceholder":227},[130,365,367],{"class":58,"line":366},14,[130,368,369],{"class":175},"ws.conditional_formatting.add(\n",[130,371,373,376,379,383,386,389,392],{"class":58,"line":372},15,[130,374,375],{"class":171},"    f",[130,377,378],{"class":139},"\"A2:A",[130,380,382],{"class":381},"sSjpA","{",[130,384,385],{"class":175},"ws.max_row",[130,387,388],{"class":381},"}",[130,390,391],{"class":139},"\"",[130,393,394],{"class":175},",\n",[130,396,398,401,404,406,409,411,414,416,419,422,424,428],{"class":58,"line":397},16,[130,399,400],{"class":175},"    Rule(",[130,402,403],{"class":282},"type",[130,405,237],{"class":171},[130,407,408],{"class":139},"\"duplicateValues\"",[130,410,291],{"class":175},[130,412,413],{"class":282},"dxf",[130,415,237],{"class":171},[130,417,418],{"class":175},"style, ",[130,420,421],{"class":282},"stopIfTrue",[130,423,237],{"class":171},[130,425,427],{"class":426},"sP0c6","False",[130,429,430],{"class":175},"),\n",[130,432,434],{"class":58,"line":433},17,[130,435,246],{"class":175},[130,437,439,442,444],{"class":58,"line":438},18,[130,440,441],{"class":175},"wb.save(",[130,443,243],{"class":139},[130,445,246],{"class":175},[10,447,448,449,451],{},"The colours are Excel's own \"Light Red Fill with Dark Red Text\", which readers recognise instantly — worth using rather than inventing a palette. Note the range is computed from ",[127,450,385],{},", so it covers the data and nothing else; a rule over an entire column also flags the blank cells against each other in some versions.",[115,453,455],{"id":454},"highlight-only-the-repeats-not-the-first-occurrence","Highlight only the repeats, not the first occurrence",[10,457,458,459,462],{},"The built-in rule marks every copy, including the first. Usually the first row is the one to keep and the later ones are the problem, which needs a ",[127,460,461],{},"COUNTIF"," over the rows above:",[120,464,466],{"className":156,"code":465,"language":158,"meta":125,"style":125},"from openpyxl.formatting.rule import FormulaRule\n\nws.conditional_formatting.add(\n    f\"A2:A{ws.max_row}\",\n    FormulaRule(formula=[\"COUNTIF($A$2:$A2,$A2)>1\"], fill=pink, font=red_text),\n)\n",[127,467,468,479,483,487,503,535],{"__ignoreMap":125},[130,469,470,472,474,476],{"class":58,"line":132},[130,471,172],{"class":171},[130,473,190],{"class":175},[130,475,179],{"class":171},[130,477,478],{"class":175}," FormulaRule\n",[130,480,481],{"class":58,"line":168},[130,482,228],{"emptyLinePlaceholder":227},[130,484,485],{"class":58,"line":185},[130,486,369],{"class":175},[130,488,489,491,493,495,497,499,501],{"class":58,"line":198},[130,490,375],{"class":171},[130,492,378],{"class":139},[130,494,382],{"class":381},[130,496,385],{"class":175},[130,498,388],{"class":381},[130,500,391],{"class":139},[130,502,394],{"class":175},[130,504,505,508,511,513,516,519,522,524,526,528,530,532],{"class":58,"line":211},[130,506,507],{"class":175},"    FormulaRule(",[130,509,510],{"class":282},"formula",[130,512,237],{"class":171},[130,514,515],{"class":175},"[",[130,517,518],{"class":139},"\"COUNTIF($A$2:$A2,$A2)>1\"",[130,520,521],{"class":175},"], ",[130,523,345],{"class":282},[130,525,237],{"class":171},[130,527,350],{"class":175},[130,529,353],{"class":282},[130,531,237],{"class":171},[130,533,534],{"class":175},"red_text),\n",[130,536,537],{"class":58,"line":224},[130,538,246],{"class":175},[10,540,541,542,545,546,549,550,554],{},"The anchoring is the whole trick. ",[127,543,544],{},"$A$2"," is fixed, ",[127,547,548],{},"$A2"," grows as the rule is applied down the range, so each row counts only itself and the rows above it — a first occurrence scores 1 and stays unhighlighted, while every later copy scores 2 or more. Write the formula as it would appear in the ",[551,552,553],"em",{},"top-left cell of the range",", and Excel adjusts it for the rest.",[115,556,558],{"id":557},"colour-the-whole-row","Colour the whole row",[10,560,561],{},"A highlighted cell in column A is easy to miss on a wide sheet. Apply the same test across the row, with the column anchored:",[120,563,565],{"className":156,"code":564,"language":158,"meta":125,"style":125},"from openpyxl.formatting.rule import FormulaRule\n\nlast_col = ws.cell(row=1, column=ws.max_column).column_letter\nws.conditional_formatting.add(\n    f\"A2:{last_col}{ws.max_row}\",\n    FormulaRule(formula=[f\"COUNTIF($A$2:$A${ws.max_row},$A2)>1\"], fill=pink),\n)\n",[127,566,567,577,581,609,613,636,670],{"__ignoreMap":125},[130,568,569,571,573,575],{"class":58,"line":132},[130,570,172],{"class":171},[130,572,190],{"class":175},[130,574,179],{"class":171},[130,576,478],{"class":175},[130,578,579],{"class":58,"line":168},[130,580,228],{"emptyLinePlaceholder":227},[130,582,583,586,588,591,594,596,599,601,604,606],{"class":58,"line":185},[130,584,585],{"class":175},"last_col ",[130,587,237],{"class":171},[130,589,590],{"class":175}," ws.cell(",[130,592,593],{"class":282},"row",[130,595,237],{"class":171},[130,597,598],{"class":426},"1",[130,600,291],{"class":175},[130,602,603],{"class":282},"column",[130,605,237],{"class":171},[130,607,608],{"class":175},"ws.max_column).column_letter\n",[130,610,611],{"class":58,"line":198},[130,612,369],{"class":175},[130,614,615,617,620,622,625,628,630,632,634],{"class":58,"line":211},[130,616,375],{"class":171},[130,618,619],{"class":139},"\"A2:",[130,621,382],{"class":381},[130,623,624],{"class":175},"last_col",[130,626,627],{"class":381},"}{",[130,629,385],{"class":175},[130,631,388],{"class":381},[130,633,391],{"class":139},[130,635,394],{"class":175},[130,637,638,640,642,644,646,649,652,654,656,658,661,663,665,667],{"class":58,"line":224},[130,639,507],{"class":175},[130,641,510],{"class":282},[130,643,237],{"class":171},[130,645,515],{"class":175},[130,647,648],{"class":171},"f",[130,650,651],{"class":139},"\"COUNTIF($A$2:$A$",[130,653,382],{"class":381},[130,655,385],{"class":175},[130,657,388],{"class":381},[130,659,660],{"class":139},",$A2)>1\"",[130,662,521],{"class":175},[130,664,345],{"class":282},[130,666,237],{"class":171},[130,668,669],{"class":175},"pink),\n",[130,671,672],{"class":58,"line":231},[130,673,246],{"class":175},[10,675,676,678],{},[127,677,548],{}," keeps every cell in the row testing column A, while the row number varies down the sheet. Getting the dollar signs wrong here is the single most common reason a rule \"does nothing\" — the formula ends up testing each cell against its own column.",[20,680,29,685,29,688,29,691,29,694,29,699,29,704,29,708,29,713,29,718,29,723,29,729,29,734,29,737,29,745,29,750,29,754,29,757,29,760,29,764,29,767,29,769,29,771,29,773,29,776,29,780,29,782,29,785,29,787,29,789],{"viewBox":681,"role":23,"ariaLabelledBy":682,"xmlns":27,"style":28},"0 0 760 238",[683,684],"dup2-t","dup2-d",[31,686,687],{"id":683},"What each rule highlights on the same data",[35,689,690],{"id":684},"The built-in rule marks all three copies of a repeated reference, the COUNTIF rule marks only the second and third, and the row rule extends the mark across every column.",[39,692],{"x":41,"y":41,"width":42,"height":693,"fill":44},"238",[46,695,698],{"x":60,"y":696,"style":697},"26","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","Same sheet, three rules",[46,700,593],{"x":701,"y":702,"style":703},"90","62","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:start",[46,705,707],{"x":706,"y":702,"style":703},"190","value",[46,709,712],{"x":710,"y":702,"style":711},"330","font-size:11.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","duplicateValues",[46,714,717],{"x":715,"y":702,"style":716},"500","font-size:11.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","COUNTIF above",[46,719,722],{"x":720,"y":702,"style":721},"640","font-size:11.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","whole row",[39,724],{"x":725,"y":75,"width":720,"height":726,"rx":727,"fill":728,"stroke":63},"60","34","6","#f0f2f5",[46,730,733],{"x":701,"y":731,"style":732},"96","font-size:12px;fill:var(--text,#172033);text-anchor:start","2",[46,735,736],{"x":706,"y":731,"style":732},"00417",[39,738],{"x":739,"y":740,"width":741,"height":742,"rx":743,"fill":744,"stroke":63},"326","80","120","22","4","#FFC7CE",[46,746,749],{"x":747,"y":731,"style":748},"386","font-size:11px;fill:#9C0006;text-anchor:middle","marked",[46,751,753],{"x":715,"y":731,"style":752},"font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:start","first — clean",[46,755,756],{"x":720,"y":731,"style":752},"clean",[39,758],{"x":725,"y":759,"width":720,"height":726,"rx":727,"fill":728,"stroke":63},"114",[46,761,763],{"x":701,"y":762,"style":732},"136","3",[46,765,766],{"x":706,"y":762,"style":732},"00418",[46,768,756],{"x":710,"y":762,"style":752},[46,770,756],{"x":715,"y":762,"style":752},[46,772,756],{"x":720,"y":762,"style":752},[39,774],{"x":725,"y":775,"width":720,"height":726,"rx":727,"fill":744,"stroke":63},"154",[46,777,743],{"x":701,"y":778,"style":779},"176","font-size:12px;fill:#9C0006;text-anchor:start",[46,781,736],{"x":706,"y":778,"style":779},[46,783,749],{"x":710,"y":778,"style":784},"font-size:11.5px;fill:#9C0006;text-anchor:start",[46,786,749],{"x":715,"y":778,"style":784},[46,788,722],{"x":720,"y":778,"style":784},[46,790,793],{"x":60,"y":791,"style":792},"218","font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:middle","Choose by what the reader is meant to do: review both copies, or delete the later one",[115,795,797],{"id":796},"duplicates-across-a-combination-of-columns","Duplicates across a combination of columns",[10,799,800,801,804],{},"Business duplicates are rarely one column — the same customer, the same date and the same amount is a duplicate even when the reference differs. ",[127,802,803],{},"COUNTIFS"," handles it:",[120,806,808],{"className":156,"code":807,"language":158,"meta":125,"style":125},"from openpyxl.formatting.rule import FormulaRule\n\nlast = ws.max_row\nws.conditional_formatting.add(\n    f\"A2:F{last}\",\n    FormulaRule(\n        formula=[f\"COUNTIFS($B$2:$B${last},$B2,$C$2:$C${last},$C2,$D$2:$D${last},$D2)>1\"],\n        fill=pink,\n    ),\n)\n",[127,809,810,820,824,834,838,856,861,905,915,920],{"__ignoreMap":125},[130,811,812,814,816,818],{"class":58,"line":132},[130,813,172],{"class":171},[130,815,190],{"class":175},[130,817,179],{"class":171},[130,819,478],{"class":175},[130,821,822],{"class":58,"line":168},[130,823,228],{"emptyLinePlaceholder":227},[130,825,826,829,831],{"class":58,"line":185},[130,827,828],{"class":175},"last ",[130,830,237],{"class":171},[130,832,833],{"class":175}," ws.max_row\n",[130,835,836],{"class":58,"line":198},[130,837,369],{"class":175},[130,839,840,842,845,847,850,852,854],{"class":58,"line":211},[130,841,375],{"class":171},[130,843,844],{"class":139},"\"A2:F",[130,846,382],{"class":381},[130,848,849],{"class":175},"last",[130,851,388],{"class":381},[130,853,391],{"class":139},[130,855,394],{"class":175},[130,857,858],{"class":58,"line":224},[130,859,860],{"class":175},"    FormulaRule(\n",[130,862,863,866,868,870,872,875,877,879,881,884,886,888,890,893,895,897,899,902],{"class":58,"line":231},[130,864,865],{"class":282},"        formula",[130,867,237],{"class":171},[130,869,515],{"class":175},[130,871,648],{"class":171},[130,873,874],{"class":139},"\"COUNTIFS($B$2:$B$",[130,876,382],{"class":381},[130,878,849],{"class":175},[130,880,388],{"class":381},[130,882,883],{"class":139},",$B2,$C$2:$C$",[130,885,382],{"class":381},[130,887,849],{"class":175},[130,889,388],{"class":381},[130,891,892],{"class":139},",$C2,$D$2:$D$",[130,894,382],{"class":381},[130,896,849],{"class":175},[130,898,388],{"class":381},[130,900,901],{"class":139},",$D2)>1\"",[130,903,904],{"class":175},"],\n",[130,906,907,910,912],{"class":58,"line":249},[130,908,909],{"class":282},"        fill",[130,911,237],{"class":171},[130,913,914],{"class":175},"pink,\n",[130,916,917],{"class":58,"line":266},[130,918,919],{"class":175},"    ),\n",[130,921,922],{"class":58,"line":271},[130,923,246],{"class":175},[10,925,926,927,929],{},"Keep the number of criteria small: ",[127,928,803],{}," over several columns on tens of thousands of rows is genuinely slow to recalculate, and Excel re-evaluates the whole rule on every edit.",[115,931,933],{"id":932},"or-find-them-in-python-and-paint-the-cells","Or find them in Python and paint the cells",[10,935,936],{},"When you already know which rows are duplicates — or the rule would be too slow, or the file will be exported to PDF where conditional formats do not render — compute in pandas and write a static fill:",[120,938,940],{"className":156,"code":939,"language":158,"meta":125,"style":125},"import pandas as pd\nfrom openpyxl import load_workbook\nfrom openpyxl.styles import PatternFill\n\ndf = pd.read_excel(\"orders.xlsx\", sheet_name=\"Orders\")\ndupes = df.duplicated(subset=[\"customer\", \"ordered\", \"total\"], keep=\"first\")\nprint(f\"{dupes.sum()} duplicate row(s)\")\n\nwb = load_workbook(\"orders.xlsx\")\nws = wb[\"Orders\"]\npink = PatternFill(start_color=\"FFC7CE\", end_color=\"FFC7CE\", fill_type=\"solid\")\n\nfor offset, is_dupe in enumerate(dupes, start=2):     # +2 for header and 1-based rows\n    if is_dupe:\n        for cell in ws[offset]:\n            cell.fill = pink\n\nwb.save(\"orders_flagged.xlsx\")\n",[127,941,942,955,965,976,980,1003,1045,1069,1073,1085,1097,1129,1133,1164,1172,1185,1195,1199],{"__ignoreMap":125},[130,943,944,946,949,952],{"class":58,"line":132},[130,945,179],{"class":171},[130,947,948],{"class":175}," pandas ",[130,950,951],{"class":171},"as",[130,953,954],{"class":175}," pd\n",[130,956,957,959,961,963],{"class":58,"line":168},[130,958,172],{"class":171},[130,960,176],{"class":175},[130,962,179],{"class":171},[130,964,182],{"class":175},[130,966,967,969,971,973],{"class":58,"line":185},[130,968,172],{"class":171},[130,970,203],{"class":175},[130,972,179],{"class":171},[130,974,975],{"class":175}," PatternFill\n",[130,977,978],{"class":58,"line":198},[130,979,228],{"emptyLinePlaceholder":227},[130,981,982,985,987,990,992,994,997,999,1001],{"class":58,"line":211},[130,983,984],{"class":175},"df ",[130,986,237],{"class":171},[130,988,989],{"class":175}," pd.read_excel(",[130,991,243],{"class":139},[130,993,291],{"class":175},[130,995,996],{"class":282},"sheet_name",[130,998,237],{"class":171},[130,1000,260],{"class":139},[130,1002,246],{"class":175},[130,1004,1005,1008,1010,1013,1016,1018,1020,1023,1025,1028,1030,1033,1035,1038,1040,1043],{"class":58,"line":224},[130,1006,1007],{"class":175},"dupes ",[130,1009,237],{"class":171},[130,1011,1012],{"class":175}," df.duplicated(",[130,1014,1015],{"class":282},"subset",[130,1017,237],{"class":171},[130,1019,515],{"class":175},[130,1021,1022],{"class":139},"\"customer\"",[130,1024,291],{"class":175},[130,1026,1027],{"class":139},"\"ordered\"",[130,1029,291],{"class":175},[130,1031,1032],{"class":139},"\"total\"",[130,1034,521],{"class":175},[130,1036,1037],{"class":282},"keep",[130,1039,237],{"class":171},[130,1041,1042],{"class":139},"\"first\"",[130,1044,246],{"class":175},[130,1046,1047,1050,1053,1055,1057,1059,1062,1064,1067],{"class":58,"line":231},[130,1048,1049],{"class":426},"print",[130,1051,1052],{"class":175},"(",[130,1054,648],{"class":171},[130,1056,391],{"class":139},[130,1058,382],{"class":381},[130,1060,1061],{"class":175},"dupes.sum()",[130,1063,388],{"class":381},[130,1065,1066],{"class":139}," duplicate row(s)\"",[130,1068,246],{"class":175},[130,1070,1071],{"class":58,"line":249},[130,1072,228],{"emptyLinePlaceholder":227},[130,1074,1075,1077,1079,1081,1083],{"class":58,"line":266},[130,1076,234],{"class":175},[130,1078,237],{"class":171},[130,1080,240],{"class":175},[130,1082,243],{"class":139},[130,1084,246],{"class":175},[130,1086,1087,1089,1091,1093,1095],{"class":58,"line":271},[130,1088,252],{"class":175},[130,1090,237],{"class":171},[130,1092,257],{"class":175},[130,1094,260],{"class":139},[130,1096,263],{"class":175},[130,1098,1099,1101,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121,1123,1125,1127],{"class":58,"line":313},[130,1100,274],{"class":175},[130,1102,237],{"class":171},[130,1104,279],{"class":175},[130,1106,283],{"class":282},[130,1108,237],{"class":171},[130,1110,288],{"class":139},[130,1112,291],{"class":175},[130,1114,294],{"class":282},[130,1116,237],{"class":171},[130,1118,288],{"class":139},[130,1120,291],{"class":175},[130,1122,303],{"class":282},[130,1124,237],{"class":171},[130,1126,308],{"class":139},[130,1128,246],{"class":175},[130,1130,1131],{"class":58,"line":334},[130,1132,228],{"emptyLinePlaceholder":227},[130,1134,1135,1138,1141,1144,1147,1150,1153,1155,1157,1160],{"class":58,"line":361},[130,1136,1137],{"class":171},"for",[130,1139,1140],{"class":175}," offset, is_dupe ",[130,1142,1143],{"class":171},"in",[130,1145,1146],{"class":426}," enumerate",[130,1148,1149],{"class":175},"(dupes, ",[130,1151,1152],{"class":282},"start",[130,1154,237],{"class":171},[130,1156,733],{"class":426},[130,1158,1159],{"class":175},"):     ",[130,1161,1163],{"class":1162},"s-wDw","# +2 for header and 1-based rows\n",[130,1165,1166,1169],{"class":58,"line":366},[130,1167,1168],{"class":171},"    if",[130,1170,1171],{"class":175}," is_dupe:\n",[130,1173,1174,1177,1180,1182],{"class":58,"line":372},[130,1175,1176],{"class":171},"        for",[130,1178,1179],{"class":175}," cell ",[130,1181,1143],{"class":171},[130,1183,1184],{"class":175}," ws[offset]:\n",[130,1186,1187,1190,1192],{"class":58,"line":397},[130,1188,1189],{"class":175},"            cell.fill ",[130,1191,237],{"class":171},[130,1193,1194],{"class":175}," pink\n",[130,1196,1197],{"class":58,"line":433},[130,1198,228],{"emptyLinePlaceholder":227},[130,1200,1201,1203,1206],{"class":58,"line":438},[130,1202,441],{"class":175},[130,1204,1205],{"class":139},"\"orders_flagged.xlsx\"",[130,1207,246],{"class":175},[10,1209,1210,1213,1214,1216,1217,18],{},[127,1211,1212],{},"keep=\"first\""," marks the later copies only, matching the ",[127,1215,461],{}," behaviour above. This route also lets you report the count in a log or an email, which a conditional rule cannot do — the detection side is covered in ",[14,1218,1220],{"href":1219},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Ffind-duplicate-rows-in-excel-with-python\u002F","Find duplicate rows in Excel with Python",[115,1222,1224],{"id":1223},"add-a-summary-the-reader-sees-first","Add a summary the reader sees first",[10,1226,1227],{},"Highlighting helps someone already looking at the right sheet. A count at the top tells them whether to look at all:",[120,1229,1231],{"className":156,"code":1230,"language":158,"meta":125,"style":125},"ws[\"H1\"] = f\"Duplicate rows: {int(dupes.sum())}\"\nws[\"H1\"].font = Font(bold=True, color=\"9C0006\" if dupes.any() else \"0B6157\")\n",[127,1232,1233,1265],{"__ignoreMap":125},[130,1234,1235,1238,1241,1244,1246,1249,1252,1254,1257,1260,1262],{"class":58,"line":132},[130,1236,1237],{"class":175},"ws[",[130,1239,1240],{"class":139},"\"H1\"",[130,1242,1243],{"class":175},"] ",[130,1245,237],{"class":171},[130,1247,1248],{"class":171}," f",[130,1250,1251],{"class":139},"\"Duplicate rows: ",[130,1253,382],{"class":381},[130,1255,1256],{"class":426},"int",[130,1258,1259],{"class":175},"(dupes.sum())",[130,1261,388],{"class":381},[130,1263,1264],{"class":139},"\"\n",[130,1266,1267,1269,1271,1274,1276,1278,1281,1283,1286,1288,1290,1292,1294,1297,1300,1303,1306],{"class":58,"line":168},[130,1268,1237],{"class":175},[130,1270,1240],{"class":139},[130,1272,1273],{"class":175},"].font ",[130,1275,237],{"class":171},[130,1277,321],{"class":175},[130,1279,1280],{"class":282},"bold",[130,1282,237],{"class":171},[130,1284,1285],{"class":426},"True",[130,1287,291],{"class":175},[130,1289,324],{"class":282},[130,1291,237],{"class":171},[130,1293,329],{"class":139},[130,1295,1296],{"class":171}," if",[130,1298,1299],{"class":175}," dupes.any() ",[130,1301,1302],{"class":171},"else",[130,1304,1305],{"class":139}," \"0B6157\"",[130,1307,246],{"class":175},[10,1309,1310,1311,18],{},"Pair it with a summary sheet when the workbook has several tabs, as in ",[14,1312,1314],{"href":1313},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-summary-sheet-to-excel-report-python\u002F","Add a summary sheet to an Excel report with Python",[115,1316,1318],{"id":1317},"check-the-rule-actually-landed","Check the rule actually landed",[10,1320,1321],{},"A conditional format is written into the file rather than applied to it, so the only way to be sure is to read the rules back:",[120,1323,1325],{"className":156,"code":1324,"language":158,"meta":125,"style":125},"from openpyxl import load_workbook\n\nwb = load_workbook(\"orders.xlsx\")\nws = wb[\"Orders\"]\n\nfor rng in ws.conditional_formatting:\n    for rule in rng.rules:\n        print(rng.sqref, rule.type, getattr(rule, \"formula\", \"\"))\n",[127,1326,1327,1337,1341,1353,1365,1369,1381,1394],{"__ignoreMap":125},[130,1328,1329,1331,1333,1335],{"class":58,"line":132},[130,1330,172],{"class":171},[130,1332,176],{"class":175},[130,1334,179],{"class":171},[130,1336,182],{"class":175},[130,1338,1339],{"class":58,"line":168},[130,1340,228],{"emptyLinePlaceholder":227},[130,1342,1343,1345,1347,1349,1351],{"class":58,"line":185},[130,1344,234],{"class":175},[130,1346,237],{"class":171},[130,1348,240],{"class":175},[130,1350,243],{"class":139},[130,1352,246],{"class":175},[130,1354,1355,1357,1359,1361,1363],{"class":58,"line":198},[130,1356,252],{"class":175},[130,1358,237],{"class":171},[130,1360,257],{"class":175},[130,1362,260],{"class":139},[130,1364,263],{"class":175},[130,1366,1367],{"class":58,"line":211},[130,1368,228],{"emptyLinePlaceholder":227},[130,1370,1371,1373,1376,1378],{"class":58,"line":224},[130,1372,1137],{"class":171},[130,1374,1375],{"class":175}," rng ",[130,1377,1143],{"class":171},[130,1379,1380],{"class":175}," ws.conditional_formatting:\n",[130,1382,1383,1386,1389,1391],{"class":58,"line":231},[130,1384,1385],{"class":171},"    for",[130,1387,1388],{"class":175}," rule ",[130,1390,1143],{"class":171},[130,1392,1393],{"class":175}," rng.rules:\n",[130,1395,1396,1399,1402,1405,1408,1411,1413,1416],{"class":58,"line":249},[130,1397,1398],{"class":426},"        print",[130,1400,1401],{"class":175},"(rng.sqref, rule.type, ",[130,1403,1404],{"class":426},"getattr",[130,1406,1407],{"class":175},"(rule, ",[130,1409,1410],{"class":139},"\"formula\"",[130,1412,291],{"class":175},[130,1414,1415],{"class":139},"\"\"",[130,1417,1418],{"class":175},"))\n",[120,1420,1424],{"className":1421,"code":1423,"language":46,"meta":125},[1422],"language-text","A2:A501 duplicateValues []\nA2:F501 expression ['COUNTIF($A$2:$A$501,$A2)>1']\n",[127,1425,1423],{"__ignoreMap":125},[10,1427,1428,1429,1431,1432,1435],{},"Two things to look for. The range must cover the rows the data actually occupies — a rule ending at row 501 on a sheet with 900 rows silently ignores the rest. And a rule whose ",[127,1430,403],{}," is ",[127,1433,1434],{},"expression"," must carry a formula; an empty list means the rule was constructed without one and Excel will ignore it entirely.",[20,1437,29,1442,29,1445,29,1448,29,1451,29,1454,29,1459,29,1464,29,1469,29,1473,29,1475,29,1478,29,1481],{"viewBox":1438,"role":23,"ariaLabelledBy":1439,"xmlns":27,"style":28},"0 0 760 200",[1440,1441],"dup3-t","dup3-d",[31,1443,1444],{"id":1440},"Two ways a duplicate rule silently does nothing",[35,1446,1447],{"id":1441},"A rule whose range stops short of the data ignores later rows, and a formula rule anchored to the wrong cell tests each cell against its own column instead of the key column.",[39,1449],{"x":41,"y":41,"width":42,"height":1450,"fill":44},"200",[46,1452,1453],{"x":60,"y":696,"style":697},"Both look correct in the code",[39,1455],{"x":67,"y":68,"width":69,"height":1456,"rx":1457,"fill":1458,"stroke":63},"122","12","#fee8f2",[46,1460,1463],{"x":48,"y":1461,"style":1462},"78","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","range stops short",[46,1465,1468],{"x":48,"y":1466,"style":1467},"108","font-size:11.5px;fill:var(--text,#172033);text-anchor:middle","A2:A501 on 900 rows",[46,1470,1472],{"x":48,"y":762,"style":1471},"font-size:11.5px;fill:var(--accent-ink,#be185d);text-anchor:middle","rows 502+ never checked",[39,1474],{"x":96,"y":68,"width":69,"height":1456,"rx":1457,"fill":1458,"stroke":63},[46,1476,1477],{"x":100,"y":1461,"style":1462},"wrong anchor",[46,1479,1480],{"x":100,"y":1466,"style":1467},"A2 instead of $A2",[46,1482,1483],{"x":100,"y":762,"style":1471},"each column tests itself",[10,1485,1486,1487,18],{},"Add the read-back to the report job's own checks and both failures become impossible to ship — the same pre-flight idea as ",[14,1488,1490],{"href":1489},"\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",[115,1492,1494],{"id":1493},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[1496,1497,1498,1512,1521,1535,1554],"ul",{},[1499,1500,1501,1505,1506,1508,1509,1511],"li",{},[1502,1503,1504],"strong",{},"Wrong anchors."," Write the formula for the top-left cell of the range; ",[127,1507,548],{}," for a row test, ",[127,1510,544],{}," for a fixed corner.",[1499,1513,1514,1517,1518,1520],{},[1502,1515,1516],{},"A range that misses new rows."," Compute it from ",[127,1519,385],{}," at write time, or apply it to the table's range so it grows with the data.",[1499,1522,1523,1526,1527,1530,1531,1534],{},[1502,1524,1525],{},"Whitespace hiding duplicates."," ",[127,1528,1529],{},"\"00417 \""," and ",[127,1532,1533],{},"\"00417\""," are different values to Excel; normalise text before writing.",[1499,1536,1537,1526,1540,1542,1543,1530,1546,1549,1550,1553],{},[1502,1538,1539],{},"Case sensitivity.",[127,1541,461],{}," is case-insensitive, so ",[127,1544,1545],{},"ACME",[127,1547,1548],{},"Acme"," count as the same; pandas' ",[127,1551,1552],{},"duplicated"," is case-sensitive. The two approaches can disagree.",[1499,1555,1556,1559],{},[1502,1557,1558],{},"PDF export."," Conditional formats are applied by Excel at display time; a static fill is safer when the destination is a PDF.",[115,1561,1563],{"id":1562},"performance-and-scale-notes","Performance and scale notes",[10,1565,1566,1567,1569],{},"Conditional formatting rules cost nothing to write and are evaluated by Excel on the reader's machine, which is exactly where the cost lands: a ",[127,1568,461],{}," rule over 100,000 rows makes the workbook sluggish to edit, because every keystroke re-evaluates it. Above a few thousand rows, prefer the pandas route and a static fill — the detection is a single vectorised pass and the resulting file is inert. If the sheet must stay interactive, restrict the rule's range to the columns that matter and consider sorting so duplicates are adjacent, which makes them visible without any formatting at all.",[115,1571,1573],{"id":1572},"conclusion","Conclusion",[10,1575,1576,1577,1579,1580,1582],{},"Excel's built-in duplicate rule is one call and marks every copy; a ",[127,1578,461],{}," rule anchored to the rows above marks only the repeats, and extending it across the row makes them visible on a wide sheet. When the duplicate definition spans columns, ",[127,1581,803],{}," expresses it — but past a few thousand rows, find the duplicates in pandas and write a static fill instead, so the workbook stays fast and the marks survive a PDF export.",[115,1584,1586],{"id":1585},"frequently-asked-questions","Frequently asked questions",[10,1588,1589,1592,1593,1595,1596,1598],{},[1502,1590,1591],{},"What is the difference between the built-in rule and a COUNTIF rule?","\nThe built-in ",[127,1594,712],{}," rule highlights every cell whose value appears more than once in the range, and Excel evaluates it. A ",[127,1597,461],{}," formula rule can do more — highlight only the second and later copies, span several columns, or colour the whole row.",[10,1600,1601,1604],{},[1502,1602,1603],{},"Does openpyxl detect the duplicates itself?","\nNo. It writes a rule into the file and Excel applies it when the workbook opens. If you need the duplicates in Python, find them with pandas and write a static fill instead.",[10,1606,1607,1610,1611,1614,1615,1618],{},[1502,1608,1609],{},"How do I highlight the whole row, not just the cell?","\nApply a formula rule across the row range with the column reference anchored — for example ",[127,1612,1613],{},"=COUNTIF($A:$A,$A2)>1"," applied to ",[127,1616,1617],{},"A2:F500",". The dollar sign fixes the column so every cell in the row evaluates the same test.",[10,1620,1621,1624],{},[1502,1622,1623],{},"Why is nothing highlighted when I open the file?","\nThe usual causes are a range that does not include the data, a formula written with the wrong anchor for the top-left cell of the range, or a rule added to a worksheet that was then replaced.",[10,1626,1627,1630,1631,1633],{},[1502,1628,1629],{},"Can I highlight duplicates across two sheets?","\nNot reliably with a plain ",[127,1632,461],{}," against another sheet. It is more dependable to compute the comparison in pandas and write a static fill.",[115,1635,1637],{"id":1636},"related","Related",[1496,1639,1640,1648,1655,1660,1667],{},[1499,1641,1642,1526,1645,1647],{},[1502,1643,1644],{},"Up:",[14,1646,17],{"href":16}," — the full rule vocabulary.",[1499,1649,1650,1654],{},[14,1651,1653],{"href":1652},"\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"," — the simplest rule type, in detail.",[1499,1656,1657,1659],{},[14,1658,1220],{"href":1219}," — detecting duplicates rather than displaying them.",[1499,1661,1662,1666],{},[14,1663,1665],{"href":1664},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fpandas-drop-duplicates-from-excel-column\u002F","pandas drop_duplicates from an Excel column"," — removing them once they are confirmed.",[1499,1668,1669,1673],{},[14,1670,1672],{"href":1671},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fhighlight-invalid-cells-in-excel-with-python\u002F","Highlight invalid cells in Excel with Python"," — the same marking technique for validation failures.",[1675,1676,1677],"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 .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}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":125,"searchDepth":168,"depth":168,"links":1679},[1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692],{"id":117,"depth":168,"text":118},{"id":149,"depth":168,"text":150},{"id":454,"depth":168,"text":455},{"id":557,"depth":168,"text":558},{"id":796,"depth":168,"text":797},{"id":932,"depth":168,"text":933},{"id":1223,"depth":168,"text":1224},{"id":1317,"depth":168,"text":1318},{"id":1493,"depth":168,"text":1494},{"id":1562,"depth":168,"text":1563},{"id":1572,"depth":168,"text":1573},{"id":1585,"depth":168,"text":1586},{"id":1636,"depth":168,"text":1637},"2026-08-27","Flag repeated values in a worksheet: the built-in duplicateValues rule, formula rules for duplicates across columns, whole-row highlighting, and a pandas alternative.","md",[1697,1699,1701,1703,1705],{"q":1591,"a":1698},"The built-in duplicateValues rule highlights every cell whose value appears more than once in the range, and Excel evaluates it. A COUNTIF formula rule can do more — highlight only the second and later copies, span several columns, or colour the whole row.",{"q":1603,"a":1700},"No. It writes a rule into the file and Excel applies it when the workbook opens. If you need the duplicates in Python, find them with pandas and write a static fill instead.",{"q":1609,"a":1702},"Apply a formula rule across the row range with the column reference anchored — for example =COUNTIF($A:$A,$A2)>1 applied to A2:F500. The dollar sign fixes the column so every cell in the row evaluates the same test.",{"q":1623,"a":1704},"The usual causes are a range that does not include the data, a formula written with the wrong anchor for the top-left cell of the range, or a rule added to a worksheet that was then replaced.",{"q":1629,"a":1706},"Not with a plain COUNTIF against another sheet in older Excel versions. It is more reliable to compute the comparison in pandas and write a static fill.",{},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl",{"title":1710,"description":1711},"Highlight Duplicates in Excel with openpyxl","Use openpyxl conditional formatting to highlight duplicate values: the duplicateValues rule, COUNTIF formula rules, whole-row banding, and marking first versus later copies.","highlight-duplicate-values-in-excel-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-duplicate-values-in-excel-with-openpyxl\u002Findex","how-to","yqqvhQidYeeghSErOH2L1wqntOtxGPgW70T_PYKSIBQ",[1717,1721],{"title":1718,"path":1719,"stem":1720,"children":-1},"Highlight Cells Above a Threshold with openpyxl","\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-above-a-threshold-with-openpyxl","advanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-above-a-threshold-with-openpyxl\u002Findex",{"title":1722,"path":1723,"stem":1724,"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",1788710162517]