[{"data":1,"prerenderedAt":2724},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel":2691,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel":2700,"children:\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel":2703,"related:\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel":2709},{"id":4,"title":5,"body":6,"dateModified":2656,"datePublished":2656,"description":2657,"extension":2658,"faq":2659,"keyword":2672,"kind":2673,"meta":2674,"navigation":439,"path":2681,"seo":2682,"slug":2685,"stem":2686,"topics":2687,"type":2689,"__hash__":2690},"docs\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Findex.md","Using Python in Excel",{"type":7,"value":8,"toc":2639},"minimark",[9,29,160,165,204,228,232,256,305,320,323,327,340,450,460,536,540,589,595,732,736,739,899,911,915,934,1045,1062,1066,1073,1076,1236,1251,1392,1396,1412,1613,1618,1622,1666,1669,1774,1779,1783,1786,1903,1910,1914,1917,1943,2053,2061,2065,2068,2455,2468,2475,2479,2525,2529,2535,2541,2547,2553,2559,2565,2569,2618,2621,2635],[10,11,12,13,17,18,22,23,28],"p",{},"Most of this site is about Python working ",[14,15,16],"em",{},"on"," Excel files from the outside: scripts that read, clean,\nformat and deliver workbooks. Python in Excel is the other direction. It lets you type Python into a cell\nwith a ",[19,20,21],"code",{},"=PY"," formula, runs it in a Microsoft cloud container with pandas, NumPy, matplotlib, seaborn and\nstatsmodels available, and puts the result back into the grid. For analysts who already live in Excel it\nremoves the whole question of environments and files; for developers it is a new place where Python code\nends up, with its own rules. This section of\n",[24,25,27],"a",{"href":26},"\u002Fgetting-started-with-python-excel-automation\u002F","Getting Started with Python Excel Automation"," covers how\nthose rules work in practice — and how to tell when a job belongs in a script instead.",[30,31,39,40,39,44,39,48,39,55,39,64,39,71,39,76,39,81,39,86,39,91,39,97,39,99,39,101,39,107,39,112,39,117,39,122,39,127,39,130,39,134,39,139,39,143,39,147,39,152,39,155],"svg",{"viewBox":32,"role":33,"ariaLabelledBy":34,"xmlns":37,"style":38},"0 0 720 316","img",[35,36],"pie-seq-t","pie-seq-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:720px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[41,42,43],"title",{"id":35},"What happens when a Python in Excel formula calculates",[45,46,47],"desc",{"id":36},"The workbook sends the referenced data and the formula code to the Microsoft cloud Python runtime, which executes it with pandas and returns either a Python object or converted Excel values to the cell.",[49,50],"rect",{"x":51,"y":51,"width":52,"height":53,"fill":54},"0","720","316","#ffffff",[49,56],{"x":57,"y":57,"width":58,"height":59,"rx":60,"fill":61,"stroke":62,"style":63},"20","150","40","10","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[65,66,70],"text",{"x":67,"y":68,"style":69},"95","45","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Excel workbook",[49,72],{"x":73,"y":57,"width":58,"height":59,"rx":60,"fill":74,"stroke":75,"style":63},"285","#e7ebef","var(--line,#cdd5e6)",[65,77,80],{"x":78,"y":68,"style":79},"360","font-size:13px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","xl() references",[49,82],{"x":83,"y":57,"width":58,"height":59,"rx":60,"fill":84,"stroke":85,"style":63},"550","#f0f4ff","var(--brand,#5b5cf0)",[65,87,90],{"x":88,"y":68,"style":89},"625","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","cloud runtime",[92,93],"line",{"x1":67,"y1":94,"x2":67,"y2":95,"stroke":75,"style":96},"60","270","stroke-width:2px;stroke-dasharray:5 5",[92,98],{"x1":78,"y1":94,"x2":78,"y2":95,"stroke":75,"style":96},[92,100],{"x1":88,"y1":94,"x2":88,"y2":95,"stroke":75,"style":96},[65,102,106],{"x":103,"y":104,"style":105},"227.5","101","font-size:11.5px;font-weight:600;fill:var(--text,#172033);text-anchor:middle","formula calculates",[92,108],{"x1":109,"y1":110,"x2":111,"y2":110,"stroke":85,"style":63},"99","110","352",[113,114],"polygon",{"points":115,"fill":116},"357,110 348,105 348,115","#5b5cf0",[65,118,121],{"x":119,"y":120,"style":105},"492.5","147","code + referenced data",[92,123],{"x1":124,"y1":125,"x2":126,"y2":125,"stroke":85,"style":63},"364","156","617",[113,128],{"points":129,"fill":116},"622,156 613,151 613,161",[65,131,133],{"x":119,"y":132,"style":105},"193","result after pandas runs",[92,135],{"x1":136,"y1":137,"x2":138,"y2":137,"stroke":62,"style":63},"621","202","368",[113,140],{"points":141,"fill":142},"363,202 372,197 372,207","#0f9488",[65,144,146],{"x":103,"y":145,"style":105},"239","object or Excel values",[92,148],{"x1":149,"y1":150,"x2":151,"y2":150,"stroke":62,"style":63},"356","248","103",[113,153],{"points":154,"fill":142},"98,248 107,243 107,253",[65,156,159],{"x":78,"y":157,"style":158},"296","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","the cell is the trigger; the cloud container does the work",[161,162,164],"h2",{"id":163},"what-this-section-covers","What this section covers",[166,167,168,176,183,190,197],"ul",{},[169,170,171,175],"li",{},[24,172,174],{"href":173},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Freference-cells-ranges-and-tables-with-xl-in-python-in-excel\u002F","Reference Cells, Ranges and Tables with xl() in Python in Excel"," — the only way data gets into a formula.",[169,177,178,182],{},[24,179,181],{"href":180},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Freturn-dataframes-and-values-from-python-in-excel-cells\u002F","Return DataFrames and Values from Python in Excel Cells"," — output types, spilling and structuring a sheet.",[169,184,185,189],{},[24,186,188],{"href":187},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fplot-charts-with-matplotlib-in-python-in-excel\u002F","Plot Charts with matplotlib in Python in Excel"," — images in cells and over the grid.",[169,191,192,196],{},[24,193,195],{"href":194},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Ffix-python-in-excel-errors\u002F","Fix Python in Excel Errors"," — every error value and its fix.",[169,198,199,203],{},[24,200,202],{"href":201},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fpython-in-excel-vs-openpyxl-and-xlwings\u002F","Python in Excel vs openpyxl and xlwings"," — choosing between in-cell Python and scripts.",[10,205,206,207,209,210,213,214,213,217,213,220,223,224,227],{},"Code on these pages is formula code: it runs inside a ",[19,208,21],{}," cell, where ",[19,211,212],{},"xl",", ",[19,215,216],{},"pd",[19,218,219],{},"np",[19,221,222],{},"plt"," and ",[19,225,226],{},"sns"," already exist.\nIt does not run as a standalone script unless you provide those names yourself.",[161,229,231],{"id":230},"entering-your-first-formula","Entering your first formula",[10,233,234,235,239,240,243,244,247,248,251,252,255],{},"Select a cell and choose ",[236,237,238],"strong",{},"Formulas → Insert Python",", or type ",[19,241,242],{},"=PY("," and choose Python from AutoComplete. The cell enters\nPython editing mode, where ",[236,245,246],{},"Enter"," starts a new line and ",[236,249,250],{},"Ctrl+Enter"," commits the formula. While editing, selecting cells\nwith the mouse inserts the matching ",[19,253,254],{},"xl()"," reference for you.",[257,258,263],"pre",{"className":259,"code":260,"language":261,"meta":262,"style":262},"language-python shiki shiki-themes github-light github-dark-high-contrast","sales = xl(\"Sales[#All]\", headers=True)\nsales.describe()\n","python","",[19,264,265,299],{"__ignoreMap":262},[266,267,269,273,277,280,284,286,290,292,296],"span",{"class":92,"line":268},1,[266,270,272],{"class":271},"skGVy","sales ",[266,274,276],{"class":275},"s-kum","=",[266,278,279],{"class":271}," xl(",[266,281,283],{"class":282},"srMev","\"Sales[#All]\"",[266,285,213],{"class":271},[266,287,289],{"class":288},"sa561","headers",[266,291,276],{"class":275},[266,293,295],{"class":294},"sP0c6","True",[266,297,298],{"class":271},")\n",[266,300,302],{"class":92,"line":301},2,[266,303,304],{"class":271},"sales.describe()\n",[10,306,307,308,311,312,315,316,319],{},"That two-line formula already shows the model. The first line pulls an Excel table named ",[19,309,310],{},"Sales"," into a pandas DataFrame, using\nits header row as column names. The second line is the formula's result: a formula has no ",[19,313,314],{},"return",", and the value of the ",[236,317,318],{},"last\nexpression"," is what reaches the cell. Everything a pandas user knows applies from here on.",[10,321,322],{},"What does not carry over is access to the outside world. The runtime cannot read files from your disk, cannot make network\nrequests and cannot install packages. The workbook is the data source, and anything external has to be brought into it — usually\nthrough Power Query — before Python can see it.",[161,324,326],{"id":325},"getting-data-in-with-xl","Getting data in with xl()",[10,328,329,331,332,335,336,339],{},[19,330,254],{}," accepts the same reference text as an Excel formula, and what it returns depends on what you point it at: a single cell gives\na Python scalar, and anything larger gives a DataFrame. For blocks of records, always pass ",[19,333,334],{},"headers=True",", and prefer an Excel table\nwith the ",[19,337,338],{},"[#All]"," specifier over a fixed range, because tables grow when rows are added.",[257,341,343],{"className":259,"code":342,"language":261,"meta":262,"style":262},"sales = xl(\"Sales[#All]\", headers=True)         # a table that grows with the data\ntax_rate = xl(\"TaxRate\")                        # a named single cell\nraw = xl(\"'Raw data'!A1:C200\", headers=True)    # a fixed range on another sheet\norders = xl(\"Orders\")                           # a Power Query query, by name\n\nlen(sales), tax_rate, raw.shape, orders.shape\n",[19,344,345,370,388,415,434,441],{"__ignoreMap":262},[266,346,347,349,351,353,355,357,359,361,363,366],{"class":92,"line":268},[266,348,272],{"class":271},[266,350,276],{"class":275},[266,352,279],{"class":271},[266,354,283],{"class":282},[266,356,213],{"class":271},[266,358,289],{"class":288},[266,360,276],{"class":275},[266,362,295],{"class":294},[266,364,365],{"class":271},")         ",[266,367,369],{"class":368},"s-wDw","# a table that grows with the data\n",[266,371,372,375,377,379,382,385],{"class":92,"line":301},[266,373,374],{"class":271},"tax_rate ",[266,376,276],{"class":275},[266,378,279],{"class":271},[266,380,381],{"class":282},"\"TaxRate\"",[266,383,384],{"class":271},")                        ",[266,386,387],{"class":368},"# a named single cell\n",[266,389,391,394,396,398,401,403,405,407,409,412],{"class":92,"line":390},3,[266,392,393],{"class":271},"raw ",[266,395,276],{"class":275},[266,397,279],{"class":271},[266,399,400],{"class":282},"\"'Raw data'!A1:C200\"",[266,402,213],{"class":271},[266,404,289],{"class":288},[266,406,276],{"class":275},[266,408,295],{"class":294},[266,410,411],{"class":271},")    ",[266,413,414],{"class":368},"# a fixed range on another sheet\n",[266,416,418,421,423,425,428,431],{"class":92,"line":417},4,[266,419,420],{"class":271},"orders ",[266,422,276],{"class":275},[266,424,279],{"class":271},[266,426,427],{"class":282},"\"Orders\"",[266,429,430],{"class":271},")                           ",[266,432,433],{"class":368},"# a Power Query query, by name\n",[266,435,437],{"class":92,"line":436},5,[266,438,440],{"emptyLinePlaceholder":439},true,"\n",[266,442,444,447],{"class":92,"line":443},6,[266,445,446],{"class":294},"len",[266,448,449],{"class":271},"(sales), tax_rate, raw.shape, orders.shape\n",[10,451,452,453,456,457,459],{},"Power Query is the supported bridge for external data: connect to a file, database or web source with ",[236,454,455],{},"Data → Get Data",", load the\nquery (a connection-only load is enough), and reference it by name. Refreshing the query recalculates every Python formula that uses it.\nOther workbooks cannot be referenced directly. The details, including the types you receive and how to check them, are in\n",[24,458,174],{"href":173},".",[30,461,39,466,39,469,39,472,39,475,39,480,39,485,39,489,39,492,39,496,39,499,39,502,39,506,39,509,39,512,39,517,39,520,39,525,39,530,39,533],{"viewBox":462,"role":33,"ariaLabelledBy":463,"xmlns":37,"style":38},"0 0 720 380",[464,465],"pie-sources-t","pie-sources-d",[41,467,468],{"id":464},"Where Python in Excel data can come from",[45,470,471],{"id":465},"Cells, ranges and tables in the workbook, defined names, and Power Query queries can all be referenced with xl. Local files, web APIs, databases queried directly, and other workbooks cannot be reached from the formula.",[49,473],{"x":51,"y":51,"width":52,"height":474,"fill":54},"380",[49,476],{"x":57,"y":57,"width":477,"height":478,"rx":479,"fill":61,"stroke":62,"style":63},"680","52","12",[65,481,484],{"x":59,"y":482,"style":483},"51","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","cells and ranges",[65,486,488],{"x":95,"y":482,"style":487},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","xl(\"B1\"), xl(\"A1:D50\", headers=True)",[49,490],{"x":57,"y":491,"width":477,"height":478,"rx":479,"fill":61,"stroke":62,"style":63},"84",[65,493,495],{"x":59,"y":494,"style":483},"115","Excel tables",[65,497,498],{"x":95,"y":494,"style":487},"xl(\"Sales[#All]\", headers=True) — grows with the table",[49,500],{"x":57,"y":501,"width":477,"height":478,"rx":479,"fill":61,"stroke":62,"style":63},"148",[65,503,505],{"x":59,"y":504,"style":483},"179","defined names",[65,507,508],{"x":95,"y":504,"style":487},"xl(\"TaxRate\")",[49,510],{"x":57,"y":511,"width":477,"height":478,"rx":479,"fill":84,"stroke":85,"style":63},"212",[65,513,516],{"x":59,"y":514,"style":515},"243","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","Power Query",[65,518,519],{"x":95,"y":514,"style":487},"xl(\"Orders\") — the bridge to files, databases, web",[49,521],{"x":57,"y":522,"width":477,"height":478,"rx":479,"fill":523,"stroke":524,"style":63},"276","#fee8f2","var(--accent,#f43f8f)",[65,526,529],{"x":59,"y":527,"style":528},"307","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:start","not reachable",[65,531,532],{"x":95,"y":527,"style":487},"local files, direct API calls, other workbooks",[65,534,535],{"x":78,"y":78,"style":158},"bring external data in first; then reference it",[161,537,539],{"id":538},"the-initialization-code-behind-every-formula","The initialization code behind every formula",[10,541,542,543,546,547,550,551,554,555,558,559,223,562,565,566,568,569,572,573,575,576,578,579,581,582,585,586,588],{},"Before any of your formulas run, the runtime executes the workbook's initialization code, which you can inspect under\n",[236,544,545],{},"Formulas → Initialization",". It contains two kinds of statement. The ",[236,548,549],{},"required"," ones — ",[19,552,553],{},"import excel",", the ",[19,556,557],{},"warnings","\nsettings and the ",[19,560,561],{},"excel.set_xl_scalar_conversion",[19,563,564],{},"excel.set_xl_array_conversion"," calls — control how ",[19,567,254],{}," converts cells\ninto Python values, and removing them can break formulas. The ",[236,570,571],{},"library imports"," — NumPy as ",[19,574,219],{},", pandas as ",[19,577,216],{},", matplotlib's\npyplot as ",[19,580,222],{},", statsmodels as ",[19,583,584],{},"sm"," and seaborn as ",[19,587,226],{}," — are there for convenience, and you can add imports for other available\nlibraries or remove ones you do not use.",[10,590,591,592,594],{},"Treat changes to initialization as changes to every formula in the workbook. Adding an import is harmless; changing how conversions\nbehave alters what every existing ",[19,593,254],{}," call returns. If a formula needs a less common library, importing it inside that formula is\nthe more contained option:",[257,596,598],{"className":259,"code":597,"language":261,"meta":262,"style":262},"from scipy import stats\n\nsales = xl(\"Sales[#All]\", headers=True)\nnorth = sales.loc[sales[\"Region\"] == \"North\", \"Amount\"]\nsouth = sales.loc[sales[\"Region\"] == \"South\", \"Amount\"]\nresult = stats.ttest_ind(north, south, equal_var=False)\nround(float(result.pvalue), 4)\n",[19,599,600,614,618,638,668,692,712],{"__ignoreMap":262},[266,601,602,605,608,611],{"class":92,"line":268},[266,603,604],{"class":275},"from",[266,606,607],{"class":271}," scipy ",[266,609,610],{"class":275},"import",[266,612,613],{"class":271}," stats\n",[266,615,616],{"class":92,"line":301},[266,617,440],{"emptyLinePlaceholder":439},[266,619,620,622,624,626,628,630,632,634,636],{"class":92,"line":390},[266,621,272],{"class":271},[266,623,276],{"class":275},[266,625,279],{"class":271},[266,627,283],{"class":282},[266,629,213],{"class":271},[266,631,289],{"class":288},[266,633,276],{"class":275},[266,635,295],{"class":294},[266,637,298],{"class":271},[266,639,640,643,645,648,651,654,657,660,662,665],{"class":92,"line":417},[266,641,642],{"class":271},"north ",[266,644,276],{"class":275},[266,646,647],{"class":271}," sales.loc[sales[",[266,649,650],{"class":282},"\"Region\"",[266,652,653],{"class":271},"] ",[266,655,656],{"class":275},"==",[266,658,659],{"class":282}," \"North\"",[266,661,213],{"class":271},[266,663,664],{"class":282},"\"Amount\"",[266,666,667],{"class":271},"]\n",[266,669,670,673,675,677,679,681,683,686,688,690],{"class":92,"line":436},[266,671,672],{"class":271},"south ",[266,674,276],{"class":275},[266,676,647],{"class":271},[266,678,650],{"class":282},[266,680,653],{"class":271},[266,682,656],{"class":275},[266,684,685],{"class":282}," \"South\"",[266,687,213],{"class":271},[266,689,664],{"class":282},[266,691,667],{"class":271},[266,693,694,697,699,702,705,707,710],{"class":92,"line":443},[266,695,696],{"class":271},"result ",[266,698,276],{"class":275},[266,700,701],{"class":271}," stats.ttest_ind(north, south, ",[266,703,704],{"class":288},"equal_var",[266,706,276],{"class":275},[266,708,709],{"class":294},"False",[266,711,298],{"class":271},[266,713,715,718,721,724,727,730],{"class":92,"line":714},7,[266,716,717],{"class":294},"round",[266,719,720],{"class":271},"(",[266,722,723],{"class":294},"float",[266,725,726],{"class":271},"(result.pvalue), ",[266,728,729],{"class":294},"4",[266,731,298],{"class":271},[161,733,735],{"id":734},"cleaning-data-inside-a-formula","Cleaning data inside a formula",[10,737,738],{},"Data typed by people arrives in formulas with the same problems it has everywhere: amounts stored as text, stray spaces in labels,\nblank rows at the bottom of a range. The difference in Python in Excel is that the cleaning runs on every recalculation, so it should be\nquick, deterministic and written once in a load cell that every output reuses.",[257,740,742],{"className":259,"code":741,"language":261,"meta":262,"style":262},"raw = xl(\"Sales[#All]\", headers=True)\nclean = (\n    raw.dropna(how=\"all\")\n       .assign(\n           Region=lambda d: d[\"Region\"].astype(str).str.strip().str.title(),\n           Amount=lambda d: pd.to_numeric(d[\"Amount\"], errors=\"coerce\"),\n       )\n       .dropna(subset=[\"Amount\"])\n)\nproblems = len(raw) - len(clean)\nclean\n",[19,743,744,764,774,789,794,816,842,847,866,871,893],{"__ignoreMap":262},[266,745,746,748,750,752,754,756,758,760,762],{"class":92,"line":268},[266,747,393],{"class":271},[266,749,276],{"class":275},[266,751,279],{"class":271},[266,753,283],{"class":282},[266,755,213],{"class":271},[266,757,289],{"class":288},[266,759,276],{"class":275},[266,761,295],{"class":294},[266,763,298],{"class":271},[266,765,766,769,771],{"class":92,"line":301},[266,767,768],{"class":271},"clean ",[266,770,276],{"class":275},[266,772,773],{"class":271}," (\n",[266,775,776,779,782,784,787],{"class":92,"line":390},[266,777,778],{"class":271},"    raw.dropna(",[266,780,781],{"class":288},"how",[266,783,276],{"class":275},[266,785,786],{"class":282},"\"all\"",[266,788,298],{"class":271},[266,790,791],{"class":92,"line":417},[266,792,793],{"class":271},"       .assign(\n",[266,795,796,799,802,805,807,810,813],{"class":92,"line":436},[266,797,798],{"class":288},"           Region",[266,800,801],{"class":275},"=lambda",[266,803,804],{"class":271}," d: d[",[266,806,650],{"class":282},[266,808,809],{"class":271},"].astype(",[266,811,812],{"class":294},"str",[266,814,815],{"class":271},").str.strip().str.title(),\n",[266,817,818,821,823,826,828,831,834,836,839],{"class":92,"line":443},[266,819,820],{"class":288},"           Amount",[266,822,801],{"class":275},[266,824,825],{"class":271}," d: pd.to_numeric(d[",[266,827,664],{"class":282},[266,829,830],{"class":271},"], ",[266,832,833],{"class":288},"errors",[266,835,276],{"class":275},[266,837,838],{"class":282},"\"coerce\"",[266,840,841],{"class":271},"),\n",[266,843,844],{"class":92,"line":714},[266,845,846],{"class":271},"       )\n",[266,848,850,853,856,858,861,863],{"class":92,"line":849},8,[266,851,852],{"class":271},"       .dropna(",[266,854,855],{"class":288},"subset",[266,857,276],{"class":275},[266,859,860],{"class":271},"[",[266,862,664],{"class":282},[266,864,865],{"class":271},"])\n",[266,867,869],{"class":92,"line":868},9,[266,870,298],{"class":271},[266,872,874,877,879,882,885,888,890],{"class":92,"line":873},10,[266,875,876],{"class":271},"problems ",[266,878,276],{"class":275},[266,880,881],{"class":294}," len",[266,883,884],{"class":271},"(raw) ",[266,886,887],{"class":275},"-",[266,889,881],{"class":294},[266,891,892],{"class":271},"(clean)\n",[266,894,896],{"class":92,"line":895},11,[266,897,898],{"class":271},"clean\n",[10,900,901,902,905,906,910],{},"Keep a count such as ",[19,903,904],{},"problems"," and surface it in its own small output cell, so a reader notices when rows start disappearing. The techniques\nthemselves are ordinary pandas, and ",[24,907,909],{"href":908},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002F","Cleaning Excel Data With Pandas","\ncovers them in depth — though a workbook that needs heavy cleaning on every calculation is often better served by fixing the source in Power\nQuery, which runs once per refresh rather than once per recalculation.",[161,912,914],{"id":913},"getting-results-out-objects-and-values","Getting results out: objects and values",[10,916,917,918,921,922,925,926,929,930,933],{},"Each Python formula has an output type, switched from the ",[236,919,920],{},"Python output"," menu by the formula bar or with ",[236,923,924],{},"Ctrl+Alt+Shift+M",". As a\n",[236,927,928],{},"Python object",", the result stays a live Python value in one cell, shown as a card; later Python cells can use it through its variable.\nAs an ",[236,931,932],{},"Excel value",", the result is converted: scalars become ordinary numbers, text and dates, and DataFrames spill into the cells below\nand to the right, where charts, conditional formats and normal formulas can use them.",[257,935,937],{"className":259,"code":936,"language":261,"meta":262,"style":262},"sales = xl(\"Sales[#All]\", headers=True)\n(\n    sales.groupby([\"Region\", \"Rep\"])[\"Amount\"]\n         .agg(Total=\"sum\", Deals=\"count\")\n         .sort_values(\"Total\", ascending=False)\n         .reset_index()\n         .head(10)\n)\n",[19,938,939,959,964,983,1008,1027,1032,1041],{"__ignoreMap":262},[266,940,941,943,945,947,949,951,953,955,957],{"class":92,"line":268},[266,942,272],{"class":271},[266,944,276],{"class":275},[266,946,279],{"class":271},[266,948,283],{"class":282},[266,950,213],{"class":271},[266,952,289],{"class":288},[266,954,276],{"class":275},[266,956,295],{"class":294},[266,958,298],{"class":271},[266,960,961],{"class":92,"line":301},[266,962,963],{"class":271},"(\n",[266,965,966,969,971,973,976,979,981],{"class":92,"line":390},[266,967,968],{"class":271},"    sales.groupby([",[266,970,650],{"class":282},[266,972,213],{"class":271},[266,974,975],{"class":282},"\"Rep\"",[266,977,978],{"class":271},"])[",[266,980,664],{"class":282},[266,982,667],{"class":271},[266,984,985,988,991,993,996,998,1001,1003,1006],{"class":92,"line":417},[266,986,987],{"class":271},"         .agg(",[266,989,990],{"class":288},"Total",[266,992,276],{"class":275},[266,994,995],{"class":282},"\"sum\"",[266,997,213],{"class":271},[266,999,1000],{"class":288},"Deals",[266,1002,276],{"class":275},[266,1004,1005],{"class":282},"\"count\"",[266,1007,298],{"class":271},[266,1009,1010,1013,1016,1018,1021,1023,1025],{"class":92,"line":436},[266,1011,1012],{"class":271},"         .sort_values(",[266,1014,1015],{"class":282},"\"Total\"",[266,1017,213],{"class":271},[266,1019,1020],{"class":288},"ascending",[266,1022,276],{"class":275},[266,1024,709],{"class":294},[266,1026,298],{"class":271},[266,1028,1029],{"class":92,"line":443},[266,1030,1031],{"class":271},"         .reset_index()\n",[266,1033,1034,1037,1039],{"class":92,"line":714},[266,1035,1036],{"class":271},"         .head(",[266,1038,60],{"class":294},[266,1040,298],{"class":271},[266,1042,1043],{"class":92,"line":849},[266,1044,298],{"class":271},[10,1046,1047,1048,1051,1052,1055,1056,1059,1060,459],{},"Shape a DataFrame before it spills: ",[19,1049,1050],{},"reset_index()"," turns group keys into real columns, rounding and renaming tidy the block, and ",[19,1053,1054],{},"head()","\ncaps its height so that it never runs into content below — the cause of ",[19,1057,1058],{},"#SPILL!",". A spilled block has no number formats, so format its\ncells in Excel; the formatting is kept when the formula recalculates. More patterns, including a guard for spills that grow over time, are\nin ",[24,1061,181],{"href":180},[161,1063,1065],{"id":1064},"calculation-order-and-structuring-a-workbook","Calculation order and structuring a workbook",[10,1067,1068,1069,1072],{},"Python formulas share state: a variable assigned in one Python cell is available to Python cells that calculate after it. The order is\nfixed and worth memorising — ",[236,1070,1071],{},"row-major",": across row 1 from column A to the last column, then across row 2, and so on down the sheet,\nwith worksheets processed in order.",[10,1074,1075],{},"That rule suggests a structure that keeps workbooks maintainable. Put a small number of \"load\" cells at the top-left of the first sheet\nthat read tables, clean them and define helper functions, returning Python objects. Put \"output\" cells below and to the right, each\nproducing one view as Excel values or one chart. The expensive work runs once, and every output is small, independent and easy to move.",[257,1077,1079],{"className":259,"code":1078,"language":261,"meta":262,"style":262},"# A1 — load and clean once (Python object)\nsales = xl(\"Sales[#All]\", headers=True).dropna(subset=[\"Amount\"])\nsales[\"Month\"] = sales[\"Date\"].dt.to_period(\"M\").astype(str)\n\ndef top_reps(frame, n=5):\n    return frame.groupby(\"Rep\", as_index=False)[\"Amount\"].sum().nlargest(n, \"Amount\")\n\nsales\n\n# A3 — an output that reuses the load cell (Excel values)\ntop_reps(sales, n=3)\n",[19,1080,1081,1086,1117,1148,1152,1172,1203,1207,1212,1216,1221],{"__ignoreMap":262},[266,1082,1083],{"class":92,"line":268},[266,1084,1085],{"class":368},"# A1 — load and clean once (Python object)\n",[266,1087,1088,1090,1092,1094,1096,1098,1100,1102,1104,1107,1109,1111,1113,1115],{"class":92,"line":301},[266,1089,272],{"class":271},[266,1091,276],{"class":275},[266,1093,279],{"class":271},[266,1095,283],{"class":282},[266,1097,213],{"class":271},[266,1099,289],{"class":288},[266,1101,276],{"class":275},[266,1103,295],{"class":294},[266,1105,1106],{"class":271},").dropna(",[266,1108,855],{"class":288},[266,1110,276],{"class":275},[266,1112,860],{"class":271},[266,1114,664],{"class":282},[266,1116,865],{"class":271},[266,1118,1119,1122,1125,1127,1129,1132,1135,1138,1141,1144,1146],{"class":92,"line":390},[266,1120,1121],{"class":271},"sales[",[266,1123,1124],{"class":282},"\"Month\"",[266,1126,653],{"class":271},[266,1128,276],{"class":275},[266,1130,1131],{"class":271}," sales[",[266,1133,1134],{"class":282},"\"Date\"",[266,1136,1137],{"class":271},"].dt.to_period(",[266,1139,1140],{"class":282},"\"M\"",[266,1142,1143],{"class":271},").astype(",[266,1145,812],{"class":294},[266,1147,298],{"class":271},[266,1149,1150],{"class":92,"line":417},[266,1151,440],{"emptyLinePlaceholder":439},[266,1153,1154,1157,1161,1164,1166,1169],{"class":92,"line":436},[266,1155,1156],{"class":275},"def",[266,1158,1160],{"class":1159},"s_Opv"," top_reps",[266,1162,1163],{"class":271},"(frame, n",[266,1165,276],{"class":275},[266,1167,1168],{"class":294},"5",[266,1170,1171],{"class":271},"):\n",[266,1173,1174,1177,1180,1182,1184,1187,1189,1191,1194,1196,1199,1201],{"class":92,"line":443},[266,1175,1176],{"class":275},"    return",[266,1178,1179],{"class":271}," frame.groupby(",[266,1181,975],{"class":282},[266,1183,213],{"class":271},[266,1185,1186],{"class":288},"as_index",[266,1188,276],{"class":275},[266,1190,709],{"class":294},[266,1192,1193],{"class":271},")[",[266,1195,664],{"class":282},[266,1197,1198],{"class":271},"].sum().nlargest(n, ",[266,1200,664],{"class":282},[266,1202,298],{"class":271},[266,1204,1205],{"class":92,"line":714},[266,1206,440],{"emptyLinePlaceholder":439},[266,1208,1209],{"class":92,"line":849},[266,1210,1211],{"class":271},"sales\n",[266,1213,1214],{"class":92,"line":868},[266,1215,440],{"emptyLinePlaceholder":439},[266,1217,1218],{"class":92,"line":873},[266,1219,1220],{"class":368},"# A3 — an output that reuses the load cell (Excel values)\n",[266,1222,1223,1226,1229,1231,1234],{"class":92,"line":895},[266,1224,1225],{"class":271},"top_reps(sales, ",[266,1227,1228],{"class":288},"n",[266,1230,276],{"class":275},[266,1232,1233],{"class":294},"3",[266,1235,298],{"class":271},[10,1237,1238,1239,1242,1243,1246,1247,1250],{},"A ",[19,1240,1241],{},"NameError"," in a formula almost always means this order was violated: the cell that defines the name calculates after the cell that uses\nit. While you are editing a workbook with many Python cells, switch to ",[236,1244,1245],{},"Partial"," calculation (",[236,1248,1249],{},"Formulas → Calculation Options",") so Python\nformulas only recalculate when you press F9.",[30,1252,39,1258,39,1261,39,1264,39,1268,39,1273,39,1277,39,1282,39,1285,39,1289,39,1291,39,1295,39,1298,39,1303,39,1305,39,1309,39,1311,39,1314,39,1316,39,1320,39,1326,39,1331,39,1334,39,1338,39,1340,39,1344,39,1346,39,1349,39,1351,39,1354,39,1357,39,1360,39,1362,39,1364,39,1366,39,1369,39,1371,39,1374,39,1376,39,1380,39,1383,39,1387],{"viewBox":1253,"role":33,"ariaLabelledBy":1254,"xmlns":37,"style":1257},"0 0 646 194",[1255,1256],"pie-order-t","pie-order-d","width:100%;max-width:646px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[41,1259,1260],{"id":1255},"Row-major calculation order on a sheet",[45,1262,1263],{"id":1256},"Python cells calculate across row one from column A, then across row two, then row three. A load cell in A1 is available to every later cell; a helper defined in C3 is not available to B2.",[49,1265],{"x":51,"y":51,"width":1266,"height":1267,"fill":54},"646","194",[49,1269],{"x":57,"y":57,"width":1270,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},"36","30","stroke-width:1px",[49,1274],{"x":1275,"y":57,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},"56","130",[65,1278,1281],{"x":1279,"y":59,"style":1280},"121","font-size:11.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[49,1283],{"x":1284,"y":57,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},"186",[65,1286,1288],{"x":1287,"y":59,"style":1280},"251","B",[49,1290],{"x":53,"y":57,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},[65,1292,1294],{"x":1293,"y":59,"style":1280},"381","C",[49,1296],{"x":57,"y":1297,"width":1270,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},"50",[65,1299,1302],{"x":1300,"y":1301,"style":1280},"38","70","1",[49,1304],{"x":1275,"y":1297,"width":1276,"height":1271,"rx":51,"fill":84,"stroke":85,"style":1272},[65,1306,1308],{"x":1279,"y":1301,"style":1307},"font-size:11.5px;font-weight:600;fill:var(--brand-strong,#4338ca);text-anchor:middle","1st: load data",[49,1310],{"x":1284,"y":1297,"width":1276,"height":1271,"rx":51,"fill":84,"stroke":85,"style":1272},[65,1312,1313],{"x":1287,"y":1301,"style":1307},"2nd: helpers",[49,1315],{"x":53,"y":1297,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},[65,1317,1319],{"x":1293,"y":1301,"style":1318},"font-size:11.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","3rd",[49,1321],{"x":1322,"y":478,"width":1323,"height":1324,"rx":1325,"fill":84,"stroke":85,"style":1272},"466","160","26","8",[65,1327,1330],{"x":1328,"y":1329,"style":1307},"546","69","definitions first",[49,1332],{"x":57,"y":1333,"width":1270,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},"80",[65,1335,1337],{"x":1300,"y":1336,"style":1280},"100","2",[49,1339],{"x":1275,"y":1333,"width":1276,"height":1271,"rx":51,"fill":61,"stroke":62,"style":1272},[65,1341,1343],{"x":1279,"y":1336,"style":1342},"font-size:11.5px;font-weight:600;fill:var(--teal-ink,#0b6157);text-anchor:middle","4th: KPI value",[49,1345],{"x":1284,"y":1333,"width":1276,"height":1271,"rx":51,"fill":61,"stroke":62,"style":1272},[65,1347,1348],{"x":1287,"y":1336,"style":1342},"5th: uses A1, B1",[49,1350],{"x":53,"y":1333,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},[65,1352,1353],{"x":1293,"y":1336,"style":1318},"6th",[49,1355],{"x":1322,"y":1356,"width":1323,"height":1324,"rx":1325,"fill":61,"stroke":62,"style":1272},"82",[65,1358,1359],{"x":1328,"y":109,"style":1342},"outputs follow",[49,1361],{"x":57,"y":110,"width":1270,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},[65,1363,1233],{"x":1300,"y":1276,"style":1280},[49,1365],{"x":1275,"y":110,"width":1276,"height":1271,"rx":51,"fill":61,"stroke":62,"style":1272},[65,1367,1368],{"x":1279,"y":1276,"style":1342},"7th: report spill",[49,1370],{"x":1284,"y":110,"width":1276,"height":1271,"rx":51,"fill":74,"stroke":75,"style":1272},[65,1372,1373],{"x":1287,"y":1276,"style":1318},"8th",[49,1375],{"x":53,"y":110,"width":1276,"height":1271,"rx":51,"fill":523,"stroke":524,"style":1272},[65,1377,1379],{"x":1293,"y":1276,"style":1378},"font-size:11.5px;font-weight:600;fill:var(--accent-ink,#be185d);text-anchor:middle","9th: defines x",[49,1381],{"x":1322,"y":1382,"width":1323,"height":1324,"rx":1325,"fill":523,"stroke":524,"style":1272},"112",[65,1384,1386],{"x":1328,"y":1385,"style":1378},"129","too late for B2",[65,1388,1391],{"x":1389,"y":1390,"style":158},"323","172","across each row, then down; sheets in order",[161,1393,1395],{"id":1394},"charts-from-python-formulas","Charts from Python formulas",[10,1397,1398,1399,223,1401,1403,1404,1407,1408,1411],{},"matplotlib and seaborn are imported by default as ",[19,1400,222],{},[19,1402,226],{},", so a formula can draw anything they can. Build an explicit figure, finish\nthe formula with it, and Excel receives an image object. ",[236,1405,1406],{},"Display Plot over Cells"," (Ctrl+Alt+Shift+C) places a resizable floating copy;\nswitching the output to ",[236,1409,1410],{},"Excel Value"," draws the image inside the cell, sized by the cell.",[257,1413,1415],{"className":259,"code":1414,"language":261,"meta":262,"style":262},"sales = xl(\"Sales[#All]\", headers=True)\nmonthly = sales.set_index(\"Date\").groupby(\"Region\")[\"Amount\"].resample(\"MS\").sum().unstack(0)\n\nfig, ax = plt.subplots(figsize=(6, 3), dpi=150)\nmonthly.plot(ax=ax, marker=\"o\", linewidth=1.8)\nax.set_title(\"Revenue by month and region\", loc=\"left\", fontsize=10)\nax.set_xlabel(\"\")\nax.spines[[\"top\", \"right\"]].set_visible(False)\nfig.tight_layout()\nfig\n",[19,1416,1417,1437,1471,1475,1511,1544,1573,1583,1603,1608],{"__ignoreMap":262},[266,1418,1419,1421,1423,1425,1427,1429,1431,1433,1435],{"class":92,"line":268},[266,1420,272],{"class":271},[266,1422,276],{"class":275},[266,1424,279],{"class":271},[266,1426,283],{"class":282},[266,1428,213],{"class":271},[266,1430,289],{"class":288},[266,1432,276],{"class":275},[266,1434,295],{"class":294},[266,1436,298],{"class":271},[266,1438,1439,1442,1444,1447,1449,1452,1454,1456,1458,1461,1464,1467,1469],{"class":92,"line":301},[266,1440,1441],{"class":271},"monthly ",[266,1443,276],{"class":275},[266,1445,1446],{"class":271}," sales.set_index(",[266,1448,1134],{"class":282},[266,1450,1451],{"class":271},").groupby(",[266,1453,650],{"class":282},[266,1455,1193],{"class":271},[266,1457,664],{"class":282},[266,1459,1460],{"class":271},"].resample(",[266,1462,1463],{"class":282},"\"MS\"",[266,1465,1466],{"class":271},").sum().unstack(",[266,1468,51],{"class":294},[266,1470,298],{"class":271},[266,1472,1473],{"class":92,"line":390},[266,1474,440],{"emptyLinePlaceholder":439},[266,1476,1477,1480,1482,1485,1488,1490,1492,1495,1497,1499,1502,1505,1507,1509],{"class":92,"line":417},[266,1478,1479],{"class":271},"fig, ax ",[266,1481,276],{"class":275},[266,1483,1484],{"class":271}," plt.subplots(",[266,1486,1487],{"class":288},"figsize",[266,1489,276],{"class":275},[266,1491,720],{"class":271},[266,1493,1494],{"class":294},"6",[266,1496,213],{"class":271},[266,1498,1233],{"class":294},[266,1500,1501],{"class":271},"), ",[266,1503,1504],{"class":288},"dpi",[266,1506,276],{"class":275},[266,1508,58],{"class":294},[266,1510,298],{"class":271},[266,1512,1513,1516,1519,1521,1524,1527,1529,1532,1534,1537,1539,1542],{"class":92,"line":436},[266,1514,1515],{"class":271},"monthly.plot(",[266,1517,1518],{"class":288},"ax",[266,1520,276],{"class":275},[266,1522,1523],{"class":271},"ax, ",[266,1525,1526],{"class":288},"marker",[266,1528,276],{"class":275},[266,1530,1531],{"class":282},"\"o\"",[266,1533,213],{"class":271},[266,1535,1536],{"class":288},"linewidth",[266,1538,276],{"class":275},[266,1540,1541],{"class":294},"1.8",[266,1543,298],{"class":271},[266,1545,1546,1549,1552,1554,1557,1559,1562,1564,1567,1569,1571],{"class":92,"line":443},[266,1547,1548],{"class":271},"ax.set_title(",[266,1550,1551],{"class":282},"\"Revenue by month and region\"",[266,1553,213],{"class":271},[266,1555,1556],{"class":288},"loc",[266,1558,276],{"class":275},[266,1560,1561],{"class":282},"\"left\"",[266,1563,213],{"class":271},[266,1565,1566],{"class":288},"fontsize",[266,1568,276],{"class":275},[266,1570,60],{"class":294},[266,1572,298],{"class":271},[266,1574,1575,1578,1581],{"class":92,"line":714},[266,1576,1577],{"class":271},"ax.set_xlabel(",[266,1579,1580],{"class":282},"\"\"",[266,1582,298],{"class":271},[266,1584,1585,1588,1591,1593,1596,1599,1601],{"class":92,"line":849},[266,1586,1587],{"class":271},"ax.spines[[",[266,1589,1590],{"class":282},"\"top\"",[266,1592,213],{"class":271},[266,1594,1595],{"class":282},"\"right\"",[266,1597,1598],{"class":271},"]].set_visible(",[266,1600,709],{"class":294},[266,1602,298],{"class":271},[266,1604,1605],{"class":92,"line":868},[266,1606,1607],{"class":271},"fig.tight_layout()\n",[266,1609,1610],{"class":92,"line":873},[266,1611,1612],{"class":271},"fig\n",[10,1614,1615,1616,459],{},"The value of Python charts is in what Excel's gallery cannot do: small multiples, distributions, regression and density overlays. For simple\nbar and line charts that readers need to hover over, spill the numbers as Excel values and insert a native chart — it is interactive and does\nnot need a cloud round trip to redraw. Both routes are compared in\n",[24,1617,188],{"href":187},[161,1619,1621],{"id":1620},"when-formulas-fail","When formulas fail",[10,1623,1624,1625,1628,1629,1632,1633,1636,1637,1640,1641,1643,1644,213,1647,1650,1651,1654,1655,1658,1659,223,1662,1665],{},"Python formulas report failures as error values, and each points at a different layer. ",[19,1626,1627],{},"#PYTHON!"," is an exception in your code; right-click\nthe cell and open ",[236,1630,1631],{},"Diagnostics for this cell"," to see the message and line number, along with anything printed. ",[19,1634,1635],{},"#CALC!"," concerns the data —\nover the 100 MB limit for one calculation, or a volatile input such as ",[19,1638,1639],{},"RAND()",". ",[19,1642,1058],{}," means the result has no room. ",[19,1645,1646],{},"#BUSY!",[19,1648,1649],{},"#CONNECT!","\nand ",[19,1652,1653],{},"#TIMEOUT!"," come from the cloud runtime; ",[236,1656,1657],{},"Formulas → Reset runtime"," (Ctrl+Alt+Shift+F9) fixes most of them, and the timeout is adjustable\nin Excel's advanced options. ",[19,1660,1661],{},"#BLOCKED!",[19,1663,1664],{},"#UNKNOWN!"," are about access and client support rather than code.",[10,1667,1668],{},"For formulas that other people's data feeds, check inputs first and return a readable message rather than letting an exception reach the cell:",[257,1670,1672],{"className":259,"code":1671,"language":261,"meta":262,"style":262},"sales = xl(\"Sales[#All]\", headers=True)\nmissing = {\"Date\", \"Region\", \"Amount\"} - set(sales.columns)\nf\"Missing columns: {sorted(missing)}\" if missing else sales.groupby(\"Region\")[\"Amount\"].sum().round(0)\n",[19,1673,1674,1694,1725],{"__ignoreMap":262},[266,1675,1676,1678,1680,1682,1684,1686,1688,1690,1692],{"class":92,"line":268},[266,1677,272],{"class":271},[266,1679,276],{"class":275},[266,1681,279],{"class":271},[266,1683,283],{"class":282},[266,1685,213],{"class":271},[266,1687,289],{"class":288},[266,1689,276],{"class":275},[266,1691,295],{"class":294},[266,1693,298],{"class":271},[266,1695,1696,1699,1701,1704,1706,1708,1710,1712,1714,1717,1719,1722],{"class":92,"line":301},[266,1697,1698],{"class":271},"missing ",[266,1700,276],{"class":275},[266,1702,1703],{"class":271}," {",[266,1705,1134],{"class":282},[266,1707,213],{"class":271},[266,1709,650],{"class":282},[266,1711,213],{"class":271},[266,1713,664],{"class":282},[266,1715,1716],{"class":271},"} ",[266,1718,887],{"class":275},[266,1720,1721],{"class":294}," set",[266,1723,1724],{"class":271},"(sales.columns)\n",[266,1726,1727,1730,1733,1737,1740,1743,1746,1749,1752,1755,1758,1761,1763,1765,1767,1770,1772],{"class":92,"line":390},[266,1728,1729],{"class":275},"f",[266,1731,1732],{"class":282},"\"Missing columns: ",[266,1734,1736],{"class":1735},"sSjpA","{",[266,1738,1739],{"class":294},"sorted",[266,1741,1742],{"class":271},"(missing)",[266,1744,1745],{"class":1735},"}",[266,1747,1748],{"class":282},"\"",[266,1750,1751],{"class":275}," if",[266,1753,1754],{"class":271}," missing ",[266,1756,1757],{"class":275},"else",[266,1759,1760],{"class":271}," sales.groupby(",[266,1762,650],{"class":282},[266,1764,1193],{"class":271},[266,1766,664],{"class":282},[266,1768,1769],{"class":271},"].sum().round(",[266,1771,51],{"class":294},[266,1773,298],{"class":271},[10,1775,1776,1777,459],{},"The complete list, with causes and fixes, is in ",[24,1778,195],{"href":194},[161,1780,1782],{"id":1781},"debugging-a-formula-step-by-step","Debugging a formula step by step",[10,1784,1785],{},"There is no breakpoint in a cell, but the last-expression rule gives you something almost as good: whatever you put on the final line is\nwhat you see. When a long formula produces a wrong number, temporarily end it earlier — on the intermediate frame, its shape, or its\ndtypes — and move the inspection point down one step at a time until the result stops making sense.",[257,1787,1789],{"className":259,"code":1788,"language":261,"meta":262,"style":262},"sales = xl(\"Sales[#All]\", headers=True)\nfiltered = sales[sales[\"Date\"] >= \"2026-03-01\"]\nby_rep = filtered.groupby(\"Rep\")[\"Amount\"].sum()\n\n# Inspection lines — keep exactly one of them last while debugging:\n# sales.dtypes\n# filtered.shape\npd.DataFrame({\"rows in\": [len(sales)], \"rows after filter\": [len(filtered)], \"reps\": [by_rep.size]})\n",[19,1790,1791,1811,1833,1852,1856,1861,1866,1871],{"__ignoreMap":262},[266,1792,1793,1795,1797,1799,1801,1803,1805,1807,1809],{"class":92,"line":268},[266,1794,272],{"class":271},[266,1796,276],{"class":275},[266,1798,279],{"class":271},[266,1800,283],{"class":282},[266,1802,213],{"class":271},[266,1804,289],{"class":288},[266,1806,276],{"class":275},[266,1808,295],{"class":294},[266,1810,298],{"class":271},[266,1812,1813,1816,1818,1821,1823,1825,1828,1831],{"class":92,"line":301},[266,1814,1815],{"class":271},"filtered ",[266,1817,276],{"class":275},[266,1819,1820],{"class":271}," sales[sales[",[266,1822,1134],{"class":282},[266,1824,653],{"class":271},[266,1826,1827],{"class":275},">=",[266,1829,1830],{"class":282}," \"2026-03-01\"",[266,1832,667],{"class":271},[266,1834,1835,1838,1840,1843,1845,1847,1849],{"class":92,"line":390},[266,1836,1837],{"class":271},"by_rep ",[266,1839,276],{"class":275},[266,1841,1842],{"class":271}," filtered.groupby(",[266,1844,975],{"class":282},[266,1846,1193],{"class":271},[266,1848,664],{"class":282},[266,1850,1851],{"class":271},"].sum()\n",[266,1853,1854],{"class":92,"line":417},[266,1855,440],{"emptyLinePlaceholder":439},[266,1857,1858],{"class":92,"line":436},[266,1859,1860],{"class":368},"# Inspection lines — keep exactly one of them last while debugging:\n",[266,1862,1863],{"class":92,"line":443},[266,1864,1865],{"class":368},"# sales.dtypes\n",[266,1867,1868],{"class":92,"line":714},[266,1869,1870],{"class":368},"# filtered.shape\n",[266,1872,1873,1876,1879,1882,1884,1887,1890,1892,1894,1897,1900],{"class":92,"line":849},[266,1874,1875],{"class":271},"pd.DataFrame({",[266,1877,1878],{"class":282},"\"rows in\"",[266,1880,1881],{"class":271},": [",[266,1883,446],{"class":294},[266,1885,1886],{"class":271},"(sales)], ",[266,1888,1889],{"class":282},"\"rows after filter\"",[266,1891,1881],{"class":271},[266,1893,446],{"class":294},[266,1895,1896],{"class":271},"(filtered)], ",[266,1898,1899],{"class":282},"\"reps\"",[266,1901,1902],{"class":271},": [by_rep.size]})\n",[10,1904,1905,1906,1909],{},"A one-row summary frame like the one above answers the usual questions at a glance: did the reference return the rows you expected, did the\nfilter keep a sensible number, and did the grouping produce the right number of keys. ",[19,1907,1908],{},"print()"," works too, with its output going to the\nDiagnostics pane, which is handy when you want to inspect several values without changing what the cell returns. Once the formula is right,\nremove the inspection lines so the cell returns its real result again.",[161,1911,1913],{"id":1912},"limits-that-shape-what-you-build","Limits that shape what you build",[10,1915,1916],{},"A few constraints are fundamental rather than temporary, and they should guide design from the start.",[166,1918,1919,1925,1931,1937],{},[169,1920,1921,1924],{},[236,1922,1923],{},"It needs Excel and the cloud."," Formulas calculate only in supported Excel clients with an internet connection. Someone opening the file\non a mobile app, an unsupported licence or without connectivity sees error values.",[169,1926,1927,1930],{},[236,1928,1929],{},"It runs when the workbook calculates."," Nothing happens unless the file is open and calculating, so it cannot produce a report on a\nschedule by itself.",[169,1932,1933,1936],{},[236,1934,1935],{},"It is sandboxed."," No local files, no network, no package installs, and a 100 MB ceiling on the data in one calculation.",[169,1938,1939,1942],{},[236,1940,1941],{},"Code lives in cells."," That is convenient for one analyst and awkward for review, version control and testing as a workbook grows.",[30,1944,39,1950,39,1953,39,1956,39,1960,39,1964,39,1968,39,1971,39,1975,39,1978,39,1981,39,1986,39,1990,39,1994,39,1999,39,2003,39,2005,39,2008,39,2011,39,2015,39,2019,39,2022,39,2025,39,2027,39,2030,39,2035,39,2039,39,2043,39,2046,39,2049],{"viewBox":1945,"role":33,"ariaLabelledBy":1946,"xmlns":37,"style":1949},"0 0 760 282",[1947,1948],"pie-choose-t","pie-choose-d","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[41,1951,1952],{"id":1947},"Deciding between Python in Excel and a script",[45,1954,1955],{"id":1948},"If a person is exploring data already in the workbook, use Python in Excel. If the job must run on a schedule or reach external systems, use a pandas and openpyxl script. If a step needs Excel itself to recalculate, refresh or run macros, use xlwings.",[49,1957],{"x":51,"y":51,"width":1958,"height":1959,"fill":54},"760","282",[49,1961],{"x":1962,"y":57,"width":1963,"height":478,"rx":479,"fill":84,"stroke":85,"style":63},"220","320",[65,1965,1967],{"x":474,"y":478,"style":1966},"font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","what does the job need?",[92,1969],{"x1":474,"y1":1970,"x2":474,"y2":1336,"stroke":85,"style":63},"72",[92,1972],{"x1":1973,"y1":1336,"x2":1974,"y2":1336,"stroke":85,"style":63},"133.3","626.7",[92,1976],{"x1":1973,"y1":1336,"x2":1973,"y2":1977,"stroke":85,"style":63},"124",[113,1979],{"points":1980,"fill":116},"133.3,127 128.3,118 138.3,118",[49,1982],{"x":57,"y":1983,"width":1984,"height":1985,"rx":479,"fill":84,"stroke":85,"style":63},"128","226.7","104",[65,1987,1989],{"x":1973,"y":58,"style":1988},"font-size:11px;font-weight:600;fill:var(--brand-strong,#4338ca);text-anchor:middle","person exploring",[65,1991,1993],{"x":1973,"y":1992,"style":1966},"174","Python in Excel",[65,1995,1998],{"x":1973,"y":1996,"style":1997},"196","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","data already in",[65,2000,2002],{"x":1973,"y":2001,"style":1997},"216","the workbook",[92,2004],{"x1":474,"y1":1336,"x2":474,"y2":1977,"stroke":85,"style":63},[113,2006],{"points":2007,"fill":116},"380,127 375,118 385,118",[49,2009],{"x":2010,"y":1983,"width":1984,"height":1985,"rx":479,"fill":61,"stroke":62,"style":63},"266.7",[65,2012,2014],{"x":474,"y":58,"style":2013},"font-size:11px;font-weight:600;fill:var(--teal-ink,#0b6157);text-anchor:middle","schedule or external data",[65,2016,2018],{"x":474,"y":1992,"style":2017},"font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","pandas + openpyxl",[65,2020,2021],{"x":474,"y":1996,"style":1997},"script, no Excel",[65,2023,2024],{"x":474,"y":2001,"style":1997},"needed to run",[92,2026],{"x1":1974,"y1":1336,"x2":1974,"y2":1977,"stroke":85,"style":63},[113,2028],{"points":2029,"fill":116},"626.7,127 621.7,118 631.7,118",[49,2031],{"x":2032,"y":1983,"width":1984,"height":1985,"rx":479,"fill":2033,"stroke":2034,"style":63},"513.3","#fdefd8","var(--gold,#b4740a)",[65,2036,2038],{"x":1974,"y":58,"style":2037},"font-size:11px;font-weight:600;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Excel itself",[65,2040,2042],{"x":1974,"y":1992,"style":2041},"font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","xlwings",[65,2044,2045],{"x":1974,"y":1996,"style":1997},"recalc, refresh,",[65,2047,2048],{"x":1974,"y":2001,"style":1997},"macros",[65,2050,2052],{"x":474,"y":2051,"style":158},"266","many setups use a script for data and =PY for analysis",[10,2054,2055,2056,2058,2059,459],{},"Those limits are exactly the strengths of the rest of this site's tooling. A scheduled pandas and openpyxl script can pull from a database at\n06:00, build a formatted workbook with an Excel table in it, and deliver it; analysts can then add ",[19,2057,21],{}," formulas on top for exploration. The\ncomparison, with the same report built three ways, is in\n",[24,2060,202],{"href":201},[161,2062,2064],{"id":2063},"a-worked-example-a-regional-review-sheet","A worked example: a regional review sheet",[10,2066,2067],{},"Putting the pieces together, here is a compact review sheet built from four formulas. Each is shown with the cell it lives in; together they follow\nthe load-then-output structure and the calculation order described above.",[257,2069,2071],{"className":259,"code":2070,"language":261,"meta":262,"style":262},"# A1 — load (Python object)\nsales = xl(\"Sales[#All]\", headers=True)\nbudget = xl(\"Budget[#All]\", headers=True)\nsales[\"Quarter\"] = sales[\"Date\"].dt.to_period(\"Q\").astype(str)\nsales\n\n# A3 — actual against budget by region (Excel values)\nactual = sales.groupby(\"Region\", as_index=False)[\"Amount\"].sum()\nreview = actual.merge(budget, on=\"Region\", how=\"left\")\nreview[\"Variance\"] = review[\"Amount\"] - review[\"Budget\"]\nreview[\"Variance %\"] = (review[\"Variance\"] \u002F review[\"Budget\"]).round(3)\nreview\n\n# F3 — headline number (Excel value)\nfloat(review[\"Variance\"].sum())\n\n# A10 — quarterly trend per region (image)\nfig, ax = plt.subplots(figsize=(6, 3), dpi=150)\nsales.pivot_table(index=\"Quarter\", columns=\"Region\", values=\"Amount\", aggfunc=\"sum\").plot(kind=\"bar\", ax=ax)\nax.set_title(\"Revenue by quarter\", loc=\"left\", fontsize=10)\nax.spines[[\"top\", \"right\"]].set_visible(False)\nfig.tight_layout()\nfig\n",[19,2072,2073,2078,2098,2120,2146,2150,2154,2159,2184,2210,2238,2270,2276,2281,2287,2300,2305,2311,2342,2402,2428,2445,2450],{"__ignoreMap":262},[266,2074,2075],{"class":92,"line":268},[266,2076,2077],{"class":368},"# A1 — load (Python object)\n",[266,2079,2080,2082,2084,2086,2088,2090,2092,2094,2096],{"class":92,"line":301},[266,2081,272],{"class":271},[266,2083,276],{"class":275},[266,2085,279],{"class":271},[266,2087,283],{"class":282},[266,2089,213],{"class":271},[266,2091,289],{"class":288},[266,2093,276],{"class":275},[266,2095,295],{"class":294},[266,2097,298],{"class":271},[266,2099,2100,2103,2105,2107,2110,2112,2114,2116,2118],{"class":92,"line":390},[266,2101,2102],{"class":271},"budget ",[266,2104,276],{"class":275},[266,2106,279],{"class":271},[266,2108,2109],{"class":282},"\"Budget[#All]\"",[266,2111,213],{"class":271},[266,2113,289],{"class":288},[266,2115,276],{"class":275},[266,2117,295],{"class":294},[266,2119,298],{"class":271},[266,2121,2122,2124,2127,2129,2131,2133,2135,2137,2140,2142,2144],{"class":92,"line":417},[266,2123,1121],{"class":271},[266,2125,2126],{"class":282},"\"Quarter\"",[266,2128,653],{"class":271},[266,2130,276],{"class":275},[266,2132,1131],{"class":271},[266,2134,1134],{"class":282},[266,2136,1137],{"class":271},[266,2138,2139],{"class":282},"\"Q\"",[266,2141,1143],{"class":271},[266,2143,812],{"class":294},[266,2145,298],{"class":271},[266,2147,2148],{"class":92,"line":436},[266,2149,1211],{"class":271},[266,2151,2152],{"class":92,"line":443},[266,2153,440],{"emptyLinePlaceholder":439},[266,2155,2156],{"class":92,"line":714},[266,2157,2158],{"class":368},"# A3 — actual against budget by region (Excel values)\n",[266,2160,2161,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182],{"class":92,"line":849},[266,2162,2163],{"class":271},"actual ",[266,2165,276],{"class":275},[266,2167,1760],{"class":271},[266,2169,650],{"class":282},[266,2171,213],{"class":271},[266,2173,1186],{"class":288},[266,2175,276],{"class":275},[266,2177,709],{"class":294},[266,2179,1193],{"class":271},[266,2181,664],{"class":282},[266,2183,1851],{"class":271},[266,2185,2186,2189,2191,2194,2196,2198,2200,2202,2204,2206,2208],{"class":92,"line":868},[266,2187,2188],{"class":271},"review ",[266,2190,276],{"class":275},[266,2192,2193],{"class":271}," actual.merge(budget, ",[266,2195,16],{"class":288},[266,2197,276],{"class":275},[266,2199,650],{"class":282},[266,2201,213],{"class":271},[266,2203,781],{"class":288},[266,2205,276],{"class":275},[266,2207,1561],{"class":282},[266,2209,298],{"class":271},[266,2211,2212,2215,2218,2220,2222,2225,2227,2229,2231,2233,2236],{"class":92,"line":873},[266,2213,2214],{"class":271},"review[",[266,2216,2217],{"class":282},"\"Variance\"",[266,2219,653],{"class":271},[266,2221,276],{"class":275},[266,2223,2224],{"class":271}," review[",[266,2226,664],{"class":282},[266,2228,653],{"class":271},[266,2230,887],{"class":275},[266,2232,2224],{"class":271},[266,2234,2235],{"class":282},"\"Budget\"",[266,2237,667],{"class":271},[266,2239,2240,2242,2245,2247,2249,2252,2254,2256,2259,2261,2263,2266,2268],{"class":92,"line":895},[266,2241,2214],{"class":271},[266,2243,2244],{"class":282},"\"Variance %\"",[266,2246,653],{"class":271},[266,2248,276],{"class":275},[266,2250,2251],{"class":271}," (review[",[266,2253,2217],{"class":282},[266,2255,653],{"class":271},[266,2257,2258],{"class":275},"\u002F",[266,2260,2224],{"class":271},[266,2262,2235],{"class":282},[266,2264,2265],{"class":271},"]).round(",[266,2267,1233],{"class":294},[266,2269,298],{"class":271},[266,2271,2273],{"class":92,"line":2272},12,[266,2274,2275],{"class":271},"review\n",[266,2277,2279],{"class":92,"line":2278},13,[266,2280,440],{"emptyLinePlaceholder":439},[266,2282,2284],{"class":92,"line":2283},14,[266,2285,2286],{"class":368},"# F3 — headline number (Excel value)\n",[266,2288,2290,2292,2295,2297],{"class":92,"line":2289},15,[266,2291,723],{"class":294},[266,2293,2294],{"class":271},"(review[",[266,2296,2217],{"class":282},[266,2298,2299],{"class":271},"].sum())\n",[266,2301,2303],{"class":92,"line":2302},16,[266,2304,440],{"emptyLinePlaceholder":439},[266,2306,2308],{"class":92,"line":2307},17,[266,2309,2310],{"class":368},"# A10 — quarterly trend per region (image)\n",[266,2312,2314,2316,2318,2320,2322,2324,2326,2328,2330,2332,2334,2336,2338,2340],{"class":92,"line":2313},18,[266,2315,1479],{"class":271},[266,2317,276],{"class":275},[266,2319,1484],{"class":271},[266,2321,1487],{"class":288},[266,2323,276],{"class":275},[266,2325,720],{"class":271},[266,2327,1494],{"class":294},[266,2329,213],{"class":271},[266,2331,1233],{"class":294},[266,2333,1501],{"class":271},[266,2335,1504],{"class":288},[266,2337,276],{"class":275},[266,2339,58],{"class":294},[266,2341,298],{"class":271},[266,2343,2345,2348,2351,2353,2355,2357,2360,2362,2364,2366,2369,2371,2373,2375,2378,2380,2382,2385,2388,2390,2393,2395,2397,2399],{"class":92,"line":2344},19,[266,2346,2347],{"class":271},"sales.pivot_table(",[266,2349,2350],{"class":288},"index",[266,2352,276],{"class":275},[266,2354,2126],{"class":282},[266,2356,213],{"class":271},[266,2358,2359],{"class":288},"columns",[266,2361,276],{"class":275},[266,2363,650],{"class":282},[266,2365,213],{"class":271},[266,2367,2368],{"class":288},"values",[266,2370,276],{"class":275},[266,2372,664],{"class":282},[266,2374,213],{"class":271},[266,2376,2377],{"class":288},"aggfunc",[266,2379,276],{"class":275},[266,2381,995],{"class":282},[266,2383,2384],{"class":271},").plot(",[266,2386,2387],{"class":288},"kind",[266,2389,276],{"class":275},[266,2391,2392],{"class":282},"\"bar\"",[266,2394,213],{"class":271},[266,2396,1518],{"class":288},[266,2398,276],{"class":275},[266,2400,2401],{"class":271},"ax)\n",[266,2403,2405,2407,2410,2412,2414,2416,2418,2420,2422,2424,2426],{"class":92,"line":2404},20,[266,2406,1548],{"class":271},[266,2408,2409],{"class":282},"\"Revenue by quarter\"",[266,2411,213],{"class":271},[266,2413,1556],{"class":288},[266,2415,276],{"class":275},[266,2417,1561],{"class":282},[266,2419,213],{"class":271},[266,2421,1566],{"class":288},[266,2423,276],{"class":275},[266,2425,60],{"class":294},[266,2427,298],{"class":271},[266,2429,2431,2433,2435,2437,2439,2441,2443],{"class":92,"line":2430},21,[266,2432,1587],{"class":271},[266,2434,1590],{"class":282},[266,2436,213],{"class":271},[266,2438,1595],{"class":282},[266,2440,1598],{"class":271},[266,2442,709],{"class":294},[266,2444,298],{"class":271},[266,2446,2448],{"class":92,"line":2447},22,[266,2449,1607],{"class":271},[266,2451,2453],{"class":92,"line":2452},23,[266,2454,1612],{"class":271},[10,2456,2457,2458,223,2460,2463,2464,2467],{},"Every number on the sheet traces back to two tables, ",[19,2459,310],{},[19,2461,2462],{},"Budget",". When next month's rows are added to either table, the whole sheet\nrecalculates, which is the core promise of Python in Excel: analysis that stays live without anyone rerunning a script. Format the ",[19,2465,2466],{},"Variance %","\nspill as a percentage and add a conditional format to the variance column, and the sheet reads like a hand-built report.",[10,2469,2470,2471,459],{},"Before sending a sheet like this to anyone outside your team, decide what they should receive. People with Python in Excel can open the live\nworkbook and see it recalculate. Everyone else is better served by a copy in which the spilled blocks have been pasted as values and the chart\nimages placed over the cells, so nothing depends on their Excel client. If that copy has to be produced every month, that is the point at which\nthe reporting half of the job should move into a script that builds the file directly, as described in\n",[24,2472,2474],{"href":2473},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002F","Generating Excel Reports from Templates",[161,2476,2478],{"id":2477},"key-takeaways","Key takeaways",[166,2480,2481,2486,2491,2501,2504,2507,2510,2522],{},[169,2482,1238,2483,2485],{},[19,2484,21],{}," formula runs in a Microsoft cloud container and returns its last expression to the cell.",[169,2487,2488,2490],{},[19,2489,254],{}," is the only data path: cells, ranges, tables, names and Power Query queries in the same workbook.",[169,2492,2493,2494,2497,2498,2500],{},"Use ",[19,2495,2496],{},"Table[#All]"," with ",[19,2499,334],{}," as the default reference, so formulas see new rows.",[169,2502,2503],{},"Keep intermediate results as Python objects; publish final views as Excel values and format them in the grid.",[169,2505,2506],{},"Calculation runs across each row, then down, sheet by sheet — define before you use.",[169,2508,2509],{},"Return explicit matplotlib figures for charts; use native charts where interactivity matters.",[169,2511,2512,2513,2515,2516,213,2518,223,2520,459],{},"Read ",[19,2514,1627],{}," in the Diagnostics pane; reset the runtime for ",[19,2517,1646],{},[19,2519,1649],{},[19,2521,1653],{},[169,2523,2524],{},"Scheduled, external or package-heavy work belongs in a script; exploration of workbook data belongs in cells.",[161,2526,2528],{"id":2527},"frequently-asked-questions","Frequently asked questions",[10,2530,2531,2534],{},[236,2532,2533],{},"Does Python in Excel run on my computer?","\nNo. The code runs in a Microsoft cloud container. Excel sends the formula and the referenced data, and receives the result, which is why an internet connection is required.",[10,2536,2537,2540],{},[236,2538,2539],{},"Can I use my own Python packages?","\nNo. The runtime offers a curated distribution with common analysis libraries, and packages cannot be installed. Custom code has to be written in the workbook's cells.",[10,2542,2543,2546],{},[236,2544,2545],{},"Can Python in Excel read a CSV file or a database?","\nNot from the formula. Load the CSV or database table with Power Query and reference the query with xl(); refreshing the query updates the Python results.",[10,2548,2549,2552],{},[236,2550,2551],{},"Will colleagues without Python in Excel see my results?","\nThey see the last results only if you convert them to static values. In unsupported clients, live Python formulas show error values instead.",[10,2554,2555,2558],{},[236,2556,2557],{},"Is it a replacement for VBA macros?","\nNot really. Python formulas compute results for cells; they do not automate the application, respond to buttons or modify other cells. VBA, Office Scripts or an external tool such as xlwings still handle automation.",[10,2560,2561,2564],{},[236,2562,2563],{},"How do I share code between workbooks?","\nThere is no import mechanism for your own modules. Copy helper functions into a load cell, or move shared logic into a script-based workflow where it can be packaged and versioned.",[161,2566,2568],{"id":2567},"related","Related",[166,2570,2571,2577,2581,2585,2589,2593,2597,2604,2611],{},[169,2572,2573,2574,2576],{},"Up one level: ",[24,2575,27],{"href":26}," — every way Python and Excel work together.",[169,2578,2579],{},[24,2580,174],{"href":173},[169,2582,2583],{},[24,2584,181],{"href":180},[169,2586,2587],{},[24,2588,188],{"href":187},[169,2590,2591],{},[24,2592,195],{"href":194},[169,2594,2595],{},[24,2596,202],{"href":201},[169,2598,2599,2603],{},[24,2600,2602],{"href":2601},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002F","Choosing a Python Excel Library"," — the script-side libraries compared.",[169,2605,2606,2610],{},[24,2607,2609],{"href":2608},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002F","Automating Excel With xlwings: The Basics"," — driving Excel from a local script.",[169,2612,2613,2617],{},[24,2614,2616],{"href":2615},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002F","Excel Formula Equivalents in pandas"," — the pandas idioms most =PY formulas are built from.",[10,2619,2620],{},"More in this section:",[166,2622,2623,2629],{},[169,2624,2625],{},[24,2626,2628],{"href":2627},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fforecast-a-time-series-with-python-in-excel\u002F","Forecast a Time Series with Python in Excel",[169,2630,2631],{},[24,2632,2634],{"href":2633},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Frun-a-regression-with-python-in-excel\u002F","Run a Regression with Python in Excel",[2636,2637,2638],"style",{},"html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}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-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}",{"title":262,"searchDepth":301,"depth":301,"links":2640},[2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655],{"id":163,"depth":301,"text":164},{"id":230,"depth":301,"text":231},{"id":325,"depth":301,"text":326},{"id":538,"depth":301,"text":539},{"id":734,"depth":301,"text":735},{"id":913,"depth":301,"text":914},{"id":1064,"depth":301,"text":1065},{"id":1394,"depth":301,"text":1395},{"id":1620,"depth":301,"text":1621},{"id":1781,"depth":301,"text":1782},{"id":1912,"depth":301,"text":1913},{"id":2063,"depth":301,"text":2064},{"id":2477,"depth":301,"text":2478},{"id":2527,"depth":301,"text":2528},{"id":2567,"depth":301,"text":2568},"2026-09-17","Write =PY formulas that analyse workbook data with pandas, return tables and charts to the grid, and fail clearly — plus where in-cell Python ends and a real automation script begins.","md",[2660,2662,2664,2666,2668,2670],{"q":2533,"a":2661},"No. The code runs in a Microsoft cloud container. Excel sends the formula and the referenced data, and receives the result, which is why an internet connection is required.",{"q":2539,"a":2663},"No. The runtime offers a curated distribution with common analysis libraries, and packages cannot be installed. Custom code has to be written in the workbook's cells.",{"q":2545,"a":2665},"Not from the formula. Load the CSV or database table with Power Query and reference the query with xl(); refreshing the query updates the Python results.",{"q":2551,"a":2667},"They see the last results only if you convert them to static values. In unsupported clients, live Python formulas show error values instead.",{"q":2557,"a":2669},"Not really. Python formulas compute results for cells; they do not automate the application, respond to buttons or modify other cells. VBA, Office Scripts or an external tool such as xlwings still handle automation.",{"q":2563,"a":2671},"There is no import mechanism for your own modules. Copy helper functions into a load cell, or move shared logic into a script-based workflow where it can be packaged and versioned.","using python in excel",null,{"breadcrumb":2675},[2676,2678,2679],{"name":2677,"item":2258},"Home",{"name":27,"item":26},{"name":5,"item":2680},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002F","\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel",{"title":2683,"description":2684},"Using Python in Excel: =PY Formulas, xl(), Charts and Limits","A practical guide to Python in Excel: entering =PY formulas, referencing data with xl(), Python objects versus Excel values, calculation order, charts, errors, limits and when to use a script.","using-python-in-excel","getting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Findex",[2688],"python-in-excel","guide","EeqpYJSc8SGmCrccxMWfUCX20eMVU97kdZIr58hQL_E",[2692,2696],{"title":2693,"path":2694,"stem":2695,"children":-1},"What openpyxl Loses When You Save an Existing Workbook","\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook","getting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook\u002Findex",{"title":2697,"path":2698,"stem":2699,"children":-1},"Clean Data with pandas in Python in Excel","\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fclean-data-with-pandas-in-python-in-excel","getting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fclean-data-with-pandas-in-python-in-excel\u002Findex",[2701],{"path":2702,"title":27},"\u002Fgetting-started-with-python-excel-automation",[2704,2706],{"path":2698,"title":2697,"kind":2705},"how-to",{"path":2707,"title":2708,"kind":2705},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fget-external-data-into-python-in-excel","Get External Data into Python in Excel with Power Query",[2710,2713,2715,2717,2720,2722],{"path":2711,"title":195,"kind":2712},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Ffix-python-in-excel-errors","fix",{"path":2714,"title":2628,"kind":2705},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fforecast-a-time-series-with-python-in-excel",{"path":2716,"title":188,"kind":2705},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fplot-charts-with-matplotlib-in-python-in-excel",{"path":2718,"title":202,"kind":2719},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Fpython-in-excel-vs-openpyxl-and-xlwings","compare",{"path":2721,"title":174,"kind":2705},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Freference-cells-ranges-and-tables-with-xl-in-python-in-excel",{"path":2723,"title":181,"kind":2705},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-python-in-excel\u002Freturn-dataframes-and-values-from-python-in-excel-cells",1790972053407]