[{"data":1,"prerenderedAt":2770},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl":2735,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl":2744,"children:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl":2749,"related:\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl":2750},{"id":4,"title":5,"body":6,"dateModified":2700,"datePublished":2700,"description":2701,"extension":2702,"faq":2703,"keyword":2712,"kind":2713,"meta":2714,"navigation":269,"path":2723,"seo":2724,"slug":2727,"stem":2728,"topics":2729,"type":2733,"__hash__":2734},"docs\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl\u002Findex.md","Convert Excel Column Letters and Numbers in Python",{"type":7,"value":8,"toc":2685},"minimark",[9,28,199,204,234,238,241,410,421,425,428,549,552,866,869,1206,1210,1220,1247,1250,1379,1387,1391,1397,1527,1545,1549,1556,1956,1959,2174,2178,2189,2401,2408,2412,2421,2493,2511,2515,2585,2589,2596,2600,2620,2624,2630,2636,2642,2648,2652,2681],[10,11,12,13,17,18,21,22,27],"p",{},"Sooner or later every script that writes formulas needs to turn a column position into a letter. pandas knows the ",[14,15,16],"code",{},"amount"," column is the fourth; the formula has to say ",[14,19,20],{},"D2:D200",". And every script that reads a configuration like \"the totals are in column AB\" needs the reverse. It looks like a one-line conversion to base 26, and that one line is wrong for every column after Z. This page, part of ",[23,24,26],"a",{"href":25},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002F","Using openpyxl for Excel File Manipulation",", covers the library helpers, the correct algorithm, address parsing, and mapping DataFrame columns to letters.",[29,30,38,39,38,43,38,47,38,55,38,63,38,73,38,80,38,85,38,89,38,93,38,99,38,105,38,109,38,111,38,113,38,118,38,124,38,128,38,132,38,134,38,136,38,139,38,144,38,148,38,152,38,154,38,156,38,159,38,163,38,166,38,169,38,171,38,173,38,178,38,184,38,188,38,192,38,195,38,197],"svg",{"viewBox":31,"role":32,"ariaLabelledBy":33,"xmlns":36,"style":37},"4 0 752 278","img",[34,35],"col-scale-t","col-scale-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[40,41,42],"title",{"id":34},"Where column letters change length",[44,45,46],"desc",{"id":35},"Milestones along the column axis. Column 1 is A and column 26 is Z. Column 27 is AA, the first two-letter column. Column 702 is ZZ and column 703 is AAA. Column 16,384 is XFD, the last column Excel supports.",[48,49],"rect",{"x":50,"y":51,"width":52,"height":53,"fill":54},"4","0","752","278","#ffffff",[56,57],"line",{"x1":58,"y1":59,"x2":60,"y2":59,"stroke":61,"style":62},"64.0","139.0","696.0","var(--muted,#5b6780)","stroke-width:2.5px",[48,64],{"x":65,"y":66,"width":67,"height":68,"rx":69,"fill":70,"stroke":71,"style":72},"20.0","16.0","112.0","91.0","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[74,75,79],"text",{"x":76,"y":77,"style":78},"76.0","57.2","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","1 → A",[74,81,84],{"x":76,"y":82,"style":83},"75.8","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","first column",[56,86],{"x1":76,"y1":87,"x2":76,"y2":59,"stroke":61,"style":88},"107.0","stroke-width:1.5px",[90,91],"circle",{"cx":76,"cy":59,"r":92,"fill":61,"stroke":54,"style":72},"7.0",[48,94],{"x":95,"y":96,"width":67,"height":68,"rx":69,"fill":97,"stroke":98,"style":72},"141.6","171.0","#f0f4ff","var(--brand,#5b5cf0)",[74,100,104],{"x":101,"y":102,"style":103},"197.6","212.2","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","26 → Z",[74,106,108],{"x":101,"y":107,"style":83},"230.8","last single letter",[56,110],{"x1":101,"y1":59,"x2":101,"y2":96,"stroke":61,"style":88},[90,112],{"cx":101,"cy":59,"r":92,"fill":98,"stroke":54,"style":72},[48,114],{"x":115,"y":66,"width":67,"height":68,"rx":69,"fill":116,"stroke":117,"style":72},"263.2","#fdefd8","var(--gold,#b4740a)",[74,119,123],{"x":120,"y":121,"style":122},"319.2","48.8","font-size:12.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","27 → AA",[74,125,127],{"x":120,"y":126,"style":83},"67.2","no zero digit, so",[74,129,131],{"x":120,"y":130,"style":83},"84.2","AA follows Z",[56,133],{"x1":120,"y1":87,"x2":120,"y2":59,"stroke":61,"style":88},[90,135],{"cx":120,"cy":59,"r":92,"fill":117,"stroke":54,"style":72},[48,137],{"x":138,"y":96,"width":67,"height":68,"rx":69,"fill":97,"stroke":98,"style":72},"384.8",[74,140,143],{"x":141,"y":142,"style":103},"440.8","203.8","702 → ZZ",[74,145,147],{"x":141,"y":146,"style":83},"222.2","last two-letter",[74,149,151],{"x":141,"y":150,"style":83},"239.2","column",[56,153],{"x1":141,"y1":59,"x2":141,"y2":96,"stroke":61,"style":88},[90,155],{"cx":141,"cy":59,"r":92,"fill":98,"stroke":54,"style":72},[48,157],{"x":158,"y":66,"width":67,"height":68,"rx":69,"fill":116,"stroke":117,"style":72},"506.4",[74,160,162],{"x":161,"y":121,"style":122},"562.4","703 → AAA",[74,164,165],{"x":161,"y":126,"style":83},"three letters",[74,167,168],{"x":161,"y":130,"style":83},"begin",[56,170],{"x1":161,"y1":87,"x2":161,"y2":59,"stroke":61,"style":88},[90,172],{"cx":161,"cy":59,"r":92,"fill":117,"stroke":54,"style":72},[48,174],{"x":175,"y":96,"width":67,"height":68,"rx":69,"fill":176,"stroke":177,"style":72},"628.0","#fee8f2","var(--accent,#f43f8f)",[74,179,183],{"x":180,"y":181,"style":182},"684.0","195.5","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","16,384 →",[74,185,187],{"x":180,"y":186,"style":182},"212.0","XFD",[74,189,191],{"x":180,"y":190,"style":83},"230.5","Excel's last",[74,193,151],{"x":180,"y":194,"style":83},"247.5",[56,196],{"x1":180,"y1":59,"x2":180,"y2":96,"stroke":61,"style":88},[90,198],{"cx":180,"cy":59,"r":92,"fill":177,"stroke":54,"style":72},[200,201,203],"h2",{"id":202},"prerequisites","Prerequisites",[205,206,211],"pre",{"className":207,"code":208,"language":209,"meta":210,"style":210},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas xlsxwriter\n","bash","",[14,212,213],{"__ignoreMap":210},[214,215,217,221,225,228,231],"span",{"class":56,"line":216},1,[214,218,220],{"class":219},"sMTad","pip",[214,222,224],{"class":223},"srMev"," install",[214,226,227],{"class":223}," openpyxl",[214,229,230],{"class":223}," pandas",[214,232,233],{"class":223}," xlsxwriter\n",[200,235,237],{"id":236},"step-1-use-the-openpyxl-helpers","Step 1 — Use the openpyxl helpers",[10,239,240],{},"Two functions cover the everyday cases. Both count from 1, like Excel:",[205,242,246],{"className":243,"code":244,"language":245,"meta":210,"style":210},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl.utils import get_column_letter, column_index_from_string\n\nprint([get_column_letter(n) for n in (1, 26, 27, 52, 53, 702, 703, 16384)])\n# ['A', 'Z', 'AA', 'AZ', 'BA', 'ZZ', 'AAA', 'XFD']\n\nprint([column_index_from_string(s) for s in (\"A\", \"Z\", \"AA\", \"AZ\", \"ZZ\", \"AAA\", \"XFD\", \"xfd\")])\n# [1, 26, 27, 52, 702, 703, 16384, 16384]\n","python",[14,247,248,264,271,335,342,347,404],{"__ignoreMap":210},[214,249,250,254,258,261],{"class":56,"line":216},[214,251,253],{"class":252},"s-kum","from",[214,255,257],{"class":256},"skGVy"," openpyxl.utils ",[214,259,260],{"class":252},"import",[214,262,263],{"class":256}," get_column_letter, column_index_from_string\n",[214,265,267],{"class":56,"line":266},2,[214,268,270],{"emptyLinePlaceholder":269},true,"\n",[214,272,274,278,281,284,287,290,293,296,299,302,304,307,309,312,314,317,319,322,324,327,329,332],{"class":56,"line":273},3,[214,275,277],{"class":276},"sP0c6","print",[214,279,280],{"class":256},"([get_column_letter(n) ",[214,282,283],{"class":252},"for",[214,285,286],{"class":256}," n ",[214,288,289],{"class":252},"in",[214,291,292],{"class":256}," (",[214,294,295],{"class":276},"1",[214,297,298],{"class":256},", ",[214,300,301],{"class":276},"26",[214,303,298],{"class":256},[214,305,306],{"class":276},"27",[214,308,298],{"class":256},[214,310,311],{"class":276},"52",[214,313,298],{"class":256},[214,315,316],{"class":276},"53",[214,318,298],{"class":256},[214,320,321],{"class":276},"702",[214,323,298],{"class":256},[214,325,326],{"class":276},"703",[214,328,298],{"class":256},[214,330,331],{"class":276},"16384",[214,333,334],{"class":256},")])\n",[214,336,338],{"class":56,"line":337},4,[214,339,341],{"class":340},"s-wDw","# ['A', 'Z', 'AA', 'AZ', 'BA', 'ZZ', 'AAA', 'XFD']\n",[214,343,345],{"class":56,"line":344},5,[214,346,270],{"emptyLinePlaceholder":269},[214,348,350,352,355,357,360,362,364,367,369,372,374,377,379,382,384,387,389,392,394,397,399,402],{"class":56,"line":349},6,[214,351,277],{"class":276},[214,353,354],{"class":256},"([column_index_from_string(s) ",[214,356,283],{"class":252},[214,358,359],{"class":256}," s ",[214,361,289],{"class":252},[214,363,292],{"class":256},[214,365,366],{"class":223},"\"A\"",[214,368,298],{"class":256},[214,370,371],{"class":223},"\"Z\"",[214,373,298],{"class":256},[214,375,376],{"class":223},"\"AA\"",[214,378,298],{"class":256},[214,380,381],{"class":223},"\"AZ\"",[214,383,298],{"class":256},[214,385,386],{"class":223},"\"ZZ\"",[214,388,298],{"class":256},[214,390,391],{"class":223},"\"AAA\"",[214,393,298],{"class":256},[214,395,396],{"class":223},"\"XFD\"",[214,398,298],{"class":256},[214,400,401],{"class":223},"\"xfd\"",[214,403,334],{"class":256},[214,405,407],{"class":56,"line":406},7,[214,408,409],{"class":340},"# [1, 26, 27, 52, 702, 703, 16384, 16384]\n",[10,411,412,413,416,417,420],{},"Lower-case letters are accepted, which helps when addresses come from configuration files or user input. ",[14,414,415],{},"get_column_letter(0)"," raises ",[14,418,419],{},"ValueError",", which is usually the first sign that a 0-based index from pandas has leaked into openpyxl code.",[200,422,424],{"id":423},"step-2-understand-why-naive-base-26-fails","Step 2 — Understand why naive base-26 fails",[10,426,427],{},"Column letters look like base 26 but have no zero digit: after Z comes AA, not \"BA\" or \"A0\". The common first attempt maps 1–26 correctly and then goes wrong:",[205,429,431],{"className":243,"code":430,"language":245,"meta":210,"style":210},"def naive_letter(n):\n    s = \"\"\n    while n:\n        n, r = divmod(n, 26)\n        s = chr(64 + r) + s\n    return s\n\nprint(naive_letter(26), naive_letter(27), naive_letter(52))\n# A@ AA B@  — wrong for every multiple of 26\n",[14,432,433,445,456,464,482,510,517,521,543],{"__ignoreMap":210},[214,434,435,438,442],{"class":56,"line":216},[214,436,437],{"class":252},"def",[214,439,441],{"class":440},"s_Opv"," naive_letter",[214,443,444],{"class":256},"(n):\n",[214,446,447,450,453],{"class":56,"line":266},[214,448,449],{"class":256},"    s ",[214,451,452],{"class":252},"=",[214,454,455],{"class":223}," \"\"\n",[214,457,458,461],{"class":56,"line":273},[214,459,460],{"class":252},"    while",[214,462,463],{"class":256}," n:\n",[214,465,466,469,471,474,477,479],{"class":56,"line":337},[214,467,468],{"class":256},"        n, r ",[214,470,452],{"class":252},[214,472,473],{"class":276}," divmod",[214,475,476],{"class":256},"(n, ",[214,478,301],{"class":276},[214,480,481],{"class":256},")\n",[214,483,484,487,489,492,495,498,501,504,507],{"class":56,"line":344},[214,485,486],{"class":256},"        s ",[214,488,452],{"class":252},[214,490,491],{"class":276}," chr",[214,493,494],{"class":256},"(",[214,496,497],{"class":276},"64",[214,499,500],{"class":252}," +",[214,502,503],{"class":256}," r) ",[214,505,506],{"class":252},"+",[214,508,509],{"class":256}," s\n",[214,511,512,515],{"class":56,"line":349},[214,513,514],{"class":252},"    return",[214,516,509],{"class":256},[214,518,519],{"class":56,"line":406},[214,520,270],{"emptyLinePlaceholder":269},[214,522,524,526,529,531,534,536,538,540],{"class":56,"line":523},8,[214,525,277],{"class":276},[214,527,528],{"class":256},"(naive_letter(",[214,530,301],{"class":276},[214,532,533],{"class":256},"), naive_letter(",[214,535,306],{"class":276},[214,537,533],{"class":256},[214,539,311],{"class":276},[214,541,542],{"class":256},"))\n",[214,544,546],{"class":56,"line":545},9,[214,547,548],{"class":340},"# A@ AA B@  — wrong for every multiple of 26\n",[10,550,551],{},"The fix is to subtract one before each division, which turns the 1–26 digits into 0–25:",[205,553,555],{"className":243,"code":554,"language":245,"meta":210,"style":210},"def col_letter(n):\n    if not 1 \u003C= n \u003C= 16384:\n        raise ValueError(f\"column {n} is outside Excel's range 1-16384\")\n    s = \"\"\n    while n:\n        n, r = divmod(n - 1, 26)\n        s = chr(65 + r) + s\n    return s\n\ndef col_number(letters):\n    n = 0\n    for ch in letters.upper():\n        n = n * 26 + (ord(ch) - 64)\n    return n\n\nassert all(col_letter(n) == get_column_letter(n) for n in range(1, 16385))\nassert all(col_number(get_column_letter(n)) == n for n in range(1, 16385))\nprint(col_letter(28), col_number(\"AB\"))\n# AB 28\n",[14,556,557,566,591,622,630,636,658,679,685,689,700,711,725,758,766,771,809,841,860],{"__ignoreMap":210},[214,558,559,561,564],{"class":56,"line":216},[214,560,437],{"class":252},[214,562,563],{"class":440}," col_letter",[214,565,444],{"class":256},[214,567,568,571,574,577,580,582,585,588],{"class":56,"line":266},[214,569,570],{"class":252},"    if",[214,572,573],{"class":252}," not",[214,575,576],{"class":276}," 1",[214,578,579],{"class":252}," \u003C=",[214,581,286],{"class":256},[214,583,584],{"class":252},"\u003C=",[214,586,587],{"class":276}," 16384",[214,589,590],{"class":256},":\n",[214,592,593,596,599,601,604,607,611,614,617,620],{"class":56,"line":273},[214,594,595],{"class":252},"        raise",[214,597,598],{"class":276}," ValueError",[214,600,494],{"class":256},[214,602,603],{"class":252},"f",[214,605,606],{"class":223},"\"column ",[214,608,610],{"class":609},"sSjpA","{",[214,612,613],{"class":256},"n",[214,615,616],{"class":609},"}",[214,618,619],{"class":223}," is outside Excel's range 1-16384\"",[214,621,481],{"class":256},[214,623,624,626,628],{"class":56,"line":337},[214,625,449],{"class":256},[214,627,452],{"class":252},[214,629,455],{"class":223},[214,631,632,634],{"class":56,"line":344},[214,633,460],{"class":252},[214,635,463],{"class":256},[214,637,638,640,642,644,647,650,652,654,656],{"class":56,"line":349},[214,639,468],{"class":256},[214,641,452],{"class":252},[214,643,473],{"class":276},[214,645,646],{"class":256},"(n ",[214,648,649],{"class":252},"-",[214,651,576],{"class":276},[214,653,298],{"class":256},[214,655,301],{"class":276},[214,657,481],{"class":256},[214,659,660,662,664,666,668,671,673,675,677],{"class":56,"line":406},[214,661,486],{"class":256},[214,663,452],{"class":252},[214,665,491],{"class":276},[214,667,494],{"class":256},[214,669,670],{"class":276},"65",[214,672,500],{"class":252},[214,674,503],{"class":256},[214,676,506],{"class":252},[214,678,509],{"class":256},[214,680,681,683],{"class":56,"line":523},[214,682,514],{"class":252},[214,684,509],{"class":256},[214,686,687],{"class":56,"line":545},[214,688,270],{"emptyLinePlaceholder":269},[214,690,692,694,697],{"class":56,"line":691},10,[214,693,437],{"class":252},[214,695,696],{"class":440}," col_number",[214,698,699],{"class":256},"(letters):\n",[214,701,703,706,708],{"class":56,"line":702},11,[214,704,705],{"class":256},"    n ",[214,707,452],{"class":252},[214,709,710],{"class":276}," 0\n",[214,712,714,717,720,722],{"class":56,"line":713},12,[214,715,716],{"class":252},"    for",[214,718,719],{"class":256}," ch ",[214,721,289],{"class":252},[214,723,724],{"class":256}," letters.upper():\n",[214,726,728,731,733,735,738,741,743,745,748,751,753,756],{"class":56,"line":727},13,[214,729,730],{"class":256},"        n ",[214,732,452],{"class":252},[214,734,286],{"class":256},[214,736,737],{"class":252},"*",[214,739,740],{"class":276}," 26",[214,742,500],{"class":252},[214,744,292],{"class":256},[214,746,747],{"class":276},"ord",[214,749,750],{"class":256},"(ch) ",[214,752,649],{"class":252},[214,754,755],{"class":276}," 64",[214,757,481],{"class":256},[214,759,761,763],{"class":56,"line":760},14,[214,762,514],{"class":252},[214,764,765],{"class":256}," n\n",[214,767,769],{"class":56,"line":768},15,[214,770,270],{"emptyLinePlaceholder":269},[214,772,774,777,780,783,786,789,791,793,795,798,800,802,804,807],{"class":56,"line":773},16,[214,775,776],{"class":252},"assert",[214,778,779],{"class":276}," all",[214,781,782],{"class":256},"(col_letter(n) ",[214,784,785],{"class":252},"==",[214,787,788],{"class":256}," get_column_letter(n) ",[214,790,283],{"class":252},[214,792,286],{"class":256},[214,794,289],{"class":252},[214,796,797],{"class":276}," range",[214,799,494],{"class":256},[214,801,295],{"class":276},[214,803,298],{"class":256},[214,805,806],{"class":276},"16385",[214,808,542],{"class":256},[214,810,812,814,816,819,821,823,825,827,829,831,833,835,837,839],{"class":56,"line":811},17,[214,813,776],{"class":252},[214,815,779],{"class":276},[214,817,818],{"class":256},"(col_number(get_column_letter(n)) ",[214,820,785],{"class":252},[214,822,286],{"class":256},[214,824,283],{"class":252},[214,826,286],{"class":256},[214,828,289],{"class":252},[214,830,797],{"class":276},[214,832,494],{"class":256},[214,834,295],{"class":276},[214,836,298],{"class":256},[214,838,806],{"class":276},[214,840,542],{"class":256},[214,842,844,846,849,852,855,858],{"class":56,"line":843},18,[214,845,277],{"class":276},[214,847,848],{"class":256},"(col_letter(",[214,850,851],{"class":276},"28",[214,853,854],{"class":256},"), col_number(",[214,856,857],{"class":223},"\"AB\"",[214,859,542],{"class":256},[214,861,863],{"class":56,"line":862},19,[214,864,865],{"class":340},"# AB 28\n",[10,867,868],{},"The two asserts check every valid Excel column against openpyxl, so the functions are safe to use where openpyxl is not installed — in a small validation script, say. Most of the time, use the library.",[29,870,38,875,38,878,38,881,38,884,38,888,38,893,38,898,38,903,38,928,38,932,38,939,38,942,38,983,38,987,38,1007,38,1010,38,1026,38,1030,38,1043,38,1047,38,1051,38,1053,38,1096,38,1100,38,1104,38,1106,38,1143,38,1147,38,1158,38,1164,38,1168,38,1171,38,1175,38,1178,38,1181,38,1183,38,1188,38,1192,38,1197,38,1200,38,1202],{"viewBox":871,"role":32,"ariaLabelledBy":872,"xmlns":36,"style":37},"4 0 752 310",[873,874],"col-algo-t","col-algo-d",[40,876,877],{"id":873},"The bijective base-26 conversion",[44,879,880],{"id":874},"A six-line Python function converting a column number to letters. Callouts mark the range check against Excel's 16,384 columns, the subtraction of one before divmod that makes the digits run from 0 to 25, and the use of 65 (the code for A) to turn each digit into a letter.",[48,882],{"x":50,"y":51,"width":52,"height":883,"fill":54},"310",[48,885],{"x":65,"y":66,"width":886,"height":186,"rx":69,"fill":887,"stroke":71,"style":88},"720.0","#f0f2f5",[74,889,892],{"x":890,"y":890,"style":891},"36.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:start;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","col_letter.py",[56,894],{"x1":65,"y1":895,"x2":896,"y2":895,"stroke":71,"style":897},"46.0","740.0","stroke-width:1px",[74,899,295],{"x":900,"y":901,"style":902},"60.0","67.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[74,904,907,911,915,918,920,922,925],{"x":905,"y":901,"style":906},"82.0","font-size:12.5px;text-anchor:start;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",[908,909,437],"tspan",{"style":910},"fill:var(--brand-strong,#4338ca);font-weight:700",[908,912,914],{"style":913},"fill:var(--text,#172033);font-weight:400"," ",[908,916,917],{"style":913},"col_letter",[908,919,494],{"style":913},[908,921,613],{"style":913},[908,923,924],{"style":913},")",[908,926,927],{"style":913},":",[74,929,931],{"x":900,"y":930,"style":902},"88.0","2",[90,933],{"cx":890,"cy":934,"r":935,"fill":936,"stroke":937,"style":938},"83.5","11.0","#be185d","none","stroke-width:0px",[74,940,295],{"x":890,"y":930,"style":941},"font-size:12px;font-weight:700;fill:#ffffff;text-anchor:middle",[74,943,944,947,950,952,955,957,960,962,965,967,969,971,973,975,977,979,981],{"x":905,"y":930,"style":906},[908,945,946],{"style":913},"    ",[908,948,949],{"style":910},"if",[908,951,914],{"style":913},[908,953,954],{"style":910},"not",[908,956,914],{"style":913},[908,958,295],{"style":959},"fill:var(--gold-ink,#7a4e06);font-weight:400",[908,961,914],{"style":913},[908,963,964],{"style":913},"\u003C",[908,966,452],{"style":913},[908,968,914],{"style":913},[908,970,613],{"style":913},[908,972,914],{"style":913},[908,974,964],{"style":913},[908,976,452],{"style":913},[908,978,914],{"style":913},[908,980,331],{"style":959},[908,982,927],{"style":913},[74,984,986],{"x":900,"y":985,"style":902},"109.0","3",[74,988,989,992,995,997,999,1001,1005],{"x":905,"y":985,"style":906},[908,990,991],{"style":913},"        ",[908,993,994],{"style":910},"raise",[908,996,914],{"style":913},[908,998,419],{"style":913},[908,1000,494],{"style":913},[908,1002,1004],{"style":1003},"fill:var(--teal-ink,#0b6157);font-weight:400","\"outside A-XFD\"",[908,1006,924],{"style":913},[74,1008,50],{"x":900,"y":1009,"style":902},"130.0",[74,1011,1012,1014,1017,1019,1021,1023],{"x":905,"y":1009,"style":906},[908,1013,946],{"style":913},[908,1015,1016],{"style":913},"s",[908,1018,914],{"style":913},[908,1020,452],{"style":913},[908,1022,914],{"style":913},[908,1024,1025],{"style":1003},"\"\"",[74,1027,1029],{"x":900,"y":1028,"style":902},"151.0","5",[74,1031,1032,1034,1037,1039,1041],{"x":905,"y":1028,"style":906},[908,1033,946],{"style":913},[908,1035,1036],{"style":910},"while",[908,1038,914],{"style":913},[908,1040,613],{"style":913},[908,1042,927],{"style":913},[74,1044,1046],{"x":900,"y":1045,"style":902},"172.0","6",[90,1048],{"cx":890,"cy":1049,"r":935,"fill":1050,"stroke":937,"style":938},"167.5","#4338ca",[74,1052,931],{"x":890,"y":1045,"style":941},[74,1054,1055,1057,1059,1062,1064,1067,1069,1071,1073,1076,1078,1080,1082,1084,1086,1088,1090,1092,1094],{"x":905,"y":1045,"style":906},[908,1056,991],{"style":913},[908,1058,613],{"style":913},[908,1060,1061],{"style":913},",",[908,1063,914],{"style":913},[908,1065,1066],{"style":913},"r",[908,1068,914],{"style":913},[908,1070,452],{"style":913},[908,1072,914],{"style":913},[908,1074,1075],{"style":913},"divmod",[908,1077,494],{"style":913},[908,1079,613],{"style":913},[908,1081,914],{"style":913},[908,1083,649],{"style":913},[908,1085,914],{"style":913},[908,1087,295],{"style":959},[908,1089,1061],{"style":913},[908,1091,914],{"style":913},[908,1093,301],{"style":959},[908,1095,924],{"style":913},[74,1097,1099],{"x":900,"y":1098,"style":902},"193.0","7",[90,1101],{"cx":890,"cy":1102,"r":935,"fill":1103,"stroke":937,"style":938},"188.5","#0b6157",[74,1105,986],{"x":890,"y":1098,"style":941},[74,1107,1108,1110,1112,1114,1116,1118,1121,1123,1125,1127,1129,1131,1133,1135,1137,1139,1141],{"x":905,"y":1098,"style":906},[908,1109,991],{"style":913},[908,1111,1016],{"style":913},[908,1113,914],{"style":913},[908,1115,452],{"style":913},[908,1117,914],{"style":913},[908,1119,1120],{"style":913},"chr",[908,1122,494],{"style":913},[908,1124,670],{"style":959},[908,1126,914],{"style":913},[908,1128,506],{"style":913},[908,1130,914],{"style":913},[908,1132,1066],{"style":913},[908,1134,924],{"style":913},[908,1136,914],{"style":913},[908,1138,506],{"style":913},[908,1140,914],{"style":913},[908,1142,1016],{"style":913},[74,1144,1146],{"x":900,"y":1145,"style":902},"214.0","8",[74,1148,1149,1151,1154,1156],{"x":905,"y":1145,"style":906},[908,1150,946],{"style":913},[908,1152,1153],{"style":910},"return",[908,1155,914],{"style":913},[908,1157,1016],{"style":913},[48,1159],{"x":65,"y":1160,"width":1161,"height":1162,"rx":1163,"fill":176,"stroke":177,"style":88},"242.0","230.7","52.0","10",[90,1165],{"cx":1166,"cy":1167,"r":935,"fill":936,"stroke":937,"style":938},"40.0","268.0",[74,1169,295],{"x":1166,"y":1170,"style":941},"272.5",[74,1172,1174],{"x":900,"y":1170,"style":1173},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","Excel has 16,384 columns",[48,1176],{"x":1177,"y":1160,"width":1161,"height":1162,"rx":1163,"fill":97,"stroke":98,"style":88},"264.7",[90,1179],{"cx":1180,"cy":1167,"r":935,"fill":1050,"stroke":937,"style":938},"284.7",[74,1182,931],{"x":1180,"y":1170,"style":941},[74,1184,1187],{"x":1185,"y":1186,"style":1173},"304.7","264.0","n - 1 makes each digit 0-25:",[74,1189,1191],{"x":1185,"y":1190,"style":1173},"281.0","no zero letter",[48,1193],{"x":1194,"y":1160,"width":1161,"height":1162,"rx":1163,"fill":1195,"stroke":1196,"style":88},"509.3","#d9f4f1","var(--teal,#0f9488)",[90,1198],{"cx":1199,"cy":1167,"r":935,"fill":1103,"stroke":937,"style":938},"529.3",[74,1201,986],{"x":1199,"y":1170,"style":941},[74,1203,1205],{"x":1204,"y":1170,"style":1173},"549.3","chr(65) is \"A\"",[200,1207,1209],{"id":1208},"step-3-validate-against-excels-real-limit","Step 3 — Validate against Excel's real limit",[10,1211,1212,1213,1216,1217,1219],{},"openpyxl's helpers accept more than Excel does. They work up to ",[14,1214,1215],{},"ZZZ",", column 18,278, while Excel stops at ",[14,1218,187],{},", column 16,384:",[205,1221,1223],{"className":243,"code":1222,"language":245,"meta":210,"style":210},"print(get_column_letter(16385), column_index_from_string(\"XFE\"))\n# XFE 16385 — accepted by openpyxl, beyond Excel's last column\n",[14,1224,1225,1242],{"__ignoreMap":210},[214,1226,1227,1229,1232,1234,1237,1240],{"class":56,"line":216},[214,1228,277],{"class":276},[214,1230,1231],{"class":256},"(get_column_letter(",[214,1233,806],{"class":276},[214,1235,1236],{"class":256},"), column_index_from_string(",[214,1238,1239],{"class":223},"\"XFE\"",[214,1241,542],{"class":256},[214,1243,1244],{"class":56,"line":266},[214,1245,1246],{"class":340},"# XFE 16385 — accepted by openpyxl, beyond Excel's last column\n",[10,1248,1249],{},"A computed column past XFD produces a workbook Excel cannot represent. Check before writing whenever a column number comes from data — the width of a wide pivot, the number of days in a range:",[205,1251,1253],{"className":243,"code":1252,"language":245,"meta":210,"style":210},"MAX_COL = 16384\n\ndef safe_letter(n):\n    if not 1 \u003C= n \u003C= MAX_COL:\n        raise ValueError(f\"column {n} is beyond Excel's limit of {MAX_COL} (XFD)\")\n    return get_column_letter(n)\n\ntry:\n    safe_letter(20000)\nexcept ValueError as exc:\n    print(exc)\n",[14,1254,1255,1266,1270,1279,1298,1330,1337,1341,1348,1358,1371],{"__ignoreMap":210},[214,1256,1257,1260,1263],{"class":56,"line":216},[214,1258,1259],{"class":276},"MAX_COL",[214,1261,1262],{"class":252}," =",[214,1264,1265],{"class":276}," 16384\n",[214,1267,1268],{"class":56,"line":266},[214,1269,270],{"emptyLinePlaceholder":269},[214,1271,1272,1274,1277],{"class":56,"line":273},[214,1273,437],{"class":252},[214,1275,1276],{"class":440}," safe_letter",[214,1278,444],{"class":256},[214,1280,1281,1283,1285,1287,1289,1291,1293,1296],{"class":56,"line":337},[214,1282,570],{"class":252},[214,1284,573],{"class":252},[214,1286,576],{"class":276},[214,1288,579],{"class":252},[214,1290,286],{"class":256},[214,1292,584],{"class":252},[214,1294,1295],{"class":276}," MAX_COL",[214,1297,590],{"class":256},[214,1299,1300,1302,1304,1306,1308,1310,1312,1314,1316,1319,1321,1323,1325,1328],{"class":56,"line":344},[214,1301,595],{"class":252},[214,1303,598],{"class":276},[214,1305,494],{"class":256},[214,1307,603],{"class":252},[214,1309,606],{"class":223},[214,1311,610],{"class":609},[214,1313,613],{"class":256},[214,1315,616],{"class":609},[214,1317,1318],{"class":223}," is beyond Excel's limit of ",[214,1320,610],{"class":609},[214,1322,1259],{"class":276},[214,1324,616],{"class":609},[214,1326,1327],{"class":223}," (XFD)\"",[214,1329,481],{"class":256},[214,1331,1332,1334],{"class":56,"line":349},[214,1333,514],{"class":252},[214,1335,1336],{"class":256}," get_column_letter(n)\n",[214,1338,1339],{"class":56,"line":406},[214,1340,270],{"emptyLinePlaceholder":269},[214,1342,1343,1346],{"class":56,"line":523},[214,1344,1345],{"class":252},"try",[214,1347,590],{"class":256},[214,1349,1350,1353,1356],{"class":56,"line":545},[214,1351,1352],{"class":256},"    safe_letter(",[214,1354,1355],{"class":276},"20000",[214,1357,481],{"class":256},[214,1359,1360,1363,1365,1368],{"class":56,"line":691},[214,1361,1362],{"class":252},"except",[214,1364,598],{"class":276},[214,1366,1367],{"class":252}," as",[214,1369,1370],{"class":256}," exc:\n",[214,1372,1373,1376],{"class":56,"line":702},[214,1374,1375],{"class":276},"    print",[214,1377,1378],{"class":256},"(exc)\n",[10,1380,1381,1382,1386],{},"The row limit is 1,048,576; ",[23,1383,1385],{"href":1384},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-this-sheet-is-too-large-error\u002F","Fix \"This sheet is too large\" When Writing Excel with pandas"," covers what to do when data exceeds either.",[200,1388,1390],{"id":1389},"step-4-parse-cell-and-range-addresses","Step 4 — Parse cell and range addresses",[10,1392,1393,1396],{},[14,1394,1395],{},"openpyxl.utils.cell"," has helpers for the other half of the job — taking addresses apart and putting them together:",[205,1398,1400],{"className":243,"code":1399,"language":245,"meta":210,"style":210},"from openpyxl.utils.cell import coordinate_from_string, range_boundaries, range_to_tuple\nfrom openpyxl.utils import absolute_coordinate, quote_sheetname\n\nprint(coordinate_from_string(\"AB12\"))             # ('AB', 12)\nprint(range_boundaries(\"B3:F20\"))                  # (2, 3, 6, 20) = min_col, min_row, max_col, max_row\nprint(range_boundaries(\"C:E\"), range_boundaries(\"2:4\"))\nprint(range_to_tuple(\"'Sales Data'!B3:F20\"))       # ('Sales Data', (2, 3, 6, 20))\nprint(absolute_coordinate(\"B3:F20\"))               # $B$3:$F$20\nprint(quote_sheetname(\"Sales Data\"), quote_sheetname(\"O'Brien\"))\n",[14,1401,1402,1414,1425,1429,1445,1461,1478,1494,1509],{"__ignoreMap":210},[214,1403,1404,1406,1409,1411],{"class":56,"line":216},[214,1405,253],{"class":252},[214,1407,1408],{"class":256}," openpyxl.utils.cell ",[214,1410,260],{"class":252},[214,1412,1413],{"class":256}," coordinate_from_string, range_boundaries, range_to_tuple\n",[214,1415,1416,1418,1420,1422],{"class":56,"line":266},[214,1417,253],{"class":252},[214,1419,257],{"class":256},[214,1421,260],{"class":252},[214,1423,1424],{"class":256}," absolute_coordinate, quote_sheetname\n",[214,1426,1427],{"class":56,"line":273},[214,1428,270],{"emptyLinePlaceholder":269},[214,1430,1431,1433,1436,1439,1442],{"class":56,"line":337},[214,1432,277],{"class":276},[214,1434,1435],{"class":256},"(coordinate_from_string(",[214,1437,1438],{"class":223},"\"AB12\"",[214,1440,1441],{"class":256},"))             ",[214,1443,1444],{"class":340},"# ('AB', 12)\n",[214,1446,1447,1449,1452,1455,1458],{"class":56,"line":344},[214,1448,277],{"class":276},[214,1450,1451],{"class":256},"(range_boundaries(",[214,1453,1454],{"class":223},"\"B3:F20\"",[214,1456,1457],{"class":256},"))                  ",[214,1459,1460],{"class":340},"# (2, 3, 6, 20) = min_col, min_row, max_col, max_row\n",[214,1462,1463,1465,1467,1470,1473,1476],{"class":56,"line":349},[214,1464,277],{"class":276},[214,1466,1451],{"class":256},[214,1468,1469],{"class":223},"\"C:E\"",[214,1471,1472],{"class":256},"), range_boundaries(",[214,1474,1475],{"class":223},"\"2:4\"",[214,1477,542],{"class":256},[214,1479,1480,1482,1485,1488,1491],{"class":56,"line":406},[214,1481,277],{"class":276},[214,1483,1484],{"class":256},"(range_to_tuple(",[214,1486,1487],{"class":223},"\"'Sales Data'!B3:F20\"",[214,1489,1490],{"class":256},"))       ",[214,1492,1493],{"class":340},"# ('Sales Data', (2, 3, 6, 20))\n",[214,1495,1496,1498,1501,1503,1506],{"class":56,"line":523},[214,1497,277],{"class":276},[214,1499,1500],{"class":256},"(absolute_coordinate(",[214,1502,1454],{"class":223},[214,1504,1505],{"class":256},"))               ",[214,1507,1508],{"class":340},"# $B$3:$F$20\n",[214,1510,1511,1513,1516,1519,1522,1525],{"class":56,"line":545},[214,1512,277],{"class":276},[214,1514,1515],{"class":256},"(quote_sheetname(",[214,1517,1518],{"class":223},"\"Sales Data\"",[214,1520,1521],{"class":256},"), quote_sheetname(",[214,1523,1524],{"class":223},"\"O'Brien\"",[214,1526,542],{"class":256},[10,1528,1529,1532,1533,1536,1537,1540,1541,1544],{},[14,1530,1531],{},"range_boundaries"," returns numbers in the order ",[14,1534,1535],{},"min_col, min_row, max_col, max_row"," — columns first, which trips people who expect row first — and ",[14,1538,1539],{},"None"," for the open ends of whole-column or whole-row ranges. ",[14,1542,1543],{},"quote_sheetname"," always adds quotes and doubles any apostrophe inside the name, which is exactly what a cross-sheet formula needs.",[200,1546,1548],{"id":1547},"step-5-map-dataframe-columns-to-letters","Step 5 — Map DataFrame columns to letters",[10,1550,1551,1552,1555],{},"The most common real use is writing formulas under a DataFrame that pandas has just written. Build the mapping once from the DataFrame's column positions, allowing for ",[14,1553,1554],{},"startcol"," and the index if it was written:",[205,1557,1559],{"className":243,"code":1558,"language":245,"meta":210,"style":210},"import pandas as pd\nfrom openpyxl import load_workbook\n\nsales = pd.DataFrame({\"region\": [\"North\", \"South\", \"East\"], \"units\": [12, 7, 9], \"revenue\": [1200.0, 700.0, 950.0]})\nstart_col = 1                                     # write from column B\nsales.to_excel(\"sales.xlsx\", index=False, startcol=start_col)\n\nletters = {name: get_column_letter(start_col + i + 1) for i, name in enumerate(sales.columns)}\nprint(letters)\n# {'region': 'B', 'units': 'C', 'revenue': 'D'}\n\nwb = load_workbook(\"sales.xlsx\")\nws = wb.active\nlast = len(sales) + 1                             # header is row 1\ntotal_row = last + 1\nws[f\"{letters['region']}{total_row}\"] = \"Total\"\nfor col in (\"units\", \"revenue\"):\n    ws[f\"{letters[col]}{total_row}\"] = f\"=SUM({letters[col]}2:{letters[col]}{last})\"\nwb.save(\"sales.xlsx\")\nprint([c.value for c in ws[total_row]])\n",[14,1560,1561,1574,1586,1590,1661,1673,1701,1705,1740,1747,1752,1756,1770,1780,1800,1815,1854,1874,1929,1938],{"__ignoreMap":210},[214,1562,1563,1565,1568,1571],{"class":56,"line":216},[214,1564,260],{"class":252},[214,1566,1567],{"class":256}," pandas ",[214,1569,1570],{"class":252},"as",[214,1572,1573],{"class":256}," pd\n",[214,1575,1576,1578,1581,1583],{"class":56,"line":266},[214,1577,253],{"class":252},[214,1579,1580],{"class":256}," openpyxl ",[214,1582,260],{"class":252},[214,1584,1585],{"class":256}," load_workbook\n",[214,1587,1588],{"class":56,"line":273},[214,1589,270],{"emptyLinePlaceholder":269},[214,1591,1592,1595,1597,1600,1603,1606,1609,1611,1614,1616,1619,1622,1625,1627,1629,1631,1633,1635,1638,1640,1643,1645,1648,1650,1653,1655,1658],{"class":56,"line":337},[214,1593,1594],{"class":256},"sales ",[214,1596,452],{"class":252},[214,1598,1599],{"class":256}," pd.DataFrame({",[214,1601,1602],{"class":223},"\"region\"",[214,1604,1605],{"class":256},": [",[214,1607,1608],{"class":223},"\"North\"",[214,1610,298],{"class":256},[214,1612,1613],{"class":223},"\"South\"",[214,1615,298],{"class":256},[214,1617,1618],{"class":223},"\"East\"",[214,1620,1621],{"class":256},"], ",[214,1623,1624],{"class":223},"\"units\"",[214,1626,1605],{"class":256},[214,1628,69],{"class":276},[214,1630,298],{"class":256},[214,1632,1099],{"class":276},[214,1634,298],{"class":256},[214,1636,1637],{"class":276},"9",[214,1639,1621],{"class":256},[214,1641,1642],{"class":223},"\"revenue\"",[214,1644,1605],{"class":256},[214,1646,1647],{"class":276},"1200.0",[214,1649,298],{"class":256},[214,1651,1652],{"class":276},"700.0",[214,1654,298],{"class":256},[214,1656,1657],{"class":276},"950.0",[214,1659,1660],{"class":256},"]})\n",[214,1662,1663,1666,1668,1670],{"class":56,"line":344},[214,1664,1665],{"class":256},"start_col ",[214,1667,452],{"class":252},[214,1669,576],{"class":276},[214,1671,1672],{"class":340},"                                     # write from column B\n",[214,1674,1675,1678,1681,1683,1687,1689,1692,1694,1696,1698],{"class":56,"line":349},[214,1676,1677],{"class":256},"sales.to_excel(",[214,1679,1680],{"class":223},"\"sales.xlsx\"",[214,1682,298],{"class":256},[214,1684,1686],{"class":1685},"sa561","index",[214,1688,452],{"class":252},[214,1690,1691],{"class":276},"False",[214,1693,298],{"class":256},[214,1695,1554],{"class":1685},[214,1697,452],{"class":252},[214,1699,1700],{"class":256},"start_col)\n",[214,1702,1703],{"class":56,"line":406},[214,1704,270],{"emptyLinePlaceholder":269},[214,1706,1707,1710,1712,1715,1717,1720,1722,1724,1727,1729,1732,1734,1737],{"class":56,"line":523},[214,1708,1709],{"class":256},"letters ",[214,1711,452],{"class":252},[214,1713,1714],{"class":256}," {name: get_column_letter(start_col ",[214,1716,506],{"class":252},[214,1718,1719],{"class":256}," i ",[214,1721,506],{"class":252},[214,1723,576],{"class":276},[214,1725,1726],{"class":256},") ",[214,1728,283],{"class":252},[214,1730,1731],{"class":256}," i, name ",[214,1733,289],{"class":252},[214,1735,1736],{"class":276}," enumerate",[214,1738,1739],{"class":256},"(sales.columns)}\n",[214,1741,1742,1744],{"class":56,"line":545},[214,1743,277],{"class":276},[214,1745,1746],{"class":256},"(letters)\n",[214,1748,1749],{"class":56,"line":691},[214,1750,1751],{"class":340},"# {'region': 'B', 'units': 'C', 'revenue': 'D'}\n",[214,1753,1754],{"class":56,"line":702},[214,1755,270],{"emptyLinePlaceholder":269},[214,1757,1758,1761,1763,1766,1768],{"class":56,"line":713},[214,1759,1760],{"class":256},"wb ",[214,1762,452],{"class":252},[214,1764,1765],{"class":256}," load_workbook(",[214,1767,1680],{"class":223},[214,1769,481],{"class":256},[214,1771,1772,1775,1777],{"class":56,"line":727},[214,1773,1774],{"class":256},"ws ",[214,1776,452],{"class":252},[214,1778,1779],{"class":256}," wb.active\n",[214,1781,1782,1785,1787,1790,1793,1795,1797],{"class":56,"line":760},[214,1783,1784],{"class":256},"last ",[214,1786,452],{"class":252},[214,1788,1789],{"class":276}," len",[214,1791,1792],{"class":256},"(sales) ",[214,1794,506],{"class":252},[214,1796,576],{"class":276},[214,1798,1799],{"class":340},"                             # header is row 1\n",[214,1801,1802,1805,1807,1810,1812],{"class":56,"line":768},[214,1803,1804],{"class":256},"total_row ",[214,1806,452],{"class":252},[214,1808,1809],{"class":256}," last ",[214,1811,506],{"class":252},[214,1813,1814],{"class":276}," 1\n",[214,1816,1817,1820,1822,1825,1827,1830,1833,1836,1839,1842,1844,1846,1849,1851],{"class":56,"line":773},[214,1818,1819],{"class":256},"ws[",[214,1821,603],{"class":252},[214,1823,1824],{"class":223},"\"",[214,1826,610],{"class":609},[214,1828,1829],{"class":256},"letters[",[214,1831,1832],{"class":223},"'region'",[214,1834,1835],{"class":256},"]",[214,1837,1838],{"class":609},"}{",[214,1840,1841],{"class":256},"total_row",[214,1843,616],{"class":609},[214,1845,1824],{"class":223},[214,1847,1848],{"class":256},"] ",[214,1850,452],{"class":252},[214,1852,1853],{"class":223}," \"Total\"\n",[214,1855,1856,1858,1861,1863,1865,1867,1869,1871],{"class":56,"line":811},[214,1857,283],{"class":252},[214,1859,1860],{"class":256}," col ",[214,1862,289],{"class":252},[214,1864,292],{"class":256},[214,1866,1624],{"class":223},[214,1868,298],{"class":256},[214,1870,1642],{"class":223},[214,1872,1873],{"class":256},"):\n",[214,1875,1876,1879,1881,1883,1885,1888,1890,1892,1894,1896,1898,1900,1903,1906,1908,1910,1912,1915,1917,1919,1921,1924,1926],{"class":56,"line":843},[214,1877,1878],{"class":256},"    ws[",[214,1880,603],{"class":252},[214,1882,1824],{"class":223},[214,1884,610],{"class":609},[214,1886,1887],{"class":256},"letters[col]",[214,1889,1838],{"class":609},[214,1891,1841],{"class":256},[214,1893,616],{"class":609},[214,1895,1824],{"class":223},[214,1897,1848],{"class":256},[214,1899,452],{"class":252},[214,1901,1902],{"class":252}," f",[214,1904,1905],{"class":223},"\"=SUM(",[214,1907,610],{"class":609},[214,1909,1887],{"class":256},[214,1911,616],{"class":609},[214,1913,1914],{"class":223},"2:",[214,1916,610],{"class":609},[214,1918,1887],{"class":256},[214,1920,1838],{"class":609},[214,1922,1923],{"class":256},"last",[214,1925,616],{"class":609},[214,1927,1928],{"class":223},")\"\n",[214,1930,1931,1934,1936],{"class":56,"line":862},[214,1932,1933],{"class":256},"wb.save(",[214,1935,1680],{"class":223},[214,1937,481],{"class":256},[214,1939,1941,1943,1946,1948,1951,1953],{"class":56,"line":1940},20,[214,1942,277],{"class":276},[214,1944,1945],{"class":256},"([c.value ",[214,1947,283],{"class":252},[214,1949,1950],{"class":256}," c ",[214,1952,289],{"class":252},[214,1954,1955],{"class":256}," ws[total_row]])\n",[10,1957,1958],{},"Deriving letters from the DataFrame rather than hard-coding \"C\" and \"D\" keeps the formulas right when a column is added or reordered next month. If the index is written, it occupies the first column, so add one more to every position.",[29,1960,38,1966,38,1969,38,1972,38,1977,38,1983,38,1989,38,1993,38,1999,38,2003,38,2007,38,2011,38,2015,38,2019,38,2023,38,2027,38,2030,38,2032,38,2034,38,2038,38,2040,38,2043,38,2045,38,2048,38,2051,38,2054,38,2056,38,2058,38,2062,38,2064,38,2066,38,2068,38,2071,38,2074,38,2077,38,2079,38,2081,38,2084,38,2086,38,2088,38,2090,38,2093,38,2096,38,2099,38,2101,38,2103,38,2106,38,2108,38,2110,38,2112,38,2115,38,2118,38,2121,38,2123,38,2125,38,2128,38,2130,38,2134,38,2136,38,2139,38,2143,38,2148,38,2153,38,2163,38,2169],{"viewBox":1961,"role":32,"ariaLabelledBy":1962,"xmlns":36,"style":1965},"46 0 668 228",[1963,1964],"col-map-t","col-map-d","width:100%;max-width:668px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[40,1967,1968],{"id":1963},"DataFrame columns mapped to worksheet letters",[44,1970,1971],{"id":1964},"A worksheet written from a DataFrame with startcol=1, so the data begins in column B: region in B, units in C, revenue in D. A total row uses the mapped letters in its formulas, =SUM(C2:C4) and =SUM(D2:D4).",[48,1973],{"x":1974,"y":51,"width":1975,"height":1976,"fill":54},"46","668","228",[74,1978,1982],{"x":1979,"y":1980,"style":1981},"380.0","31.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","sales.xlsx — written with startcol=1",[48,1984],{"x":1985,"y":1986,"width":1987,"height":1988,"rx":51,"fill":70,"stroke":71,"style":897},"62.3","48.0","32.0","24.0",[48,1990],{"x":1991,"y":1986,"width":1992,"height":1988,"rx":51,"fill":70,"stroke":71,"style":897},"94.3","44.0",[74,1994,1998],{"x":1995,"y":1996,"style":1997},"116.3","65.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[48,2000],{"x":2001,"y":1986,"width":2002,"height":1988,"rx":51,"fill":70,"stroke":71,"style":897},"138.3","63.6",[74,2004,2006],{"x":2005,"y":1996,"style":1997},"170.1","B",[48,2008],{"x":2009,"y":1986,"width":2010,"height":1988,"rx":51,"fill":70,"stroke":71,"style":897},"201.9","110.6",[74,2012,2014],{"x":2013,"y":1996,"style":1997},"257.2","C",[48,2016],{"x":2017,"y":1986,"width":2018,"height":1988,"rx":51,"fill":70,"stroke":71,"style":897},"312.5","110.1",[74,2020,2022],{"x":2021,"y":1996,"style":1997},"367.5","D",[48,2024],{"x":1985,"y":2025,"width":1987,"height":2026,"rx":51,"fill":70,"stroke":71,"style":897},"72.0","28.0",[74,2028,295],{"x":2029,"y":68,"style":1997},"78.3",[48,2031],{"x":1991,"y":2025,"width":1992,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[48,2033],{"x":2001,"y":2025,"width":2002,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2035,2037],{"x":2005,"y":68,"style":2036},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","region",[48,2039],{"x":2009,"y":2025,"width":2010,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2041,2042],{"x":2013,"y":68,"style":2036},"units",[48,2044],{"x":2017,"y":2025,"width":2018,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2046,2047],{"x":2021,"y":68,"style":2036},"revenue",[48,2049],{"x":1985,"y":2050,"width":1987,"height":2026,"rx":51,"fill":70,"stroke":71,"style":897},"100.0",[74,2052,931],{"x":2029,"y":2053,"style":1997},"119.0",[48,2055],{"x":1991,"y":2050,"width":1992,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[48,2057],{"x":2001,"y":2050,"width":2002,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2059,2061],{"x":2005,"y":2053,"style":2060},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","North",[48,2063],{"x":2009,"y":2050,"width":2010,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2065,69],{"x":2013,"y":2053,"style":2060},[48,2067],{"x":2017,"y":2050,"width":2018,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2069,2070],{"x":2021,"y":2053,"style":2060},"1200",[48,2072],{"x":1985,"y":2073,"width":1987,"height":2026,"rx":51,"fill":70,"stroke":71,"style":897},"128.0",[74,2075,986],{"x":2029,"y":2076,"style":1997},"147.0",[48,2078],{"x":1991,"y":2073,"width":1992,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[48,2080],{"x":2001,"y":2073,"width":2002,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2082,2083],{"x":2005,"y":2076,"style":2060},"South",[48,2085],{"x":2009,"y":2073,"width":2010,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2087,1099],{"x":2013,"y":2076,"style":2060},[48,2089],{"x":2017,"y":2073,"width":2018,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2091,2092],{"x":2021,"y":2076,"style":2060},"700",[48,2094],{"x":1985,"y":2095,"width":1987,"height":2026,"rx":51,"fill":70,"stroke":71,"style":897},"156.0",[74,2097,50],{"x":2029,"y":2098,"style":1997},"175.0",[48,2100],{"x":1991,"y":2095,"width":1992,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[48,2102],{"x":2001,"y":2095,"width":2002,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2104,2105],{"x":2005,"y":2098,"style":2060},"East",[48,2107],{"x":2009,"y":2095,"width":2010,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2109,1637],{"x":2013,"y":2098,"style":2060},[48,2111],{"x":2017,"y":2095,"width":2018,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2113,2114],{"x":2021,"y":2098,"style":2060},"950",[48,2116],{"x":1985,"y":2117,"width":1987,"height":2026,"rx":51,"fill":70,"stroke":71,"style":897},"184.0",[74,2119,1029],{"x":2029,"y":2120,"style":1997},"203.0",[48,2122],{"x":1991,"y":2117,"width":1992,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[48,2124],{"x":2001,"y":2117,"width":2002,"height":2026,"rx":51,"fill":54,"stroke":71,"style":897},[74,2126,2127],{"x":2005,"y":2120,"style":2060},"Total",[48,2129],{"x":2009,"y":2117,"width":2010,"height":2026,"rx":51,"fill":1195,"stroke":1196,"style":88},[74,2131,2133],{"x":2013,"y":2120,"style":2132},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","=SUM(C2:C4)",[48,2135],{"x":2017,"y":2117,"width":2018,"height":2026,"rx":51,"fill":1195,"stroke":1196,"style":88},[74,2137,2138],{"x":2021,"y":2120,"style":2132},"=SUM(D2:D4)",[56,2140],{"x1":2141,"y1":1009,"x2":2142,"y2":1009,"stroke":98,"style":72},"430.6","462.6",[2144,2145],"polygon",{"points":2146,"fill":2147},"466.6,130.0 457.6,135.0 457.6,125.0","#5b5cf0",[48,2149],{"x":2150,"y":934,"width":2151,"height":2152,"rx":69,"fill":97,"stroke":98,"style":72},"472.6","225.1","93.0",[2154,2155,2157],"g",{"transform":2156},"translate(573.2,96.5) scale(1.000)",[2158,2159],"path",{"d":2160,"fill":937,"stroke":2161,"style":2162},"M9 8l-4 4 4 4 M15 8l4 4-4 4","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[74,2164,2168],{"x":2165,"y":2166,"style":2167},"585.2","143.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","letters from positions",[74,2170,2173],{"x":2165,"y":2171,"style":2172},"162.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","get_column_letter(start_col + i + 1)",[200,2175,2177],{"id":2176},"step-6-use-letters-when-reading-with-pandas","Step 6 — Use letters when reading with pandas",[10,2179,2180,2181,2184,2185,2188],{},"The conversion also runs the other way when a colleague says \"the figures are in column AB\". ",[14,2182,2183],{},"read_excel"," accepts letters directly in ",[14,2186,2187],{},"usecols",", including ranges and lists, so often no conversion is needed at all:",[205,2190,2192],{"className":243,"code":2191,"language":245,"meta":210,"style":210},"wide = pd.DataFrame([[f\"r{r}c{c}\" for c in range(1, 31)] for r in range(3)],\n                    columns=[f\"col{c}\" for c in range(1, 31)])\nwide.to_excel(\"wide.xlsx\", index=False)\n\nprint(pd.read_excel(\"wide.xlsx\", usecols=\"AB\").columns.tolist())\nprint(pd.read_excel(\"wide.xlsx\", usecols=\"A,C:E\").columns.tolist())\n\nfull = pd.read_excel(\"wide.xlsx\")\nprint(full.iloc[:, column_index_from_string(\"AB\") - 1].name)\n",[14,2193,2194,2263,2304,2322,2326,2346,2365,2369,2383],{"__ignoreMap":210},[214,2195,2196,2199,2201,2204,2206,2209,2211,2213,2215,2218,2220,2222,2224,2226,2229,2231,2233,2235,2237,2239,2241,2244,2247,2249,2252,2254,2256,2258,2260],{"class":56,"line":216},[214,2197,2198],{"class":256},"wide ",[214,2200,452],{"class":252},[214,2202,2203],{"class":256}," pd.DataFrame([[",[214,2205,603],{"class":252},[214,2207,2208],{"class":223},"\"r",[214,2210,610],{"class":609},[214,2212,1066],{"class":256},[214,2214,616],{"class":609},[214,2216,2217],{"class":223},"c",[214,2219,610],{"class":609},[214,2221,2217],{"class":256},[214,2223,616],{"class":609},[214,2225,1824],{"class":223},[214,2227,2228],{"class":252}," for",[214,2230,1950],{"class":256},[214,2232,289],{"class":252},[214,2234,797],{"class":276},[214,2236,494],{"class":256},[214,2238,295],{"class":276},[214,2240,298],{"class":256},[214,2242,2243],{"class":276},"31",[214,2245,2246],{"class":256},")] ",[214,2248,283],{"class":252},[214,2250,2251],{"class":256}," r ",[214,2253,289],{"class":252},[214,2255,797],{"class":276},[214,2257,494],{"class":256},[214,2259,986],{"class":276},[214,2261,2262],{"class":256},")],\n",[214,2264,2265,2268,2270,2273,2275,2278,2280,2282,2284,2286,2288,2290,2292,2294,2296,2298,2300,2302],{"class":56,"line":266},[214,2266,2267],{"class":1685},"                    columns",[214,2269,452],{"class":252},[214,2271,2272],{"class":256},"[",[214,2274,603],{"class":252},[214,2276,2277],{"class":223},"\"col",[214,2279,610],{"class":609},[214,2281,2217],{"class":256},[214,2283,616],{"class":609},[214,2285,1824],{"class":223},[214,2287,2228],{"class":252},[214,2289,1950],{"class":256},[214,2291,289],{"class":252},[214,2293,797],{"class":276},[214,2295,494],{"class":256},[214,2297,295],{"class":276},[214,2299,298],{"class":256},[214,2301,2243],{"class":276},[214,2303,334],{"class":256},[214,2305,2306,2309,2312,2314,2316,2318,2320],{"class":56,"line":273},[214,2307,2308],{"class":256},"wide.to_excel(",[214,2310,2311],{"class":223},"\"wide.xlsx\"",[214,2313,298],{"class":256},[214,2315,1686],{"class":1685},[214,2317,452],{"class":252},[214,2319,1691],{"class":276},[214,2321,481],{"class":256},[214,2323,2324],{"class":56,"line":337},[214,2325,270],{"emptyLinePlaceholder":269},[214,2327,2328,2330,2333,2335,2337,2339,2341,2343],{"class":56,"line":344},[214,2329,277],{"class":276},[214,2331,2332],{"class":256},"(pd.read_excel(",[214,2334,2311],{"class":223},[214,2336,298],{"class":256},[214,2338,2187],{"class":1685},[214,2340,452],{"class":252},[214,2342,857],{"class":223},[214,2344,2345],{"class":256},").columns.tolist())\n",[214,2347,2348,2350,2352,2354,2356,2358,2360,2363],{"class":56,"line":349},[214,2349,277],{"class":276},[214,2351,2332],{"class":256},[214,2353,2311],{"class":223},[214,2355,298],{"class":256},[214,2357,2187],{"class":1685},[214,2359,452],{"class":252},[214,2361,2362],{"class":223},"\"A,C:E\"",[214,2364,2345],{"class":256},[214,2366,2367],{"class":56,"line":406},[214,2368,270],{"emptyLinePlaceholder":269},[214,2370,2371,2374,2376,2379,2381],{"class":56,"line":523},[214,2372,2373],{"class":256},"full ",[214,2375,452],{"class":252},[214,2377,2378],{"class":256}," pd.read_excel(",[214,2380,2311],{"class":223},[214,2382,481],{"class":256},[214,2384,2385,2387,2390,2392,2394,2396,2398],{"class":56,"line":545},[214,2386,277],{"class":276},[214,2388,2389],{"class":256},"(full.iloc[:, column_index_from_string(",[214,2391,857],{"class":223},[214,2393,1726],{"class":256},[214,2395,649],{"class":252},[214,2397,576],{"class":276},[214,2399,2400],{"class":256},"].name)\n",[10,2402,2403,2404,2407],{},"When the whole sheet is already in a DataFrame, subtract one from the column number to get a pandas position for ",[14,2405,2406],{},"iloc",". That subtraction — or the addition in the other direction — is the single place in a script where the two numbering systems should meet.",[200,2409,2411],{"id":2410},"step-7-keep-0-based-and-1-based-straight","Step 7 — Keep 0-based and 1-based straight",[10,2413,2414,2415,298,2417,2420],{},"Three libraries, two conventions. pandas positions (",[14,2416,2406],{},[14,2418,2419],{},"get_loc",") and xlsxwriter's row\u002Fcolumn arguments count from 0; openpyxl and Excel count from 1. xlsxwriter has its own helpers that follow its 0-based convention:",[205,2422,2424],{"className":243,"code":2423,"language":245,"meta":210,"style":210},"from xlsxwriter.utility import xl_col_to_name, xl_rowcol_to_cell, xl_cell_to_rowcol\n\nprint(xl_col_to_name(0), xl_rowcol_to_cell(0, 0), xl_cell_to_rowcol(\"B3\"))\n# A A1 (2, 1)\nprint(get_column_letter(1), sales.columns.get_loc(\"units\"))\n# A 1\n",[14,2425,2426,2438,2442,2468,2473,2488],{"__ignoreMap":210},[214,2427,2428,2430,2433,2435],{"class":56,"line":216},[214,2429,253],{"class":252},[214,2431,2432],{"class":256}," xlsxwriter.utility ",[214,2434,260],{"class":252},[214,2436,2437],{"class":256}," xl_col_to_name, xl_rowcol_to_cell, xl_cell_to_rowcol\n",[214,2439,2440],{"class":56,"line":266},[214,2441,270],{"emptyLinePlaceholder":269},[214,2443,2444,2446,2449,2451,2454,2456,2458,2460,2463,2466],{"class":56,"line":273},[214,2445,277],{"class":276},[214,2447,2448],{"class":256},"(xl_col_to_name(",[214,2450,51],{"class":276},[214,2452,2453],{"class":256},"), xl_rowcol_to_cell(",[214,2455,51],{"class":276},[214,2457,298],{"class":256},[214,2459,51],{"class":276},[214,2461,2462],{"class":256},"), xl_cell_to_rowcol(",[214,2464,2465],{"class":223},"\"B3\"",[214,2467,542],{"class":256},[214,2469,2470],{"class":56,"line":337},[214,2471,2472],{"class":340},"# A A1 (2, 1)\n",[214,2474,2475,2477,2479,2481,2484,2486],{"class":56,"line":344},[214,2476,277],{"class":276},[214,2478,1231],{"class":256},[214,2480,295],{"class":276},[214,2482,2483],{"class":256},"), sales.columns.get_loc(",[214,2485,1624],{"class":223},[214,2487,542],{"class":256},[214,2489,2490],{"class":56,"line":349},[214,2491,2492],{"class":340},"# A 1\n",[10,2494,2495,2498,2499,2502,2503,2506,2507,2510],{},[14,2496,2497],{},"xl_col_to_name(0)"," and ",[14,2500,2501],{},"get_column_letter(1)"," both give \"A\". Mixing the two families in one script is the classic source of formulas that sit one column to the left of where they should. Pick the helpers that match the library you are writing with, and convert explicitly (",[14,2504,2505],{},"+ 1"," or ",[14,2508,2509],{},"- 1",") at the one place where a pandas position crosses into openpyxl.",[200,2512,2514],{"id":2513},"common-pitfalls","Common pitfalls",[2516,2517,2518,2530,2543,2551,2579],"ul",{},[2519,2520,2521,2529],"li",{},[2522,2523,2524,2525,2528],"strong",{},"Passing a pandas position to ",[14,2526,2527],{},"get_column_letter","."," Position 0 raises; position 1 gives \"A\" for what pandas calls the second column. Add one.",[2519,2531,2532,914,2535,2538,2539,2542],{},[2522,2533,2534],{},"Forgetting the index column.",[14,2536,2537],{},"to_excel"," with the default ",[14,2540,2541],{},"index=True"," shifts every data column right by one.",[2519,2544,2545,2550],{},[2522,2546,2547,2548,2528],{},"Expecting row-first from ",[14,2549,1531],{}," It returns columns first.",[2519,2552,2553,2556,2557,2506,2560,2563,2564,2567,2568,2571,2572,2575,2576,2528],{},[2522,2554,2555],{},"Addresses copied from formulas."," Configuration values like ",[14,2558,2559],{},"$AB$2",[14,2561,2562],{},"'Q1 Sales'!AB2"," carry dollar signs and sheet names. Strip the ",[14,2565,2566],{},"$"," before calling ",[14,2569,2570],{},"column_index_from_string",", and split off the sheet with ",[14,2573,2574],{},"range_to_tuple"," rather than with string slicing, which breaks on quoted names containing ",[14,2577,2578],{},"!",[2519,2580,2581,2584],{},[2522,2582,2583],{},"Trusting openpyxl to reject XFE."," It does not; validate against 16,384 yourself.",[200,2586,2588],{"id":2587},"performance-notes","Performance notes",[10,2590,2591,2592,2595],{},"Both conversions are a few arithmetic operations; converting all 16,384 columns takes milliseconds. If a hot loop converts the same numbers repeatedly, a list of all letters built once — ",[14,2593,2594],{},"[get_column_letter(n) for n in range(1, 16385)]"," — turns each conversion into an index lookup. In practice the conversion is never the slow part of a report; the cell writes around it are.",[200,2597,2599],{"id":2598},"conclusion","Conclusion",[10,2601,2602,2603,2498,2605,2607,2608,2611,2612,2614,2615,2498,2617,2619],{},"Use ",[14,2604,2527],{},[14,2606,2570],{}," (1-based) with openpyxl, or ",[14,2609,2610],{},"xl_col_to_name"," and friends (0-based) with xlsxwriter. If you write your own, subtract one before each ",[14,2613,1075],{}," — column letters are base 26 without a zero digit. Validate computed columns against Excel's 16,384 limit, parse addresses with ",[14,2616,1531],{},[14,2618,2574],{},", and derive formula letters from DataFrame positions so they follow the data.",[200,2621,2623],{"id":2622},"frequently-asked-questions","Frequently asked questions",[10,2625,2626,2629],{},[2522,2627,2628],{},"How do I convert a column number to a letter in Python?","\nUse get_column_letter(n) from openpyxl.utils, where n starts at 1: get_column_letter(28) returns \"AB\". With xlsxwriter, xl_col_to_name(n) does the same but counts from 0.",[10,2631,2632,2635],{},[2522,2633,2634],{},"Why does my own conversion give wrong letters after Z?","\nColumn letters are not ordinary base 26: there is no zero digit, so AA follows Z. Code that uses divmod(n, 26) without subtracting one first produces \"A@\" or skips letters. Use the library functions or the corrected loop shown here.",[10,2637,2638,2641],{},[2522,2639,2640],{},"What is the last column in Excel?","\nXFD, which is column 16,384. openpyxl's helpers accept letters up to ZZZ (18,278), so check the limit yourself before writing to a computed column.",[10,2643,2644,2647],{},[2522,2645,2646],{},"How do I get the column letter for a DataFrame column?","\nFind its position with df.columns.get_loc(name), add one for openpyxl's 1-based numbering plus any start column offset, and pass the result to get_column_letter.",[200,2649,2651],{"id":2650},"related","Related",[2516,2653,2654,2660,2667,2674],{},[2519,2655,2656,2657,2659],{},"Up one level: ",[23,2658,26],{"href":25}," — working with cells and ranges.",[2519,2661,2662,2666],{},[23,2663,2665],{"href":2664},"\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"," — writing totals under data.",[2519,2668,2669,2673],{},[23,2670,2672],{"href":2671},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe\u002F","Read a Cell Range Like B3:F20 into a pandas DataFrame"," — using parsed ranges to read.",[2519,2675,2676,2680],{},[23,2677,2679],{"href":2678},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formulas-that-reference-other-sheets-with-openpyxl\u002F","Write Formulas That Reference Other Sheets with openpyxl"," — where quote_sheetname earns its keep.",[2682,2683,2684],"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 .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}",{"title":210,"searchDepth":266,"depth":266,"links":2686},[2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699],{"id":202,"depth":266,"text":203},{"id":236,"depth":266,"text":237},{"id":423,"depth":266,"text":424},{"id":1208,"depth":266,"text":1209},{"id":1389,"depth":266,"text":1390},{"id":1547,"depth":266,"text":1548},{"id":2176,"depth":266,"text":2177},{"id":2410,"depth":266,"text":2411},{"id":2513,"depth":266,"text":2514},{"id":2587,"depth":266,"text":2588},{"id":2598,"depth":266,"text":2599},{"id":2622,"depth":266,"text":2623},{"id":2650,"depth":266,"text":2651},"2026-09-25","Turn 28 into \"AB\" and \"XFD\" into 16384 with openpyxl's get_column_letter and column_index_from_string, parse cell and range addresses, and map DataFrame columns to letters for formulas — plus why naive base-26 code breaks at Z and the 0-based\u002F1-based traps between pandas, openpyxl and xlsxwriter.","md",[2704,2706,2708,2710],{"q":2628,"a":2705},"Use get_column_letter(n) from openpyxl.utils, where n starts at 1: get_column_letter(28) returns \"AB\". With xlsxwriter, xl_col_to_name(n) does the same but counts from 0.",{"q":2634,"a":2707},"Column letters are not ordinary base 26: there is no zero digit, so AA follows Z. Code that uses divmod(n, 26) without subtracting one first produces \"A@\" or skips letters. Use the library functions or the corrected loop shown here.",{"q":2640,"a":2709},"XFD, which is column 16,384. openpyxl's helpers accept letters up to ZZZ (18,278), so check the limit yourself before writing to a computed column.",{"q":2646,"a":2711},"Find its position with df.columns.get_loc(name), add one for openpyxl's 1-based numbering plus any start column offset, and pass the result to get_column_letter.","convert column letters to numbers with openpyxl utils",null,{"breadcrumb":2715},[2716,2719,2722],{"name":2717,"item":2718},"Home","\u002F",{"name":2720,"item":2721},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":26,"item":25},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl",{"title":2725,"description":2726},"Excel Column Letter to Number (and Back) in Python","Convert Excel column letters to numbers and back with openpyxl get_column_letter and column_index_from_string, parse A1 addresses and ranges, validate the XFD limit, and map pandas columns to letters.","convert-column-letters-and-numbers-with-openpyxl","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fconvert-column-letters-and-numbers-with-openpyxl\u002Findex",[2730,2731,2732],"openpyxl","excel-formulas","writing-excel","how-to","dGhN0mV8DFUdZEdtsKwwskyQ2PgELOGWJleLDCkxN74",[2736,2740],{"title":2737,"path":2738,"stem":2739,"children":-1},"Clear Cell Contents and Formatting with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fclear-cell-contents-and-formatting-with-openpyxl","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fclear-cell-contents-and-formatting-with-openpyxl\u002Findex",{"title":2741,"path":2742,"stem":2743,"children":-1},"Copy Cell Styles from One Cell to Another with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fcopy-cell-styles-with-openpyxl","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fcopy-cell-styles-with-openpyxl\u002Findex",[2745,2747],{"path":2746,"title":2720},"\u002Fgetting-started-with-python-excel-automation",{"path":2748,"title":26},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation",[],[2751,2755,2758,2761,2764,2767],{"path":2752,"title":2753,"kind":2754},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl","Applying Conditional Formatting With openpyxl","guide",{"path":2756,"title":2757,"kind":2733},"\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":2759,"title":2760,"kind":2733},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fadd-icon-sets-with-openpyxl","Add Icon Sets to Excel Cells with openpyxl",{"path":2762,"title":2763,"kind":2733},"\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":2765,"title":2766,"kind":2733},"\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":2768,"title":2769,"kind":2733},"\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",1790972069764]