[{"data":1,"prerenderedAt":2431},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl":2422},{"id":4,"title":5,"body":6,"dateModified":2392,"datePublished":2392,"description":2393,"extension":2394,"faq":2395,"meta":2405,"navigation":205,"path":2415,"seo":2416,"slug":2418,"stem":2419,"type":2420,"__hash__":2421},"docs\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl\u002Findex.md","Copy a Formula Down a Column in openpyxl",{"type":7,"value":8,"toc":2378},"minimark",[9,24,141,146,170,174,177,735,754,758,770,956,971,974,1049,1053,1056,1199,1226,1230,1237,1472,1487,1491,1497,1787,1794,1798,1801,2008,2119,2130,2134,2255,2259,2265,2269,2275,2279,2289,2302,2315,2325,2329,2332,2341,2344,2374],[10,11,12,13,17,18,23],"p",{},"Excel users drag the fill handle; from Python there is no handle to drag. Copying a formula down a column means writing one formula per row, and there are two good ways to do it: generate each formula from the row number, or take one source formula and let ",[14,15,16],"code",{},"openpyxl"," translate it. This guide, part of ",[19,20,22],"a",{"href":21},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002F","Working with Excel Formulas in Python",", covers both, together with the styling and blank-row details that decide whether the result looks hand-made or generated.",[25,26,34,35,34,39,34,43,34,50,34,58,34,65,34,70,34,78,34,82,34,88,34,93,34,96,34,100,34,103,34,107,34,113,34,118,34,123,34,128,34,133,34,137],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"0 0 720 254","img",[30,31],"cd-fill-t","cd-fill-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:720px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[36,37,38],"title",{"id":30},"One source formula becoming a per-row formula on every data row",[40,41,42],"desc",{"id":31},"The source formula in D2 multiplies B2 by C2 and divides by an anchored cell dollar F dollar 1. Copied down, the relative row numbers become 3, 4 and 5 while the anchored reference stays dollar F dollar 1 on every row.",[44,45],"rect",{"x":46,"y":46,"width":47,"height":48,"fill":49},"0","720","254","#ffffff",[44,51],{"x":52,"y":53,"width":54,"height":55,"rx":56,"fill":57},"30","26","250","44","10","#5b5cf0",[59,60,64],"text",{"x":61,"y":62,"style":63},"155","53","font-size:13px;font-weight:700;fill:#ffffff;text-anchor:middle;font-family:ui-monospace,Menlo,monospace","D2: =B2*C2\u002F$F$1",[59,66,69],{"x":61,"y":67,"style":68},"88","font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:middle","source formula",[71,72],"line",{"x1":73,"y1":74,"x2":75,"y2":74,"stroke":76,"style":77},"285","48","345","var(--brand,#5b5cf0)","stroke-width:2px",[79,80],"polygon",{"points":81,"fill":57},"349,48 337,42 337,54",[44,83],{"x":84,"y":53,"width":85,"height":55,"rx":56,"fill":86,"stroke":87},"352","336","#ebebfd","var(--line,#cdd5e6)",[59,89,92],{"x":90,"y":62,"style":91},"520","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,Menlo,monospace","D3: =B3*C3\u002F$F$1",[44,94],{"x":84,"y":95,"width":85,"height":55,"rx":56,"fill":86,"stroke":87},"78",[59,97,99],{"x":90,"y":98,"style":91},"105","D4: =B4*C4\u002F$F$1",[44,101],{"x":84,"y":102,"width":85,"height":55,"rx":56,"fill":86,"stroke":87},"130",[59,104,106],{"x":90,"y":105,"style":91},"157","D5: =B5*C5\u002F$F$1",[44,108],{"x":52,"y":109,"width":54,"height":110,"rx":111,"fill":112,"stroke":87},"120","98","12","#f0f4ff",[59,114,117],{"x":61,"y":115,"style":116},"146","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","what moves",[59,119,122],{"x":61,"y":120,"style":121},"170","font-size:11.5px;fill:var(--teal,#0f9488);text-anchor:middle","B2, C2 → row of the target",[59,124,127],{"x":61,"y":125,"style":126},"192","font-size:11.5px;fill:var(--gold,#b4740a);text-anchor:middle","$F$1 → unchanged",[59,129,132],{"x":61,"y":130,"style":131},"210","font-size:11px;fill:var(--muted,#5b6780);text-anchor:middle","the anchors decide",[59,134,136],{"x":90,"y":135,"style":68},"200","one formula per row, written explicitly",[59,138,140],{"x":90,"y":139,"style":68},"226","no fill handle exists in the file format",[142,143,145],"h2",{"id":144},"prerequisites","Prerequisites",[147,148,153],"pre",{"className":149,"code":150,"language":151,"meta":152,"style":152},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[14,154,155],{"__ignoreMap":152},[156,157,159,163,167],"span",{"class":71,"line":158},1,[156,160,162],{"class":161},"sMTad","pip",[156,164,166],{"class":165},"srMev"," install",[156,168,169],{"class":165}," openpyxl\n",[142,171,173],{"id":172},"approach-1-generate-a-formula-per-row","Approach 1: generate a formula per row",[10,175,176],{},"The most transparent method. Loop over the data rows and build the string for each one:",[147,178,182],{"className":179,"code":180,"language":181,"meta":152,"style":152},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\n\nrows = [\n    (\"A-100\", 4, 19.99),\n    (\"B-200\", 2, 49.50),\n    (\"C-300\", 7, 12.25),\n    (\"D-400\", 5, 8.75),\n]\n\nwb = Workbook()\nws = wb.active\nws.title = \"Orders\"\nws.append([\"SKU\", \"Quantity\", \"Unit_Price\", \"Line_Total\", \"Share\"])\n\nfor sku, qty, price in rows:\n    ws.append([sku, qty, price])\n\nfirst, last = 2, ws.max_row\ntotal_row = last + 2\nws[f\"C{total_row}\"] = \"Total\"\nws[f\"D{total_row}\"] = f\"=SUM(D{first}:D{last})\"\n\nfor r in range(first, last + 1):\n    ws[f\"D{r}\"] = f\"=B{r}*C{r}\"\n    ws[f\"E{r}\"] = f\"=IF($D${total_row}=0,0,D{r}\u002F$D${total_row})\"\n    ws[f\"D{r}\"].number_format = \"#,##0.00\"\n    ws[f\"E{r}\"].number_format = \"0.0%\"\n\nwb.save(\"filled_down.xlsx\")\nprint(ws[\"E3\"].value)      # '=IF($D$8=0,0,D3\u002F$D$8)'\n","python",[14,183,184,200,207,219,243,263,283,303,309,314,325,336,347,379,384,399,405,410,424,441,474,522,527,551,597,650,675,699,704,716],{"__ignoreMap":152},[156,185,186,190,194,197],{"class":71,"line":158},[156,187,189],{"class":188},"s-kum","from",[156,191,193],{"class":192},"skGVy"," openpyxl ",[156,195,196],{"class":188},"import",[156,198,199],{"class":192}," Workbook\n",[156,201,203],{"class":71,"line":202},2,[156,204,206],{"emptyLinePlaceholder":205},true,"\n",[156,208,210,213,216],{"class":71,"line":209},3,[156,211,212],{"class":192},"rows ",[156,214,215],{"class":188},"=",[156,217,218],{"class":192}," [\n",[156,220,222,225,228,231,235,237,240],{"class":71,"line":221},4,[156,223,224],{"class":192},"    (",[156,226,227],{"class":165},"\"A-100\"",[156,229,230],{"class":192},", ",[156,232,234],{"class":233},"sP0c6","4",[156,236,230],{"class":192},[156,238,239],{"class":233},"19.99",[156,241,242],{"class":192},"),\n",[156,244,246,248,251,253,256,258,261],{"class":71,"line":245},5,[156,247,224],{"class":192},[156,249,250],{"class":165},"\"B-200\"",[156,252,230],{"class":192},[156,254,255],{"class":233},"2",[156,257,230],{"class":192},[156,259,260],{"class":233},"49.50",[156,262,242],{"class":192},[156,264,266,268,271,273,276,278,281],{"class":71,"line":265},6,[156,267,224],{"class":192},[156,269,270],{"class":165},"\"C-300\"",[156,272,230],{"class":192},[156,274,275],{"class":233},"7",[156,277,230],{"class":192},[156,279,280],{"class":233},"12.25",[156,282,242],{"class":192},[156,284,286,288,291,293,296,298,301],{"class":71,"line":285},7,[156,287,224],{"class":192},[156,289,290],{"class":165},"\"D-400\"",[156,292,230],{"class":192},[156,294,295],{"class":233},"5",[156,297,230],{"class":192},[156,299,300],{"class":233},"8.75",[156,302,242],{"class":192},[156,304,306],{"class":71,"line":305},8,[156,307,308],{"class":192},"]\n",[156,310,312],{"class":71,"line":311},9,[156,313,206],{"emptyLinePlaceholder":205},[156,315,317,320,322],{"class":71,"line":316},10,[156,318,319],{"class":192},"wb ",[156,321,215],{"class":188},[156,323,324],{"class":192}," Workbook()\n",[156,326,328,331,333],{"class":71,"line":327},11,[156,329,330],{"class":192},"ws ",[156,332,215],{"class":188},[156,334,335],{"class":192}," wb.active\n",[156,337,339,342,344],{"class":71,"line":338},12,[156,340,341],{"class":192},"ws.title ",[156,343,215],{"class":188},[156,345,346],{"class":165}," \"Orders\"\n",[156,348,350,353,356,358,361,363,366,368,371,373,376],{"class":71,"line":349},13,[156,351,352],{"class":192},"ws.append([",[156,354,355],{"class":165},"\"SKU\"",[156,357,230],{"class":192},[156,359,360],{"class":165},"\"Quantity\"",[156,362,230],{"class":192},[156,364,365],{"class":165},"\"Unit_Price\"",[156,367,230],{"class":192},[156,369,370],{"class":165},"\"Line_Total\"",[156,372,230],{"class":192},[156,374,375],{"class":165},"\"Share\"",[156,377,378],{"class":192},"])\n",[156,380,382],{"class":71,"line":381},14,[156,383,206],{"emptyLinePlaceholder":205},[156,385,387,390,393,396],{"class":71,"line":386},15,[156,388,389],{"class":188},"for",[156,391,392],{"class":192}," sku, qty, price ",[156,394,395],{"class":188},"in",[156,397,398],{"class":192}," rows:\n",[156,400,402],{"class":71,"line":401},16,[156,403,404],{"class":192},"    ws.append([sku, qty, price])\n",[156,406,408],{"class":71,"line":407},17,[156,409,206],{"emptyLinePlaceholder":205},[156,411,413,416,418,421],{"class":71,"line":412},18,[156,414,415],{"class":192},"first, last ",[156,417,215],{"class":188},[156,419,420],{"class":233}," 2",[156,422,423],{"class":192},", ws.max_row\n",[156,425,427,430,432,435,438],{"class":71,"line":426},19,[156,428,429],{"class":192},"total_row ",[156,431,215],{"class":188},[156,433,434],{"class":192}," last ",[156,436,437],{"class":188},"+",[156,439,440],{"class":233}," 2\n",[156,442,444,447,450,453,457,460,463,466,469,471],{"class":71,"line":443},20,[156,445,446],{"class":192},"ws[",[156,448,449],{"class":188},"f",[156,451,452],{"class":165},"\"C",[156,454,456],{"class":455},"sSjpA","{",[156,458,459],{"class":192},"total_row",[156,461,462],{"class":455},"}",[156,464,465],{"class":165},"\"",[156,467,468],{"class":192},"] ",[156,470,215],{"class":188},[156,472,473],{"class":165}," \"Total\"\n",[156,475,477,479,481,484,486,488,490,492,494,496,499,502,504,507,509,512,514,517,519],{"class":71,"line":476},21,[156,478,446],{"class":192},[156,480,449],{"class":188},[156,482,483],{"class":165},"\"D",[156,485,456],{"class":455},[156,487,459],{"class":192},[156,489,462],{"class":455},[156,491,465],{"class":165},[156,493,468],{"class":192},[156,495,215],{"class":188},[156,497,498],{"class":188}," f",[156,500,501],{"class":165},"\"=SUM(D",[156,503,456],{"class":455},[156,505,506],{"class":192},"first",[156,508,462],{"class":455},[156,510,511],{"class":165},":D",[156,513,456],{"class":455},[156,515,516],{"class":192},"last",[156,518,462],{"class":455},[156,520,521],{"class":165},")\"\n",[156,523,525],{"class":71,"line":524},22,[156,526,206],{"emptyLinePlaceholder":205},[156,528,530,532,535,537,540,543,545,548],{"class":71,"line":529},23,[156,531,389],{"class":188},[156,533,534],{"class":192}," r ",[156,536,395],{"class":188},[156,538,539],{"class":233}," range",[156,541,542],{"class":192},"(first, last ",[156,544,437],{"class":188},[156,546,547],{"class":233}," 1",[156,549,550],{"class":192},"):\n",[156,552,554,557,559,561,563,566,568,570,572,574,576,579,581,583,585,588,590,592,594],{"class":71,"line":553},24,[156,555,556],{"class":192},"    ws[",[156,558,449],{"class":188},[156,560,483],{"class":165},[156,562,456],{"class":455},[156,564,565],{"class":192},"r",[156,567,462],{"class":455},[156,569,465],{"class":165},[156,571,468],{"class":192},[156,573,215],{"class":188},[156,575,498],{"class":188},[156,577,578],{"class":165},"\"=B",[156,580,456],{"class":455},[156,582,565],{"class":192},[156,584,462],{"class":455},[156,586,587],{"class":165},"*C",[156,589,456],{"class":455},[156,591,565],{"class":192},[156,593,462],{"class":455},[156,595,596],{"class":165},"\"\n",[156,598,600,602,604,607,609,611,613,615,617,619,621,624,626,628,630,633,635,637,639,642,644,646,648],{"class":71,"line":599},25,[156,601,556],{"class":192},[156,603,449],{"class":188},[156,605,606],{"class":165},"\"E",[156,608,456],{"class":455},[156,610,565],{"class":192},[156,612,462],{"class":455},[156,614,465],{"class":165},[156,616,468],{"class":192},[156,618,215],{"class":188},[156,620,498],{"class":188},[156,622,623],{"class":165},"\"=IF($D$",[156,625,456],{"class":455},[156,627,459],{"class":192},[156,629,462],{"class":455},[156,631,632],{"class":165},"=0,0,D",[156,634,456],{"class":455},[156,636,565],{"class":192},[156,638,462],{"class":455},[156,640,641],{"class":165},"\u002F$D$",[156,643,456],{"class":455},[156,645,459],{"class":192},[156,647,462],{"class":455},[156,649,521],{"class":165},[156,651,653,655,657,659,661,663,665,667,670,672],{"class":71,"line":652},26,[156,654,556],{"class":192},[156,656,449],{"class":188},[156,658,483],{"class":165},[156,660,456],{"class":455},[156,662,565],{"class":192},[156,664,462],{"class":455},[156,666,465],{"class":165},[156,668,669],{"class":192},"].number_format ",[156,671,215],{"class":188},[156,673,674],{"class":165}," \"#,##0.00\"\n",[156,676,678,680,682,684,686,688,690,692,694,696],{"class":71,"line":677},27,[156,679,556],{"class":192},[156,681,449],{"class":188},[156,683,606],{"class":165},[156,685,456],{"class":455},[156,687,565],{"class":192},[156,689,462],{"class":455},[156,691,465],{"class":165},[156,693,669],{"class":192},[156,695,215],{"class":188},[156,697,698],{"class":165}," \"0.0%\"\n",[156,700,702],{"class":71,"line":701},28,[156,703,206],{"emptyLinePlaceholder":205},[156,705,707,710,713],{"class":71,"line":706},29,[156,708,709],{"class":192},"wb.save(",[156,711,712],{"class":165},"\"filled_down.xlsx\"",[156,714,715],{"class":192},")\n",[156,717,719,722,725,728,731],{"class":71,"line":718},30,[156,720,721],{"class":233},"print",[156,723,724],{"class":192},"(ws[",[156,726,727],{"class":165},"\"E3\"",[156,729,730],{"class":192},"].value)      ",[156,732,734],{"class":733},"s-wDw","# '=IF($D$8=0,0,D3\u002F$D$8)'\n",[10,736,737,738,230,740,742,743,745,746,749,750,753],{},"Everything the loop needs comes from ",[14,739,506],{},[14,741,516],{}," and ",[14,744,459],{},", so a longer dataset changes nothing but the numbers. The ",[14,747,748],{},"IF"," guard is worth the extra characters: without it, an empty dataset gives every row ",[14,751,752],{},"#DIV\u002F0!"," and the report looks broken rather than empty.",[142,755,757],{"id":756},"approach-2-translate-an-existing-formula","Approach 2: translate an existing formula",[10,759,760,761,765,766,769],{},"When the source formula already exists — because you wrote it once, or because it came from a ",[19,762,764],{"href":763},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002F","template"," — ",[14,767,768],{},"Translator"," shifts it for you and gets the anchoring right without string surgery:",[147,771,773],{"className":179,"code":772,"language":181,"meta":152,"style":152},"from openpyxl import load_workbook\nfrom openpyxl.formula.translate import Translator\n\nwb = load_workbook(\"filled_down.xlsx\")\nws = wb[\"Orders\"]\n\nsource_coord = \"D2\"\nsource_formula = ws[source_coord].value        # '=B2*C2'\n\nfor r in range(3, 6):\n    ws[f\"D{r}\"] = Translator(source_formula, origin=source_coord).translate_formula(f\"D{r}\")\n\nprint(ws[\"D5\"].value)      # '=B5*C5'\nwb.save(\"translated.xlsx\")\n",[14,774,775,786,798,802,815,829,833,843,856,860,883,929,933,947],{"__ignoreMap":152},[156,776,777,779,781,783],{"class":71,"line":158},[156,778,189],{"class":188},[156,780,193],{"class":192},[156,782,196],{"class":188},[156,784,785],{"class":192}," load_workbook\n",[156,787,788,790,793,795],{"class":71,"line":202},[156,789,189],{"class":188},[156,791,792],{"class":192}," openpyxl.formula.translate ",[156,794,196],{"class":188},[156,796,797],{"class":192}," Translator\n",[156,799,800],{"class":71,"line":209},[156,801,206],{"emptyLinePlaceholder":205},[156,803,804,806,808,811,813],{"class":71,"line":221},[156,805,319],{"class":192},[156,807,215],{"class":188},[156,809,810],{"class":192}," load_workbook(",[156,812,712],{"class":165},[156,814,715],{"class":192},[156,816,817,819,821,824,827],{"class":71,"line":245},[156,818,330],{"class":192},[156,820,215],{"class":188},[156,822,823],{"class":192}," wb[",[156,825,826],{"class":165},"\"Orders\"",[156,828,308],{"class":192},[156,830,831],{"class":71,"line":265},[156,832,206],{"emptyLinePlaceholder":205},[156,834,835,838,840],{"class":71,"line":285},[156,836,837],{"class":192},"source_coord ",[156,839,215],{"class":188},[156,841,842],{"class":165}," \"D2\"\n",[156,844,845,848,850,853],{"class":71,"line":305},[156,846,847],{"class":192},"source_formula ",[156,849,215],{"class":188},[156,851,852],{"class":192}," ws[source_coord].value        ",[156,854,855],{"class":733},"# '=B2*C2'\n",[156,857,858],{"class":71,"line":311},[156,859,206],{"emptyLinePlaceholder":205},[156,861,862,864,866,868,870,873,876,878,881],{"class":71,"line":316},[156,863,389],{"class":188},[156,865,534],{"class":192},[156,867,395],{"class":188},[156,869,539],{"class":233},[156,871,872],{"class":192},"(",[156,874,875],{"class":233},"3",[156,877,230],{"class":192},[156,879,880],{"class":233},"6",[156,882,550],{"class":192},[156,884,885,887,889,891,893,895,897,899,901,903,906,910,912,915,917,919,921,923,925,927],{"class":71,"line":327},[156,886,556],{"class":192},[156,888,449],{"class":188},[156,890,483],{"class":165},[156,892,456],{"class":455},[156,894,565],{"class":192},[156,896,462],{"class":455},[156,898,465],{"class":165},[156,900,468],{"class":192},[156,902,215],{"class":188},[156,904,905],{"class":192}," Translator(source_formula, ",[156,907,909],{"class":908},"sa561","origin",[156,911,215],{"class":188},[156,913,914],{"class":192},"source_coord).translate_formula(",[156,916,449],{"class":188},[156,918,483],{"class":165},[156,920,456],{"class":455},[156,922,565],{"class":192},[156,924,462],{"class":455},[156,926,465],{"class":165},[156,928,715],{"class":192},[156,930,931],{"class":71,"line":338},[156,932,206],{"emptyLinePlaceholder":205},[156,934,935,937,939,942,944],{"class":71,"line":349},[156,936,721],{"class":233},[156,938,724],{"class":192},[156,940,941],{"class":165},"\"D5\"",[156,943,730],{"class":192},[156,945,946],{"class":733},"# '=B5*C5'\n",[156,948,949,951,954],{"class":71,"line":381},[156,950,709],{"class":192},[156,952,953],{"class":165},"\"translated.xlsx\"",[156,955,715],{"class":192},[10,957,958,960,961,963,964,742,967,970],{},[14,959,768],{}," parses the formula, applies the row and column offset between ",[14,962,909],{}," and the destination to every relative reference, and leaves absolute parts untouched — exactly what Excel does on a copy-paste. It also handles the awkward cases string replacement gets wrong, such as a formula mentioning both ",[14,965,966],{},"B2",[14,968,969],{},"AB2",", or a sheet name that happens to contain something that looks like a reference.",[10,972,973],{},"The origin argument must be the coordinate the formula currently lives at. Passing the wrong origin produces a formula that is offset twice, which is a bug that survives review because the result still looks like a valid formula.",[25,975,34,980,34,983,34,986,34,988,34,994,34,1000,34,1004,34,1008,34,1012,34,1018,34,1023,34,1028,34,1033,34,1036,34,1039,34,1042,34,1045],{"viewBox":976,"role":28,"ariaLabelledBy":977,"xmlns":32,"style":33},"0 0 720 226",[978,979],"cd-choose-t","cd-choose-d",[36,981,982],{"id":978},"Choosing between generating and translating a formula",[40,984,985],{"id":979},"Generate the formula per row when your own code owns the layout, because the pattern is visible in the loop. Translate an existing formula when the source lives in a template you did not write, because the template author owns the expression.",[44,987],{"x":46,"y":46,"width":47,"height":139,"fill":49},[44,989],{"x":990,"y":990,"width":991,"height":992,"rx":993,"fill":112,"stroke":76,"style":77},"24","320","176","14",[59,995,999],{"x":996,"y":997,"style":998},"184","52","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","generate per row",[59,1001,1003],{"x":996,"y":1002,"style":68},"80","you own the layout and the maths",[59,1005,1007],{"x":996,"y":1006,"style":68},"102","the pattern is readable in the loop",[59,1009,1011],{"x":996,"y":1010,"style":68},"124","easy to add guards such as IF()",[44,1013],{"x":997,"y":1014,"width":1015,"height":1016,"rx":1017,"fill":86},"140","264","40","8",[59,1019,1022],{"x":996,"y":1020,"style":1021},"165","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,Menlo,monospace","ws[f\"D{r}\"] = f\"=B{r}*C{r}\"",[44,1024],{"x":1025,"y":990,"width":991,"height":992,"rx":993,"fill":1026,"stroke":1027,"style":77},"376","#d9f4f1","var(--teal,#0f9488)",[59,1029,1032],{"x":1030,"y":997,"style":1031},"536","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","translate an existing one",[59,1034,1035],{"x":1030,"y":1002,"style":68},"the formula came from a template",[59,1037,1038],{"x":1030,"y":1006,"style":68},"anchoring is preserved for you",[59,1040,1041],{"x":1030,"y":1010,"style":68},"no fragile string replacement",[44,1043],{"x":1044,"y":1014,"width":1015,"height":1016,"rx":1017,"fill":49,"stroke":87},"404",[59,1046,1048],{"x":1030,"y":1020,"style":1047},"font-size:10px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle;font-family:ui-monospace,Menlo,monospace","Translator(…).translate_formula()",[142,1050,1052],{"id":1051},"copy-the-source-cells-formatting-too","Copy the source cell's formatting too",[10,1054,1055],{},"Assigning a value never carries style with it. If the source cell is currency-formatted and bold, the copies are not — which is usually the first thing a reader notices:",[147,1057,1059],{"className":179,"code":1058,"language":181,"meta":152,"style":152},"from copy import copy\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\"filled_down.xlsx\")\nws = wb[\"Orders\"]\n\nsource = ws[\"D2\"]\nfor r in range(3, 6):\n    target = ws[f\"D{r}\"]\n    target._style = copy(source._style)      # font, fill, border, alignment, number format\n\nwb.save(\"styled_fill.xlsx\")\n",[14,1060,1061,1073,1083,1087,1099,1111,1115,1130,1150,1173,1186,1190],{"__ignoreMap":152},[156,1062,1063,1065,1068,1070],{"class":71,"line":158},[156,1064,189],{"class":188},[156,1066,1067],{"class":192}," copy ",[156,1069,196],{"class":188},[156,1071,1072],{"class":192}," copy\n",[156,1074,1075,1077,1079,1081],{"class":71,"line":202},[156,1076,189],{"class":188},[156,1078,193],{"class":192},[156,1080,196],{"class":188},[156,1082,785],{"class":192},[156,1084,1085],{"class":71,"line":209},[156,1086,206],{"emptyLinePlaceholder":205},[156,1088,1089,1091,1093,1095,1097],{"class":71,"line":221},[156,1090,319],{"class":192},[156,1092,215],{"class":188},[156,1094,810],{"class":192},[156,1096,712],{"class":165},[156,1098,715],{"class":192},[156,1100,1101,1103,1105,1107,1109],{"class":71,"line":245},[156,1102,330],{"class":192},[156,1104,215],{"class":188},[156,1106,823],{"class":192},[156,1108,826],{"class":165},[156,1110,308],{"class":192},[156,1112,1113],{"class":71,"line":265},[156,1114,206],{"emptyLinePlaceholder":205},[156,1116,1117,1120,1122,1125,1128],{"class":71,"line":285},[156,1118,1119],{"class":192},"source ",[156,1121,215],{"class":188},[156,1123,1124],{"class":192}," ws[",[156,1126,1127],{"class":165},"\"D2\"",[156,1129,308],{"class":192},[156,1131,1132,1134,1136,1138,1140,1142,1144,1146,1148],{"class":71,"line":305},[156,1133,389],{"class":188},[156,1135,534],{"class":192},[156,1137,395],{"class":188},[156,1139,539],{"class":233},[156,1141,872],{"class":192},[156,1143,875],{"class":233},[156,1145,230],{"class":192},[156,1147,880],{"class":233},[156,1149,550],{"class":192},[156,1151,1152,1155,1157,1159,1161,1163,1165,1167,1169,1171],{"class":71,"line":311},[156,1153,1154],{"class":192},"    target ",[156,1156,215],{"class":188},[156,1158,1124],{"class":192},[156,1160,449],{"class":188},[156,1162,483],{"class":165},[156,1164,456],{"class":455},[156,1166,565],{"class":192},[156,1168,462],{"class":455},[156,1170,465],{"class":165},[156,1172,308],{"class":192},[156,1174,1175,1178,1180,1183],{"class":71,"line":316},[156,1176,1177],{"class":192},"    target._style ",[156,1179,215],{"class":188},[156,1181,1182],{"class":192}," copy(source._style)      ",[156,1184,1185],{"class":733},"# font, fill, border, alignment, number format\n",[156,1187,1188],{"class":71,"line":327},[156,1189,206],{"emptyLinePlaceholder":205},[156,1191,1192,1194,1197],{"class":71,"line":338},[156,1193,709],{"class":192},[156,1195,1196],{"class":165},"\"styled_fill.xlsx\"",[156,1198,715],{"class":192},[10,1200,1201,1204,1205,230,1208,230,1211,742,1214,1217,1218,1221,1222,1225],{},[14,1202,1203],{},"_style"," is a single object holding the whole style record, so copying it is both faster and more complete than setting ",[14,1206,1207],{},"font",[14,1209,1210],{},"fill",[14,1212,1213],{},"border",[14,1215,1216],{},"number_format"," one by one. Copy it — do not assign the same object to many cells — because openpyxl styles are shared immutable records and assigning without ",[14,1219,1220],{},"copy()"," can tie cells together in ways that surprise you later. When only the number format matters, setting ",[14,1223,1224],{},"target.number_format"," directly is simpler and clearer.",[142,1227,1229],{"id":1228},"only-fill-where-there-is-data","Only fill where there is data",[10,1231,1232,1233,1236],{},"Filling a formula down a fixed range leaves ",[14,1234,1235],{},"#VALUE!"," or zeros on empty rows below the data. Two defences, used together:",[147,1238,1240],{"className":179,"code":1239,"language":181,"meta":152,"style":152},"from openpyxl import load_workbook\n\nwb = load_workbook(\"filled_down.xlsx\")\nws = wb[\"Orders\"]\n\n# 1. Derive the last data row from a column that is always populated\nlast_data = max(\n    (cell.row for cell in ws[\"A\"] if cell.value not in (None, \"\")),\n    default=1,\n)\n\n# 2. Make each formula self-blanking, in case a row is cleared later\nfor r in range(2, last_data + 1):\n    ws[f\"D{r}\"] = f'=IF(A{r}=\"\",\"\",B{r}*C{r})'\n\nwb.save(\"safe_fill.xlsx\")\nprint(\"filled rows 2 to\", last_data)\n",[14,1241,1242,1252,1256,1268,1280,1284,1289,1302,1347,1360,1364,1368,1373,1396,1447,1451,1460],{"__ignoreMap":152},[156,1243,1244,1246,1248,1250],{"class":71,"line":158},[156,1245,189],{"class":188},[156,1247,193],{"class":192},[156,1249,196],{"class":188},[156,1251,785],{"class":192},[156,1253,1254],{"class":71,"line":202},[156,1255,206],{"emptyLinePlaceholder":205},[156,1257,1258,1260,1262,1264,1266],{"class":71,"line":209},[156,1259,319],{"class":192},[156,1261,215],{"class":188},[156,1263,810],{"class":192},[156,1265,712],{"class":165},[156,1267,715],{"class":192},[156,1269,1270,1272,1274,1276,1278],{"class":71,"line":221},[156,1271,330],{"class":192},[156,1273,215],{"class":188},[156,1275,823],{"class":192},[156,1277,826],{"class":165},[156,1279,308],{"class":192},[156,1281,1282],{"class":71,"line":245},[156,1283,206],{"emptyLinePlaceholder":205},[156,1285,1286],{"class":71,"line":265},[156,1287,1288],{"class":733},"# 1. Derive the last data row from a column that is always populated\n",[156,1290,1291,1294,1296,1299],{"class":71,"line":285},[156,1292,1293],{"class":192},"last_data ",[156,1295,215],{"class":188},[156,1297,1298],{"class":233}," max",[156,1300,1301],{"class":192},"(\n",[156,1303,1304,1307,1309,1312,1314,1316,1319,1321,1324,1327,1330,1333,1336,1339,1341,1344],{"class":71,"line":305},[156,1305,1306],{"class":192},"    (cell.row ",[156,1308,389],{"class":188},[156,1310,1311],{"class":192}," cell ",[156,1313,395],{"class":188},[156,1315,1124],{"class":192},[156,1317,1318],{"class":165},"\"A\"",[156,1320,468],{"class":192},[156,1322,1323],{"class":188},"if",[156,1325,1326],{"class":192}," cell.value ",[156,1328,1329],{"class":188},"not",[156,1331,1332],{"class":188}," in",[156,1334,1335],{"class":192}," (",[156,1337,1338],{"class":233},"None",[156,1340,230],{"class":192},[156,1342,1343],{"class":165},"\"\"",[156,1345,1346],{"class":192},")),\n",[156,1348,1349,1352,1354,1357],{"class":71,"line":311},[156,1350,1351],{"class":908},"    default",[156,1353,215],{"class":188},[156,1355,1356],{"class":233},"1",[156,1358,1359],{"class":192},",\n",[156,1361,1362],{"class":71,"line":316},[156,1363,715],{"class":192},[156,1365,1366],{"class":71,"line":327},[156,1367,206],{"emptyLinePlaceholder":205},[156,1369,1370],{"class":71,"line":338},[156,1371,1372],{"class":733},"# 2. Make each formula self-blanking, in case a row is cleared later\n",[156,1374,1375,1377,1379,1381,1383,1385,1387,1390,1392,1394],{"class":71,"line":349},[156,1376,389],{"class":188},[156,1378,534],{"class":192},[156,1380,395],{"class":188},[156,1382,539],{"class":233},[156,1384,872],{"class":192},[156,1386,255],{"class":233},[156,1388,1389],{"class":192},", last_data ",[156,1391,437],{"class":188},[156,1393,547],{"class":233},[156,1395,550],{"class":192},[156,1397,1398,1400,1402,1404,1406,1408,1410,1412,1414,1416,1418,1421,1423,1425,1427,1430,1432,1434,1436,1438,1440,1442,1444],{"class":71,"line":381},[156,1399,556],{"class":192},[156,1401,449],{"class":188},[156,1403,483],{"class":165},[156,1405,456],{"class":455},[156,1407,565],{"class":192},[156,1409,462],{"class":455},[156,1411,465],{"class":165},[156,1413,468],{"class":192},[156,1415,215],{"class":188},[156,1417,498],{"class":188},[156,1419,1420],{"class":165},"'=IF(A",[156,1422,456],{"class":455},[156,1424,565],{"class":192},[156,1426,462],{"class":455},[156,1428,1429],{"class":165},"=\"\",\"\",B",[156,1431,456],{"class":455},[156,1433,565],{"class":192},[156,1435,462],{"class":455},[156,1437,587],{"class":165},[156,1439,456],{"class":455},[156,1441,565],{"class":192},[156,1443,462],{"class":455},[156,1445,1446],{"class":165},")'\n",[156,1448,1449],{"class":71,"line":386},[156,1450,206],{"emptyLinePlaceholder":205},[156,1452,1453,1455,1458],{"class":71,"line":401},[156,1454,709],{"class":192},[156,1456,1457],{"class":165},"\"safe_fill.xlsx\"",[156,1459,715],{"class":192},[156,1461,1462,1464,1466,1469],{"class":71,"line":407},[156,1463,721],{"class":233},[156,1465,872],{"class":192},[156,1467,1468],{"class":165},"\"filled rows 2 to\"",[156,1470,1471],{"class":192},", last_data)\n",[10,1473,1474,1475,1478,1479,1482,1483,1486],{},"Deriving ",[14,1476,1477],{},"last_data"," from the key column rather than ",[14,1480,1481],{},"ws.max_row"," matters on a sheet that has a total block or stray formatting at the bottom: ",[14,1484,1485],{},"max_row"," counts any row Excel considers used, including one that only holds a border, so it routinely overshoots the real data.",[142,1488,1490],{"id":1489},"filling-across-columns-as-well","Filling across columns as well",[10,1492,1493,1494,1496],{},"The same two approaches extend to a rectangle. ",[14,1495,768],{}," shifts columns as readily as rows, which makes a monthly grid a two-line job:",[147,1498,1500],{"className":179,"code":1499,"language":181,"meta":152,"style":152},"from openpyxl import Workbook\nfrom openpyxl.formula.translate import Translator\nfrom openpyxl.utils import get_column_letter\n\nwb = Workbook()\nws = wb.active\nws.append([\"Region\", \"Jan\", \"Feb\", \"Mar\", \"Q1 %\"])\nfor region, jan, feb, mar in ((\"North\", 100, 120, 140), (\"South\", 90, 95, 99)):\n    ws.append([region, jan, feb, mar])\n\nws[\"E2\"] = \"=SUM(B2:D2)\u002FSUM($B$2:$D$3)\"\norigin = \"E2\"\nfor r in range(3, ws.max_row + 1):\n    ws[f\"E{r}\"] = Translator(ws[origin].value, origin=origin).translate_formula(f\"E{r}\")\n    ws[f\"E{r}\"].number_format = \"0.0%\"\n\nprint(get_column_letter(5), ws[\"E3\"].value)\nwb.save(\"grid_fill.xlsx\")\n",[14,1501,1502,1512,1522,1534,1538,1546,1554,1583,1635,1640,1644,1658,1668,1691,1735,1757,1761,1778],{"__ignoreMap":152},[156,1503,1504,1506,1508,1510],{"class":71,"line":158},[156,1505,189],{"class":188},[156,1507,193],{"class":192},[156,1509,196],{"class":188},[156,1511,199],{"class":192},[156,1513,1514,1516,1518,1520],{"class":71,"line":202},[156,1515,189],{"class":188},[156,1517,792],{"class":192},[156,1519,196],{"class":188},[156,1521,797],{"class":192},[156,1523,1524,1526,1529,1531],{"class":71,"line":209},[156,1525,189],{"class":188},[156,1527,1528],{"class":192}," openpyxl.utils ",[156,1530,196],{"class":188},[156,1532,1533],{"class":192}," get_column_letter\n",[156,1535,1536],{"class":71,"line":221},[156,1537,206],{"emptyLinePlaceholder":205},[156,1539,1540,1542,1544],{"class":71,"line":245},[156,1541,319],{"class":192},[156,1543,215],{"class":188},[156,1545,324],{"class":192},[156,1547,1548,1550,1552],{"class":71,"line":265},[156,1549,330],{"class":192},[156,1551,215],{"class":188},[156,1553,335],{"class":192},[156,1555,1556,1558,1561,1563,1566,1568,1571,1573,1576,1578,1581],{"class":71,"line":285},[156,1557,352],{"class":192},[156,1559,1560],{"class":165},"\"Region\"",[156,1562,230],{"class":192},[156,1564,1565],{"class":165},"\"Jan\"",[156,1567,230],{"class":192},[156,1569,1570],{"class":165},"\"Feb\"",[156,1572,230],{"class":192},[156,1574,1575],{"class":165},"\"Mar\"",[156,1577,230],{"class":192},[156,1579,1580],{"class":165},"\"Q1 %\"",[156,1582,378],{"class":192},[156,1584,1585,1587,1590,1592,1595,1598,1600,1603,1605,1607,1609,1611,1614,1617,1619,1622,1624,1627,1629,1632],{"class":71,"line":305},[156,1586,389],{"class":188},[156,1588,1589],{"class":192}," region, jan, feb, mar ",[156,1591,395],{"class":188},[156,1593,1594],{"class":192}," ((",[156,1596,1597],{"class":165},"\"North\"",[156,1599,230],{"class":192},[156,1601,1602],{"class":233},"100",[156,1604,230],{"class":192},[156,1606,109],{"class":233},[156,1608,230],{"class":192},[156,1610,1014],{"class":233},[156,1612,1613],{"class":192},"), (",[156,1615,1616],{"class":165},"\"South\"",[156,1618,230],{"class":192},[156,1620,1621],{"class":233},"90",[156,1623,230],{"class":192},[156,1625,1626],{"class":233},"95",[156,1628,230],{"class":192},[156,1630,1631],{"class":233},"99",[156,1633,1634],{"class":192},")):\n",[156,1636,1637],{"class":71,"line":311},[156,1638,1639],{"class":192},"    ws.append([region, jan, feb, mar])\n",[156,1641,1642],{"class":71,"line":316},[156,1643,206],{"emptyLinePlaceholder":205},[156,1645,1646,1648,1651,1653,1655],{"class":71,"line":327},[156,1647,446],{"class":192},[156,1649,1650],{"class":165},"\"E2\"",[156,1652,468],{"class":192},[156,1654,215],{"class":188},[156,1656,1657],{"class":165}," \"=SUM(B2:D2)\u002FSUM($B$2:$D$3)\"\n",[156,1659,1660,1663,1665],{"class":71,"line":338},[156,1661,1662],{"class":192},"origin ",[156,1664,215],{"class":188},[156,1666,1667],{"class":165}," \"E2\"\n",[156,1669,1670,1672,1674,1676,1678,1680,1682,1685,1687,1689],{"class":71,"line":349},[156,1671,389],{"class":188},[156,1673,534],{"class":192},[156,1675,395],{"class":188},[156,1677,539],{"class":233},[156,1679,872],{"class":192},[156,1681,875],{"class":233},[156,1683,1684],{"class":192},", ws.max_row ",[156,1686,437],{"class":188},[156,1688,547],{"class":233},[156,1690,550],{"class":192},[156,1692,1693,1695,1697,1699,1701,1703,1705,1707,1709,1711,1714,1716,1718,1721,1723,1725,1727,1729,1731,1733],{"class":71,"line":381},[156,1694,556],{"class":192},[156,1696,449],{"class":188},[156,1698,606],{"class":165},[156,1700,456],{"class":455},[156,1702,565],{"class":192},[156,1704,462],{"class":455},[156,1706,465],{"class":165},[156,1708,468],{"class":192},[156,1710,215],{"class":188},[156,1712,1713],{"class":192}," Translator(ws[origin].value, ",[156,1715,909],{"class":908},[156,1717,215],{"class":188},[156,1719,1720],{"class":192},"origin).translate_formula(",[156,1722,449],{"class":188},[156,1724,606],{"class":165},[156,1726,456],{"class":455},[156,1728,565],{"class":192},[156,1730,462],{"class":455},[156,1732,465],{"class":165},[156,1734,715],{"class":192},[156,1736,1737,1739,1741,1743,1745,1747,1749,1751,1753,1755],{"class":71,"line":386},[156,1738,556],{"class":192},[156,1740,449],{"class":188},[156,1742,606],{"class":165},[156,1744,456],{"class":455},[156,1746,565],{"class":192},[156,1748,462],{"class":455},[156,1750,465],{"class":165},[156,1752,669],{"class":192},[156,1754,215],{"class":188},[156,1756,698],{"class":165},[156,1758,1759],{"class":71,"line":401},[156,1760,206],{"emptyLinePlaceholder":205},[156,1762,1763,1765,1768,1770,1773,1775],{"class":71,"line":407},[156,1764,721],{"class":233},[156,1766,1767],{"class":192},"(get_column_letter(",[156,1769,295],{"class":233},[156,1771,1772],{"class":192},"), ws[",[156,1774,727],{"class":165},[156,1776,1777],{"class":192},"].value)\n",[156,1779,1780,1782,1785],{"class":71,"line":412},[156,1781,709],{"class":192},[156,1783,1784],{"class":165},"\"grid_fill.xlsx\"",[156,1786,715],{"class":192},[10,1788,1789,1790,1793],{},"Note how the denominator stays ",[14,1791,1792],{},"$B$2:$D$3"," on every row: it is anchored, so both the row fill and any later column fill leave it alone. Choosing the anchors carefully in the one source formula is what makes the rest of the grid correct for free.",[142,1795,1797],{"id":1796},"filling-into-an-excel-table","Filling into an Excel table",[10,1799,1800],{},"If the destination range is a real Excel table, a formula written into one cell of a calculated column is expected to appear in every row of that column when a person edits it — but openpyxl writes only the cell you assign. Fill the whole column yourself, then extend the table reference so the new rows belong to it:",[147,1802,1804],{"className":179,"code":1803,"language":181,"meta":152,"style":152},"from openpyxl import load_workbook\n\nwb = load_workbook(\"orders_table.xlsx\")\nws = wb.active\ntable = ws.tables[\"Orders\"]\n\nstart, end = table.ref.split(\":\")\nlast_row = ws.max_row\ntable.ref = f\"{start}:{end[0]}{last_row}\"     # stretch to the new last row\n\nfor r in range(2, last_row + 1):\n    ws[f\"D{r}\"] = f\"=B{r}*C{r}\"\n\nwb.save(\"orders_table_filled.xlsx\")\n",[14,1805,1806,1816,1820,1833,1841,1855,1859,1874,1884,1928,1932,1955,1995,1999],{"__ignoreMap":152},[156,1807,1808,1810,1812,1814],{"class":71,"line":158},[156,1809,189],{"class":188},[156,1811,193],{"class":192},[156,1813,196],{"class":188},[156,1815,785],{"class":192},[156,1817,1818],{"class":71,"line":202},[156,1819,206],{"emptyLinePlaceholder":205},[156,1821,1822,1824,1826,1828,1831],{"class":71,"line":209},[156,1823,319],{"class":192},[156,1825,215],{"class":188},[156,1827,810],{"class":192},[156,1829,1830],{"class":165},"\"orders_table.xlsx\"",[156,1832,715],{"class":192},[156,1834,1835,1837,1839],{"class":71,"line":221},[156,1836,330],{"class":192},[156,1838,215],{"class":188},[156,1840,335],{"class":192},[156,1842,1843,1846,1848,1851,1853],{"class":71,"line":245},[156,1844,1845],{"class":192},"table ",[156,1847,215],{"class":188},[156,1849,1850],{"class":192}," ws.tables[",[156,1852,826],{"class":165},[156,1854,308],{"class":192},[156,1856,1857],{"class":71,"line":265},[156,1858,206],{"emptyLinePlaceholder":205},[156,1860,1861,1864,1866,1869,1872],{"class":71,"line":285},[156,1862,1863],{"class":192},"start, end ",[156,1865,215],{"class":188},[156,1867,1868],{"class":192}," table.ref.split(",[156,1870,1871],{"class":165},"\":\"",[156,1873,715],{"class":192},[156,1875,1876,1879,1881],{"class":71,"line":305},[156,1877,1878],{"class":192},"last_row ",[156,1880,215],{"class":188},[156,1882,1883],{"class":192}," ws.max_row\n",[156,1885,1886,1889,1891,1893,1895,1897,1900,1902,1905,1907,1910,1912,1915,1918,1921,1923,1925],{"class":71,"line":311},[156,1887,1888],{"class":192},"table.ref ",[156,1890,215],{"class":188},[156,1892,498],{"class":188},[156,1894,465],{"class":165},[156,1896,456],{"class":455},[156,1898,1899],{"class":192},"start",[156,1901,462],{"class":455},[156,1903,1904],{"class":165},":",[156,1906,456],{"class":455},[156,1908,1909],{"class":192},"end[",[156,1911,46],{"class":233},[156,1913,1914],{"class":192},"]",[156,1916,1917],{"class":455},"}{",[156,1919,1920],{"class":192},"last_row",[156,1922,462],{"class":455},[156,1924,465],{"class":165},[156,1926,1927],{"class":733},"     # stretch to the new last row\n",[156,1929,1930],{"class":71,"line":316},[156,1931,206],{"emptyLinePlaceholder":205},[156,1933,1934,1936,1938,1940,1942,1944,1946,1949,1951,1953],{"class":71,"line":327},[156,1935,389],{"class":188},[156,1937,534],{"class":192},[156,1939,395],{"class":188},[156,1941,539],{"class":233},[156,1943,872],{"class":192},[156,1945,255],{"class":233},[156,1947,1948],{"class":192},", last_row ",[156,1950,437],{"class":188},[156,1952,547],{"class":233},[156,1954,550],{"class":192},[156,1956,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993],{"class":71,"line":338},[156,1958,556],{"class":192},[156,1960,449],{"class":188},[156,1962,483],{"class":165},[156,1964,456],{"class":455},[156,1966,565],{"class":192},[156,1968,462],{"class":455},[156,1970,465],{"class":165},[156,1972,468],{"class":192},[156,1974,215],{"class":188},[156,1976,498],{"class":188},[156,1978,578],{"class":165},[156,1980,456],{"class":455},[156,1982,565],{"class":192},[156,1984,462],{"class":455},[156,1986,587],{"class":165},[156,1988,456],{"class":455},[156,1990,565],{"class":192},[156,1992,462],{"class":455},[156,1994,596],{"class":165},[156,1996,1997],{"class":71,"line":349},[156,1998,206],{"emptyLinePlaceholder":205},[156,2000,2001,2003,2006],{"class":71,"line":381},[156,2002,709],{"class":192},[156,2004,2005],{"class":165},"\"orders_table_filled.xlsx\"",[156,2007,715],{"class":192},[25,2009,34,2014,34,2017,34,2020,34,2023,34,2028,34,2030,34,2036,34,2040,34,2043,34,2048,34,2051,34,2053,34,2057,34,2060,34,2063,34,2067,34,2070,34,2075,34,2079,34,2082,34,2085,34,2089,34,2092,34,2097,34,2103,34,2107,34,2110,34,2115],{"viewBox":2010,"role":28,"ariaLabelledBy":2011,"xmlns":32,"style":33},"0 0 720 216",[2012,2013],"cd-table-t","cd-table-d",[36,2015,2016],{"id":2012},"Rows written below a table's range are outside the table",[40,2018,2019],{"id":2013},"A table whose reference ends at row 4 keeps its banding and structured references for rows 2 to 4. Two rows written at 5 and 6 carry the formula but sit outside the range, so they are plain cells until table.ref is stretched to include them.",[44,2021],{"x":46,"y":46,"width":47,"height":2022,"fill":49},"216",[59,2024,2027],{"x":135,"y":2025,"style":2026},"28","font-size:12px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","table.ref = A1:D4",[44,2029],{"x":1016,"y":1016,"width":991,"height":52,"fill":57},[59,2031,2035],{"x":2032,"y":2033,"style":2034},"56","60","font-size:12px;font-weight:700;fill:#ffffff","SKU",[59,2037,2039],{"x":2038,"y":2033,"style":2034},"260","Line_Total",[44,2041],{"x":1016,"y":2042,"width":991,"height":2025,"fill":86,"stroke":87},"70",[59,2044,2047],{"x":2032,"y":2045,"style":2046},"89","font-size:11.5px;fill:var(--text,#172033)","A-100",[59,2049,2050],{"x":2038,"y":2045,"style":2046},"=B2*C2",[44,2052],{"x":1016,"y":110,"width":991,"height":2025,"fill":49,"stroke":87},[59,2054,2056],{"x":2032,"y":2055,"style":2046},"117","B-200",[59,2058,2059],{"x":2038,"y":2055,"style":2046},"=B3*C3",[44,2061],{"x":1016,"y":2062,"width":991,"height":2025,"fill":86,"stroke":87},"126",[59,2064,2066],{"x":2032,"y":2065,"style":2046},"145","C-300",[59,2068,2069],{"x":2038,"y":2065,"style":2046},"=B4*C4",[44,2071],{"x":1016,"y":2072,"width":991,"height":53,"fill":49,"stroke":2073,"strokeDashArray":2074},"158","var(--danger,#dc2626)",[234,875],[59,2076,2078],{"x":2032,"y":992,"style":2077},"font-size:11.5px;fill:var(--muted,#5b6780)","D-400",[59,2080,2081],{"x":2038,"y":992,"style":2077},"=B5*C5",[44,2083],{"x":1016,"y":996,"width":991,"height":53,"fill":49,"stroke":2073,"strokeDashArray":2084},[234,875],[59,2086,2088],{"x":2032,"y":2087,"style":2077},"202","E-500",[59,2090,2091],{"x":2038,"y":2087,"style":2077},"=B6*C6",[44,2093],{"x":2094,"y":2033,"width":2095,"height":2096,"rx":111,"fill":1026,"stroke":1027},"392","300","66",[59,2098,2102],{"x":2099,"y":2100,"style":2101},"542","86","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","inside the range",[59,2104,2106],{"x":2099,"y":2105,"style":68},"108","banded, counted by Orders[Line_Total]",[44,2108],{"x":2094,"y":115,"width":2095,"height":2096,"rx":111,"fill":2109,"stroke":2073},"#fce9e9",[59,2111,2114],{"x":2099,"y":2112,"style":2113},"172","font-size:12px;font-weight:700;fill:var(--danger,#dc2626);text-anchor:middle","outside the range",[59,2116,2118],{"x":2099,"y":2117,"style":68},"194","formulas run, summaries ignore them",[10,2120,2121,2122,2125,2126,2129],{},"Stretching ",[14,2123,2124],{},"table.ref"," matters because Excel treats the table range as authoritative: rows outside it are ordinary cells, so they lose the banded formatting and are ignored by any structured reference such as ",[14,2127,2128],{},"Orders[Line_Total]",". Writing the formulas and forgetting the range is the usual reason a filled column looks right but a summary elsewhere under-reports.",[142,2131,2133],{"id":2132},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[2135,2136,2137,2153],"table",{},[2138,2139,2140],"thead",{},[2141,2142,2143,2147,2150],"tr",{},[2144,2145,2146],"th",{},"Symptom",[2144,2148,2149],{},"Cause",[2144,2151,2152],{},"Fix",[2154,2155,2156,2170,2188,2205,2218,2237],"tbody",{},[2141,2157,2158,2162,2165],{},[2159,2160,2161],"td",{},"Every copied row references the same cells",[2159,2163,2164],{},"Formula string was reused without offsetting",[2159,2166,2167,2168],{},"Generate per row, or use ",[14,2169,768],{},[2141,2171,2172,2175,2183],{},[2159,2173,2174],{},"Copies point one row too far",[2159,2176,2177,2178,2180,2181],{},"Wrong ",[14,2179,909],{}," passed to ",[14,2182,768],{},[2159,2184,2185,2187],{},[14,2186,909],{}," must be where the formula currently lives",[2141,2189,2190,2193,2196],{},[2159,2191,2192],{},"Copies are unstyled",[2159,2194,2195],{},"Assigning a value does not copy style",[2159,2197,2198,2199,2201,2202,2204],{},"Copy ",[14,2200,1203],{},", or set ",[14,2203,1216],{}," per cell",[2141,2206,2207,2210,2215],{},[2159,2208,2209],{},"Formulas run past the data",[2159,2211,2212,2213],{},"Range built from ",[14,2214,1481],{},[2159,2216,2217],{},"Derive the last row from a key column",[2141,2219,2220,2225,2228],{},[2159,2221,2222,2224],{},[14,2223,752],{}," down the column",[2159,2226,2227],{},"Divisor is blank or zero",[2159,2229,2230,2231,2233,2234],{},"Wrap in ",[14,2232,748],{},"\u002F",[14,2235,2236],{},"IFERROR",[2141,2238,2239,2242,2252],{},[2159,2240,2241],{},"Anchored cell moved anyway",[2159,2243,2244,2245,2248,2249],{},"Reference was written ",[14,2246,2247],{},"D14"," instead of ",[14,2250,2251],{},"$D$14",[2159,2253,2254],{},"Add the dollar signs in the source formula",[142,2256,2258],{"id":2257},"performance-and-scale-notes","Performance and scale notes",[10,2260,2261,2262,2264],{},"Both approaches write one formula string per cell, so the cost is linear in rows. ",[14,2263,768],{}," parses each formula it shifts, which makes it measurably slower than an f-string in a tight loop — on 100,000 rows that difference is worth caring about, and generating the string yourself wins. The bigger scale question is whether the reader needs formulas at all: 100,000 live formulas make a workbook slow to open and recalculate, while computing the column in pandas and writing numbers keeps the file fast. Reserve the filled column for sheets where someone is expected to change an input.",[142,2266,2268],{"id":2267},"conclusion","Conclusion",[10,2270,2271,2272,2274],{},"There is no fill handle in the file format, so filling down is always \"write one formula per row\". Generate the strings when your code owns the layout, translate when the source formula belongs to a template, copy ",[14,2273,1203],{}," if the cells should look alike, and derive the last row from a column that always has data. Get the anchors right once and every copied row inherits correct references.",[142,2276,2278],{"id":2277},"frequently-asked-questions","Frequently asked questions",[10,2280,2281,2285,2286,2288],{},[2282,2283,2284],"strong",{},"Does openpyxl have a fill handle?","\nNo. Copying a formula down means writing one formula per row, either generated in a loop or produced from a source formula with the ",[14,2287,768],{}," class.",[10,2290,2291,2297,2298,2301],{},[2282,2292,2293,2294,2296],{},"What does ",[14,2295,768],{}," actually change?","\nIt shifts relative references by the row and column offset between the origin cell and the destination, and leaves anchored parts such as ",[14,2299,2300],{},"$B$1"," exactly as they are.",[10,2303,2304,2307,2308,2311,2312,2314],{},[2282,2305,2306],{},"Does copying the formula copy the formatting too?","\nNo. Assigning a value never copies style. Use ",[14,2309,2310],{},"copy(source._style)"," or set ",[14,2313,1216],{},", font and fill explicitly on each destination cell.",[10,2316,2317,2320,2321,2324],{},[2282,2318,2319],{},"How do I stop the formula appearing on blank rows?","\nOnly write it where the source data exists, or wrap the expression in ",[14,2322,2323],{},"IF(A2=\"\",\"\",…)"," so the cell shows nothing when the row is empty.",[142,2326,2328],{"id":2327},"related","Related",[10,2330,2331],{},"Up to the parent guide:",[2333,2334,2335],"ul",{},[2336,2337,2338,2340],"li",{},[19,2339,22],{"href":21}," — anchoring, names and the formula round trip.",[10,2342,2343],{},"Related guides:",[2333,2345,2346,2353,2360,2367],{},[2336,2347,2348,2352],{},[19,2349,2351],{"href":2350},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl\u002F","Write a Formula to an Excel Cell with openpyxl"," — the single-cell case in detail.",[2336,2354,2355,2359],{},[19,2356,2358],{"href":2357},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fadd-sum-and-average-formulas-with-python\u002F","Add SUM and AVERAGE Formulas with Python"," — the total row under a filled column.",[2336,2361,2362,2366],{},[19,2363,2365],{"href":2364},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Fset-column-width-and-row-height-in-openpyxl\u002F","Set Column Width and Row Height in openpyxl"," — making the filled column readable.",[2336,2368,2369,2373],{},[19,2370,2372],{"href":2371},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl"," — fonts, fills and formats you may want to copy.",[2375,2376,2377],"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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}",{"title":152,"searchDepth":202,"depth":202,"links":2379},[2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391],{"id":144,"depth":202,"text":145},{"id":172,"depth":202,"text":173},{"id":756,"depth":202,"text":757},{"id":1051,"depth":202,"text":1052},{"id":1228,"depth":202,"text":1229},{"id":1489,"depth":202,"text":1490},{"id":1796,"depth":202,"text":1797},{"id":2132,"depth":202,"text":2133},{"id":2257,"depth":202,"text":2258},{"id":2267,"depth":202,"text":2268},{"id":2277,"depth":202,"text":2278},{"id":2327,"depth":202,"text":2328},"2026-08-01","Fill a formula down every data row from Python — generating references per row, translating an existing formula with openpyxl's Translator, and copying the source cell's style.","md",[2396,2398,2401,2403],{"q":2284,"a":2397},"No. Copying a formula down means writing one formula per row, either generated in a loop or produced from a source formula with the Translator class.",{"q":2399,"a":2400},"What does Translator actually change?","It shifts relative references by the row and column offset between the origin cell and the destination, and leaves anchored parts such as $B$1 exactly as they are.",{"q":2306,"a":2402},"No. Assigning a value never copies style. Use copy(source.\\_style) or set number_format, font and fill explicitly on each destination cell.",{"q":2319,"a":2404},"Only write it where the source data exists, or wrap the expression in IF(A2=\"\",\"\",…) so the cell shows nothing when the row is empty.",{"breadcrumb":2406},[2407,2409,2412,2413],{"name":2408,"item":2233},"Home",{"name":2410,"item":2411},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":22,"item":21},{"name":5,"item":2414},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl\u002F","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl",{"title":5,"description":2417},"openpyxl has no fill handle. Generate per-row formulas in a loop, or use openpyxl.formula.translate.Translator to shift an existing formula down a range.","copy-formula-down-a-column-in-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl\u002Findex","how-to","GfpPZ9q8NJ9-UUPr4gIKeQZeFK2VTZmSAw8MGX4HvGI",[2423,2427],{"title":2424,"path":2425,"stem":2426,"children":-1},"Convert Excel Formulas to Values with Python","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fconvert-excel-formulas-to-values-with-python","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fconvert-excel-formulas-to-values-with-python\u002Findex",{"title":2428,"path":2429,"stem":2430,"children":-1},"Create a Named Range in Excel with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl\u002Findex",1785584462714]