[{"data":1,"prerenderedAt":2294},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl":2263,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl":2270,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl":2274,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl":2275},{"id":4,"title":5,"body":6,"dateModified":2228,"datePublished":2228,"description":2229,"extension":2230,"faq":2231,"keyword":2240,"kind":2241,"meta":2242,"navigation":295,"path":2251,"seo":2252,"slug":2255,"stem":2256,"topics":2257,"type":2261,"__hash__":2262},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl\u002Findex.md","Add Alternating Row Colors with openpyxl",{"type":7,"value":8,"toc":2215},"minimark",[9,19,207,212,238,241,571,575,578,727,730,734,746,800,803,1114,1118,1128,1225,1237,1241,1244,1362,1390,1394,1397,1669,1672,1786,1790,1801,2069,2080,2084,2129,2133,2147,2151,2160,2166,2172,2178,2182,2211],[10,11,12,13,18],"p",{},"A long list of rows is hard to read across: the eye slips from one row to the next halfway along. Banded rows — a light shade on every other row — fix that, which is why every table style in Excel has them. From Python there are several ways to add them, and the obvious one, filling every second row, is the one that breaks first: readers sort the sheet and the stripes scramble. This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl",", compares the approaches and shows the ones that keep working after sorting, inserting and filtering, all checked by rendering the workbook.",[20,21,29,30,29,34,29,38,29,46,29,54,29,61,29,68,29,71,29,75,29,78,29,82,29,87,29,93,29,95,29,106,29,108,29,113,29,115,29,120,29,123,29,127,29,129,29,137,29,139,29,144,29,146,29,151,29,154,29,158,29,160,29,165,29,167,29,172,29,174,29,179,29,182,29,186,29,188,29,193,29,195,29,200,29,202],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"4 0 752 208","img",[25,26],"ab-approaches-t","ab-approaches-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  ",[31,32,33],"title",{"id":25},"Which banding survives what readers do",[35,36,37],"desc",{"id":26},"Static fills break when rows are sorted, inserted or filtered. A MOD ROW conditional format survives sorting and inserting but breaks when rows are filtered or hidden. A SUBTOTAL 103 rule survives all three. Table stripes survive all three but require the data to be an Excel table.",[39,40],"rect",{"x":41,"y":42,"width":43,"height":44,"fill":45},"4","0","752","208","#ffffff",[39,47],{"x":48,"y":49,"width":50,"height":51,"rx":42,"fill":45,"stroke":52,"style":53},"20.0","16.0","178.2","40.0","var(--line,#cdd5e6)","stroke-width:1px",[39,55],{"x":56,"y":49,"width":57,"height":51,"rx":42,"fill":58,"stroke":59,"style":60},"198.2","180.6","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.2px",[62,63,67],"text",{"x":64,"y":65,"style":66},"288.5","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Sort",[39,69],{"x":70,"y":49,"width":57,"height":51,"rx":42,"fill":58,"stroke":59,"style":60},"378.8",[62,72,74],{"x":73,"y":65,"style":66},"469.1","Insert rows",[39,76],{"x":77,"y":49,"width":57,"height":51,"rx":42,"fill":58,"stroke":59,"style":60},"559.4",[62,79,81],{"x":80,"y":65,"style":66},"649.7","Filter",[39,83],{"x":48,"y":84,"width":50,"height":85,"rx":42,"fill":86,"stroke":52,"style":53},"56.0","34.0","#e7ebef",[62,88,92],{"x":89,"y":90,"style":91},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Static fill per row",[39,94],{"x":56,"y":84,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,97,99],"g",{"transform":98},"translate(280.5,65.0) scale(0.667)",[100,101],"path",{"d":102,"fill":103,"stroke":104,"style":105},"M6 6l12 12 M18 6L6 18","none","var(--accent,#f43f8f)","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[39,107],{"x":70,"y":84,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,109,111],{"transform":110},"translate(461.1,65.0) scale(0.667)",[100,112],{"d":102,"fill":103,"stroke":104,"style":105},[39,114],{"x":77,"y":84,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,116,118],{"transform":117},"translate(641.7,65.0) scale(0.667)",[100,119],{"d":102,"fill":103,"stroke":104,"style":105},[39,121],{"x":48,"y":122,"width":50,"height":85,"rx":42,"fill":86,"stroke":52,"style":53},"90.0",[62,124,126],{"x":89,"y":125,"style":91},"112.0","MOD(ROW(),2) rule",[39,128],{"x":56,"y":122,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,130,132],{"transform":131},"translate(279.5,98.0) scale(0.750)",[100,133],{"d":134,"fill":103,"stroke":135,"style":136},"M5 12.5l4.5 4.5L19 7","var(--teal,#0f9488)","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[39,138],{"x":70,"y":122,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,140,142],{"transform":141},"translate(460.1,98.0) scale(0.750)",[100,143],{"d":134,"fill":103,"stroke":135,"style":136},[39,145],{"x":77,"y":122,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,147,149],{"transform":148},"translate(641.7,99.0) scale(0.667)",[100,150],{"d":102,"fill":103,"stroke":104,"style":105},[39,152],{"x":48,"y":153,"width":50,"height":85,"rx":42,"fill":86,"stroke":52,"style":53},"124.0",[62,155,157],{"x":89,"y":156,"style":91},"146.0","SUBTOTAL(103,…) rule",[39,159],{"x":56,"y":153,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,161,163],{"transform":162},"translate(279.5,132.0) scale(0.750)",[100,164],{"d":134,"fill":103,"stroke":135,"style":136},[39,166],{"x":70,"y":153,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,168,170],{"transform":169},"translate(460.1,132.0) scale(0.750)",[100,171],{"d":134,"fill":103,"stroke":135,"style":136},[39,173],{"x":77,"y":153,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,175,177],{"transform":176},"translate(640.7,132.0) scale(0.750)",[100,178],{"d":134,"fill":103,"stroke":135,"style":136},[39,180],{"x":48,"y":181,"width":50,"height":85,"rx":42,"fill":86,"stroke":52,"style":53},"158.0",[62,183,185],{"x":89,"y":184,"style":91},"180.0","Table showRowStripes",[39,187],{"x":56,"y":181,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,189,191],{"transform":190},"translate(279.5,166.0) scale(0.750)",[100,192],{"d":134,"fill":103,"stroke":135,"style":136},[39,194],{"x":70,"y":181,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,196,198],{"transform":197},"translate(460.1,166.0) scale(0.750)",[100,199],{"d":134,"fill":103,"stroke":135,"style":136},[39,201],{"x":77,"y":181,"width":57,"height":85,"rx":42,"fill":45,"stroke":52,"style":53},[96,203,205],{"transform":204},"translate(640.7,166.0) scale(0.750)",[100,206],{"d":134,"fill":103,"stroke":135,"style":136},[208,209,211],"h2",{"id":210},"prerequisites","Prerequisites",[213,214,219],"pre",{"className":215,"code":216,"language":217,"meta":218,"style":218},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[220,221,222],"code",{"__ignoreMap":218},[223,224,227,231,235],"span",{"class":225,"line":226},"line",1,[223,228,230],{"class":229},"sMTad","pip",[223,232,234],{"class":233},"srMev"," install",[223,236,237],{"class":233}," openpyxl\n",[10,239,240],{},"An order list to band:",[213,242,246],{"className":243,"code":244,"language":245,"meta":218,"style":218},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.formatting.rule import FormulaRule\nfrom openpyxl.styles import PatternFill\n\nORDERS = [(101, \"North\", 120), (102, \"South\", 90), (103, \"North\", 75), (104, \"East\", 640),\n          (105, \"South\", 820), (106, \"North\", 310), (107, \"West\", 150), (108, \"East\", 60)]\nBAND = PatternFill(\"solid\", fgColor=\"E7EBEF\")\n\ndef orders_sheet(wb, title):\n    ws = wb.create_sheet(title)\n    ws.append([\"Order\", \"Region\", \"Amount\"])\n    for row in ORDERS:\n        ws.append(row)\n    return ws\n\nwb = Workbook()\nwb.remove(wb.active)\n","python",[220,247,248,264,277,290,297,372,436,465,470,483,494,516,534,540,549,554,565],{"__ignoreMap":218},[223,249,250,254,258,261],{"class":225,"line":226},[223,251,253],{"class":252},"s-kum","from",[223,255,257],{"class":256},"skGVy"," openpyxl ",[223,259,260],{"class":252},"import",[223,262,263],{"class":256}," Workbook\n",[223,265,267,269,272,274],{"class":225,"line":266},2,[223,268,253],{"class":252},[223,270,271],{"class":256}," openpyxl.formatting.rule ",[223,273,260],{"class":252},[223,275,276],{"class":256}," FormulaRule\n",[223,278,280,282,285,287],{"class":225,"line":279},3,[223,281,253],{"class":252},[223,283,284],{"class":256}," openpyxl.styles ",[223,286,260],{"class":252},[223,288,289],{"class":256}," PatternFill\n",[223,291,293],{"class":225,"line":292},4,[223,294,296],{"emptyLinePlaceholder":295},true,"\n",[223,298,300,304,307,310,313,316,319,321,324,327,330,332,335,337,340,342,345,347,349,351,354,356,359,361,364,366,369],{"class":225,"line":299},5,[223,301,303],{"class":302},"sP0c6","ORDERS",[223,305,306],{"class":252}," =",[223,308,309],{"class":256}," [(",[223,311,312],{"class":302},"101",[223,314,315],{"class":256},", ",[223,317,318],{"class":233},"\"North\"",[223,320,315],{"class":256},[223,322,323],{"class":302},"120",[223,325,326],{"class":256},"), (",[223,328,329],{"class":302},"102",[223,331,315],{"class":256},[223,333,334],{"class":233},"\"South\"",[223,336,315],{"class":256},[223,338,339],{"class":302},"90",[223,341,326],{"class":256},[223,343,344],{"class":302},"103",[223,346,315],{"class":256},[223,348,318],{"class":233},[223,350,315],{"class":256},[223,352,353],{"class":302},"75",[223,355,326],{"class":256},[223,357,358],{"class":302},"104",[223,360,315],{"class":256},[223,362,363],{"class":233},"\"East\"",[223,365,315],{"class":256},[223,367,368],{"class":302},"640",[223,370,371],{"class":256},"),\n",[223,373,375,378,381,383,385,387,390,392,395,397,399,401,404,406,409,411,414,416,419,421,424,426,428,430,433],{"class":225,"line":374},6,[223,376,377],{"class":256},"          (",[223,379,380],{"class":302},"105",[223,382,315],{"class":256},[223,384,334],{"class":233},[223,386,315],{"class":256},[223,388,389],{"class":302},"820",[223,391,326],{"class":256},[223,393,394],{"class":302},"106",[223,396,315],{"class":256},[223,398,318],{"class":233},[223,400,315],{"class":256},[223,402,403],{"class":302},"310",[223,405,326],{"class":256},[223,407,408],{"class":302},"107",[223,410,315],{"class":256},[223,412,413],{"class":233},"\"West\"",[223,415,315],{"class":256},[223,417,418],{"class":302},"150",[223,420,326],{"class":256},[223,422,423],{"class":302},"108",[223,425,315],{"class":256},[223,427,363],{"class":233},[223,429,315],{"class":256},[223,431,432],{"class":302},"60",[223,434,435],{"class":256},")]\n",[223,437,439,442,444,447,450,452,456,459,462],{"class":225,"line":438},7,[223,440,441],{"class":302},"BAND",[223,443,306],{"class":252},[223,445,446],{"class":256}," PatternFill(",[223,448,449],{"class":233},"\"solid\"",[223,451,315],{"class":256},[223,453,455],{"class":454},"sa561","fgColor",[223,457,458],{"class":252},"=",[223,460,461],{"class":233},"\"E7EBEF\"",[223,463,464],{"class":256},")\n",[223,466,468],{"class":225,"line":467},8,[223,469,296],{"emptyLinePlaceholder":295},[223,471,473,476,480],{"class":225,"line":472},9,[223,474,475],{"class":252},"def",[223,477,479],{"class":478},"s_Opv"," orders_sheet",[223,481,482],{"class":256},"(wb, title):\n",[223,484,486,489,491],{"class":225,"line":485},10,[223,487,488],{"class":256},"    ws ",[223,490,458],{"class":252},[223,492,493],{"class":256}," wb.create_sheet(title)\n",[223,495,497,500,503,505,508,510,513],{"class":225,"line":496},11,[223,498,499],{"class":256},"    ws.append([",[223,501,502],{"class":233},"\"Order\"",[223,504,315],{"class":256},[223,506,507],{"class":233},"\"Region\"",[223,509,315],{"class":256},[223,511,512],{"class":233},"\"Amount\"",[223,514,515],{"class":256},"])\n",[223,517,519,522,525,528,531],{"class":225,"line":518},12,[223,520,521],{"class":252},"    for",[223,523,524],{"class":256}," row ",[223,526,527],{"class":252},"in",[223,529,530],{"class":302}," ORDERS",[223,532,533],{"class":256},":\n",[223,535,537],{"class":225,"line":536},13,[223,538,539],{"class":256},"        ws.append(row)\n",[223,541,543,546],{"class":225,"line":542},14,[223,544,545],{"class":252},"    return",[223,547,548],{"class":256}," ws\n",[223,550,552],{"class":225,"line":551},15,[223,553,296],{"emptyLinePlaceholder":295},[223,555,557,560,562],{"class":225,"line":556},16,[223,558,559],{"class":256},"wb ",[223,561,458],{"class":252},[223,563,564],{"class":256}," Workbook()\n",[223,566,568],{"class":225,"line":567},17,[223,569,570],{"class":256},"wb.remove(wb.active)\n",[208,572,574],{"id":573},"step-1-static-fills-and-why-they-break","Step 1 — Static fills, and why they break",[10,576,577],{},"Filling every even row directly is the first thing most people write:",[213,579,581],{"className":243,"code":580,"language":245,"meta":218,"style":218},"static = orders_sheet(wb, \"Static\")\nfor row in static.iter_rows(min_row=2):\n    if row[0].row % 2 == 0:\n        for cell in row:\n            cell.fill = BAND\nprint([r for r in range(2, 10) if static.cell(r, 1).fill.fgColor.rgb == \"00E7EBEF\"])   # [2, 4, 6, 8]\n",[220,582,583,598,621,648,661,671],{"__ignoreMap":218},[223,584,585,588,590,593,596],{"class":225,"line":226},[223,586,587],{"class":256},"static ",[223,589,458],{"class":252},[223,591,592],{"class":256}," orders_sheet(wb, ",[223,594,595],{"class":233},"\"Static\"",[223,597,464],{"class":256},[223,599,600,603,605,607,610,613,615,618],{"class":225,"line":266},[223,601,602],{"class":252},"for",[223,604,524],{"class":256},[223,606,527],{"class":252},[223,608,609],{"class":256}," static.iter_rows(",[223,611,612],{"class":454},"min_row",[223,614,458],{"class":252},[223,616,617],{"class":302},"2",[223,619,620],{"class":256},"):\n",[223,622,623,626,629,631,634,637,640,643,646],{"class":225,"line":279},[223,624,625],{"class":252},"    if",[223,627,628],{"class":256}," row[",[223,630,42],{"class":302},[223,632,633],{"class":256},"].row ",[223,635,636],{"class":252},"%",[223,638,639],{"class":302}," 2",[223,641,642],{"class":252}," ==",[223,644,645],{"class":302}," 0",[223,647,533],{"class":256},[223,649,650,653,656,658],{"class":225,"line":292},[223,651,652],{"class":252},"        for",[223,654,655],{"class":256}," cell ",[223,657,527],{"class":252},[223,659,660],{"class":256}," row:\n",[223,662,663,666,668],{"class":225,"line":299},[223,664,665],{"class":256},"            cell.fill ",[223,667,458],{"class":252},[223,669,670],{"class":302}," BAND\n",[223,672,673,676,679,681,684,686,689,692,694,696,699,702,705,708,711,714,717,720,723],{"class":225,"line":374},[223,674,675],{"class":302},"print",[223,677,678],{"class":256},"([r ",[223,680,602],{"class":252},[223,682,683],{"class":256}," r ",[223,685,527],{"class":252},[223,687,688],{"class":302}," range",[223,690,691],{"class":256},"(",[223,693,617],{"class":302},[223,695,315],{"class":256},[223,697,698],{"class":302},"10",[223,700,701],{"class":256},") ",[223,703,704],{"class":252},"if",[223,706,707],{"class":256}," static.cell(r, ",[223,709,710],{"class":302},"1",[223,712,713],{"class":256},").fill.fgColor.rgb ",[223,715,716],{"class":252},"==",[223,718,719],{"class":233}," \"00E7EBEF\"",[223,721,722],{"class":256},"])   ",[223,724,726],{"class":725},"s-wDw","# [2, 4, 6, 8]\n",[10,728,729],{},"It looks right until a reader sorts by amount: the fills travel with their cells, and the stripes end up in random places. Inserting a row shifts the pattern, and filtering hides some shaded rows but not others. Static fills are fine only for a finished printout nobody will touch — a PDF export, for instance, where the file is never sorted again.",[208,731,733],{"id":732},"step-2-a-rule-based-on-the-row-number","Step 2 — A rule based on the row number",[10,735,736,737,741,742,745],{},"A conditional formatting rule is evaluated where the cell ",[738,739,740],"em",{},"is",", not where it came from, so sorting cannot scramble it. ",[220,743,744],{},"MOD(ROW(),2)=0"," is true on every even sheet row:",[213,747,749],{"className":243,"code":748,"language":245,"meta":218,"style":218},"by_row = orders_sheet(wb, \"ByRow\")\nby_row.conditional_formatting.add(\"A2:C9\", FormulaRule(formula=[\"MOD(ROW(),2)=0\"], fill=BAND))\n",[220,750,751,765],{"__ignoreMap":218},[223,752,753,756,758,760,763],{"class":225,"line":226},[223,754,755],{"class":256},"by_row ",[223,757,458],{"class":252},[223,759,592],{"class":256},[223,761,762],{"class":233},"\"ByRow\"",[223,764,464],{"class":256},[223,766,767,770,773,776,779,781,784,787,790,793,795,797],{"class":225,"line":266},[223,768,769],{"class":256},"by_row.conditional_formatting.add(",[223,771,772],{"class":233},"\"A2:C9\"",[223,774,775],{"class":256},", FormulaRule(",[223,777,778],{"class":454},"formula",[223,780,458],{"class":252},[223,782,783],{"class":256},"[",[223,785,786],{"class":233},"\"MOD(ROW(),2)=0\"",[223,788,789],{"class":256},"], ",[223,791,792],{"class":454},"fill",[223,794,458],{"class":252},[223,796,441],{"class":302},[223,798,799],{"class":256},"))\n",[10,801,802],{},"Sort the data, insert a row in the middle — the stripes stay perfect. They break in one situation: when rows are hidden, by a filter or by hand. Rendering this sheet with rows 3, 5 and 6 hidden shows orders 101 and 103 both shaded and next to each other, because their sheet rows, 2 and 4, are both even. For reports that people filter, the rule needs to count visible rows instead.",[20,804,29,810,29,813,29,816,29,821,29,825,29,829,29,835,29,839,29,843,29,847,29,851,29,855,29,859,29,861,29,865,29,867,29,870,29,872,29,875,29,878,29,881,29,883,29,886,29,888,29,891,29,893,29,896,29,899,29,903,29,905,29,907,29,909,29,911,29,913,29,915,29,918,29,921,29,923,29,925,29,927,29,929,29,931,29,934,29,938,29,940,29,942,29,944,29,947,29,949,29,951,29,953,29,957,29,959,29,961,29,963,29,966,29,968,29,971,29,974,29,977,29,980,29,983,29,986,29,989,29,991,29,994,29,996,29,998,29,1000,29,1002,29,1004,29,1006,29,1008,29,1010,29,1012,29,1014,29,1016,29,1018,29,1020,29,1022,29,1024,29,1026,29,1028,29,1030,29,1032,29,1034,29,1036,29,1038,29,1040,29,1042,29,1044,29,1046,29,1048,29,1050,29,1052,29,1054,29,1056,29,1058,29,1060,29,1062,29,1064,29,1066,29,1068,29,1070,29,1072,29,1074,29,1076,29,1078,29,1080,29,1086,29,1090,29,1096,29,1101,29,1108],{"viewBox":805,"role":23,"ariaLabelledBy":806,"xmlns":27,"style":809},"29 0 701 248",[807,808],"ab-filter-t","ab-filter-d","width:100%;max-width:701px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[31,811,812],{"id":807},"What filtering does to MOD(ROW()) banding",[35,814,815],{"id":808},"With rows 3, 5 and 6 hidden, the MOD ROW rule shades orders 101 and 103, which sit on even sheet rows and now appear next to each other, and leaves 106 and 108 plain. The SUBTOTAL rule counts only visible rows, so it shades 103 and 107 and the visible rows alternate correctly.",[39,817],{"x":818,"y":42,"width":819,"height":820,"fill":45},"29","701","248",[39,822],{"x":823,"y":51,"width":89,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"45.9","24.0",[39,826],{"x":827,"y":51,"width":828,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"77.9","59.4",[62,830,834],{"x":831,"y":832,"style":833},"107.6","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[39,836],{"x":837,"y":51,"width":838,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"137.3","66.7",[62,840,842],{"x":841,"y":832,"style":833},"170.7","B",[39,844],{"x":845,"y":51,"width":846,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"204.0","61.7",[62,848,850],{"x":849,"y":832,"style":833},"234.9","C",[39,852],{"x":823,"y":853,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},"64.0","28.0",[62,856,710],{"x":857,"y":858,"style":833},"61.9","83.0",[39,860],{"x":827,"y":853,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,862,864],{"x":831,"y":858,"style":863},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Order",[39,866],{"x":837,"y":853,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,868,869],{"x":841,"y":858,"style":863},"Region",[39,871],{"x":845,"y":853,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,873,874],{"x":849,"y":858,"style":863},"shade",[39,876],{"x":823,"y":877,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},"92.0",[62,879,617],{"x":857,"y":880,"style":833},"111.0",[39,882],{"x":827,"y":877,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,884,312],{"x":831,"y":880,"style":885},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[39,887],{"x":837,"y":877,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,889,890],{"x":841,"y":880,"style":885},"North",[39,892],{"x":845,"y":877,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,894,895],{"x":849,"y":880,"style":885},"■",[39,897],{"x":823,"y":898,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},"120.0",[62,900,902],{"x":857,"y":901,"style":833},"139.0","3",[39,904],{"x":827,"y":898,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,906,344],{"x":831,"y":901,"style":885},[39,908],{"x":837,"y":898,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,910,890],{"x":841,"y":901,"style":885},[39,912],{"x":845,"y":898,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,914,895],{"x":849,"y":901,"style":885},[39,916],{"x":823,"y":917,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},"148.0",[62,919,41],{"x":857,"y":920,"style":833},"167.0",[39,922],{"x":827,"y":917,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,924,394],{"x":831,"y":920,"style":885},[39,926],{"x":837,"y":917,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,928,890],{"x":841,"y":920,"style":885},[39,930],{"x":845,"y":917,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[39,932],{"x":823,"y":933,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},"176.0",[62,935,937],{"x":857,"y":936,"style":833},"195.0","5",[39,939],{"x":827,"y":933,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,941,408],{"x":831,"y":936,"style":885},[39,943],{"x":837,"y":933,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,945,946],{"x":841,"y":936,"style":885},"West",[39,948],{"x":845,"y":933,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,950,895],{"x":849,"y":936,"style":885},[39,952],{"x":823,"y":845,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,954,956],{"x":857,"y":955,"style":833},"223.0","6",[39,958],{"x":827,"y":845,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,960,423],{"x":831,"y":955,"style":885},[39,962],{"x":837,"y":845,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,964,965],{"x":841,"y":955,"style":885},"East",[39,967],{"x":845,"y":845,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[39,969],{"x":970,"y":51,"width":89,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"494.3",[39,972],{"x":973,"y":51,"width":828,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"526.3",[62,975,834],{"x":976,"y":832,"style":833},"556.0",[39,978],{"x":979,"y":51,"width":838,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"585.7",[62,981,842],{"x":982,"y":832,"style":833},"619.1",[39,984],{"x":985,"y":51,"width":846,"height":824,"rx":42,"fill":86,"stroke":52,"style":53},"652.4",[62,987,850],{"x":988,"y":832,"style":833},"683.3",[39,990],{"x":970,"y":853,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,992,710],{"x":993,"y":858,"style":833},"510.3",[39,995],{"x":973,"y":853,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,997,864],{"x":976,"y":858,"style":863},[39,999],{"x":979,"y":853,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1001,869],{"x":982,"y":858,"style":863},[39,1003],{"x":985,"y":853,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1005,874],{"x":988,"y":858,"style":863},[39,1007],{"x":970,"y":877,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,1009,617],{"x":993,"y":880,"style":833},[39,1011],{"x":973,"y":877,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1013,312],{"x":976,"y":880,"style":885},[39,1015],{"x":979,"y":877,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1017,890],{"x":982,"y":880,"style":885},[39,1019],{"x":985,"y":877,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[39,1021],{"x":970,"y":898,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,1023,902],{"x":993,"y":901,"style":833},[39,1025],{"x":973,"y":898,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1027,344],{"x":976,"y":901,"style":885},[39,1029],{"x":979,"y":898,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1031,890],{"x":982,"y":901,"style":885},[39,1033],{"x":985,"y":898,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1035,895],{"x":988,"y":901,"style":885},[39,1037],{"x":970,"y":917,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,1039,41],{"x":993,"y":920,"style":833},[39,1041],{"x":973,"y":917,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1043,394],{"x":976,"y":920,"style":885},[39,1045],{"x":979,"y":917,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1047,890],{"x":982,"y":920,"style":885},[39,1049],{"x":985,"y":917,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[39,1051],{"x":970,"y":933,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,1053,937],{"x":993,"y":936,"style":833},[39,1055],{"x":973,"y":933,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1057,408],{"x":976,"y":936,"style":885},[39,1059],{"x":979,"y":933,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1061,946],{"x":982,"y":936,"style":885},[39,1063],{"x":985,"y":933,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1065,895],{"x":988,"y":936,"style":885},[39,1067],{"x":970,"y":845,"width":89,"height":854,"rx":42,"fill":86,"stroke":52,"style":53},[62,1069,956],{"x":993,"y":955,"style":833},[39,1071],{"x":973,"y":845,"width":828,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1073,423],{"x":976,"y":955,"style":885},[39,1075],{"x":979,"y":845,"width":838,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1077,965],{"x":982,"y":955,"style":885},[39,1079],{"x":985,"y":845,"width":846,"height":854,"rx":42,"fill":45,"stroke":52,"style":53},[62,1081,1085],{"x":1082,"y":1083,"style":1084},"155.8","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[62,1087,1089],{"x":1088,"y":1083,"style":1084},"604.2","after",[225,1091],{"x1":1092,"y1":1093,"x2":1094,"y2":1093,"stroke":59,"style":1095},"275.7","136.0","480.3","stroke-width:2px",[1097,1098],"polygon",{"points":1099,"fill":1100},"484.3,136.0 475.3,141.0 475.3,131.0","#5b5cf0",[39,1102],{"x":1103,"y":1104,"width":1105,"height":1106,"rx":1107,"fill":45,"stroke":52,"style":60},"304.6","103.0","150.8","22.0","11",[62,1109,1113],{"x":1110,"y":1111,"style":1112},"380.0","118.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","count visible rows",[208,1115,1117],{"id":1116},"step-3-banding-that-follows-filters","Step 3 — Banding that follows filters",[10,1119,1120,1123,1124,1127],{},[220,1121,1122],{},"SUBTOTAL(103, range)"," counts non-empty ",[738,1125,1126],{},"visible"," cells. Anchor the start of the range and let the end move with the row, and it numbers the visible rows 1, 2, 3 — whatever is hidden:",[213,1129,1131],{"className":243,"code":1130,"language":245,"meta":218,"style":218},"visible = orders_sheet(wb, \"Visible\")\nvisible.conditional_formatting.add(\n    \"A2:C9\", FormulaRule(formula=[\"MOD(SUBTOTAL(103,$A$2:$A2),2)=0\"], fill=BAND))\nfor r in (3, 5, 6):                         # as if a filter had hidden them\n    visible.row_dimensions[r].hidden = True\nwb.save(\"banded.xlsx\")\n",[220,1132,1133,1147,1152,1178,1205,1215],{"__ignoreMap":218},[223,1134,1135,1138,1140,1142,1145],{"class":225,"line":226},[223,1136,1137],{"class":256},"visible ",[223,1139,458],{"class":252},[223,1141,592],{"class":256},[223,1143,1144],{"class":233},"\"Visible\"",[223,1146,464],{"class":256},[223,1148,1149],{"class":225,"line":266},[223,1150,1151],{"class":256},"visible.conditional_formatting.add(\n",[223,1153,1154,1157,1159,1161,1163,1165,1168,1170,1172,1174,1176],{"class":225,"line":279},[223,1155,1156],{"class":233},"    \"A2:C9\"",[223,1158,775],{"class":256},[223,1160,778],{"class":454},[223,1162,458],{"class":252},[223,1164,783],{"class":256},[223,1166,1167],{"class":233},"\"MOD(SUBTOTAL(103,$A$2:$A2),2)=0\"",[223,1169,789],{"class":256},[223,1171,792],{"class":454},[223,1173,458],{"class":252},[223,1175,441],{"class":302},[223,1177,799],{"class":256},[223,1179,1180,1182,1184,1186,1189,1191,1193,1195,1197,1199,1202],{"class":225,"line":292},[223,1181,602],{"class":252},[223,1183,683],{"class":256},[223,1185,527],{"class":252},[223,1187,1188],{"class":256}," (",[223,1190,902],{"class":302},[223,1192,315],{"class":256},[223,1194,937],{"class":302},[223,1196,315],{"class":256},[223,1198,956],{"class":302},[223,1200,1201],{"class":256},"):                         ",[223,1203,1204],{"class":725},"# as if a filter had hidden them\n",[223,1206,1207,1210,1212],{"class":225,"line":299},[223,1208,1209],{"class":256},"    visible.row_dimensions[r].hidden ",[223,1211,458],{"class":252},[223,1213,1214],{"class":302}," True\n",[223,1216,1217,1220,1223],{"class":225,"line":374},[223,1218,1219],{"class":256},"wb.save(",[223,1221,1222],{"class":233},"\"banded.xlsx\"",[223,1224,464],{"class":256},[10,1226,1227,1228,1231,1232,1236],{},"Rendered with the same rows hidden, the visible orders 101, 103, 106, 107 and 108 alternate plain, shaded, plain, shaded, plain. The counting column — A here — must never be empty in the data, because ",[220,1229,1230],{},"SUBTOTAL(103, …)"," counts non-empty cells; use a key column such as an order number. The formula recalculates on every filter change, which is fine for thousands of rows; for very large sheets, a table (Step 4) is lighter. Filters themselves are covered in ",[14,1233,1235],{"href":1234},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fapply-autofilter-criteria-and-hide-rows\u002F","Apply Autofilter Criteria and Hide the Filtered Rows with openpyxl",".",[208,1238,1240],{"id":1239},"step-4-or-let-an-excel-table-do-it","Step 4 — Or let an Excel table do it",[10,1242,1243],{},"When the data is a proper Excel table, banding is a table style option. Stripes, filtering and new rows are all handled by Excel:",[213,1245,1247],{"className":243,"code":1246,"language":245,"meta":218,"style":218},"from openpyxl.worksheet.table import Table, TableStyleInfo\n\ntabled = orders_sheet(wb, \"Tabled\")\ntable = Table(displayName=\"Orders\", ref=\"A1:C9\")\ntable.tableStyleInfo = TableStyleInfo(name=\"TableStyleLight9\", showRowStripes=True)\ntabled.add_table(table)\nwb.save(\"banded.xlsx\")\nprint(table.tableStyleInfo.showRowStripes)       # True\n",[220,1248,1249,1261,1265,1279,1309,1339,1344,1352],{"__ignoreMap":218},[223,1250,1251,1253,1256,1258],{"class":225,"line":226},[223,1252,253],{"class":252},[223,1254,1255],{"class":256}," openpyxl.worksheet.table ",[223,1257,260],{"class":252},[223,1259,1260],{"class":256}," Table, TableStyleInfo\n",[223,1262,1263],{"class":225,"line":266},[223,1264,296],{"emptyLinePlaceholder":295},[223,1266,1267,1270,1272,1274,1277],{"class":225,"line":279},[223,1268,1269],{"class":256},"tabled ",[223,1271,458],{"class":252},[223,1273,592],{"class":256},[223,1275,1276],{"class":233},"\"Tabled\"",[223,1278,464],{"class":256},[223,1280,1281,1284,1286,1289,1292,1294,1297,1299,1302,1304,1307],{"class":225,"line":292},[223,1282,1283],{"class":256},"table ",[223,1285,458],{"class":252},[223,1287,1288],{"class":256}," Table(",[223,1290,1291],{"class":454},"displayName",[223,1293,458],{"class":252},[223,1295,1296],{"class":233},"\"Orders\"",[223,1298,315],{"class":256},[223,1300,1301],{"class":454},"ref",[223,1303,458],{"class":252},[223,1305,1306],{"class":233},"\"A1:C9\"",[223,1308,464],{"class":256},[223,1310,1311,1314,1316,1319,1322,1324,1327,1329,1332,1334,1337],{"class":225,"line":299},[223,1312,1313],{"class":256},"table.tableStyleInfo ",[223,1315,458],{"class":252},[223,1317,1318],{"class":256}," TableStyleInfo(",[223,1320,1321],{"class":454},"name",[223,1323,458],{"class":252},[223,1325,1326],{"class":233},"\"TableStyleLight9\"",[223,1328,315],{"class":256},[223,1330,1331],{"class":454},"showRowStripes",[223,1333,458],{"class":252},[223,1335,1336],{"class":302},"True",[223,1338,464],{"class":256},[223,1340,1341],{"class":225,"line":374},[223,1342,1343],{"class":256},"tabled.add_table(table)\n",[223,1345,1346,1348,1350],{"class":225,"line":438},[223,1347,1219],{"class":256},[223,1349,1222],{"class":233},[223,1351,464],{"class":256},[223,1353,1354,1356,1359],{"class":225,"line":467},[223,1355,675],{"class":302},[223,1357,1358],{"class":256},"(table.tableStyleInfo.showRowStripes)       ",[223,1360,1361],{"class":725},"# True\n",[10,1363,1364,1365,1368,1369,315,1372,1368,1375,1378,1379,1368,1382,1385,1386,1236],{},"The stripe colours come from the table style — ",[220,1366,1367],{},"TableStyleLight1"," to ",[220,1370,1371],{},"Light21",[220,1373,1374],{},"Medium1",[220,1376,1377],{},"Medium28"," and ",[220,1380,1381],{},"Dark1",[220,1383,1384],{},"Dark11"," — rather than from your palette. If the report must use exact brand colours, use the conditional formatting rules with a table style that has no stripes. Tables are covered in ",[14,1387,1389],{"href":1388},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fcreate-an-excel-table-with-python\u002F","Create an Excel Table with Python",[208,1391,1393],{"id":1392},"step-5-alternate-by-group-not-by-row","Step 5 — Alternate by group, not by row",[10,1395,1396],{},"In a list sorted by region, shading whole groups — all North rows one shade, all South rows the next — shows where each group starts and ends. A helper column flips between 0 and 1 whenever the region changes; the fill rule reads it, and the column is hidden:",[213,1398,1400],{"className":243,"code":1399,"language":245,"meta":218,"style":218},"grouped = orders_sheet(wb, \"ByGroup\")\nrows = sorted(ORDERS, key=lambda r: r[1])\nfor r, values in enumerate(rows, start=2):\n    for c, value in enumerate(values, start=1):\n        grouped.cell(r, c, value)\n    grouped.cell(r, 4, 0 if r == 2 else f\"=IF(B{r}=B{r - 1},D{r - 1},1-D{r - 1})\")\ngrouped.column_dimensions[\"D\"].hidden = True\ngrouped.conditional_formatting.add(\"A2:C9\", FormulaRule(formula=[\"$D2=1\"], fill=BAND))\nwb.save(\"banded.xlsx\")\nprint([grouped.cell(r, 2).value for r in range(2, 10)])\n# ['East', 'East', 'North', 'North', 'North', 'South', 'South', 'West']\n",[220,1401,1402,1416,1445,1469,1491,1496,1582,1597,1625,1633,1664],{"__ignoreMap":218},[223,1403,1404,1407,1409,1411,1414],{"class":225,"line":226},[223,1405,1406],{"class":256},"grouped ",[223,1408,458],{"class":252},[223,1410,592],{"class":256},[223,1412,1413],{"class":233},"\"ByGroup\"",[223,1415,464],{"class":256},[223,1417,1418,1421,1423,1426,1428,1430,1432,1435,1438,1441,1443],{"class":225,"line":266},[223,1419,1420],{"class":256},"rows ",[223,1422,458],{"class":252},[223,1424,1425],{"class":302}," sorted",[223,1427,691],{"class":256},[223,1429,303],{"class":302},[223,1431,315],{"class":256},[223,1433,1434],{"class":454},"key",[223,1436,1437],{"class":252},"=lambda",[223,1439,1440],{"class":256}," r: r[",[223,1442,710],{"class":302},[223,1444,515],{"class":256},[223,1446,1447,1449,1452,1454,1457,1460,1463,1465,1467],{"class":225,"line":279},[223,1448,602],{"class":252},[223,1450,1451],{"class":256}," r, values ",[223,1453,527],{"class":252},[223,1455,1456],{"class":302}," enumerate",[223,1458,1459],{"class":256},"(rows, ",[223,1461,1462],{"class":454},"start",[223,1464,458],{"class":252},[223,1466,617],{"class":302},[223,1468,620],{"class":256},[223,1470,1471,1473,1476,1478,1480,1483,1485,1487,1489],{"class":225,"line":292},[223,1472,521],{"class":252},[223,1474,1475],{"class":256}," c, value ",[223,1477,527],{"class":252},[223,1479,1456],{"class":302},[223,1481,1482],{"class":256},"(values, ",[223,1484,1462],{"class":454},[223,1486,458],{"class":252},[223,1488,710],{"class":302},[223,1490,620],{"class":256},[223,1492,1493],{"class":225,"line":299},[223,1494,1495],{"class":256},"        grouped.cell(r, c, value)\n",[223,1497,1498,1501,1503,1505,1507,1510,1512,1514,1516,1519,1522,1525,1529,1532,1535,1538,1540,1543,1546,1549,1551,1554,1556,1558,1560,1562,1564,1567,1569,1571,1573,1575,1577,1580],{"class":225,"line":374},[223,1499,1500],{"class":256},"    grouped.cell(r, ",[223,1502,41],{"class":302},[223,1504,315],{"class":256},[223,1506,42],{"class":302},[223,1508,1509],{"class":252}," if",[223,1511,683],{"class":256},[223,1513,716],{"class":252},[223,1515,639],{"class":302},[223,1517,1518],{"class":252}," else",[223,1520,1521],{"class":252}," f",[223,1523,1524],{"class":233},"\"=IF(B",[223,1526,1528],{"class":1527},"sSjpA","{",[223,1530,1531],{"class":256},"r",[223,1533,1534],{"class":1527},"}",[223,1536,1537],{"class":233},"=B",[223,1539,1528],{"class":1527},[223,1541,1542],{"class":256},"r ",[223,1544,1545],{"class":252},"-",[223,1547,1548],{"class":302}," 1",[223,1550,1534],{"class":1527},[223,1552,1553],{"class":233},",D",[223,1555,1528],{"class":1527},[223,1557,1542],{"class":256},[223,1559,1545],{"class":252},[223,1561,1548],{"class":302},[223,1563,1534],{"class":1527},[223,1565,1566],{"class":233},",1-D",[223,1568,1528],{"class":1527},[223,1570,1542],{"class":256},[223,1572,1545],{"class":252},[223,1574,1548],{"class":302},[223,1576,1534],{"class":1527},[223,1578,1579],{"class":233},")\"",[223,1581,464],{"class":256},[223,1583,1584,1587,1590,1593,1595],{"class":225,"line":438},[223,1585,1586],{"class":256},"grouped.column_dimensions[",[223,1588,1589],{"class":233},"\"D\"",[223,1591,1592],{"class":256},"].hidden ",[223,1594,458],{"class":252},[223,1596,1214],{"class":302},[223,1598,1599,1602,1604,1606,1608,1610,1612,1615,1617,1619,1621,1623],{"class":225,"line":467},[223,1600,1601],{"class":256},"grouped.conditional_formatting.add(",[223,1603,772],{"class":233},[223,1605,775],{"class":256},[223,1607,778],{"class":454},[223,1609,458],{"class":252},[223,1611,783],{"class":256},[223,1613,1614],{"class":233},"\"$D2=1\"",[223,1616,789],{"class":256},[223,1618,792],{"class":454},[223,1620,458],{"class":252},[223,1622,441],{"class":302},[223,1624,799],{"class":256},[223,1626,1627,1629,1631],{"class":225,"line":472},[223,1628,1219],{"class":256},[223,1630,1222],{"class":233},[223,1632,464],{"class":256},[223,1634,1635,1637,1640,1642,1645,1647,1649,1651,1653,1655,1657,1659,1661],{"class":225,"line":485},[223,1636,675],{"class":302},[223,1638,1639],{"class":256},"([grouped.cell(r, ",[223,1641,617],{"class":302},[223,1643,1644],{"class":256},").value ",[223,1646,602],{"class":252},[223,1648,683],{"class":256},[223,1650,527],{"class":252},[223,1652,688],{"class":302},[223,1654,691],{"class":256},[223,1656,617],{"class":302},[223,1658,315],{"class":256},[223,1660,698],{"class":302},[223,1662,1663],{"class":256},")])\n",[223,1665,1666],{"class":225,"line":496},[223,1667,1668],{"class":725},"# ['East', 'East', 'North', 'North', 'North', 'South', 'South', 'West']\n",[10,1670,1671],{},"Rendered, the two East rows are plain, the three North rows shaded, the South rows plain and West shaded. Because the flip is a formula, re-sorting the sheet by region keeps the groups banded; sorting by something else breaks the grouping, as it should. The same idea without formulas — compute the group parity in pandas and write it — works for finished reports.",[20,1673,29,1678,29,1681,29,1684,29,1687,29,1693,29,1701,29,1707,29,1711,29,1716,29,1719,29,1722,29,1729,29,1734,29,1737,29,1741,29,1744,29,1747,29,1753,29,1757,29,1760,29,1763,29,1766,29,1771,29,1778,29,1783],{"viewBox":1674,"role":23,"ariaLabelledBy":1675,"xmlns":27,"style":28},"4 0 752 125",[1676,1677],"ab-choose-t","ab-choose-d",[31,1679,1680],{"id":1676},"Picking the banding approach",[35,1682,1683],{"id":1677},"If the data is an Excel table, use the table style's row stripes. Otherwise add a conditional formatting rule, using MOD ROW when the sheet will not be filtered, SUBTOTAL 103 when it will, and a helper column with a group flip when rows should be shaded by group rather than individually.",[39,1685],{"x":41,"y":42,"width":43,"height":1686,"fill":45},"125",[39,1688],{"x":48,"y":49,"width":1689,"height":1690,"rx":1691,"fill":1692,"stroke":135,"style":1095},"153.0","93.0","12","#d9f4f1",[96,1694,1696],{"transform":1695},"translate(84.5,29.0) scale(1.000)",[100,1697],{"d":1698,"fill":103,"stroke":1699,"style":1700},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--teal-ink,#0b6157)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[62,1702,1706],{"x":1703,"y":1704,"style":1705},"96.5","75.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Data in a table",[62,1708,1331],{"x":1703,"y":1709,"style":1710},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[225,1712],{"x1":1713,"y1":1714,"x2":1715,"y2":1714,"stroke":59,"style":1095},"178.0","62.5","200.0",[1097,1717],{"points":1718,"fill":1100},"204.0,62.5 195.0,67.5 195.0,57.5",[39,1720],{"x":1721,"y":49,"width":1689,"height":1690,"rx":1691,"fill":58,"stroke":59,"style":1095},"209.0",[96,1723,1725],{"transform":1724},"translate(273.5,29.0) scale(1.000)",[100,1726],{"d":1727,"fill":103,"stroke":1728,"style":1700},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--brand-strong,#4338ca)",[62,1730,1733],{"x":1731,"y":1704,"style":1732},"285.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Not filtered",[62,1735,1736],{"x":1731,"y":1709,"style":1710},"MOD(ROW(),2)",[225,1738],{"x1":1739,"y1":1714,"x2":1740,"y2":1714,"stroke":59,"style":1095},"367.0","389.0",[1097,1742],{"points":1743,"fill":1100},"393.0,62.5 384.0,67.5 384.0,57.5",[39,1745],{"x":1746,"y":49,"width":1689,"height":1690,"rx":1691,"fill":58,"stroke":59,"style":1095},"398.0",[96,1748,1750],{"transform":1749},"translate(462.5,29.0) scale(1.000)",[100,1751],{"d":1752,"fill":103,"stroke":1728,"style":1700},"M3 5h18l-7 8v6l-4 2v-8z",[62,1754,1756],{"x":1755,"y":1704,"style":1732},"474.5","Filtered",[62,1758,1759],{"x":1755,"y":1709,"style":1710},"SUBTOTAL(103,…)",[225,1761],{"x1":976,"y1":1714,"x2":1762,"y2":1714,"stroke":59,"style":1095},"578.0",[1097,1764],{"points":1765,"fill":1100},"582.0,62.5 573.0,67.5 573.0,57.5",[39,1767],{"x":1768,"y":49,"width":1689,"height":1690,"rx":1691,"fill":1769,"stroke":1770,"style":1095},"587.0","#fdefd8","var(--gold,#b4740a)",[96,1772,1774],{"transform":1773},"translate(651.5,29.0) scale(1.000)",[100,1775],{"d":1776,"fill":103,"stroke":1777,"style":1700},"M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6 M16 4.5a3.3 3.3 0 0 1 0 6.3 M18 14.3c2.2.7 3.5 2.8 3.5 5.7","var(--gold-ink,#7a4e06)",[62,1779,1782],{"x":1780,"y":1704,"style":1781},"663.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","By group",[62,1784,1785],{"x":1780,"y":1709,"style":1710},"helper flip column",[208,1787,1789],{"id":1788},"step-6-band-a-report-written-by-pandas","Step 6 — Band a report written by pandas",[10,1791,1792,1793,1796,1797,1800],{},"For a DataFrame written with ",[220,1794,1795],{},"to_excel",", add the rule in the same ",[220,1798,1799],{},"ExcelWriter"," block. Size the range from the frame, leave room for growth, and guard against empty rows so the space below the data stays clean:",[213,1802,1804],{"className":243,"code":1803,"language":245,"meta":218,"style":218},"import pandas as pd\nfrom openpyxl.utils import get_column_letter\n\nframe = pd.DataFrame(ORDERS, columns=[\"Order\", \"Region\", \"Amount\"])\nwith pd.ExcelWriter(\"banded_pd.xlsx\", engine=\"openpyxl\") as writer:\n    frame.to_excel(writer, sheet_name=\"Orders\", index=False)\n    sheet = writer.sheets[\"Orders\"]\n    last_col = get_column_letter(len(frame.columns))\n    band_rule = FormulaRule(formula=['AND($A2\u003C>\"\",MOD(SUBTOTAL(103,$A$2:$A2),2)=0)'], fill=BAND)\n    sheet.conditional_formatting.add(f\"A2:{last_col}{len(frame) + 500}\", band_rule)\n    sheet.auto_filter.ref = f\"A1:{last_col}{len(frame) + 1}\"\nprint(len(frame) + 500)                           # 508\n",[220,1805,1806,1819,1831,1835,1868,1896,1920,1935,1951,1980,2018,2049],{"__ignoreMap":218},[223,1807,1808,1810,1813,1816],{"class":225,"line":226},[223,1809,260],{"class":252},[223,1811,1812],{"class":256}," pandas ",[223,1814,1815],{"class":252},"as",[223,1817,1818],{"class":256}," pd\n",[223,1820,1821,1823,1826,1828],{"class":225,"line":266},[223,1822,253],{"class":252},[223,1824,1825],{"class":256}," openpyxl.utils ",[223,1827,260],{"class":252},[223,1829,1830],{"class":256}," get_column_letter\n",[223,1832,1833],{"class":225,"line":279},[223,1834,296],{"emptyLinePlaceholder":295},[223,1836,1837,1840,1842,1845,1847,1849,1852,1854,1856,1858,1860,1862,1864,1866],{"class":225,"line":292},[223,1838,1839],{"class":256},"frame ",[223,1841,458],{"class":252},[223,1843,1844],{"class":256}," pd.DataFrame(",[223,1846,303],{"class":302},[223,1848,315],{"class":256},[223,1850,1851],{"class":454},"columns",[223,1853,458],{"class":252},[223,1855,783],{"class":256},[223,1857,502],{"class":233},[223,1859,315],{"class":256},[223,1861,507],{"class":233},[223,1863,315],{"class":256},[223,1865,512],{"class":233},[223,1867,515],{"class":256},[223,1869,1870,1873,1876,1879,1881,1884,1886,1889,1891,1893],{"class":225,"line":299},[223,1871,1872],{"class":252},"with",[223,1874,1875],{"class":256}," pd.ExcelWriter(",[223,1877,1878],{"class":233},"\"banded_pd.xlsx\"",[223,1880,315],{"class":256},[223,1882,1883],{"class":454},"engine",[223,1885,458],{"class":252},[223,1887,1888],{"class":233},"\"openpyxl\"",[223,1890,701],{"class":256},[223,1892,1815],{"class":252},[223,1894,1895],{"class":256}," writer:\n",[223,1897,1898,1901,1904,1906,1908,1910,1913,1915,1918],{"class":225,"line":374},[223,1899,1900],{"class":256},"    frame.to_excel(writer, ",[223,1902,1903],{"class":454},"sheet_name",[223,1905,458],{"class":252},[223,1907,1296],{"class":233},[223,1909,315],{"class":256},[223,1911,1912],{"class":454},"index",[223,1914,458],{"class":252},[223,1916,1917],{"class":302},"False",[223,1919,464],{"class":256},[223,1921,1922,1925,1927,1930,1932],{"class":225,"line":438},[223,1923,1924],{"class":256},"    sheet ",[223,1926,458],{"class":252},[223,1928,1929],{"class":256}," writer.sheets[",[223,1931,1296],{"class":233},[223,1933,1934],{"class":256},"]\n",[223,1936,1937,1940,1942,1945,1948],{"class":225,"line":467},[223,1938,1939],{"class":256},"    last_col ",[223,1941,458],{"class":252},[223,1943,1944],{"class":256}," get_column_letter(",[223,1946,1947],{"class":302},"len",[223,1949,1950],{"class":256},"(frame.columns))\n",[223,1952,1953,1956,1958,1961,1963,1965,1967,1970,1972,1974,1976,1978],{"class":225,"line":472},[223,1954,1955],{"class":256},"    band_rule ",[223,1957,458],{"class":252},[223,1959,1960],{"class":256}," FormulaRule(",[223,1962,778],{"class":454},[223,1964,458],{"class":252},[223,1966,783],{"class":256},[223,1968,1969],{"class":233},"'AND($A2\u003C>\"\",MOD(SUBTOTAL(103,$A$2:$A2),2)=0)'",[223,1971,789],{"class":256},[223,1973,792],{"class":454},[223,1975,458],{"class":252},[223,1977,441],{"class":302},[223,1979,464],{"class":256},[223,1981,1982,1985,1988,1991,1993,1996,1999,2001,2004,2007,2010,2012,2015],{"class":225,"line":485},[223,1983,1984],{"class":256},"    sheet.conditional_formatting.add(",[223,1986,1987],{"class":252},"f",[223,1989,1990],{"class":233},"\"A2:",[223,1992,1528],{"class":1527},[223,1994,1995],{"class":256},"last_col",[223,1997,1998],{"class":1527},"}{",[223,2000,1947],{"class":302},[223,2002,2003],{"class":256},"(frame) ",[223,2005,2006],{"class":252},"+",[223,2008,2009],{"class":302}," 500",[223,2011,1534],{"class":1527},[223,2013,2014],{"class":233},"\"",[223,2016,2017],{"class":256},", band_rule)\n",[223,2019,2020,2023,2025,2027,2030,2032,2034,2036,2038,2040,2042,2044,2046],{"class":225,"line":496},[223,2021,2022],{"class":256},"    sheet.auto_filter.ref ",[223,2024,458],{"class":252},[223,2026,1521],{"class":252},[223,2028,2029],{"class":233},"\"A1:",[223,2031,1528],{"class":1527},[223,2033,1995],{"class":256},[223,2035,1998],{"class":1527},[223,2037,1947],{"class":302},[223,2039,2003],{"class":256},[223,2041,2006],{"class":252},[223,2043,1548],{"class":302},[223,2045,1534],{"class":1527},[223,2047,2048],{"class":233},"\"\n",[223,2050,2051,2053,2055,2057,2059,2061,2063,2066],{"class":225,"line":518},[223,2052,675],{"class":302},[223,2054,691],{"class":256},[223,2056,1947],{"class":302},[223,2058,2003],{"class":256},[223,2060,2006],{"class":252},[223,2062,2009],{"class":302},[223,2064,2065],{"class":256},")                           ",[223,2067,2068],{"class":725},"# 508\n",[10,2070,2071,2072,2075,2076,2079],{},"The rule covers 500 rows beyond the data, so a reader pasting in more orders gets banding without anyone touching the file, and the ",[220,2073,2074],{},"AND($A2\u003C>\"\", …)"," keeps those empty rows plain until something is written in them. The autofilter makes the ",[220,2077,2078],{},"SUBTOTAL"," version worthwhile: readers can filter by region and the stripes follow the visible rows. When the same report is regenerated each month, the rule is rebuilt with the file, so there is no risk of rules piling up as there is when an existing workbook is edited in place.",[208,2081,2083],{"id":2082},"common-pitfalls","Common pitfalls",[2085,2086,2087,2099,2117,2123],"ul",{},[2088,2089,2090,2094,2095,2098],"li",{},[2091,2092,2093],"strong",{},"Dark bands."," A band dark enough to notice on screen can make text hard to read and prints heavily. Use a very light tint, such as ",[220,2096,2097],{},"E7EBEF",", and keep text black.",[2088,2100,2101,2104,2105,2108,2109,2112,2113,2116],{},[2091,2102,2103],{},"Rules that miss new rows."," A rule on ",[220,2106,2107],{},"A2:C9"," does not shade row 10. Apply it to a generous range such as ",[220,2110,2111],{},"A2:C5000",", and add a test for an empty key cell — ",[220,2114,2115],{},"AND($A2\u003C>\"\", MOD(ROW(),2)=0)"," — so the empty rows below the data stay plain.",[2088,2118,2119,2122],{},[2091,2120,2121],{},"Colour as the only cue."," Some screens and projectors wash out light tints entirely. Banding is a reading aid, not information; never use the band colour to mean something.",[2088,2124,2125,2128],{},[2091,2126,2127],{},"Banding plus a full grid."," Stripes already separate rows; a heavy grid on top looks busy. Keep borders to the header and outline.",[208,2130,2132],{"id":2131},"conclusion","Conclusion",[10,2134,2135,2136,2138,2139,2142,2143,2146],{},"Static fills are the least robust way to band rows. Use a conditional formatting rule — ",[220,2137,744],{}," for sheets that are sorted but not filtered, ",[220,2140,2141],{},"MOD(SUBTOTAL(103,$A$2:$A2),2)=0"," for sheets that are filtered — or an Excel table with ",[220,2144,2145],{},"showRowStripes=True",". For grouped lists, drive the fill from a hidden helper column that flips when the group changes, and keep the band colour light.",[208,2148,2150],{"id":2149},"frequently-asked-questions","Frequently asked questions",[10,2152,2153,2156,2157,2159],{},[2091,2154,2155],{},"How do I shade every other row with openpyxl?","\nThe robust way is a conditional formatting rule, FormulaRule(formula=",[223,2158,786],{},", fill=...), applied to the table range. Unlike fills set cell by cell, the rule keeps alternating after readers sort or insert rows.",[10,2161,2162,2165],{},[2091,2163,2164],{},"Why does the banding break when I filter?","\nMOD(ROW()) looks at the sheet row number, so hiding rows leaves two shaded or two plain rows next to each other. Use MOD(SUBTOTAL(103,$A$2:$A2),2)=0 instead, which counts only visible rows.",[10,2167,2168,2171],{},[2091,2169,2170],{},"Should I use an Excel table instead?","\nIf the data is a table anyway, yes — a table style with showRowStripes=True bands the rows and handles filtering and new rows automatically. Conditional formatting is for ranges that are not tables.",[10,2173,2174,2177],{},[2091,2175,2176],{},"How do I alternate colours by group, such as by region?","\nSort by the group column, add a helper column that flips between 0 and 1 whenever the group changes, hide it, and base the fill rule on it. Each group then shares one shade.",[208,2179,2181],{"id":2180},"related","Related",[2085,2183,2184,2190,2197,2204],{},[2088,2185,2186,2187,2189],{},"Up one level: ",[14,2188,17],{"href":16}," — fonts, fills, borders and layout.",[2088,2191,2192,2196],{},[14,2193,2195],{"href":2194},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-borders-to-a-range-with-openpyxl\u002F","Add Borders to a Range with openpyxl"," — structure to pair with banding.",[2088,2198,2199,2203],{},[14,2200,2202],{"href":2201},"\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"," — formula rules for whole rows.",[2088,2205,2206,2210],{},[14,2207,2209],{"href":2208},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Flist-and-remove-conditional-formatting-with-openpyxl\u002F","List and Remove Conditional Formatting with openpyxl"," — keeping rules tidy on reruns.",[2212,2213,2214],"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 .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":218,"searchDepth":266,"depth":266,"links":2216},[2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227],{"id":210,"depth":266,"text":211},{"id":573,"depth":266,"text":574},{"id":732,"depth":266,"text":733},{"id":1116,"depth":266,"text":1117},{"id":1239,"depth":266,"text":1240},{"id":1392,"depth":266,"text":1393},{"id":1788,"depth":266,"text":1789},{"id":2082,"depth":266,"text":2083},{"id":2131,"depth":266,"text":2132},{"id":2149,"depth":266,"text":2150},{"id":2180,"depth":266,"text":2181},"2026-09-23","Band the rows of an Excel report so long lists are easy to follow — with static fills, a MOD(ROW()) conditional format that survives sorting, a SUBTOTAL-based rule that keeps alternating when rows are filtered, table stripes, and banding by group instead of by row.","md",[2232,2234,2236,2238],{"q":2155,"a":2233},"The robust way is a conditional formatting rule, FormulaRule(formula=[\"MOD(ROW(),2)=0\"], fill=...), applied to the table range. Unlike fills set cell by cell, the rule keeps alternating after readers sort or insert rows.",{"q":2164,"a":2235},"MOD(ROW()) looks at the sheet row number, so hiding rows leaves two shaded or two plain rows next to each other. Use MOD(SUBTOTAL(103,$A$2:$A2),2)=0 instead, which counts only visible rows.",{"q":2170,"a":2237},"If the data is a table anyway, yes — a table style with showRowStripes=True bands the rows and handles filtering and new rows automatically. Conditional formatting is for ranges that are not tables.",{"q":2176,"a":2239},"Sort by the group column, add a helper column that flips between 0 and 1 whenever the group changes, hide it, and base the fill rule on it. Each group then shares one shade.","add alternating row colors with openpyxl",null,{"breadcrumb":2243},[2244,2247,2250],{"name":2245,"item":2246},"Home","\u002F",{"name":2248,"item":2249},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":17,"item":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl",{"title":2253,"description":2254},"Add Alternating Row Colors in Excel with openpyxl (banded rows)","Zebra stripes for Excel from Python — static PatternFill per row, conditional formatting with MOD(ROW(),2), SUBTOTAL(103) banding that respects filters and hidden rows, Excel table showRowStripes, and alternating colours per group of rows.","add-alternating-row-colors-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-alternating-row-colors-with-openpyxl\u002Findex",[2258,2259,2260],"cell-styling","conditional-formatting","openpyxl","how-to","3EpOseoQy0b4-oXSNZ6hDipd7dacA3lVDdnpewsfxLo",[2264,2267],{"title":17,"path":2265,"stem":2266,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Findex",{"title":2195,"path":2268,"stem":2269,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-borders-to-a-range-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fadd-borders-to-a-range-with-openpyxl\u002Findex",[2271,2273],{"path":2272,"title":2248},"\u002Fformatting-and-charting-excel-reports-with-python",{"path":2265,"title":17},[],[2276,2279,2282,2285,2288,2291],{"path":2277,"title":2278,"kind":2261},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-rich-text-in-a-cell-with-xlsxwriter","Write Rich Text with Mixed Formats in One Cell with xlsxwriter",{"path":2280,"title":2281,"kind":2261},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fcopy-cell-styles-with-openpyxl","Copy Cell Styles from One Cell to Another with openpyxl",{"path":2283,"title":2284,"kind":2261},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fauto-fit-column-widths-when-writing-with-pandas","Auto-Fit Column Widths When Writing with pandas",{"path":2286,"title":2287,"kind":2261},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fexport-a-styled-pandas-dataframe-to-excel","Export a Styled pandas DataFrame to Excel",{"path":2289,"title":2290,"kind":2261},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fgenerate-a-staff-rota-in-excel-with-python","Generate a Staff Rota in Excel with Python",{"path":2292,"title":2293,"kind":2261},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel","Add a Table of Contents Sheet with Hyperlinks in Excel",1790972117081]