[{"data":1,"prerenderedAt":2695},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl":2660,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl":2669,"children:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl":2674,"related:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl":2675},{"id":4,"title":5,"body":6,"dateModified":2625,"datePublished":2625,"description":2626,"extension":2627,"faq":2628,"keyword":2637,"kind":2638,"meta":2639,"navigation":427,"path":2648,"seo":2649,"slug":2652,"stem":2653,"topics":2654,"type":2658,"__hash__":2659},"docs\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl\u002Findex.md","Move a Range of Cells with openpyxl move_range",{"type":7,"value":8,"toc":2612},"minimark",[9,24,357,362,386,687,691,701,758,773,777,792,795,1271,1282,1290,1501,1505,1518,1686,1697,1701,1706,2109,2120,2124,2127,2286,2301,2470,2474,2518,2522,2537,2541,2547,2551,2557,2563,2569,2575,2579,2608],[10,11,12,13,17,18,23],"p",{},"Report templates change shape: a title row needs to go above the table, a new column has to squeeze in on the left, a block of inputs should sit further right. openpyxl's ",[14,15,16],"code",{},"ws.move_range()"," shifts a rectangular block of cells by a number of rows and columns, and with one argument it keeps the formulas inside that block working. It does less than Excel's cut-and-paste, though, and the parts it leaves behind are exactly the ones that break reports quietly. This page, part of ",[19,20,22],"a",{"href":21},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002F","Using openpyxl for Excel File Manipulation",", shows what moves, what does not, and how to move a table safely.",[25,26,34,35,34,39,34,43,34,51,34,60,34,64,34,71,34,75,34,79,34,83,34,87,34,91,34,95,34,99,34,104,34,106,34,110,34,112,34,115,34,117,34,120,34,122,34,125,34,128,34,132,34,134,34,137,34,139,34,141,34,143,34,146,34,151,34,155,34,158,34,161,34,163,34,166,34,168,34,171,34,173,34,176,34,178,34,181,34,184,34,188,34,191,34,194,34,197,34,200,34,203,34,206,34,209,34,213,34,217,34,219,34,222,34,224,34,226,34,228,34,230,34,232,34,234,34,236,34,238,34,240,34,242,34,244,34,246,34,248,34,250,34,252,34,254,34,256,34,258,34,260,34,262,34,264,34,266,34,268,34,271,34,274,34,276,34,278,34,280,34,282,34,284,34,286,34,288,34,292,34,296,34,299,34,302,34,304,34,306,34,308,34,310,34,312,34,314,34,316,34,318,34,321,34,327,34,331,34,338,34,343,34,351],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"30 0 700 220","img",[30,31],"mvr-shift-t","mvr-shift-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:700px;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},"Moving a table two rows down and one column right",[40,41,42],"desc",{"id":31},"Before: a table in A1:D3 with item, qty, price and a total formula =B2*C2. After move_range(\"A1:D3\", rows=2, cols=1, translate=True): the table sits in B3:E5 and its formula has become =C4*D4, still multiplying its own row's qty and price.",[44,45],"rect",{"x":46,"y":47,"width":48,"height":49,"fill":50},"30","0","700","220","#ffffff",[44,52],{"x":53,"y":54,"width":55,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"46.1","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[44,61],{"x":62,"y":54,"width":63,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"78.1","51.0",[65,66,70],"text",{"x":67,"y":68,"style":69},"103.6","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[44,72],{"x":73,"y":54,"width":74,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"129.2","44.1",[65,76,78],{"x":77,"y":68,"style":69},"151.2","B",[44,80],{"x":81,"y":54,"width":82,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"173.3","55.4",[65,84,86],{"x":85,"y":68,"style":69},"201.0","C",[44,88],{"x":89,"y":54,"width":90,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"228.7","73.5",[65,92,94],{"x":93,"y":68,"style":69},"265.5","D",[44,96],{"x":53,"y":97,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"64.0","28.0",[65,100,103],{"x":101,"y":102,"style":69},"62.1","83.0","1",[44,105],{"x":62,"y":97,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,107,109],{"x":67,"y":102,"style":108},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","item",[44,111],{"x":73,"y":97,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,113,114],{"x":77,"y":102,"style":108},"qty",[44,116],{"x":81,"y":97,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,118,119],{"x":85,"y":102,"style":108},"price",[44,121],{"x":89,"y":97,"width":90,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,123,124],{"x":93,"y":102,"style":108},"total",[44,126],{"x":53,"y":127,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"92.0",[65,129,131],{"x":101,"y":130,"style":69},"111.0","2",[44,133],{"x":62,"y":127,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,135,19],{"x":67,"y":130,"style":136},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[44,138],{"x":73,"y":127,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,140,131],{"x":77,"y":130,"style":136},[44,142],{"x":81,"y":127,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,144,145],{"x":85,"y":130,"style":136},"3",[44,147],{"x":89,"y":127,"width":90,"height":98,"rx":47,"fill":148,"stroke":149,"style":150},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[65,152,154],{"x":93,"y":130,"style":153},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","=B2*C2",[44,156],{"x":53,"y":157,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"120.0",[65,159,145],{"x":101,"y":160,"style":69},"139.0",[44,162],{"x":62,"y":157,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,164,165],{"x":67,"y":160,"style":136},"b",[44,167],{"x":73,"y":157,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,169,170],{"x":77,"y":160,"style":136},"4",[44,172],{"x":81,"y":157,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,174,175],{"x":85,"y":160,"style":136},"5",[44,177],{"x":89,"y":157,"width":90,"height":98,"rx":47,"fill":148,"stroke":149,"style":150},[65,179,180],{"x":93,"y":160,"style":153},"=B3*C3",[44,182],{"x":183,"y":54,"width":55,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"412.2",[44,185],{"x":186,"y":54,"width":187,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"444.2","44.0",[65,189,70],{"x":190,"y":68,"style":69},"466.2",[44,192],{"x":193,"y":54,"width":63,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"488.2",[65,195,78],{"x":196,"y":68,"style":69},"513.8",[44,198],{"x":199,"y":54,"width":74,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"539.3",[65,201,86],{"x":202,"y":68,"style":69},"561.4",[44,204],{"x":205,"y":54,"width":82,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"583.4",[65,207,94],{"x":208,"y":68,"style":69},"611.1",[44,210],{"x":211,"y":54,"width":212,"height":56,"rx":47,"fill":57,"stroke":58,"style":59},"638.8","75.1",[65,214,216],{"x":215,"y":68,"style":69},"676.3","E",[44,218],{"x":183,"y":97,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,220,103],{"x":221,"y":102,"style":69},"428.2",[44,223],{"x":186,"y":97,"width":187,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,225],{"x":193,"y":97,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,227],{"x":199,"y":97,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,229],{"x":205,"y":97,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,231],{"x":211,"y":97,"width":212,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,233],{"x":183,"y":127,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,235,131],{"x":221,"y":130,"style":69},[44,237],{"x":186,"y":127,"width":187,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,239],{"x":193,"y":127,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,241],{"x":199,"y":127,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,243],{"x":205,"y":127,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,245],{"x":211,"y":127,"width":212,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,247],{"x":183,"y":157,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},[65,249,145],{"x":221,"y":160,"style":69},[44,251],{"x":186,"y":157,"width":187,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,253],{"x":193,"y":157,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,255,109],{"x":196,"y":160,"style":136},[44,257],{"x":199,"y":157,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,259,114],{"x":202,"y":160,"style":136},[44,261],{"x":205,"y":157,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,263,119],{"x":208,"y":160,"style":136},[44,265],{"x":211,"y":157,"width":212,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,267,124],{"x":215,"y":160,"style":136},[44,269],{"x":183,"y":270,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"148.0",[65,272,170],{"x":221,"y":273,"style":69},"167.0",[44,275],{"x":186,"y":270,"width":187,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,277],{"x":193,"y":270,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,279,19],{"x":196,"y":273,"style":136},[44,281],{"x":199,"y":270,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,283,131],{"x":202,"y":273,"style":136},[44,285],{"x":205,"y":270,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,287,145],{"x":208,"y":273,"style":136},[44,289],{"x":211,"y":270,"width":212,"height":98,"rx":47,"fill":290,"stroke":291,"style":150},"#d9f4f1","var(--teal,#0f9488)",[65,293,295],{"x":215,"y":273,"style":294},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","=C4*D4",[44,297],{"x":183,"y":298,"width":55,"height":98,"rx":47,"fill":57,"stroke":58,"style":59},"176.0",[65,300,175],{"x":221,"y":301,"style":69},"195.0",[44,303],{"x":186,"y":298,"width":187,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[44,305],{"x":193,"y":298,"width":63,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,307,165],{"x":196,"y":301,"style":136},[44,309],{"x":199,"y":298,"width":74,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,311,170],{"x":202,"y":301,"style":136},[44,313],{"x":205,"y":298,"width":82,"height":98,"rx":47,"fill":50,"stroke":58,"style":59},[65,315,175],{"x":208,"y":301,"style":136},[44,317],{"x":211,"y":298,"width":212,"height":98,"rx":47,"fill":290,"stroke":291,"style":150},[65,319,320],{"x":215,"y":301,"style":294},"=C5*D5",[65,322,326],{"x":323,"y":324,"style":325},"174.2","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before — A1:D3",[65,328,330],{"x":329,"y":324,"style":325},"563.1","after — B3:E5",[332,333],"line",{"x1":334,"y1":335,"x2":336,"y2":335,"stroke":149,"style":337},"312.2","94.0","398.2","stroke-width:2px",[339,340],"polygon",{"points":341,"fill":342},"402.2,94.0 393.2,99.0 393.2,89.0","#5b5cf0",[44,344],{"x":345,"y":346,"width":347,"height":348,"rx":349,"fill":50,"stroke":58,"style":350},"332.7","61.0","49.1","22.0","11","stroke-width:1.2px",[65,352,356],{"x":353,"y":354,"style":355},"357.2","76.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","move",[358,359,361],"h2",{"id":360},"prerequisites","Prerequisites",[363,364,369],"pre",{"className":365,"code":366,"language":367,"meta":368,"style":368},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[14,370,371],{"__ignoreMap":368},[372,373,375,379,383],"span",{"class":332,"line":374},1,[372,376,378],{"class":377},"sMTad","pip",[372,380,382],{"class":381},"srMev"," install",[372,384,385],{"class":381}," openpyxl\n",[363,387,391],{"className":388,"code":389,"language":390,"meta":368,"style":368},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\nfrom openpyxl.styles import Font\n\ndef build():\n    wb = Workbook()\n    ws = wb.active\n    ws.append([\"item\", \"qty\", \"price\", \"total\"])\n    ws.append([\"a\", 2, 3, \"=B2*C2\"])\n    ws.append([\"b\", 4, 5, \"=B3*C3\"])\n    ws[\"A1\"].font = Font(bold=True)\n    ws[\"F1\"] = \"=SUM(D2:D3)\"          # a formula outside the block that points into it\n    return wb, ws\n\ndef show(ws, rows=6, cols=6):\n    for row in ws.iter_rows(min_row=1, max_row=rows, max_col=cols, values_only=True):\n        print(row)\n","python",[14,392,393,409,422,429,442,454,465,493,517,540,569,589,598,603,629,678],{"__ignoreMap":368},[372,394,395,399,403,406],{"class":332,"line":374},[372,396,398],{"class":397},"s-kum","from",[372,400,402],{"class":401},"skGVy"," openpyxl ",[372,404,405],{"class":397},"import",[372,407,408],{"class":401}," Workbook\n",[372,410,412,414,417,419],{"class":332,"line":411},2,[372,413,398],{"class":397},[372,415,416],{"class":401}," openpyxl.styles ",[372,418,405],{"class":397},[372,420,421],{"class":401}," Font\n",[372,423,425],{"class":332,"line":424},3,[372,426,428],{"emptyLinePlaceholder":427},true,"\n",[372,430,432,435,439],{"class":332,"line":431},4,[372,433,434],{"class":397},"def",[372,436,438],{"class":437},"s_Opv"," build",[372,440,441],{"class":401},"():\n",[372,443,445,448,451],{"class":332,"line":444},5,[372,446,447],{"class":401},"    wb ",[372,449,450],{"class":397},"=",[372,452,453],{"class":401}," Workbook()\n",[372,455,457,460,462],{"class":332,"line":456},6,[372,458,459],{"class":401},"    ws ",[372,461,450],{"class":397},[372,463,464],{"class":401}," wb.active\n",[372,466,468,471,474,477,480,482,485,487,490],{"class":332,"line":467},7,[372,469,470],{"class":401},"    ws.append([",[372,472,473],{"class":381},"\"item\"",[372,475,476],{"class":401},", ",[372,478,479],{"class":381},"\"qty\"",[372,481,476],{"class":401},[372,483,484],{"class":381},"\"price\"",[372,486,476],{"class":401},[372,488,489],{"class":381},"\"total\"",[372,491,492],{"class":401},"])\n",[372,494,496,498,501,503,506,508,510,512,515],{"class":332,"line":495},8,[372,497,470],{"class":401},[372,499,500],{"class":381},"\"a\"",[372,502,476],{"class":401},[372,504,131],{"class":505},"sP0c6",[372,507,476],{"class":401},[372,509,145],{"class":505},[372,511,476],{"class":401},[372,513,514],{"class":381},"\"=B2*C2\"",[372,516,492],{"class":401},[372,518,520,522,525,527,529,531,533,535,538],{"class":332,"line":519},9,[372,521,470],{"class":401},[372,523,524],{"class":381},"\"b\"",[372,526,476],{"class":401},[372,528,170],{"class":505},[372,530,476],{"class":401},[372,532,175],{"class":505},[372,534,476],{"class":401},[372,536,537],{"class":381},"\"=B3*C3\"",[372,539,492],{"class":401},[372,541,543,546,549,552,554,557,561,563,566],{"class":332,"line":542},10,[372,544,545],{"class":401},"    ws[",[372,547,548],{"class":381},"\"A1\"",[372,550,551],{"class":401},"].font ",[372,553,450],{"class":397},[372,555,556],{"class":401}," Font(",[372,558,560],{"class":559},"sa561","bold",[372,562,450],{"class":397},[372,564,565],{"class":505},"True",[372,567,568],{"class":401},")\n",[372,570,572,574,577,580,582,585],{"class":332,"line":571},11,[372,573,545],{"class":401},[372,575,576],{"class":381},"\"F1\"",[372,578,579],{"class":401},"] ",[372,581,450],{"class":397},[372,583,584],{"class":381}," \"=SUM(D2:D3)\"",[372,586,588],{"class":587},"s-wDw","          # a formula outside the block that points into it\n",[372,590,592,595],{"class":332,"line":591},12,[372,593,594],{"class":397},"    return",[372,596,597],{"class":401}," wb, ws\n",[372,599,601],{"class":332,"line":600},13,[372,602,428],{"emptyLinePlaceholder":427},[372,604,606,608,611,614,616,619,622,624,626],{"class":332,"line":605},14,[372,607,434],{"class":397},[372,609,610],{"class":437}," show",[372,612,613],{"class":401},"(ws, rows",[372,615,450],{"class":397},[372,617,618],{"class":505},"6",[372,620,621],{"class":401},", cols",[372,623,450],{"class":397},[372,625,618],{"class":505},[372,627,628],{"class":401},"):\n",[372,630,632,635,638,641,644,647,649,651,653,656,658,661,664,666,669,672,674,676],{"class":332,"line":631},15,[372,633,634],{"class":397},"    for",[372,636,637],{"class":401}," row ",[372,639,640],{"class":397},"in",[372,642,643],{"class":401}," ws.iter_rows(",[372,645,646],{"class":559},"min_row",[372,648,450],{"class":397},[372,650,103],{"class":505},[372,652,476],{"class":401},[372,654,655],{"class":559},"max_row",[372,657,450],{"class":397},[372,659,660],{"class":401},"rows, ",[372,662,663],{"class":559},"max_col",[372,665,450],{"class":397},[372,667,668],{"class":401},"cols, ",[372,670,671],{"class":559},"values_only",[372,673,450],{"class":397},[372,675,565],{"class":505},[372,677,628],{"class":401},[372,679,681,684],{"class":332,"line":680},16,[372,682,683],{"class":505},"        print",[372,685,686],{"class":401},"(row)\n",[358,688,690],{"id":689},"step-1-move-a-block-with-its-formulas","Step 1 — Move a block with its formulas",[10,692,693,696,697,700],{},[14,694,695],{},"move_range"," takes the block as an A1 range and offsets in rows and columns; positive numbers move down and right, negative numbers up and left. Pass ",[14,698,699],{},"translate=True"," so formulas inside the block are rewritten for their new position:",[363,702,704],{"className":388,"code":703,"language":390,"meta":368,"style":368},"wb, ws = build()\nws.move_range(\"A1:D3\", rows=2, cols=1, translate=True)\nshow(ws)\n",[14,705,706,716,753],{"__ignoreMap":368},[372,707,708,711,713],{"class":332,"line":374},[372,709,710],{"class":401},"wb, ws ",[372,712,450],{"class":397},[372,714,715],{"class":401}," build()\n",[372,717,718,721,724,726,729,731,733,735,738,740,742,744,747,749,751],{"class":332,"line":411},[372,719,720],{"class":401},"ws.move_range(",[372,722,723],{"class":381},"\"A1:D3\"",[372,725,476],{"class":401},[372,727,728],{"class":559},"rows",[372,730,450],{"class":397},[372,732,131],{"class":505},[372,734,476],{"class":401},[372,736,737],{"class":559},"cols",[372,739,450],{"class":397},[372,741,103],{"class":505},[372,743,476],{"class":401},[372,745,746],{"class":559},"translate",[372,748,450],{"class":397},[372,750,565],{"class":505},[372,752,568],{"class":401},[372,754,755],{"class":332,"line":424},[372,756,757],{"class":401},"show(ws)\n",[10,759,760,761,763,764,766,767,769,770,772],{},"The table now sits at B3:E5, and its row formulas read ",[14,762,295],{}," and ",[14,765,320],{}," — each still multiplies its own row's quantity and price. The bold header moved with its cell, because styles belong to cells. Without ",[14,768,699],{},", the moved formulas would keep their original text, ",[14,771,154],{},", and multiply the wrong cells.",[358,774,776],{"id":775},"step-2-fix-formulas-that-point-into-the-block","Step 2 — Fix formulas that point into the block",[10,778,779,780,783,784,788,789,791],{},"The last column of that output shows the catch. The formula in F1, ",[14,781,782],{},"=SUM(D2:D3)",", sat ",[785,786,787],"em",{},"outside"," the moved block, so ",[14,790,695],{}," did not touch it — and it now sums two empty cells. Excel's own cut-and-paste would have updated it; openpyxl does not track references from the rest of the sheet.",[10,793,794],{},"When other formulas refer to a block you move, rewrite their references with the same offset. openpyxl's formula tokenizer splits a formula into operands and operators, so a short helper can find every cell or range reference that lies wholly inside the moved block and shift it:",[363,796,798],{"className":388,"code":797,"language":390,"meta":368,"style":368},"from openpyxl.formula.tokenizer import Tokenizer, Token\nfrom openpyxl.utils.cell import range_boundaries, get_column_letter\n\ndef shift_refs(formula, block, rows, cols):\n    bmin_c, bmin_r, bmax_c, bmax_r = range_boundaries(block)\n    out = []\n    for tok in Tokenizer(formula).items:\n        text = tok.value\n        if tok.type == Token.OPERAND and tok.subtype == Token.RANGE and \"!\" not in text:\n            try:\n                c1, r1, c2, r2 = range_boundaries(text.replace(\"$\", \"\"))\n            except ValueError:\n                out.append(text)\n                continue\n            if bmin_c \u003C= c1 and c2 \u003C= bmax_c and bmin_r \u003C= r1 and r2 \u003C= bmax_r:\n                start = f\"{get_column_letter(c1 + cols)}{r1 + rows}\"\n                end = f\"{get_column_letter(c2 + cols)}{r2 + rows}\"\n                text = start if (c1, r1) == (c2, r2) else f\"{start}:{end}\"\n        out.append(text)\n    return \"=\" + \"\".join(out)\n\nprint(ws[\"F1\"].value)                                   # =SUM(D2:D3) — now stale\nws[\"F1\"] = shift_refs(ws[\"F1\"].value, \"A1:D3\", rows=2, cols=1)\nprint(ws[\"F1\"].value)                                   # =SUM(E4:E5)\nprint(shift_refs(\"=SUM(D2:D9)\", \"A1:D3\", 2, 1))         # partly outside: left alone\n",[14,799,800,812,824,828,838,848,858,870,880,924,932,953,963,968,973,1018,1061,1095,1143,1149,1166,1171,1188,1228,1242],{"__ignoreMap":368},[372,801,802,804,807,809],{"class":332,"line":374},[372,803,398],{"class":397},[372,805,806],{"class":401}," openpyxl.formula.tokenizer ",[372,808,405],{"class":397},[372,810,811],{"class":401}," Tokenizer, Token\n",[372,813,814,816,819,821],{"class":332,"line":411},[372,815,398],{"class":397},[372,817,818],{"class":401}," openpyxl.utils.cell ",[372,820,405],{"class":397},[372,822,823],{"class":401}," range_boundaries, get_column_letter\n",[372,825,826],{"class":332,"line":424},[372,827,428],{"emptyLinePlaceholder":427},[372,829,830,832,835],{"class":332,"line":431},[372,831,434],{"class":397},[372,833,834],{"class":437}," shift_refs",[372,836,837],{"class":401},"(formula, block, rows, cols):\n",[372,839,840,843,845],{"class":332,"line":444},[372,841,842],{"class":401},"    bmin_c, bmin_r, bmax_c, bmax_r ",[372,844,450],{"class":397},[372,846,847],{"class":401}," range_boundaries(block)\n",[372,849,850,853,855],{"class":332,"line":456},[372,851,852],{"class":401},"    out ",[372,854,450],{"class":397},[372,856,857],{"class":401}," []\n",[372,859,860,862,865,867],{"class":332,"line":467},[372,861,634],{"class":397},[372,863,864],{"class":401}," tok ",[372,866,640],{"class":397},[372,868,869],{"class":401}," Tokenizer(formula).items:\n",[372,871,872,875,877],{"class":332,"line":495},[372,873,874],{"class":401},"        text ",[372,876,450],{"class":397},[372,878,879],{"class":401}," tok.value\n",[372,881,882,885,888,891,894,897,900,903,905,907,910,912,915,918,921],{"class":332,"line":519},[372,883,884],{"class":397},"        if",[372,886,887],{"class":401}," tok.type ",[372,889,890],{"class":397},"==",[372,892,893],{"class":401}," Token.",[372,895,896],{"class":505},"OPERAND",[372,898,899],{"class":397}," and",[372,901,902],{"class":401}," tok.subtype ",[372,904,890],{"class":397},[372,906,893],{"class":401},[372,908,909],{"class":505},"RANGE",[372,911,899],{"class":397},[372,913,914],{"class":381}," \"!\"",[372,916,917],{"class":397}," not",[372,919,920],{"class":397}," in",[372,922,923],{"class":401}," text:\n",[372,925,926,929],{"class":332,"line":542},[372,927,928],{"class":397},"            try",[372,930,931],{"class":401},":\n",[372,933,934,937,939,942,945,947,950],{"class":332,"line":571},[372,935,936],{"class":401},"                c1, r1, c2, r2 ",[372,938,450],{"class":397},[372,940,941],{"class":401}," range_boundaries(text.replace(",[372,943,944],{"class":381},"\"$\"",[372,946,476],{"class":401},[372,948,949],{"class":381},"\"\"",[372,951,952],{"class":401},"))\n",[372,954,955,958,961],{"class":332,"line":591},[372,956,957],{"class":397},"            except",[372,959,960],{"class":505}," ValueError",[372,962,931],{"class":401},[372,964,965],{"class":332,"line":600},[372,966,967],{"class":401},"                out.append(text)\n",[372,969,970],{"class":332,"line":605},[372,971,972],{"class":397},"                continue\n",[372,974,975,978,981,984,987,990,993,995,998,1000,1003,1005,1008,1010,1013,1015],{"class":332,"line":631},[372,976,977],{"class":397},"            if",[372,979,980],{"class":401}," bmin_c ",[372,982,983],{"class":397},"\u003C=",[372,985,986],{"class":401}," c1 ",[372,988,989],{"class":397},"and",[372,991,992],{"class":401}," c2 ",[372,994,983],{"class":397},[372,996,997],{"class":401}," bmax_c ",[372,999,989],{"class":397},[372,1001,1002],{"class":401}," bmin_r ",[372,1004,983],{"class":397},[372,1006,1007],{"class":401}," r1 ",[372,1009,989],{"class":397},[372,1011,1012],{"class":401}," r2 ",[372,1014,983],{"class":397},[372,1016,1017],{"class":401}," bmax_r:\n",[372,1019,1020,1023,1025,1028,1031,1035,1038,1041,1044,1047,1050,1052,1055,1058],{"class":332,"line":680},[372,1021,1022],{"class":401},"                start ",[372,1024,450],{"class":397},[372,1026,1027],{"class":397}," f",[372,1029,1030],{"class":381},"\"",[372,1032,1034],{"class":1033},"sSjpA","{",[372,1036,1037],{"class":401},"get_column_letter(c1 ",[372,1039,1040],{"class":397},"+",[372,1042,1043],{"class":401}," cols)",[372,1045,1046],{"class":1033},"}{",[372,1048,1049],{"class":401},"r1 ",[372,1051,1040],{"class":397},[372,1053,1054],{"class":401}," rows",[372,1056,1057],{"class":1033},"}",[372,1059,1060],{"class":381},"\"\n",[372,1062,1064,1067,1069,1071,1073,1075,1078,1080,1082,1084,1087,1089,1091,1093],{"class":332,"line":1063},17,[372,1065,1066],{"class":401},"                end ",[372,1068,450],{"class":397},[372,1070,1027],{"class":397},[372,1072,1030],{"class":381},[372,1074,1034],{"class":1033},[372,1076,1077],{"class":401},"get_column_letter(c2 ",[372,1079,1040],{"class":397},[372,1081,1043],{"class":401},[372,1083,1046],{"class":1033},[372,1085,1086],{"class":401},"r2 ",[372,1088,1040],{"class":397},[372,1090,1054],{"class":401},[372,1092,1057],{"class":1033},[372,1094,1060],{"class":381},[372,1096,1098,1101,1103,1106,1109,1112,1114,1117,1120,1122,1124,1126,1129,1131,1134,1136,1139,1141],{"class":332,"line":1097},18,[372,1099,1100],{"class":401},"                text ",[372,1102,450],{"class":397},[372,1104,1105],{"class":401}," start ",[372,1107,1108],{"class":397},"if",[372,1110,1111],{"class":401}," (c1, r1) ",[372,1113,890],{"class":397},[372,1115,1116],{"class":401}," (c2, r2) ",[372,1118,1119],{"class":397},"else",[372,1121,1027],{"class":397},[372,1123,1030],{"class":381},[372,1125,1034],{"class":1033},[372,1127,1128],{"class":401},"start",[372,1130,1057],{"class":1033},[372,1132,1133],{"class":381},":",[372,1135,1034],{"class":1033},[372,1137,1138],{"class":401},"end",[372,1140,1057],{"class":1033},[372,1142,1060],{"class":381},[372,1144,1146],{"class":332,"line":1145},19,[372,1147,1148],{"class":401},"        out.append(text)\n",[372,1150,1152,1154,1157,1160,1163],{"class":332,"line":1151},20,[372,1153,594],{"class":397},[372,1155,1156],{"class":381}," \"=\"",[372,1158,1159],{"class":397}," +",[372,1161,1162],{"class":381}," \"\"",[372,1164,1165],{"class":401},".join(out)\n",[372,1167,1169],{"class":332,"line":1168},21,[372,1170,428],{"emptyLinePlaceholder":427},[372,1172,1174,1177,1180,1182,1185],{"class":332,"line":1173},22,[372,1175,1176],{"class":505},"print",[372,1178,1179],{"class":401},"(ws[",[372,1181,576],{"class":381},[372,1183,1184],{"class":401},"].value)                                   ",[372,1186,1187],{"class":587},"# =SUM(D2:D3) — now stale\n",[372,1189,1191,1194,1196,1198,1200,1203,1205,1208,1210,1212,1214,1216,1218,1220,1222,1224,1226],{"class":332,"line":1190},23,[372,1192,1193],{"class":401},"ws[",[372,1195,576],{"class":381},[372,1197,579],{"class":401},[372,1199,450],{"class":397},[372,1201,1202],{"class":401}," shift_refs(ws[",[372,1204,576],{"class":381},[372,1206,1207],{"class":401},"].value, ",[372,1209,723],{"class":381},[372,1211,476],{"class":401},[372,1213,728],{"class":559},[372,1215,450],{"class":397},[372,1217,131],{"class":505},[372,1219,476],{"class":401},[372,1221,737],{"class":559},[372,1223,450],{"class":397},[372,1225,103],{"class":505},[372,1227,568],{"class":401},[372,1229,1231,1233,1235,1237,1239],{"class":332,"line":1230},24,[372,1232,1176],{"class":505},[372,1234,1179],{"class":401},[372,1236,576],{"class":381},[372,1238,1184],{"class":401},[372,1240,1241],{"class":587},"# =SUM(E4:E5)\n",[372,1243,1245,1247,1250,1253,1255,1257,1259,1261,1263,1265,1268],{"class":332,"line":1244},25,[372,1246,1176],{"class":505},[372,1248,1249],{"class":401},"(shift_refs(",[372,1251,1252],{"class":381},"\"=SUM(D2:D9)\"",[372,1254,476],{"class":401},[372,1256,723],{"class":381},[372,1258,476],{"class":401},[372,1260,131],{"class":505},[372,1262,476],{"class":401},[372,1264,103],{"class":505},[372,1266,1267],{"class":401},"))         ",[372,1269,1270],{"class":587},"# partly outside: left alone\n",[10,1272,1273,1274,1277,1278,1281],{},"A range that is only partly inside the block — ",[14,1275,1276],{},"D2:D9"," here — is left as it was, because there is no single right answer for it: the report's author has to decide whether it should grow, shrink or move. The helper also skips references to other sheets and writes relative addresses, so add ",[14,1279,1280],{},"$"," markers back if your formulas relied on them. Run it over every formula on the sheet after a move, and review whatever it leaves alone.",[10,1283,1284,1285,1289],{},"For many dependent formulas, search the sheet for references into the old range before moving; ",[19,1286,1288],{"href":1287},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Faudit-every-formula-in-a-workbook-with-python\u002F","Audit Every Formula in a Workbook with Python"," shows how to list them. If the dependent formulas are numerous and mechanical, it is often simpler to regenerate them than to patch them.",[25,1291,34,1297,34,1300,34,1303,34,1307,34,1312,34,1316,34,1322,34,1325,34,1329,34,1333,34,1338,34,1340,34,1350,34,1352,34,1356,34,1359,34,1363,34,1365,34,1370,34,1372,34,1375,34,1378,34,1382,34,1384,34,1392,34,1394,34,1398,34,1401,34,1405,34,1407,34,1415,34,1417,34,1421,34,1424,34,1428,34,1430,34,1435,34,1437,34,1441,34,1444,34,1448,34,1450,34,1455,34,1457,34,1461,34,1464,34,1468,34,1470,34,1475,34,1477,34,1481,34,1484,34,1488,34,1490,34,1495,34,1497],{"viewBox":1292,"role":28,"ariaLabelledBy":1293,"xmlns":32,"style":1296},"4 0 752 344",[1294,1295],"mvr-what-t","mvr-what-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[36,1298,1299],{"id":1294},"What move_range moves and what it leaves behind",[40,1301,1302],{"id":1295},"A table of worksheet features. Cell values and cell styles move. Formulas inside the block move and are rewritten only when translate is True. Formulas elsewhere that refer to the block are not updated. Merged ranges, conditional formatting, data validation, row heights and column widths do not move. Existing cells at the destination are overwritten.",[44,1304],{"x":170,"y":47,"width":1305,"height":1306,"fill":50},"752","344",[44,1308],{"x":1309,"y":1310,"width":1311,"height":54,"rx":47,"fill":50,"stroke":58,"style":59},"20.0","16.0","265.9",[44,1313],{"x":1314,"y":1310,"width":1315,"height":54,"rx":47,"fill":148,"stroke":149,"style":350},"285.9","227.1",[65,1317,1321],{"x":1318,"y":1319,"style":1320},"399.4","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Moves with the block",[44,1323],{"x":1324,"y":1310,"width":1315,"height":54,"rx":47,"fill":148,"stroke":149,"style":350},"512.9",[65,1326,1328],{"x":1327,"y":1319,"style":1320},"626.5","Notes",[44,1330],{"x":1309,"y":1331,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"56.0","34.0",[65,1334,1337],{"x":55,"y":1335,"style":1336},"78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Values",[44,1339],{"x":1314,"y":1331,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1342,1344],"g",{"transform":1343},"translate(390.4,64.0) scale(0.750)",[1345,1346],"path",{"d":1347,"fill":1348,"stroke":291,"style":1349},"M5 12.5l4.5 4.5L19 7","none","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[44,1351],{"x":1324,"y":1331,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1353],{"x":1327,"y":1354,"style":1355},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[44,1357],{"x":1309,"y":1358,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"90.0",[65,1360,1362],{"x":55,"y":1361,"style":1336},"112.0","Fonts, fills, borders, number formats",[44,1364],{"x":1314,"y":1358,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1366,1368],{"transform":1367},"translate(390.4,98.0) scale(0.750)",[1345,1369],{"d":1347,"fill":1348,"stroke":291,"style":1349},[44,1371],{"x":1324,"y":1358,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1373,1374],{"x":1327,"y":130,"style":1355},"stored per cell",[44,1376],{"x":1309,"y":1377,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"124.0",[65,1379,1381],{"x":55,"y":1380,"style":1336},"146.0","Formulas inside the block",[44,1383],{"x":1314,"y":1377,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1385,1387],{"transform":1386},"translate(390.9,132.5) scale(0.708)",[1345,1388],{"d":1389,"fill":1348,"stroke":1390,"style":1391},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold,#b4740a)","stroke-width:2.54px;stroke-linecap:round;stroke-linejoin:round",[44,1393],{"x":1324,"y":1377,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1395,1397],{"x":1327,"y":1396,"style":1355},"145.0","rewritten only with translate=True",[44,1399],{"x":1309,"y":1400,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"158.0",[65,1402,1404],{"x":55,"y":1403,"style":1336},"180.0","Formulas elsewhere pointing in",[44,1406],{"x":1314,"y":1400,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1408,1410],{"transform":1409},"translate(391.4,167.0) scale(0.667)",[1345,1411],{"d":1412,"fill":1348,"stroke":1413,"style":1414},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[44,1416],{"x":1324,"y":1400,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1418,1420],{"x":1327,"y":1419,"style":1355},"179.0","now read the old address",[44,1422],{"x":1309,"y":1423,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"192.0",[65,1425,1427],{"x":55,"y":1426,"style":1336},"214.0","Merged ranges",[44,1429],{"x":1314,"y":1423,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1431,1433],{"transform":1432},"translate(391.4,201.0) scale(0.667)",[1345,1434],{"d":1412,"fill":1348,"stroke":1413,"style":1414},[44,1436],{"x":1324,"y":1423,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1438,1440],{"x":1327,"y":1439,"style":1355},"213.0","re-merge at the new place",[44,1442],{"x":1309,"y":1443,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"226.0",[65,1445,1447],{"x":55,"y":1446,"style":1336},"248.0","Conditional formatting and validation",[44,1449],{"x":1314,"y":1443,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1451,1453],{"transform":1452},"translate(391.4,235.0) scale(0.667)",[1345,1454],{"d":1412,"fill":1348,"stroke":1413,"style":1414},[44,1456],{"x":1324,"y":1443,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1458,1460],{"x":1327,"y":1459,"style":1355},"247.0","update their ranges",[44,1462],{"x":1309,"y":1463,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"260.0",[65,1465,1467],{"x":55,"y":1466,"style":1336},"282.0","Row heights and column widths",[44,1469],{"x":1314,"y":1463,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1471,1473],{"transform":1472},"translate(391.4,269.0) scale(0.667)",[1345,1474],{"d":1412,"fill":1348,"stroke":1413,"style":1414},[44,1476],{"x":1324,"y":1463,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1478,1480],{"x":1327,"y":1479,"style":1355},"281.0","set on rows and columns",[44,1482],{"x":1309,"y":1483,"width":1311,"height":1332,"rx":47,"fill":57,"stroke":58,"style":59},"294.0",[65,1485,1487],{"x":55,"y":1486,"style":1336},"316.0","Cells at the destination",[44,1489],{"x":1314,"y":1483,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[1341,1491,1493],{"transform":1492},"translate(391.4,303.0) scale(0.667)",[1345,1494],{"d":1412,"fill":1348,"stroke":1413,"style":1414},[44,1496],{"x":1324,"y":1483,"width":1315,"height":1332,"rx":47,"fill":50,"stroke":58,"style":59},[65,1498,1500],{"x":1327,"y":1499,"style":1355},"315.0","overwritten silently",[358,1502,1504],{"id":1503},"step-3-know-that-translate-means-copy-not-cut","Step 3 — Know that translate means copy, not cut",[10,1506,1507,1509,1510,1513,1514,1517],{},[14,1508,699],{}," shifts every ",[785,1511,1512],{},"relative"," reference in a moved formula by the same offset, the way copy-and-paste does. That is exactly right when a formula moves together with the cells it uses, as in Step 1. It is wrong when you move a formula ",[785,1515,1516],{},"away"," from inputs that stay put:",[363,1519,1521],{"className":388,"code":1520,"language":390,"meta":368,"style":368},"wb = Workbook()\nws = wb.active\nws[\"A1\"] = 10\nws[\"B1\"] = \"=A1*2\"\n\nws.move_range(\"B1\", rows=1, translate=True)\nprint(ws[\"B2\"].value)          # =A2*2 — now points at an empty cell\n\nws2 = Workbook().active\nws2[\"A1\"] = 10\nws2[\"B1\"] = \"=A1*2\"\nws2.move_range(\"B1\", rows=1)   # translate=False keeps the text\nprint(ws2[\"B2\"].value)         # =A1*2 — still points at the input\n",[14,1522,1523,1532,1541,1554,1568,1572,1596,1611,1615,1625,1638,1650,1671],{"__ignoreMap":368},[372,1524,1525,1528,1530],{"class":332,"line":374},[372,1526,1527],{"class":401},"wb ",[372,1529,450],{"class":397},[372,1531,453],{"class":401},[372,1533,1534,1537,1539],{"class":332,"line":411},[372,1535,1536],{"class":401},"ws ",[372,1538,450],{"class":397},[372,1540,464],{"class":401},[372,1542,1543,1545,1547,1549,1551],{"class":332,"line":424},[372,1544,1193],{"class":401},[372,1546,548],{"class":381},[372,1548,579],{"class":401},[372,1550,450],{"class":397},[372,1552,1553],{"class":505}," 10\n",[372,1555,1556,1558,1561,1563,1565],{"class":332,"line":431},[372,1557,1193],{"class":401},[372,1559,1560],{"class":381},"\"B1\"",[372,1562,579],{"class":401},[372,1564,450],{"class":397},[372,1566,1567],{"class":381}," \"=A1*2\"\n",[372,1569,1570],{"class":332,"line":444},[372,1571,428],{"emptyLinePlaceholder":427},[372,1573,1574,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594],{"class":332,"line":456},[372,1575,720],{"class":401},[372,1577,1560],{"class":381},[372,1579,476],{"class":401},[372,1581,728],{"class":559},[372,1583,450],{"class":397},[372,1585,103],{"class":505},[372,1587,476],{"class":401},[372,1589,746],{"class":559},[372,1591,450],{"class":397},[372,1593,565],{"class":505},[372,1595,568],{"class":401},[372,1597,1598,1600,1602,1605,1608],{"class":332,"line":467},[372,1599,1176],{"class":505},[372,1601,1179],{"class":401},[372,1603,1604],{"class":381},"\"B2\"",[372,1606,1607],{"class":401},"].value)          ",[372,1609,1610],{"class":587},"# =A2*2 — now points at an empty cell\n",[372,1612,1613],{"class":332,"line":495},[372,1614,428],{"emptyLinePlaceholder":427},[372,1616,1617,1620,1622],{"class":332,"line":519},[372,1618,1619],{"class":401},"ws2 ",[372,1621,450],{"class":397},[372,1623,1624],{"class":401}," Workbook().active\n",[372,1626,1627,1630,1632,1634,1636],{"class":332,"line":542},[372,1628,1629],{"class":401},"ws2[",[372,1631,548],{"class":381},[372,1633,579],{"class":401},[372,1635,450],{"class":397},[372,1637,1553],{"class":505},[372,1639,1640,1642,1644,1646,1648],{"class":332,"line":571},[372,1641,1629],{"class":401},[372,1643,1560],{"class":381},[372,1645,579],{"class":401},[372,1647,450],{"class":397},[372,1649,1567],{"class":381},[372,1651,1652,1655,1657,1659,1661,1663,1665,1668],{"class":332,"line":591},[372,1653,1654],{"class":401},"ws2.move_range(",[372,1656,1560],{"class":381},[372,1658,476],{"class":401},[372,1660,728],{"class":559},[372,1662,450],{"class":397},[372,1664,103],{"class":505},[372,1666,1667],{"class":401},")   ",[372,1669,1670],{"class":587},"# translate=False keeps the text\n",[372,1672,1673,1675,1678,1680,1683],{"class":332,"line":600},[372,1674,1176],{"class":505},[372,1676,1677],{"class":401},"(ws2[",[372,1679,1604],{"class":381},[372,1681,1682],{"class":401},"].value)         ",[372,1684,1685],{"class":587},"# =A1*2 — still points at the input\n",[10,1687,1688,1689,1692,1693,1696],{},"In Excel, cutting B1 and pasting it at B2 keeps ",[14,1690,1691],{},"=A1*2",", because a cut formula keeps pointing at its inputs. openpyxl has no cut mode, so choose per move: translate when the inputs travel with the formula, do not translate when they stay behind. Absolute references (",[14,1694,1695],{},"$A$1",") are never shifted, which is another way to keep a formula anchored.",[358,1698,1700],{"id":1699},"step-4-protect-the-destination","Step 4 — Protect the destination",[10,1702,1703,1705],{},[14,1704,695],{}," overwrites whatever is at the destination without warning — values, styles and all. Check the target area first:",[363,1707,1709],{"className":388,"code":1708,"language":390,"meta":368,"style":368},"from openpyxl.utils.cell import range_boundaries\n\ndef move_range_safely(ws, cell_range, rows=0, cols=0, translate=True):\n    min_col, min_row, max_col, max_row = range_boundaries(cell_range)\n    source = {(r, c) for r in range(min_row, max_row + 1) for c in range(min_col, max_col + 1)}\n    for r in range(min_row + rows, max_row + rows + 1):\n        for c in range(min_col + cols, max_col + cols + 1):\n            if (r, c) in source:\n                continue                     # overlapping part of the block itself\n            if ws.cell(row=r, column=c).value is not None:\n                raise ValueError(f\"destination {ws.cell(row=r, column=c).coordinate} is not empty\")\n    ws.move_range(cell_range, rows=rows, cols=cols, translate=translate)\n\nwb, ws = build()\nws[\"C6\"] = \"keep me\"\ntry:\n    move_range_safely(ws, \"A1:D3\", rows=4, cols=1)\nexcept ValueError as exc:\n    print(exc)\nmove_range_safely(ws, \"A1:D3\", rows=2, cols=1)\nprint(ws[\"E4\"].value)\n",[14,1710,1711,1722,1726,1755,1765,1816,1845,1875,1887,1895,1928,1969,1993,1997,2005,2019,2026,2051,2064,2072,2097],{"__ignoreMap":368},[372,1712,1713,1715,1717,1719],{"class":332,"line":374},[372,1714,398],{"class":397},[372,1716,818],{"class":401},[372,1718,405],{"class":397},[372,1720,1721],{"class":401}," range_boundaries\n",[372,1723,1724],{"class":332,"line":411},[372,1725,428],{"emptyLinePlaceholder":427},[372,1727,1728,1730,1733,1736,1738,1740,1742,1744,1746,1749,1751,1753],{"class":332,"line":424},[372,1729,434],{"class":397},[372,1731,1732],{"class":437}," move_range_safely",[372,1734,1735],{"class":401},"(ws, cell_range, rows",[372,1737,450],{"class":397},[372,1739,47],{"class":505},[372,1741,621],{"class":401},[372,1743,450],{"class":397},[372,1745,47],{"class":505},[372,1747,1748],{"class":401},", translate",[372,1750,450],{"class":397},[372,1752,565],{"class":505},[372,1754,628],{"class":401},[372,1756,1757,1760,1762],{"class":332,"line":431},[372,1758,1759],{"class":401},"    min_col, min_row, max_col, max_row ",[372,1761,450],{"class":397},[372,1763,1764],{"class":401}," range_boundaries(cell_range)\n",[372,1766,1767,1770,1772,1775,1778,1781,1783,1786,1789,1791,1794,1797,1799,1802,1804,1806,1809,1811,1813],{"class":332,"line":444},[372,1768,1769],{"class":401},"    source ",[372,1771,450],{"class":397},[372,1773,1774],{"class":401}," {(r, c) ",[372,1776,1777],{"class":397},"for",[372,1779,1780],{"class":401}," r ",[372,1782,640],{"class":397},[372,1784,1785],{"class":505}," range",[372,1787,1788],{"class":401},"(min_row, max_row ",[372,1790,1040],{"class":397},[372,1792,1793],{"class":505}," 1",[372,1795,1796],{"class":401},") ",[372,1798,1777],{"class":397},[372,1800,1801],{"class":401}," c ",[372,1803,640],{"class":397},[372,1805,1785],{"class":505},[372,1807,1808],{"class":401},"(min_col, max_col ",[372,1810,1040],{"class":397},[372,1812,1793],{"class":505},[372,1814,1815],{"class":401},")}\n",[372,1817,1818,1820,1822,1824,1826,1829,1831,1834,1836,1839,1841,1843],{"class":332,"line":456},[372,1819,634],{"class":397},[372,1821,1780],{"class":401},[372,1823,640],{"class":397},[372,1825,1785],{"class":505},[372,1827,1828],{"class":401},"(min_row ",[372,1830,1040],{"class":397},[372,1832,1833],{"class":401}," rows, max_row ",[372,1835,1040],{"class":397},[372,1837,1838],{"class":401}," rows ",[372,1840,1040],{"class":397},[372,1842,1793],{"class":505},[372,1844,628],{"class":401},[372,1846,1847,1850,1852,1854,1856,1859,1861,1864,1866,1869,1871,1873],{"class":332,"line":467},[372,1848,1849],{"class":397},"        for",[372,1851,1801],{"class":401},[372,1853,640],{"class":397},[372,1855,1785],{"class":505},[372,1857,1858],{"class":401},"(min_col ",[372,1860,1040],{"class":397},[372,1862,1863],{"class":401}," cols, max_col ",[372,1865,1040],{"class":397},[372,1867,1868],{"class":401}," cols ",[372,1870,1040],{"class":397},[372,1872,1793],{"class":505},[372,1874,628],{"class":401},[372,1876,1877,1879,1882,1884],{"class":332,"line":495},[372,1878,977],{"class":397},[372,1880,1881],{"class":401}," (r, c) ",[372,1883,640],{"class":397},[372,1885,1886],{"class":401}," source:\n",[372,1888,1889,1892],{"class":332,"line":519},[372,1890,1891],{"class":397},"                continue",[372,1893,1894],{"class":587},"                     # overlapping part of the block itself\n",[372,1896,1897,1899,1902,1905,1907,1910,1913,1915,1918,1921,1923,1926],{"class":332,"line":542},[372,1898,977],{"class":397},[372,1900,1901],{"class":401}," ws.cell(",[372,1903,1904],{"class":559},"row",[372,1906,450],{"class":397},[372,1908,1909],{"class":401},"r, ",[372,1911,1912],{"class":559},"column",[372,1914,450],{"class":397},[372,1916,1917],{"class":401},"c).value ",[372,1919,1920],{"class":397},"is",[372,1922,917],{"class":397},[372,1924,1925],{"class":505}," None",[372,1927,931],{"class":401},[372,1929,1930,1933,1935,1938,1941,1944,1946,1949,1951,1953,1955,1957,1959,1962,1964,1967],{"class":332,"line":571},[372,1931,1932],{"class":397},"                raise",[372,1934,960],{"class":505},[372,1936,1937],{"class":401},"(",[372,1939,1940],{"class":397},"f",[372,1942,1943],{"class":381},"\"destination ",[372,1945,1034],{"class":1033},[372,1947,1948],{"class":401},"ws.cell(",[372,1950,1904],{"class":559},[372,1952,450],{"class":397},[372,1954,1909],{"class":401},[372,1956,1912],{"class":559},[372,1958,450],{"class":397},[372,1960,1961],{"class":401},"c).coordinate",[372,1963,1057],{"class":1033},[372,1965,1966],{"class":381}," is not empty\"",[372,1968,568],{"class":401},[372,1970,1971,1974,1976,1978,1980,1982,1984,1986,1988,1990],{"class":332,"line":591},[372,1972,1973],{"class":401},"    ws.move_range(cell_range, ",[372,1975,728],{"class":559},[372,1977,450],{"class":397},[372,1979,660],{"class":401},[372,1981,737],{"class":559},[372,1983,450],{"class":397},[372,1985,668],{"class":401},[372,1987,746],{"class":559},[372,1989,450],{"class":397},[372,1991,1992],{"class":401},"translate)\n",[372,1994,1995],{"class":332,"line":600},[372,1996,428],{"emptyLinePlaceholder":427},[372,1998,1999,2001,2003],{"class":332,"line":605},[372,2000,710],{"class":401},[372,2002,450],{"class":397},[372,2004,715],{"class":401},[372,2006,2007,2009,2012,2014,2016],{"class":332,"line":631},[372,2008,1193],{"class":401},[372,2010,2011],{"class":381},"\"C6\"",[372,2013,579],{"class":401},[372,2015,450],{"class":397},[372,2017,2018],{"class":381}," \"keep me\"\n",[372,2020,2021,2024],{"class":332,"line":680},[372,2022,2023],{"class":397},"try",[372,2025,931],{"class":401},[372,2027,2028,2031,2033,2035,2037,2039,2041,2043,2045,2047,2049],{"class":332,"line":1063},[372,2029,2030],{"class":401},"    move_range_safely(ws, ",[372,2032,723],{"class":381},[372,2034,476],{"class":401},[372,2036,728],{"class":559},[372,2038,450],{"class":397},[372,2040,170],{"class":505},[372,2042,476],{"class":401},[372,2044,737],{"class":559},[372,2046,450],{"class":397},[372,2048,103],{"class":505},[372,2050,568],{"class":401},[372,2052,2053,2056,2058,2061],{"class":332,"line":1097},[372,2054,2055],{"class":397},"except",[372,2057,960],{"class":505},[372,2059,2060],{"class":397}," as",[372,2062,2063],{"class":401}," exc:\n",[372,2065,2066,2069],{"class":332,"line":1145},[372,2067,2068],{"class":505},"    print",[372,2070,2071],{"class":401},"(exc)\n",[372,2073,2074,2077,2079,2081,2083,2085,2087,2089,2091,2093,2095],{"class":332,"line":1151},[372,2075,2076],{"class":401},"move_range_safely(ws, ",[372,2078,723],{"class":381},[372,2080,476],{"class":401},[372,2082,728],{"class":559},[372,2084,450],{"class":397},[372,2086,131],{"class":505},[372,2088,476],{"class":401},[372,2090,737],{"class":559},[372,2092,450],{"class":397},[372,2094,103],{"class":505},[372,2096,568],{"class":401},[372,2098,2099,2101,2103,2106],{"class":332,"line":1168},[372,2100,1176],{"class":505},[372,2102,1179],{"class":401},[372,2104,2105],{"class":381},"\"E4\"",[372,2107,2108],{"class":401},"].value)\n",[10,2110,2111,2112,2114,2115,2119],{},"Cells inside the original block are allowed to overlap the destination — moving a table down by one row overlaps itself, and ",[14,2113,695],{}," handles that correctly. Merged cells deserve a special look: if the destination includes part of a merged range, the moved value can land in a covered cell and disappear from view. Unmerge first, move, then merge again at the new position; ",[19,2116,2118],{"href":2117},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-mergedcell-value-is-read-only-in-openpyxl\u002F","Fix \"MergedCell object attribute value is read-only\" in openpyxl"," has a helper that shifts merged ranges.",[358,2121,2123],{"id":2122},"step-5-move-a-whole-table-with-its-surroundings","Step 5 — Move a whole table with its surroundings",[10,2125,2126],{},"Putting the pieces together, a table move in a real report has four parts: move the cells, update formulas elsewhere, shift the ranges that formatting rules and merges use, and copy column widths if the table moved sideways:",[363,2128,2130],{"className":388,"code":2129,"language":390,"meta":368,"style":368},"wb, ws = build()\nws.column_dimensions[\"D\"].width = 14\nws.move_range(\"A1:D3\", rows=2, cols=1, translate=True)\nws[\"F1\"] = \"=SUM(E4:E5)\"                                      # dependent formula\nws.column_dimensions[\"E\"].width = ws.column_dimensions[\"D\"].width  # widths follow columns\nws[\"A1\"] = \"Order summary\"                                    # the freed space is now usable\nws[\"A1\"].font = Font(bold=True, size=14)\nshow(ws)\nwb.save(\"moved.xlsx\")\n",[14,2131,2132,2140,2156,2188,2204,2226,2242,2272,2276],{"__ignoreMap":368},[372,2133,2134,2136,2138],{"class":332,"line":374},[372,2135,710],{"class":401},[372,2137,450],{"class":397},[372,2139,715],{"class":401},[372,2141,2142,2145,2148,2151,2153],{"class":332,"line":411},[372,2143,2144],{"class":401},"ws.column_dimensions[",[372,2146,2147],{"class":381},"\"D\"",[372,2149,2150],{"class":401},"].width ",[372,2152,450],{"class":397},[372,2154,2155],{"class":505}," 14\n",[372,2157,2158,2160,2162,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186],{"class":332,"line":424},[372,2159,720],{"class":401},[372,2161,723],{"class":381},[372,2163,476],{"class":401},[372,2165,728],{"class":559},[372,2167,450],{"class":397},[372,2169,131],{"class":505},[372,2171,476],{"class":401},[372,2173,737],{"class":559},[372,2175,450],{"class":397},[372,2177,103],{"class":505},[372,2179,476],{"class":401},[372,2181,746],{"class":559},[372,2183,450],{"class":397},[372,2185,565],{"class":505},[372,2187,568],{"class":401},[372,2189,2190,2192,2194,2196,2198,2201],{"class":332,"line":431},[372,2191,1193],{"class":401},[372,2193,576],{"class":381},[372,2195,579],{"class":401},[372,2197,450],{"class":397},[372,2199,2200],{"class":381}," \"=SUM(E4:E5)\"",[372,2202,2203],{"class":587},"                                      # dependent formula\n",[372,2205,2206,2208,2211,2213,2215,2218,2220,2223],{"class":332,"line":444},[372,2207,2144],{"class":401},[372,2209,2210],{"class":381},"\"E\"",[372,2212,2150],{"class":401},[372,2214,450],{"class":397},[372,2216,2217],{"class":401}," ws.column_dimensions[",[372,2219,2147],{"class":381},[372,2221,2222],{"class":401},"].width  ",[372,2224,2225],{"class":587},"# widths follow columns\n",[372,2227,2228,2230,2232,2234,2236,2239],{"class":332,"line":456},[372,2229,1193],{"class":401},[372,2231,548],{"class":381},[372,2233,579],{"class":401},[372,2235,450],{"class":397},[372,2237,2238],{"class":381}," \"Order summary\"",[372,2240,2241],{"class":587},"                                    # the freed space is now usable\n",[372,2243,2244,2246,2248,2250,2252,2254,2256,2258,2260,2262,2265,2267,2270],{"class":332,"line":467},[372,2245,1193],{"class":401},[372,2247,548],{"class":381},[372,2249,551],{"class":401},[372,2251,450],{"class":397},[372,2253,556],{"class":401},[372,2255,560],{"class":559},[372,2257,450],{"class":397},[372,2259,565],{"class":505},[372,2261,476],{"class":401},[372,2263,2264],{"class":559},"size",[372,2266,450],{"class":397},[372,2268,2269],{"class":505},"14",[372,2271,568],{"class":401},[372,2273,2274],{"class":332,"line":495},[372,2275,757],{"class":401},[372,2277,2278,2281,2284],{"class":332,"line":519},[372,2279,2280],{"class":401},"wb.save(",[372,2282,2283],{"class":381},"\"moved.xlsx\"",[372,2285,568],{"class":401},[10,2287,2288,2289,763,2292,2295,2296,2300],{},"When a report needs space rather than a specific offset — a new first row for a title, a new column on the left — ",[14,2290,2291],{},"insert_rows",[14,2293,2294],{},"insert_cols"," are the simpler tools, though they have their own formula limitations; ",[19,2297,2299],{"href":2298},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Finsert-and-delete-rows-and-columns-with-openpyxl\u002F","Insert and Delete Rows and Columns with openpyxl"," compares them.",[25,2302,34,2307,34,2310,34,2313,34,2316,34,2321,34,2329,34,2335,34,2339,34,2343,34,2347,34,2352,34,2355,34,2358,34,2365,34,2370,34,2372,34,2375,34,2378,34,2382,34,2385,34,2389,34,2396,34,2401,34,2404,34,2407,34,2410,34,2414,34,2417,34,2420,34,2426,34,2430,34,2433,34,2436,34,2439,34,2443,34,2446,34,2449,34,2456,34,2461,34,2464,34,2467],{"viewBox":2303,"role":28,"ariaLabelledBy":2304,"xmlns":32,"style":1296},"4 0 752 160",[2305,2306],"mvr-steps-t","mvr-steps-d",[36,2308,2309],{"id":2305},"Moving a table without breaking the report",[40,2311,2312],{"id":2306},"Five steps: check the destination is empty; move the block with translate=True; rewrite formulas elsewhere that referred to the old range; re-apply merged ranges, conditional formatting and validation at the new address; copy column widths and row heights if the table moved.",[44,2314],{"x":170,"y":47,"width":1305,"height":2315,"fill":50},"160",[44,2317],{"x":1309,"y":1310,"width":2318,"height":2319,"rx":2320,"fill":57,"stroke":58,"style":337},"115.2","128.0","12",[1341,2322,2324],{"transform":2323},"translate(65.6,29.0) scale(1.000)",[1345,2325],{"d":2326,"fill":1348,"stroke":2327,"style":2328},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[65,2330,2334],{"x":2331,"y":2332,"style":2333},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Check the",[65,2336,2338],{"x":2331,"y":2337,"style":2333},"93.0","destination",[65,2340,2342],{"x":2331,"y":2341,"style":1355},"112.5","empty or part of",[65,2344,2346],{"x":2331,"y":2345,"style":1355},"130.0","the block",[332,2348],{"x1":2349,"y1":2350,"x2":2351,"y2":2350,"stroke":149,"style":337},"140.2","80.0","162.2",[339,2353],{"points":2354,"fill":342},"166.2,80.0 157.2,85.0 157.2,75.0",[44,2356],{"x":2357,"y":1310,"width":2318,"height":2319,"rx":2320,"fill":148,"stroke":149,"style":337},"171.2",[1341,2359,2361],{"transform":2360},"translate(216.8,29.0) scale(1.000)",[1345,2362],{"d":2363,"fill":1348,"stroke":2364,"style":2328},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7","var(--brand-strong,#4338ca)",[65,2366,2369],{"x":2367,"y":2332,"style":2368},"228.8","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Move with",[65,2371,746],{"x":2367,"y":2337,"style":2368},[65,2373,2374],{"x":2367,"y":2341,"style":1355},"formulas inside",[65,2376,2377],{"x":2367,"y":2345,"style":1355},"rewritten",[332,2379],{"x1":2380,"y1":2350,"x2":2381,"y2":2350,"stroke":149,"style":337},"291.4","313.4",[339,2383],{"points":2384,"fill":342},"317.4,80.0 308.4,85.0 308.4,75.0",[44,2386],{"x":2387,"y":1310,"width":2318,"height":2319,"rx":2320,"fill":2388,"stroke":1390,"style":337},"322.4","#fdefd8",[1341,2390,2392],{"transform":2391},"translate(368.0,29.0) scale(1.000)",[1345,2393],{"d":2394,"fill":1348,"stroke":2395,"style":2328},"M9 8l-4 4 4 4 M15 8l4 4-4 4","var(--gold-ink,#7a4e06)",[65,2397,2400],{"x":2398,"y":2332,"style":2399},"380.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Fix",[65,2402,2403],{"x":2398,"y":2337,"style":2399},"references in",[65,2405,2406],{"x":2398,"y":2341,"style":1355},"formulas",[65,2408,2409],{"x":2398,"y":2345,"style":1355},"elsewhere",[332,2411],{"x1":2412,"y1":2350,"x2":2413,"y2":2350,"stroke":149,"style":337},"442.6","464.6",[339,2415],{"points":2416,"fill":342},"468.6,80.0 459.6,85.0 459.6,75.0",[44,2418],{"x":2419,"y":1310,"width":2318,"height":2319,"rx":2320,"fill":2388,"stroke":1390,"style":337},"473.6",[1341,2421,2423],{"transform":2422},"translate(519.2,29.0) scale(1.000)",[1345,2424],{"d":2425,"fill":1348,"stroke":2395,"style":2328},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5",[65,2427,2429],{"x":2428,"y":2332,"style":2399},"531.2","Re-apply",[65,2431,2432],{"x":2428,"y":2337,"style":2399},"ranges",[65,2434,2435],{"x":2428,"y":2341,"style":1355},"merges, rules,",[65,2437,2438],{"x":2428,"y":2345,"style":1355},"validation",[332,2440],{"x1":2441,"y1":2350,"x2":2442,"y2":2350,"stroke":149,"style":337},"593.8","615.8",[339,2444],{"points":2445,"fill":342},"619.8,80.0 610.8,85.0 610.8,75.0",[44,2447],{"x":2448,"y":1310,"width":2318,"height":2319,"rx":2320,"fill":290,"stroke":291,"style":337},"624.8",[1341,2450,2452],{"transform":2451},"translate(670.4,29.0) scale(1.000)",[1345,2453],{"d":2454,"fill":1348,"stroke":2455,"style":2328},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--teal-ink,#0b6157)",[65,2457,2460],{"x":2458,"y":2332,"style":2459},"682.4","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Widths and",[65,2462,2463],{"x":2458,"y":2337,"style":2459},"heights",[65,2465,2466],{"x":2458,"y":2341,"style":1355},"follow rows and",[65,2468,2469],{"x":2458,"y":2345,"style":1355},"columns",[358,2471,2473],{"id":2472},"common-pitfalls","Common pitfalls",[2475,2476,2477,2488,2497,2503,2509],"ul",{},[2478,2479,2480,2487],"li",{},[2481,2482,2483,2484,2486],"strong",{},"Forgetting ",[14,2485,699],{},"."," Moved formulas keep their text and compute the wrong cells.",[2478,2489,2490,2496],{},[2481,2491,2492,2493,2495],{},"Using ",[14,2494,699],{}," when inputs stay put."," Relative references shift away from their inputs.",[2478,2498,2499,2502],{},[2481,2500,2501],{},"Assuming dependent formulas follow."," Totals, lookups and charts that referred to the old range keep the old address.",[2478,2504,2505,2508],{},[2481,2506,2507],{},"Moving into merged or occupied cells."," Data is overwritten or hidden without warning.",[2478,2510,2511,2514,2515,2517],{},[2481,2512,2513],{},"Charts."," A chart's data references are not updated by ",[14,2516,695],{},"; rebuild the reference after moving its source data.",[358,2519,2521],{"id":2520},"performance-notes","Performance notes",[10,2523,2524,2526,2527,763,2530,2533,2534,2486],{},[14,2525,695],{}," works cell by cell and is fast for report-sized blocks — thousands of cells move in milliseconds. For very large shifts (hundreds of thousands of cells), it is usually quicker and clearer to write the data at the right position in the first place, for example with ",[14,2528,2529],{},"startrow",[14,2531,2532],{},"startcol"," in pandas' ",[14,2535,2536],{},"to_excel",[358,2538,2540],{"id":2539},"conclusion","Conclusion",[10,2542,2543,2546],{},[14,2544,2545],{},"ws.move_range(range, rows=, cols=, translate=True)"," moves values and styles and rewrites formulas inside the block as a copy-paste would. It does not update formulas elsewhere that point into the block, does not move merged ranges, conditional formatting, validation, widths or heights, and overwrites the destination silently. Check the destination, translate only when inputs move with their formulas, and fix dependent references and ranges as part of every move.",[358,2548,2550],{"id":2549},"frequently-asked-questions","Frequently asked questions",[10,2552,2553,2556],{},[2481,2554,2555],{},"Does move_range update formulas that refer to the moved cells?","\nNo. With translate=True it rewrites formulas inside the moved block, but a formula elsewhere on the sheet that pointed at the block keeps its old address and now reads the empty cells left behind. Update those formulas yourself.",[10,2558,2559,2562],{},[2481,2560,2561],{},"Is translate=True the same as cut and paste in Excel?","\nNo, it behaves like copy and paste. Relative references in the moved formulas shift by the same offset. That is right when a formula moves together with its inputs, and wrong when a formula moves away from inputs that stay put.",[10,2564,2565,2568],{},[2481,2566,2567],{},"What happens to cells at the destination?","\nThey are overwritten without warning, including cells that belong to a merged range. Check that the destination is empty before moving.",[10,2570,2571,2574],{},[2481,2572,2573],{},"Do styles move with the cells?","\nYes. Fonts, fills, borders and number formats travel with each cell. Row heights, column widths, merged ranges, data validation and conditional formatting do not.",[358,2576,2578],{"id":2577},"related","Related",[2475,2580,2581,2587,2594,2601],{},[2478,2582,2583,2584,2586],{},"Up one level: ",[19,2585,22],{"href":21}," — editing workbooks cell by cell.",[2478,2588,2589,2593],{},[19,2590,2592],{"href":2591},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcopy-formula-down-a-column-in-openpyxl\u002F","Copy a Formula Down a Column in openpyxl"," — the Translator on its own.",[2478,2595,2596,2600],{},[19,2597,2599],{"href":2598},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-a-dataframe-to-a-specific-cell-in-excel\u002F","Write a DataFrame to a Specific Cell in Excel with pandas"," — placing data where it belongs from the start.",[2478,2602,2603,2607],{},[19,2604,2606],{"href":2605},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fclear-cell-contents-and-formatting-with-openpyxl\u002F","Clear Cell Contents and Formatting with openpyxl"," — tidying the area a block leaves behind.",[2609,2610,2611],"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 .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}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-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":368,"searchDepth":411,"depth":411,"links":2613},[2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624],{"id":360,"depth":411,"text":361},{"id":689,"depth":411,"text":690},{"id":775,"depth":411,"text":776},{"id":1503,"depth":411,"text":1504},{"id":1699,"depth":411,"text":1700},{"id":2122,"depth":411,"text":2123},{"id":2472,"depth":411,"text":2473},{"id":2520,"depth":411,"text":2521},{"id":2539,"depth":411,"text":2540},{"id":2549,"depth":411,"text":2550},{"id":2577,"depth":411,"text":2578},"2026-09-25","Shift a block of cells to a new position with ws.move_range: values and styles move, translate=True rewrites formulas inside the block, and everything else — formulas that point at the block, merged cells, conditional formats — stays where it was. Learn the rules and a safe way to move a table.","md",[2629,2631,2633,2635],{"q":2555,"a":2630},"No. With translate=True it rewrites formulas inside the moved block, but a formula elsewhere on the sheet that pointed at the block keeps its old address and now reads the empty cells left behind. Update those formulas yourself.",{"q":2561,"a":2632},"No, it behaves like copy and paste. Relative references in the moved formulas shift by the same offset. That is right when a formula moves together with its inputs, and wrong when a formula moves away from inputs that stay put.",{"q":2567,"a":2634},"They are overwritten without warning, including cells that belong to a merged range. Check that the destination is empty before moving.",{"q":2573,"a":2636},"Yes. Fonts, fills, borders and number formats travel with each cell. Row heights, column widths, merged ranges, data validation and conditional formatting do not.","move a range of cells with openpyxl move_range",null,{"breadcrumb":2640},[2641,2644,2647],{"name":2642,"item":2643},"Home","\u002F",{"name":2645,"item":2646},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":22,"item":21},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl",{"title":2650,"description":2651},"openpyxl move_range: Move Cells, Keep Formulas Working","How openpyxl ws.move_range works: rows and cols offsets, translate=True for formulas, what does not move (references from elsewhere, merges, conditional formatting) and how to avoid overwriting data.","move-a-range-of-cells-with-openpyxl","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmove-a-range-of-cells-with-openpyxl\u002Findex",[2655,2656,2657],"openpyxl","excel-formulas","report-layouts","how-to","z1ku-J64gGY44Ue2AvGOCs5AfR3UQmKmIE9VYMoQh7k",[2661,2665],{"title":2662,"path":2663,"stem":2664,"children":-1},"Merge Repeated Group Labels into Single Cells with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmerge-repeated-group-labels-into-single-cells-with-openpyxl","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fmerge-repeated-group-labels-into-single-cells-with-openpyxl\u002Findex",{"title":2666,"path":2667,"stem":2668,"children":-1},"openpyxl: Append Data to an Existing Excel Sheet","\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fopenpyxl-append-data-to-existing-excel-sheet","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fopenpyxl-append-data-to-existing-excel-sheet\u002Findex",[2670,2672],{"path":2671,"title":2645},"\u002Fgetting-started-with-python-excel-automation",{"path":2673,"title":22},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation",[],[2676,2680,2683,2686,2689,2692],{"path":2677,"title":2678,"kind":2679},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl","Applying Conditional Formatting With openpyxl","guide",{"path":2681,"title":2682,"kind":2658},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-data-bars-and-colour-scales-with-openpyxl","Add Data Bars and Colour Scales with openpyxl",{"path":2684,"title":2685,"kind":2658},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","Add Icon Sets to Excel Cells with openpyxl",{"path":2687,"title":2688,"kind":2658},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fapply-a-colour-scale-per-row-or-per-column-with-openpyxl","Apply a Colour Scale per Row or per Column with openpyxl",{"path":2690,"title":2691,"kind":2658},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fcontrol-conditional-formatting-rule-order-and-stop-if-true","Control Conditional Formatting Rule Order and Stop If True",{"path":2693,"title":2694,"kind":2658},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-an-entire-row-based-on-a-cell-value-with-openpyxl","Highlight an Entire Row Based on a Cell Value with openpyxl",1790972069988]