[{"data":1,"prerenderedAt":2220},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python":2186,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python":2194,"children:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python":2199,"related:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python":2200},{"id":4,"title":5,"body":6,"dateModified":2150,"datePublished":2150,"description":2151,"extension":2152,"faq":2153,"keyword":2163,"kind":2164,"meta":2165,"navigation":418,"path":2174,"seo":2175,"slug":2178,"stem":2179,"topics":2180,"type":2184,"__hash__":2185},"docs\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python\u002Findex.md","Use Structured Table References in Excel Formulas from Python",{"type":7,"value":8,"toc":2137},"minimark",[9,32,326,331,359,362,366,377,619,627,631,651,711,721,946,953,1085,1089,1092,1243,1266,1427,1444,1448,1451,1670,1684,1688,1697,1909,1924,1928,2013,2017,2027,2031,2046,2050,2064,2077,2086,2100,2104,2133],[10,11,12,13,17,18,21,22,25,26,31],"p",{},"Excel tables give columns names, and formulas can use those names instead of addresses: ",[14,15,16],"code",{},"=SUM(Sales[Total])"," rather than ",[14,19,20],{},"=SUM(D2:D250)",". The difference matters most in files that Python generates and people then extend. An address range is fixed at the size Python wrote; a structured reference follows the table as it grows. Writing these formulas from Python is straightforward with one exception — the familiar ",[14,23,24],{},"[@Column]"," shorthand is a display form, not what the file stores. This guide, part of ",[27,28,30],"a",{"href":29},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002F","Working with Excel Formulas in Python",", covers both libraries and verifies the results.",[33,34,42,43,42,47,42,51,42,59,42,67,42,71,42,78,42,83,42,88,42,92,42,98,42,102,42,106,42,110,42,114,42,118,42,122,42,125,42,129,42,133,42,137,42,140,42,145,42,150,42,155,42,161,42,166,42,168,42,172,42,175,42,178,42,180,42,184,42,187,42,190,42,192,42,196,42,199,42,202,42,204,42,207,42,210,42,212,42,217,42,220,42,223,42,226,42,229,42,231,42,235,42,237,42,239,42,241,42,244,42,248,42,252,42,254,42,258,42,262,42,265,42,269,42,271,42,274,42,276,42,278,42,280,42,282,42,284,42,287,42,289,42,291,42,294,42,298,42,300,42,303,42,305,42,307,42,309,42,312,42,314,42,316,42,318,42,320],"svg",{"viewBox":35,"role":36,"ariaLabelledBy":37,"xmlns":40,"style":41},"81 0 597 222","img",[38,39],"sr-table-t","sr-table-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:597px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[44,45,46],"title",{"id":38},"An Excel table with a calculated column and a summary formula",[48,49,50],"desc",{"id":39},"A table named Sales has Region, Qty and Price columns and a calculated Total column whose formula multiplies Qty by Price in the same row. Outside the table, F1 holds =SUM(Sales[Total]), which adds the whole Total column however long it becomes.",[52,53],"rect",{"x":54,"y":55,"width":56,"height":57,"fill":58},"81","0","597","222","#ffffff",[52,60],{"x":61,"y":62,"width":63,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},"144.2","16.0","471.6","28.0","var(--line,#cdd5e6)","stroke-width:1px",[52,68],{"x":61,"y":62,"width":69,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"40.0","#e7ebef",[72,73,77],"text",{"x":74,"y":75,"style":76},"164.2","35.0","font-size:12px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","fx",[72,79,82],{"x":80,"y":75,"style":81},"194.2","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","=Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]",[52,84],{"x":61,"y":85,"width":86,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"44.0","32.0","24.0",[52,89],{"x":90,"y":85,"width":91,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"176.2","80.7",[72,93,97],{"x":94,"y":95,"style":96},"216.6","61.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[52,99],{"x":100,"y":85,"width":101,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"256.9","60.0",[72,103,105],{"x":104,"y":95,"style":96},"286.9","B",[52,107],{"x":108,"y":85,"width":109,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"316.9","69.6",[72,111,113],{"x":112,"y":95,"style":96},"351.7","C",[52,115],{"x":116,"y":85,"width":117,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"386.5","69.5",[72,119,121],{"x":120,"y":95,"style":96},"421.3","D",[52,123],{"x":124,"y":85,"width":85,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"456.0",[72,126,128],{"x":127,"y":95,"style":96},"478.0","E",[52,130],{"x":131,"y":85,"width":132,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"500.0","115.8",[72,134,136],{"x":135,"y":95,"style":96},"557.9","F",[52,138],{"x":61,"y":139,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"68.0",[72,141,144],{"x":142,"y":143,"style":96},"160.2","87.0","1",[52,146],{"x":90,"y":139,"width":91,"height":64,"rx":55,"fill":147,"stroke":148,"style":149},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[72,151,154],{"x":152,"y":143,"style":153},"209.6","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Region",[52,156],{"x":157,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"238.9","76.0","12.0","2",[162,163],"polygon",{"points":164,"fill":165},"241.4,80.5 248.4,80.5 244.9,84.5","#5b6780",[52,167],{"x":100,"y":139,"width":101,"height":64,"rx":55,"fill":147,"stroke":148,"style":149},[72,169,171],{"x":170,"y":143,"style":153},"279.9","Qty",[52,173],{"x":174,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"298.9",[162,176],{"points":177,"fill":165},"301.4,80.5 308.4,80.5 304.9,84.5",[52,179],{"x":108,"y":139,"width":109,"height":64,"rx":55,"fill":147,"stroke":148,"style":149},[72,181,183],{"x":182,"y":143,"style":153},"344.7","Price",[52,185],{"x":186,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"368.5",[162,188],{"points":189,"fill":165},"371.0,80.5 378.0,80.5 374.5,84.5",[52,191],{"x":116,"y":139,"width":117,"height":64,"rx":55,"fill":147,"stroke":148,"style":149},[72,193,195],{"x":194,"y":143,"style":153},"414.3","Total",[52,197],{"x":198,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"438.0",[162,200],{"points":201,"fill":165},"440.5,80.5 447.5,80.5 444.0,84.5",[52,203],{"x":124,"y":139,"width":85,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[52,205],{"x":206,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"482.0",[162,208],{"points":209,"fill":165},"484.5,80.5 491.5,80.5 488.0,84.5",[52,211],{"x":131,"y":139,"width":132,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,213,216],{"x":214,"y":143,"style":215},"550.9","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Sum of Total",[52,218],{"x":219,"y":158,"width":159,"height":159,"rx":160,"fill":70,"stroke":65,"style":66},"597.8",[162,221],{"points":222,"fill":165},"600.3,80.5 607.3,80.5 603.8,84.5",[52,224],{"x":61,"y":225,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"96.0",[72,227,160],{"x":142,"y":228,"style":96},"115.0",[52,230],{"x":90,"y":225,"width":91,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,232,234],{"x":94,"y":228,"style":233},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","North",[52,236],{"x":100,"y":225,"width":101,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,238,160],{"x":104,"y":228,"style":233},[52,240],{"x":108,"y":225,"width":109,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,242,243],{"x":112,"y":228,"style":233},"10",[52,245],{"x":116,"y":225,"width":117,"height":64,"rx":55,"fill":246,"stroke":247,"style":149},"#d9f4f1","var(--teal,#0f9488)",[72,249,251],{"x":120,"y":228,"style":250},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","20",[52,253],{"x":124,"y":225,"width":85,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[52,255],{"x":131,"y":225,"width":132,"height":64,"rx":55,"fill":256,"stroke":257,"style":149},"#fdefd8","var(--gold,#b4740a)",[72,259,261],{"x":135,"y":228,"style":260},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","85",[52,263],{"x":61,"y":264,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"124.0",[72,266,268],{"x":142,"y":267,"style":96},"143.0","3",[52,270],{"x":90,"y":264,"width":91,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,272,273],{"x":94,"y":267,"style":233},"South",[52,275],{"x":100,"y":264,"width":101,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,277,268],{"x":104,"y":267,"style":233},[52,279],{"x":108,"y":264,"width":109,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,281,251],{"x":112,"y":267,"style":233},[52,283],{"x":116,"y":264,"width":117,"height":64,"rx":55,"fill":246,"stroke":247,"style":149},[72,285,286],{"x":120,"y":267,"style":250},"60",[52,288],{"x":124,"y":264,"width":85,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[52,290],{"x":131,"y":264,"width":132,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[52,292],{"x":61,"y":293,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"152.0",[72,295,297],{"x":142,"y":296,"style":96},"171.0","4",[52,299],{"x":90,"y":293,"width":91,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,301,302],{"x":94,"y":296,"style":233},"East",[52,304],{"x":100,"y":293,"width":101,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,306,144],{"x":104,"y":296,"style":233},[52,308],{"x":108,"y":293,"width":109,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,310,311],{"x":112,"y":296,"style":233},"5",[52,313],{"x":116,"y":293,"width":117,"height":64,"rx":55,"fill":246,"stroke":247,"style":149},[72,315,311],{"x":120,"y":296,"style":250},[52,317],{"x":124,"y":293,"width":85,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[52,319],{"x":131,"y":293,"width":132,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,321,325],{"x":322,"y":323,"style":324},"380.0","202.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","Total is a calculated column; F2 holds =SUM(Sales[Total]) and follows the table as it grows",[327,328,330],"h2",{"id":329},"prerequisites","Prerequisites",[332,333,338],"pre",{"className":334,"code":335,"language":336,"meta":337,"style":337},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl xlsxwriter\n","bash","",[14,339,340],{"__ignoreMap":337},[341,342,345,349,353,356],"span",{"class":343,"line":344},"line",1,[341,346,348],{"class":347},"sMTad","pip",[341,350,352],{"class":351},"srMev"," install",[341,354,355],{"class":351}," openpyxl",[341,357,358],{"class":351}," xlsxwriter\n",[10,360,361],{},"LibreOffice is used at the end to recalculate and check the openpyxl output; it is optional.",[327,363,365],{"id":364},"step-1-create-the-table-with-openpyxl","Step 1 — Create the table with openpyxl",[10,367,368,369,372,373,376],{},"A structured reference needs a real Excel table (a ListObject), not just a range that looks like one. With openpyxl, write the data including the header, then add a ",[14,370,371],{},"Table"," whose ",[14,374,375],{},"ref"," covers the header and every data row:",[332,378,382],{"className":379,"code":380,"language":381,"meta":337,"style":337},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook, load_workbook\nfrom openpyxl.worksheet.table import Table, TableStyleInfo\n\nwb = Workbook()\nws = wb.active\nws.title = \"Data\"\nws.append([\"Region\", \"Qty\", \"Price\", \"Total\"])\nfor row in [[\"North\", 2, 10], [\"South\", 3, 20], [\"East\", 1, 5]]:\n    ws.append(row)\n\nsales = Table(displayName=\"Sales\", ref=\"A1:D4\")\nsales.tableStyleInfo = TableStyleInfo(name=\"TableStyleMedium2\", showRowStripes=True)\nws.add_table(sales)\n","python",[14,383,384,400,413,420,432,443,454,482,539,545,550,582,613],{"__ignoreMap":337},[341,385,386,390,394,397],{"class":343,"line":344},[341,387,389],{"class":388},"s-kum","from",[341,391,393],{"class":392},"skGVy"," openpyxl ",[341,395,396],{"class":388},"import",[341,398,399],{"class":392}," Workbook, load_workbook\n",[341,401,403,405,408,410],{"class":343,"line":402},2,[341,404,389],{"class":388},[341,406,407],{"class":392}," openpyxl.worksheet.table ",[341,409,396],{"class":388},[341,411,412],{"class":392}," Table, TableStyleInfo\n",[341,414,416],{"class":343,"line":415},3,[341,417,419],{"emptyLinePlaceholder":418},true,"\n",[341,421,423,426,429],{"class":343,"line":422},4,[341,424,425],{"class":392},"wb ",[341,427,428],{"class":388},"=",[341,430,431],{"class":392}," Workbook()\n",[341,433,435,438,440],{"class":343,"line":434},5,[341,436,437],{"class":392},"ws ",[341,439,428],{"class":388},[341,441,442],{"class":392}," wb.active\n",[341,444,446,449,451],{"class":343,"line":445},6,[341,447,448],{"class":392},"ws.title ",[341,450,428],{"class":388},[341,452,453],{"class":351}," \"Data\"\n",[341,455,457,460,463,466,469,471,474,476,479],{"class":343,"line":456},7,[341,458,459],{"class":392},"ws.append([",[341,461,462],{"class":351},"\"Region\"",[341,464,465],{"class":392},", ",[341,467,468],{"class":351},"\"Qty\"",[341,470,465],{"class":392},[341,472,473],{"class":351},"\"Price\"",[341,475,465],{"class":392},[341,477,478],{"class":351},"\"Total\"",[341,480,481],{"class":392},"])\n",[341,483,485,488,491,494,497,500,502,505,507,509,512,515,517,519,521,523,525,528,530,532,534,536],{"class":343,"line":484},8,[341,486,487],{"class":388},"for",[341,489,490],{"class":392}," row ",[341,492,493],{"class":388},"in",[341,495,496],{"class":392}," [[",[341,498,499],{"class":351},"\"North\"",[341,501,465],{"class":392},[341,503,160],{"class":504},"sP0c6",[341,506,465],{"class":392},[341,508,243],{"class":504},[341,510,511],{"class":392},"], [",[341,513,514],{"class":351},"\"South\"",[341,516,465],{"class":392},[341,518,268],{"class":504},[341,520,465],{"class":392},[341,522,251],{"class":504},[341,524,511],{"class":392},[341,526,527],{"class":351},"\"East\"",[341,529,465],{"class":392},[341,531,144],{"class":504},[341,533,465],{"class":392},[341,535,311],{"class":504},[341,537,538],{"class":392},"]]:\n",[341,540,542],{"class":343,"line":541},9,[341,543,544],{"class":392},"    ws.append(row)\n",[341,546,548],{"class":343,"line":547},10,[341,549,419],{"emptyLinePlaceholder":418},[341,551,553,556,558,561,565,567,570,572,574,576,579],{"class":343,"line":552},11,[341,554,555],{"class":392},"sales ",[341,557,428],{"class":388},[341,559,560],{"class":392}," Table(",[341,562,564],{"class":563},"sa561","displayName",[341,566,428],{"class":388},[341,568,569],{"class":351},"\"Sales\"",[341,571,465],{"class":392},[341,573,375],{"class":563},[341,575,428],{"class":388},[341,577,578],{"class":351},"\"A1:D4\"",[341,580,581],{"class":392},")\n",[341,583,585,588,590,593,596,598,601,603,606,608,611],{"class":343,"line":584},12,[341,586,587],{"class":392},"sales.tableStyleInfo ",[341,589,428],{"class":388},[341,591,592],{"class":392}," TableStyleInfo(",[341,594,595],{"class":563},"name",[341,597,428],{"class":388},[341,599,600],{"class":351},"\"TableStyleMedium2\"",[341,602,465],{"class":392},[341,604,605],{"class":563},"showRowStripes",[341,607,428],{"class":388},[341,609,610],{"class":504},"True",[341,612,581],{"class":392},[341,614,616],{"class":343,"line":615},13,[341,617,618],{"class":392},"ws.add_table(sales)\n",[10,620,621,622,626],{},"The table name must be unique in the workbook, start with a letter or underscore, and contain no spaces. More on table options in ",[27,623,625],{"href":624},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fcreate-an-excel-table-with-python\u002F","Create an Excel Table with Python",".",[327,628,630],{"id":629},"step-2-write-the-calculated-column-in-the-stored-form","Step 2 — Write the calculated column in the stored form",[10,632,633,634,637,638,641,642,646,647,650],{},"In Excel you would type ",[14,635,636],{},"=[@Qty]*[@Price]"," into the Total column. That ",[14,639,640],{},"@"," form is what Excel ",[643,644,645],"em",{},"shows","; inside the file the same formula is stored as ",[14,648,649],{},"Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]",". openpyxl writes formula text exactly as given, so give it the stored form:",[332,652,654],{"className":379,"code":653,"language":381,"meta":337,"style":337},"for row in range(2, 5):\n    ws[f\"D{row}\"] = \"=Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]\"\n",[14,655,656,679],{"__ignoreMap":337},[341,657,658,660,662,664,667,670,672,674,676],{"class":343,"line":344},[341,659,487],{"class":388},[341,661,490],{"class":392},[341,663,493],{"class":388},[341,665,666],{"class":504}," range",[341,668,669],{"class":392},"(",[341,671,160],{"class":504},[341,673,465],{"class":392},[341,675,311],{"class":504},[341,677,678],{"class":392},"):\n",[341,680,681,684,687,690,694,697,700,703,706,708],{"class":343,"line":402},[341,682,683],{"class":392},"    ws[",[341,685,686],{"class":388},"f",[341,688,689],{"class":351},"\"D",[341,691,693],{"class":692},"sSjpA","{",[341,695,696],{"class":392},"row",[341,698,699],{"class":692},"}",[341,701,702],{"class":351},"\"",[341,704,705],{"class":392},"] ",[341,707,428],{"class":388},[341,709,710],{"class":351}," \"=Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]\"\n",[10,712,713,714,716,717,720],{},"Write ",[14,715,636],{}," instead and the file opens with ",[14,718,719],{},"#NAME?"," in every Total cell — Excel does not parse the display shorthand when loading a file. Rather than remembering the long form, convert with a small helper:",[332,722,724],{"className":379,"code":723,"language":381,"meta":337,"style":337},"import re\n\ndef expand_this_row(formula: str, table: str) -> str:\n    def repl(m):\n        column = m.group(1).strip(\"[]\")\n        return f\"{table}[[#This Row],[{column}]]\"\n    return re.sub(r\"\\[@(\\[[^\\]]+\\]|[^\\]\\s,)*+\u002F-]+)\\]?\", repl, formula)\n\nprint(expand_this_row(\"=[@Qty]*[@Price]\", \"Sales\"))\n# =Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]\nprint(expand_this_row(\"=[@[Unit Price]]*2\", \"Sales\"))\n# =Sales[[#This Row],[Unit Price]]*2\n",[14,725,726,733,737,765,776,796,826,898,902,920,926,941],{"__ignoreMap":337},[341,727,728,730],{"class":343,"line":344},[341,729,396],{"class":388},[341,731,732],{"class":392}," re\n",[341,734,735],{"class":343,"line":402},[341,736,419],{"emptyLinePlaceholder":418},[341,738,739,742,746,749,752,755,757,760,762],{"class":343,"line":415},[341,740,741],{"class":388},"def",[341,743,745],{"class":744},"s_Opv"," expand_this_row",[341,747,748],{"class":392},"(formula: ",[341,750,751],{"class":504},"str",[341,753,754],{"class":392},", table: ",[341,756,751],{"class":504},[341,758,759],{"class":392},") -> ",[341,761,751],{"class":504},[341,763,764],{"class":392},":\n",[341,766,767,770,773],{"class":343,"line":422},[341,768,769],{"class":388},"    def",[341,771,772],{"class":744}," repl",[341,774,775],{"class":392},"(m):\n",[341,777,778,781,783,786,788,791,794],{"class":343,"line":434},[341,779,780],{"class":392},"        column ",[341,782,428],{"class":388},[341,784,785],{"class":392}," m.group(",[341,787,144],{"class":504},[341,789,790],{"class":392},").strip(",[341,792,793],{"class":351},"\"[]\"",[341,795,581],{"class":392},[341,797,798,801,804,806,808,811,813,816,818,821,823],{"class":343,"line":445},[341,799,800],{"class":388},"        return",[341,802,803],{"class":388}," f",[341,805,702],{"class":351},[341,807,693],{"class":692},[341,809,810],{"class":392},"table",[341,812,699],{"class":692},[341,814,815],{"class":351},"[[#This Row],[",[341,817,693],{"class":692},[341,819,820],{"class":392},"column",[341,822,699],{"class":692},[341,824,825],{"class":351},"]]\"\n",[341,827,828,831,834,837,839,843,845,847,849,852,855,858,861,864,866,869,871,873,875,878,881,883,885,888,890,893,895],{"class":343,"line":456},[341,829,830],{"class":388},"    return",[341,832,833],{"class":392}," re.sub(",[341,835,836],{"class":388},"r",[341,838,702],{"class":351},[341,840,842],{"class":841},"s_b0D","\\[",[341,844,640],{"class":351},[341,846,669],{"class":504},[341,848,842],{"class":841},[341,850,851],{"class":504},"[",[341,853,854],{"class":388},"^",[341,856,857],{"class":841},"\\]",[341,859,860],{"class":504},"]",[341,862,863],{"class":388},"+",[341,865,857],{"class":841},[341,867,868],{"class":388},"|",[341,870,851],{"class":504},[341,872,854],{"class":388},[341,874,857],{"class":841},[341,876,877],{"class":504},"\\s",[341,879,880],{"class":692},",)*+\u002F-",[341,882,860],{"class":504},[341,884,863],{"class":388},[341,886,887],{"class":504},")",[341,889,857],{"class":841},[341,891,892],{"class":388},"?",[341,894,702],{"class":351},[341,896,897],{"class":392},", repl, formula)\n",[341,899,900],{"class":343,"line":484},[341,901,419],{"emptyLinePlaceholder":418},[341,903,904,907,910,913,915,917],{"class":343,"line":541},[341,905,906],{"class":504},"print",[341,908,909],{"class":392},"(expand_this_row(",[341,911,912],{"class":351},"\"=[@Qty]*[@Price]\"",[341,914,465],{"class":392},[341,916,569],{"class":351},[341,918,919],{"class":392},"))\n",[341,921,922],{"class":343,"line":547},[341,923,925],{"class":924},"s-wDw","# =Sales[[#This Row],[Qty]]*Sales[[#This Row],[Price]]\n",[341,927,928,930,932,935,937,939],{"class":343,"line":552},[341,929,906],{"class":504},[341,931,909],{"class":392},[341,933,934],{"class":351},"\"=[@[Unit Price]]*2\"",[341,936,465],{"class":392},[341,938,569],{"class":351},[341,940,919],{"class":392},[341,942,943],{"class":343,"line":584},[341,944,945],{"class":924},"# =Sales[[#This Row],[Unit Price]]*2\n",[10,947,948,949,952],{},"The second example shows the bracketed form Excel uses for column names with spaces, ",[14,950,951],{},"[@[Unit Price]]",", which the helper also expands.",[33,954,42,960,42,963,42,966,42,970,42,973,42,977,42,981,42,984,42,988,42,990,42,993,42,996,42,999,42,1003,42,1006,42,1009,42,1012,42,1014,42,1017,42,1020,42,1024,42,1027,42,1029,42,1032,42,1034,42,1036,42,1038,42,1040,42,1042,42,1044,42,1046,42,1048,42,1050,42,1053,42,1059,42,1063,42,1069,42,1073,42,1080],{"viewBox":955,"role":36,"ariaLabelledBy":956,"xmlns":40,"style":959},"4 0 760 164",[957,958],"sr-forms-t","sr-forms-d","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[44,961,962],{"id":957},"The display form of a this-row reference and the form stored in the file",[48,964,965],{"id":958},"On the left, formulas as typed in Excel use the at-sign shorthand, such as [@Qty] times [@Price]. On the right, the same formulas as stored in the xlsx file, using the table name and the",[52,967],{"x":297,"y":55,"width":968,"height":969,"fill":58},"760","164",[52,971],{"x":972,"y":69,"width":86,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"20.0",[52,974],{"x":975,"y":69,"width":976,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"52.0","121.4",[72,978,97],{"x":979,"y":980,"style":96},"112.7","57.0",[52,982],{"x":972,"y":983,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"64.0",[72,985,144],{"x":986,"y":987,"style":96},"36.0","83.0",[52,989],{"x":975,"y":983,"width":976,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,991,992],{"x":979,"y":987,"style":215},"formula",[52,994],{"x":972,"y":995,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"92.0",[72,997,160],{"x":986,"y":998,"style":96},"111.0",[52,1000],{"x":975,"y":995,"width":976,"height":64,"rx":55,"fill":1001,"stroke":1002,"style":149},"#fee8f2","var(--accent,#f43f8f)",[72,1004,636],{"x":979,"y":998,"style":1005},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle",[52,1007],{"x":972,"y":1008,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},"120.0",[72,1010,268],{"x":986,"y":1011,"style":96},"139.0",[52,1013],{"x":975,"y":1008,"width":976,"height":64,"rx":55,"fill":1001,"stroke":1002,"style":149},[72,1015,1016],{"x":979,"y":1011,"style":1005},"=[@[Unit Price]]*2",[52,1018],{"x":1019,"y":69,"width":86,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"392.9",[52,1021],{"x":1022,"y":69,"width":1023,"height":87,"rx":55,"fill":70,"stroke":65,"style":66},"424.9","315.1",[72,1025,97],{"x":1026,"y":980,"style":96},"582.5",[52,1028],{"x":1019,"y":983,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},[72,1030,144],{"x":1031,"y":987,"style":96},"408.9",[52,1033],{"x":1022,"y":983,"width":1023,"height":64,"rx":55,"fill":58,"stroke":65,"style":66},[72,1035,992],{"x":1026,"y":987,"style":215},[52,1037],{"x":1019,"y":995,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},[72,1039,160],{"x":1031,"y":998,"style":96},[52,1041],{"x":1022,"y":995,"width":1023,"height":64,"rx":55,"fill":246,"stroke":247,"style":149},[72,1043,82],{"x":1026,"y":998,"style":250},[52,1045],{"x":1019,"y":1008,"width":86,"height":64,"rx":55,"fill":70,"stroke":65,"style":66},[72,1047,268],{"x":1031,"y":1011,"style":96},[52,1049],{"x":1022,"y":1008,"width":1023,"height":64,"rx":55,"fill":246,"stroke":247,"style":149},[72,1051,1052],{"x":1026,"y":1011,"style":250},"=Sales[[#This Row],[Unit Price]]*2",[72,1054,1058],{"x":1055,"y":1056,"style":1057},"96.7","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","typed in Excel",[72,1060,1062],{"x":1061,"y":1056,"style":1057},"566.5","stored in the file",[343,1064],{"x1":1065,"y1":1066,"x2":1067,"y2":1066,"stroke":148,"style":1068},"183.4","94.0","378.9","stroke-width:2px",[162,1070],{"points":1071,"fill":1072},"382.9,94.0 373.9,99.0 373.9,89.0","#5b5cf0",[52,1074],{"x":1075,"y":95,"width":1076,"height":1077,"rx":1078,"fill":58,"stroke":65,"style":1079},"211.4","143.6","22.0","11","stroke-width:1.2px",[72,1081,1084],{"x":1082,"y":158,"style":1083},"283.2","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","expand_this_row()",[327,1086,1088],{"id":1087},"step-3-summary-formulas-over-table-columns","Step 3 — Summary formulas over table columns",[10,1090,1091],{},"References to a whole column need no special handling. They work in any cell, inside or outside the table, and in any function that takes a range:",[332,1093,1095],{"className":379,"code":1094,"language":381,"meta":337,"style":337},"ws[\"F1\"] = \"Sum of Total\"\nws[\"F2\"] = \"=SUM(Sales[Total])\"\nws[\"G1\"] = \"North total\"\nws[\"G2\"] = '=SUMIFS(Sales[Total],Sales[Region],\"North\")'\nws[\"H1\"] = \"Rows\"\nws[\"H2\"] = \"=ROWS(Sales[#Data])\"\nws[\"I1\"] = \"Header of col 2\"\nws[\"I2\"] = \"=INDEX(Sales[#Headers],2)\"\nwb.save(\"structured.xlsx\")\nprint(load_workbook(\"structured.xlsx\")[\"Data\"][\"G2\"].value)\n",[14,1096,1097,1112,1126,1140,1154,1168,1182,1196,1210,1220],{"__ignoreMap":337},[341,1098,1099,1102,1105,1107,1109],{"class":343,"line":344},[341,1100,1101],{"class":392},"ws[",[341,1103,1104],{"class":351},"\"F1\"",[341,1106,705],{"class":392},[341,1108,428],{"class":388},[341,1110,1111],{"class":351}," \"Sum of Total\"\n",[341,1113,1114,1116,1119,1121,1123],{"class":343,"line":402},[341,1115,1101],{"class":392},[341,1117,1118],{"class":351},"\"F2\"",[341,1120,705],{"class":392},[341,1122,428],{"class":388},[341,1124,1125],{"class":351}," \"=SUM(Sales[Total])\"\n",[341,1127,1128,1130,1133,1135,1137],{"class":343,"line":415},[341,1129,1101],{"class":392},[341,1131,1132],{"class":351},"\"G1\"",[341,1134,705],{"class":392},[341,1136,428],{"class":388},[341,1138,1139],{"class":351}," \"North total\"\n",[341,1141,1142,1144,1147,1149,1151],{"class":343,"line":422},[341,1143,1101],{"class":392},[341,1145,1146],{"class":351},"\"G2\"",[341,1148,705],{"class":392},[341,1150,428],{"class":388},[341,1152,1153],{"class":351}," '=SUMIFS(Sales[Total],Sales[Region],\"North\")'\n",[341,1155,1156,1158,1161,1163,1165],{"class":343,"line":434},[341,1157,1101],{"class":392},[341,1159,1160],{"class":351},"\"H1\"",[341,1162,705],{"class":392},[341,1164,428],{"class":388},[341,1166,1167],{"class":351}," \"Rows\"\n",[341,1169,1170,1172,1175,1177,1179],{"class":343,"line":445},[341,1171,1101],{"class":392},[341,1173,1174],{"class":351},"\"H2\"",[341,1176,705],{"class":392},[341,1178,428],{"class":388},[341,1180,1181],{"class":351}," \"=ROWS(Sales[#Data])\"\n",[341,1183,1184,1186,1189,1191,1193],{"class":343,"line":456},[341,1185,1101],{"class":392},[341,1187,1188],{"class":351},"\"I1\"",[341,1190,705],{"class":392},[341,1192,428],{"class":388},[341,1194,1195],{"class":351}," \"Header of col 2\"\n",[341,1197,1198,1200,1203,1205,1207],{"class":343,"line":484},[341,1199,1101],{"class":392},[341,1201,1202],{"class":351},"\"I2\"",[341,1204,705],{"class":392},[341,1206,428],{"class":388},[341,1208,1209],{"class":351}," \"=INDEX(Sales[#Headers],2)\"\n",[341,1211,1212,1215,1218],{"class":343,"line":541},[341,1213,1214],{"class":392},"wb.save(",[341,1216,1217],{"class":351},"\"structured.xlsx\"",[341,1219,581],{"class":392},[341,1221,1222,1224,1227,1229,1232,1235,1238,1240],{"class":343,"line":547},[341,1223,906],{"class":504},[341,1225,1226],{"class":392},"(load_workbook(",[341,1228,1217],{"class":351},[341,1230,1231],{"class":392},")[",[341,1233,1234],{"class":351},"\"Data\"",[341,1236,1237],{"class":392},"][",[341,1239,1146],{"class":351},[341,1241,1242],{"class":392},"].value)\n",[10,1244,1245,1246,1249,1250,1253,1254,1257,1258,1261,1262,1265],{},"The special items select parts of the table: ",[14,1247,1248],{},"[#Data]"," the data rows, ",[14,1251,1252],{},"[#Headers]"," the header row, ",[14,1255,1256],{},"[#Totals]"," the total row if there is one, and ",[14,1259,1260],{},"[#All]"," everything. They combine with columns — ",[14,1263,1264],{},"Sales[[#Headers],[Qty]]"," is the Qty header cell.",[33,1267,42,1273,42,1276,42,1279,42,1283,42,1286,42,1290,42,1296,42,1299,42,1303,42,1307,42,1312,42,1314,42,1319,42,1321,42,1331,42,1334,42,1338,42,1340,42,1343,42,1345,42,1350,42,1352,42,1356,42,1358,42,1362,42,1364,42,1369,42,1372,42,1376,42,1378,42,1382,42,1384,42,1389,42,1392,42,1396,42,1398,42,1402,42,1404,42,1409,42,1412,42,1416,42,1418,42,1422,42,1424],{"viewBox":1268,"role":36,"ariaLabelledBy":1269,"xmlns":40,"style":1272},"4 0 752 276",[1270,1271],"sr-items-t","sr-items-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[44,1274,1275],{"id":1270},"What each structured reference selects in the Sales table",[48,1277,1278],{"id":1271},"Sales[Total] and Sales[[#Data],[Total]] select the data cells of the Total column. Sales[#Headers] selects the header row. Sales[#Totals] selects the total row. Sales[#All] selects the header, data and total rows together. Sales[[#This Row],[Qty]] selects the Qty cell in the formula's own row and is only valid inside the table's rows.",[52,1280],{"x":297,"y":55,"width":1281,"height":1282,"fill":58},"752","276",[52,1284],{"x":972,"y":62,"width":1285,"height":69,"rx":55,"fill":58,"stroke":65,"style":66},"187.2",[52,1287],{"x":1288,"y":62,"width":1289,"height":69,"rx":55,"fill":147,"stroke":148,"style":1079},"207.2","266.4",[72,1291,1295],{"x":1292,"y":1293,"style":1294},"340.4","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Selects",[52,1297],{"x":1298,"y":62,"width":1289,"height":69,"rx":55,"fill":147,"stroke":148,"style":1079},"473.6",[72,1300,1302],{"x":1301,"y":1293,"style":1294},"606.8","Valid outside the table",[52,1304],{"x":972,"y":1305,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},"56.0","34.0",[72,1308,1311],{"x":86,"y":1309,"style":1310},"78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","Sales[Total]",[52,1313],{"x":1288,"y":1305,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1315,1318],{"x":1292,"y":1316,"style":1317},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","data cells of one column",[52,1320],{"x":1298,"y":1305,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[1322,1323,1325],"g",{"transform":1324},"translate(597.8,64.0) scale(0.750)",[1326,1327],"path",{"d":1328,"fill":1329,"stroke":247,"style":1330},"M5 12.5l4.5 4.5L19 7","none","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[52,1332],{"x":972,"y":1333,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},"90.0",[72,1335,1337],{"x":86,"y":1336,"style":1310},"112.0","Sales[#Data]",[52,1339],{"x":1288,"y":1333,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1341,1342],{"x":1292,"y":998,"style":1317},"all data rows",[52,1344],{"x":1298,"y":1333,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[1322,1346,1348],{"transform":1347},"translate(597.8,98.0) scale(0.750)",[1326,1349],{"d":1328,"fill":1329,"stroke":247,"style":1330},[52,1351],{"x":972,"y":264,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},[72,1353,1355],{"x":86,"y":1354,"style":1310},"146.0","Sales[#Headers]",[52,1357],{"x":1288,"y":264,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1359,1361],{"x":1292,"y":1360,"style":1317},"145.0","the header row",[52,1363],{"x":1298,"y":264,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[1322,1365,1367],{"transform":1366},"translate(597.8,132.0) scale(0.750)",[1326,1368],{"d":1328,"fill":1329,"stroke":247,"style":1330},[52,1370],{"x":972,"y":1371,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},"158.0",[72,1373,1375],{"x":86,"y":1374,"style":1310},"180.0","Sales[#Totals]",[52,1377],{"x":1288,"y":1371,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1379,1381],{"x":1292,"y":1380,"style":1317},"179.0","the total row",[52,1383],{"x":1298,"y":1371,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[1322,1385,1387],{"transform":1386},"translate(597.8,166.0) scale(0.750)",[1326,1388],{"d":1328,"fill":1329,"stroke":247,"style":1330},[52,1390],{"x":972,"y":1391,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},"192.0",[72,1393,1395],{"x":86,"y":1394,"style":1310},"214.0","Sales[#All]",[52,1397],{"x":1288,"y":1391,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1399,1401],{"x":1292,"y":1400,"style":1317},"213.0","headers, data and totals",[52,1403],{"x":1298,"y":1391,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[1322,1405,1407],{"transform":1406},"translate(597.8,200.0) scale(0.750)",[1326,1408],{"d":1328,"fill":1329,"stroke":247,"style":1330},[52,1410],{"x":972,"y":1411,"width":1285,"height":1306,"rx":55,"fill":70,"stroke":65,"style":66},"226.0",[72,1413,1415],{"x":86,"y":1414,"style":1310},"248.0","Sales[[#This Row],[Qty]]",[52,1417],{"x":1288,"y":1411,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1419,1421],{"x":1292,"y":1420,"style":1317},"247.0","Qty in the same row",[52,1423],{"x":1298,"y":1411,"width":1289,"height":1306,"rx":55,"fill":58,"stroke":65,"style":66},[72,1425,1426],{"x":1301,"y":1420,"style":1317},"no — rows of the table only",[10,1428,1429,1430,1433,1434,1436,1437,1439,1440,626],{},"The this-row form is the only one tied to a position: it means \"the cell in this column on the formula's own row\", so it only makes sense in a cell whose row belongs to the table. Written in a cell outside the table's rows it returns ",[14,1431,1432],{},"#VALUE!",". Everything else in the table above can be used anywhere in the workbook, on any sheet, which is what makes structured references useful for summary sheets: ",[14,1435,16],{}," on a dashboard tab keeps working when the data sheet is moved, renamed or extended. Referencing a table on another sheet needs no sheet prefix at all — the table name is unique in the workbook, so ",[14,1438,1311],{}," is enough. Totals rows are the subject of ",[27,1441,1443],{"href":1442},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fadd-a-total-row-to-an-excel-table\u002F","Add a Total Row to an Excel Table with Python",[327,1445,1447],{"id":1446},"step-4-check-the-results-by-recalculating","Step 4 — Check the results by recalculating",[10,1449,1450],{},"openpyxl does not calculate anything, so check the formulas by recalculating a copy with LibreOffice and reading the cached values:",[332,1452,1454],{"className":379,"code":1453,"language":381,"meta":337,"style":337},"import subprocess\nfrom pathlib import Path\n\nPath(\"checked\").mkdir(exist_ok=True)\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"checked\", \"structured.xlsx\"],\n               check=True, capture_output=True, timeout=120)\nv = load_workbook(\"checked\u002Fstructured.xlsx\", data_only=True)[\"Data\"]\nprint([v[f\"D{r}\"].value for r in range(2, 5)])            # [20, 60, 5]\nprint(v[\"F2\"].value, v[\"G2\"].value, v[\"H2\"].value, v[\"I2\"].value)   # 85 20 3 Qty\n",[14,1455,1456,1463,1475,1479,1499,1538,1568,1597,1642],{"__ignoreMap":337},[341,1457,1458,1460],{"class":343,"line":344},[341,1459,396],{"class":388},[341,1461,1462],{"class":392}," subprocess\n",[341,1464,1465,1467,1470,1472],{"class":343,"line":402},[341,1466,389],{"class":388},[341,1468,1469],{"class":392}," pathlib ",[341,1471,396],{"class":388},[341,1473,1474],{"class":392}," Path\n",[341,1476,1477],{"class":343,"line":415},[341,1478,419],{"emptyLinePlaceholder":418},[341,1480,1481,1484,1487,1490,1493,1495,1497],{"class":343,"line":422},[341,1482,1483],{"class":392},"Path(",[341,1485,1486],{"class":351},"\"checked\"",[341,1488,1489],{"class":392},").mkdir(",[341,1491,1492],{"class":563},"exist_ok",[341,1494,428],{"class":388},[341,1496,610],{"class":504},[341,1498,581],{"class":392},[341,1500,1501,1504,1507,1509,1512,1514,1517,1519,1522,1524,1527,1529,1531,1533,1535],{"class":343,"line":434},[341,1502,1503],{"class":392},"subprocess.run([",[341,1505,1506],{"class":351},"\"soffice\"",[341,1508,465],{"class":392},[341,1510,1511],{"class":351},"\"--headless\"",[341,1513,465],{"class":392},[341,1515,1516],{"class":351},"\"--convert-to\"",[341,1518,465],{"class":392},[341,1520,1521],{"class":351},"\"xlsx\"",[341,1523,465],{"class":392},[341,1525,1526],{"class":351},"\"--outdir\"",[341,1528,465],{"class":392},[341,1530,1486],{"class":351},[341,1532,465],{"class":392},[341,1534,1217],{"class":351},[341,1536,1537],{"class":392},"],\n",[341,1539,1540,1543,1545,1547,1549,1552,1554,1556,1558,1561,1563,1566],{"class":343,"line":445},[341,1541,1542],{"class":563},"               check",[341,1544,428],{"class":388},[341,1546,610],{"class":504},[341,1548,465],{"class":392},[341,1550,1551],{"class":563},"capture_output",[341,1553,428],{"class":388},[341,1555,610],{"class":504},[341,1557,465],{"class":392},[341,1559,1560],{"class":563},"timeout",[341,1562,428],{"class":388},[341,1564,1565],{"class":504},"120",[341,1567,581],{"class":392},[341,1569,1570,1573,1575,1578,1581,1583,1586,1588,1590,1592,1594],{"class":343,"line":456},[341,1571,1572],{"class":392},"v ",[341,1574,428],{"class":388},[341,1576,1577],{"class":392}," load_workbook(",[341,1579,1580],{"class":351},"\"checked\u002Fstructured.xlsx\"",[341,1582,465],{"class":392},[341,1584,1585],{"class":563},"data_only",[341,1587,428],{"class":388},[341,1589,610],{"class":504},[341,1591,1231],{"class":392},[341,1593,1234],{"class":351},[341,1595,1596],{"class":392},"]\n",[341,1598,1599,1601,1604,1606,1608,1610,1612,1614,1616,1619,1621,1624,1626,1628,1630,1632,1634,1636,1639],{"class":343,"line":484},[341,1600,906],{"class":504},[341,1602,1603],{"class":392},"([v[",[341,1605,686],{"class":388},[341,1607,689],{"class":351},[341,1609,693],{"class":692},[341,1611,836],{"class":392},[341,1613,699],{"class":692},[341,1615,702],{"class":351},[341,1617,1618],{"class":392},"].value ",[341,1620,487],{"class":388},[341,1622,1623],{"class":392}," r ",[341,1625,493],{"class":388},[341,1627,666],{"class":504},[341,1629,669],{"class":392},[341,1631,160],{"class":504},[341,1633,465],{"class":392},[341,1635,311],{"class":504},[341,1637,1638],{"class":392},")])            ",[341,1640,1641],{"class":924},"# [20, 60, 5]\n",[341,1643,1644,1646,1649,1651,1654,1656,1658,1660,1662,1664,1667],{"class":343,"line":541},[341,1645,906],{"class":504},[341,1647,1648],{"class":392},"(v[",[341,1650,1118],{"class":351},[341,1652,1653],{"class":392},"].value, v[",[341,1655,1146],{"class":351},[341,1657,1653],{"class":392},[341,1659,1174],{"class":351},[341,1661,1653],{"class":392},[341,1663,1202],{"class":351},[341,1665,1666],{"class":392},"].value)   ",[341,1668,1669],{"class":924},"# 85 20 3 Qty\n",[10,1671,1672,1673,1676,1677,1679,1680,1683],{},"The calculated column gives 20, 60 and 5, the column sum 85, the conditional sum 20 and the row count 3. Had the Total column been written with ",[14,1674,1675],{},"[@Qty]",", the same check would have shown ",[14,1678,719],{}," — a cheap test worth adding to any job that writes table formulas with openpyxl. In a test suite, assert that no recalculated cell in the table holds a string starting with ",[14,1681,1682],{},"#"," — that single check catches misspelled table or column names as well as the shorthand problem, because every one of those failures surfaces as an Excel error value after recalculation.",[327,1685,1687],{"id":1686},"step-5-let-xlsxwriter-do-the-conversion","Step 5 — Let xlsxwriter do the conversion",[10,1689,1690,1691,1693,1694,1696],{},"xlsxwriter builds tables with calculated columns directly, and it accepts the ",[14,1692,640],{}," shorthand in a column's ",[14,1695,992],{},", converting it to the stored form itself:",[332,1698,1700],{"className":379,"code":1699,"language":381,"meta":337,"style":337},"import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"structured_xw.xlsx\")\nsheet = book.add_worksheet(\"Data\")\nsheet.add_table(\"A1:D4\", {\n    \"name\": \"Sales\",\n    \"data\": [[\"North\", 2, 10], [\"South\", 3, 20], [\"East\", 1, 5]],\n    \"columns\": [\n        {\"header\": \"Region\"},\n        {\"header\": \"Qty\"},\n        {\"header\": \"Price\"},\n        {\"header\": \"Total\", \"formula\": \"=[@Qty]*[@Price]\"},\n    ],\n})\nsheet.write_formula(\"F2\", \"=SUM(Sales[Total])\")\nbook.close()\n",[14,1701,1702,1708,1712,1727,1741,1751,1764,1809,1817,1832,1844,1856,1877,1882,1888,1903],{"__ignoreMap":337},[341,1703,1704,1706],{"class":343,"line":344},[341,1705,396],{"class":388},[341,1707,358],{"class":392},[341,1709,1710],{"class":343,"line":402},[341,1711,419],{"emptyLinePlaceholder":418},[341,1713,1714,1717,1719,1722,1725],{"class":343,"line":415},[341,1715,1716],{"class":392},"book ",[341,1718,428],{"class":388},[341,1720,1721],{"class":392}," xlsxwriter.Workbook(",[341,1723,1724],{"class":351},"\"structured_xw.xlsx\"",[341,1726,581],{"class":392},[341,1728,1729,1732,1734,1737,1739],{"class":343,"line":422},[341,1730,1731],{"class":392},"sheet ",[341,1733,428],{"class":388},[341,1735,1736],{"class":392}," book.add_worksheet(",[341,1738,1234],{"class":351},[341,1740,581],{"class":392},[341,1742,1743,1746,1748],{"class":343,"line":434},[341,1744,1745],{"class":392},"sheet.add_table(",[341,1747,578],{"class":351},[341,1749,1750],{"class":392},", {\n",[341,1752,1753,1756,1759,1761],{"class":343,"line":445},[341,1754,1755],{"class":351},"    \"name\"",[341,1757,1758],{"class":392},": ",[341,1760,569],{"class":351},[341,1762,1763],{"class":392},",\n",[341,1765,1766,1769,1772,1774,1776,1778,1780,1782,1784,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1806],{"class":343,"line":456},[341,1767,1768],{"class":351},"    \"data\"",[341,1770,1771],{"class":392},": [[",[341,1773,499],{"class":351},[341,1775,465],{"class":392},[341,1777,160],{"class":504},[341,1779,465],{"class":392},[341,1781,243],{"class":504},[341,1783,511],{"class":392},[341,1785,514],{"class":351},[341,1787,465],{"class":392},[341,1789,268],{"class":504},[341,1791,465],{"class":392},[341,1793,251],{"class":504},[341,1795,511],{"class":392},[341,1797,527],{"class":351},[341,1799,465],{"class":392},[341,1801,144],{"class":504},[341,1803,465],{"class":392},[341,1805,311],{"class":504},[341,1807,1808],{"class":392},"]],\n",[341,1810,1811,1814],{"class":343,"line":484},[341,1812,1813],{"class":351},"    \"columns\"",[341,1815,1816],{"class":392},": [\n",[341,1818,1819,1822,1825,1827,1829],{"class":343,"line":541},[341,1820,1821],{"class":392},"        {",[341,1823,1824],{"class":351},"\"header\"",[341,1826,1758],{"class":392},[341,1828,462],{"class":351},[341,1830,1831],{"class":392},"},\n",[341,1833,1834,1836,1838,1840,1842],{"class":343,"line":547},[341,1835,1821],{"class":392},[341,1837,1824],{"class":351},[341,1839,1758],{"class":392},[341,1841,468],{"class":351},[341,1843,1831],{"class":392},[341,1845,1846,1848,1850,1852,1854],{"class":343,"line":552},[341,1847,1821],{"class":392},[341,1849,1824],{"class":351},[341,1851,1758],{"class":392},[341,1853,473],{"class":351},[341,1855,1831],{"class":392},[341,1857,1858,1860,1862,1864,1866,1868,1871,1873,1875],{"class":343,"line":584},[341,1859,1821],{"class":392},[341,1861,1824],{"class":351},[341,1863,1758],{"class":392},[341,1865,478],{"class":351},[341,1867,465],{"class":392},[341,1869,1870],{"class":351},"\"formula\"",[341,1872,1758],{"class":392},[341,1874,912],{"class":351},[341,1876,1831],{"class":392},[341,1878,1879],{"class":343,"line":615},[341,1880,1881],{"class":392},"    ],\n",[341,1883,1885],{"class":343,"line":1884},14,[341,1886,1887],{"class":392},"})\n",[341,1889,1891,1894,1896,1898,1901],{"class":343,"line":1890},15,[341,1892,1893],{"class":392},"sheet.write_formula(",[341,1895,1118],{"class":351},[341,1897,465],{"class":392},[341,1899,1900],{"class":351},"\"=SUM(Sales[Total])\"",[341,1902,581],{"class":392},[341,1904,1906],{"class":343,"line":1905},16,[341,1907,1908],{"class":392},"book.close()\n",[10,1910,1911,1912,1915,1916,1919,1920,1923],{},"xlsxwriter also records the formula as the table's ",[643,1913,1914],{},"calculated column formula",", so when someone adds a row to the table in Excel, the Total cell of the new row fills itself. openpyxl's tables do not set that property, which is one more reason to build tables with xlsxwriter when a new file is being created. One caution for testing: LibreOffice did not evaluate xlsxwriter's unqualified ",[14,1917,1918],{},"[#This Row]"," references in our check and showed ",[14,1921,1922],{},"#N\u002FA",", although the form matches what Excel writes; verify xlsxwriter table formulas in Excel.",[327,1925,1927],{"id":1926},"common-pitfalls","Common pitfalls",[1929,1930,1931,1949,1959,1984,2007],"ul",{},[1932,1933,1934,1941,1942,1944,1945,1948],"li",{},[1935,1936,1937,1938,1940],"strong",{},"Writing ",[14,1939,24],{}," with openpyxl."," It opens as ",[14,1943,719],{},". Expand to ",[14,1946,1947],{},"Table[[#This Row],[Column]]"," first.",[1932,1950,1951,1954,1955,1958],{},[1935,1952,1953],{},"Table ref without the header."," ",[14,1956,1957],{},"Table(ref=...)"," must include the header row; a ref that starts on the first data row makes Excel repair the file.",[1932,1960,1961,1964,1965,465,1967,465,1969,1971,1972,1975,1976,1979,1980,1983],{},[1935,1962,1963],{},"Special characters in column names."," Inside a reference, ",[14,1966,851],{},[14,1968,860],{},[14,1970,1682],{}," and ",[14,1973,1974],{},"'"," must be escaped with an apostrophe: a column named ",[14,1977,1978],{},"#Units"," is referenced as ",[14,1981,1982],{},"Sales['#Units]",". Simpler still, keep table column names to letters, digits, spaces and underscores.",[1932,1985,1986,1954,1989,1992,1993,1995,1996,1998,1999,2002,2003,2006],{},[1935,1987,1988],{},"Appending rows does not grow the table.",[14,1990,1991],{},"ws.append()"," writes below the table, but the table's ",[14,1994,375],{}," still ends at the old last row, so ",[14,1997,1311],{}," ignores the new rows. After appending, set ",[14,2000,2001],{},"ws.tables[\"Sales\"].ref"," to the new range, for example ",[14,2004,2005],{},"\"A1:D7\"",", and the structured formulas cover the added rows again.",[1932,2008,2009,2012],{},[1935,2010,2011],{},"Renaming columns later."," Excel updates structured references when a column is renamed in Excel, but a Python script that rewrites the header text does not update formulas. Rename columns in the data before writing formulas that use them.",[327,2014,2016],{"id":2015},"performance-and-scale-notes","Performance and scale notes",[10,2018,2019,2020,2022,2023,626],{},"Structured references cost Excel nothing extra compared with addresses; they are resolved to ranges internally. In a generated workbook their benefit is robustness: when a later job appends rows by resizing the table's ",[14,2021,375],{},", every structured formula covers the new rows without being rewritten, while address-based formulas would need regenerating. For writing large tables, xlsxwriter is also markedly faster than openpyxl, and its constant-memory mode is covered in ",[27,2024,2026],{"href":2025},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-a-million-rows-to-excel-with-xlsxwriter-constant-memory\u002F","Write a Million Rows to Excel with xlsxwriter",[327,2028,2030],{"id":2029},"conclusion","Conclusion",[10,2032,2033,2034,2036,2037,2039,2040,2042,2043,2045],{},"Structured references make generated formulas follow the table instead of a fixed range. Whole-column references like ",[14,2035,1311],{}," and special items like ",[14,2038,1248],{}," work as written in either library. This-row references must be stored in their long form, ",[14,2041,1415],{},": write that yourself with openpyxl, or let xlsxwriter convert ",[14,2044,1675],{}," in table column formulas. Check openpyxl output by recalculating a copy, and keep column names free of characters that need escaping.",[327,2047,2049],{"id":2048},"frequently-asked-questions","Frequently asked questions",[10,2051,2052,2059,2060,2063],{},[1935,2053,2054,2055,2058],{},"Why does ",[341,2056,2057],{},"@Qty"," show #NAME? when I write it with openpyxl?","\nThe @ shorthand is how Excel displays a this-row reference, but the file format stores the long form Table[[#This Row],",[341,2061,2062],{},"Column","]. openpyxl writes your text verbatim, so write the long form yourself.",[10,2065,2066,2069,2070,2072,2073,2076],{},[1935,2067,2068],{},"Does xlsxwriter accept the @ shorthand?","\nYes, in table column formulas. xlsxwriter converts ",[341,2071,2057],{}," into the stored ",[341,2074,2075],{},"#This Row"," form automatically when you pass it as a column formula in add_table.",[10,2078,2079,2082,2083,2085],{},[1935,2080,2081],{},"Do structured references update when the table grows?","\nYes. Sales",[341,2084,195],{}," always means the whole data area of that column, so when rows are added to the table — by a person or a later script run that resizes the table — every formula using it covers the new rows.",[10,2087,2088,2091,2092,2095,2096,2099],{},[1935,2089,2090],{},"How do I refer to a column whose name contains a bracket or a hash?","\nEscape the special characters ",[341,2093,2094],{},",",", # and the apostrophe with a leading apostrophe inside the reference, for example Sales",[341,2097,2098],{},"'#Units"," for a column named #Units.",[327,2101,2103],{"id":2102},"related","Related",[1929,2105,2106,2112,2119,2126],{},[1932,2107,2108,2109,2111],{},"Up one level: ",[27,2110,30],{"href":29}," — writing and reading formulas.",[1932,2113,2114,2118],{},[27,2115,2117],{"href":2116},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002F","Creating Excel Tables and Autofilters with Python"," — tables in depth.",[1932,2120,2121,2125],{},[27,2122,2124],{"href":2123},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-dynamic-array-formulas-with-python\u002F","Write Dynamic Array Formulas like FILTER and UNIQUE from Python"," — spilling formulas over table columns.",[1932,2127,2128,2132],{},[27,2129,2131],{"href":2130},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fread-an-excel-table-by-name-into-pandas\u002F","Read an Excel Table by Name into pandas"," — reading tables back.",[2134,2135,2136],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .s_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":337,"searchDepth":402,"depth":402,"links":2138},[2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149],{"id":329,"depth":402,"text":330},{"id":364,"depth":402,"text":365},{"id":629,"depth":402,"text":630},{"id":1087,"depth":402,"text":1088},{"id":1446,"depth":402,"text":1447},{"id":1686,"depth":402,"text":1687},{"id":1926,"depth":402,"text":1927},{"id":2015,"depth":402,"text":2016},{"id":2029,"depth":402,"text":2030},{"id":2048,"depth":402,"text":2049},{"id":2102,"depth":402,"text":2103},"2026-09-23","Write formulas that refer to Excel table columns by name — =SUM(Sales[Total]), calculated columns, SUMIFS over table columns — from openpyxl and xlsxwriter, including the [@Column] shorthand that must be written out in full.","md",[2154,2157,2159,2161],{"q":2155,"a":2156},"Why does [@Qty] show #NAME? when I write it with openpyxl?","The @ shorthand is how Excel displays a this-row reference, but the file format stores the long form Table[[#This Row],[Column]]. openpyxl writes your text verbatim, so write the long form yourself.",{"q":2068,"a":2158},"Yes, in table column formulas. xlsxwriter converts [@Qty] into the stored [#This Row] form automatically when you pass it as a column formula in add_table.",{"q":2081,"a":2160},"Yes. Sales[Total] always means the whole data area of that column, so when rows are added to the table — by a person or a later script run that resizes the table — every formula using it covers the new rows.",{"q":2090,"a":2162},"Escape the special characters [, ], # and the apostrophe with a leading apostrophe inside the reference, for example Sales['#Units] for a column named #Units.","use structured table references in excel formulas from python",null,{"breadcrumb":2166},[2167,2170,2173],{"name":2168,"item":2169},"Home","\u002F",{"name":2171,"item":2172},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":30,"item":29},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python",{"title":2176,"description":2177},"Structured References in Excel Formulas from Python (openpyxl, xlsxwriter)","Write Excel table formulas like Sales[Total] and Sales[[#This Row],[Qty]] from Python. Why [@Qty] gives #NAME? from openpyxl, how xlsxwriter converts it, special items, and escaping column names.","use-structured-table-references-in-formulas-from-python","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fuse-structured-table-references-in-formulas-from-python\u002Findex",[2181,2182,2183],"excel-formulas","tables-and-filters","openpyxl","how-to","WuB0f_030mLAq6fSOtRkVr6EpQTbN3vHBzU6AniXleU",[2187,2191],{"title":2188,"path":2189,"stem":2190,"children":-1},"Turn an Excel Model into a Python Function","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fturn-an-excel-model-into-a-python-function","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fturn-an-excel-model-into-a-python-function\u002Findex",{"title":2124,"path":2192,"stem":2193,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-dynamic-array-formulas-with-python","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-dynamic-array-formulas-with-python\u002Findex",[2195,2197],{"path":2196,"title":2171},"\u002Fgetting-started-with-python-excel-automation",{"path":2198,"title":30},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python",[],[2201,2204,2208,2211,2214,2217],{"path":2202,"title":2203,"kind":2184},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fstore-formula-results-with-xlsxwriter","Store Formula Results with xlsxwriter So Every Viewer Shows Values",{"path":2205,"title":2206,"kind":2207},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-cells-with-formula-errors-using-conditional-formatting","Highlight Cells with Formula Errors Using Conditional Formatting","fix",{"path":2209,"title":2210,"kind":2184},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fgoal-seek-in-python-instead-of-excel","Goal Seek in Python Instead of Excel",{"path":2212,"title":2213,"kind":2184},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fcheck-that-totals-in-a-report-add-up","Check That Totals in a Report Add Up",{"path":2215,"title":2216,"kind":2184},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fcall-excel-worksheet-functions-through-microsoft-graph","Call Excel Worksheet Functions Through Microsoft Graph",{"path":2218,"title":2219,"kind":2184},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Frecalculate-excel-online-workbooks-with-graph-sessions","Recalculate Excel Online Workbooks with Graph Sessions",1790972075854]