[{"data":1,"prerenderedAt":1822},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas":1786,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas":1795,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas":1800,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas":1801},{"id":4,"title":5,"body":6,"dateModified":1751,"datePublished":1751,"description":1752,"extension":1753,"faq":1754,"keyword":1763,"kind":1764,"meta":1765,"navigation":118,"path":1774,"seo":1775,"slug":1778,"stem":1779,"topics":1780,"type":1784,"__hash__":1785},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas\u002Findex.md","Fix Formula Cells Reading as NaN (or 0) in pandas",{"type":7,"value":8,"toc":1736},"minimark",[9,40,45,76,83,87,90,352,363,545,549,552,836,847,851,854,948,966,1098,1102,1105,1160,1168,1172,1179,1367,1378,1382,1389,1426,1457,1461,1464,1591,1594,1598,1605,1609,1658,1662,1671,1675,1681,1687,1693,1699,1703,1732],[10,11,12,13,17,18,21,22,25,26,28,29,33,34,39],"p",{},"A report job writes a workbook with a ",[14,15,16],"code",{},"Total"," column of formulas. A second job reads that workbook with ",[14,19,20],{},"pd.read_excel"," and gets ",[14,23,24],{},"NaN"," in every ",[14,27,16],{}," cell — or, depending on which library wrote it, a column of zeros. Open the file in Excel and the totals are all there. Nothing is wrong with pandas: it never calculates formulas, it reads the result that the last spreadsheet application ",[30,31,32],"em",{},"stored"," next to each formula. A workbook written by Python has never been opened by a spreadsheet application, so that stored result is missing or a placeholder. This page shows how to confirm the diagnosis and the three ways to fix it. It belongs to ",[35,36,38],"a",{"href":37},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",".",[41,42,44],"h2",{"id":43},"prerequisites","Prerequisites",[46,47,52],"pre",{"className":48,"code":49,"language":50,"meta":51,"style":51},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl xlsxwriter\n","bash","",[14,53,54],{"__ignoreMap":51},[55,56,59,63,67,70,73],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"sMTad","pip",[55,64,66],{"class":65},"srMev"," install",[55,68,69],{"class":65}," pandas",[55,71,72],{"class":65}," openpyxl",[55,74,75],{"class":65}," xlsxwriter\n",[10,77,78,79,82],{},"LibreOffice (",[14,80,81],{},"soffice",") is needed only for the recalculation fix in Step 3.",[41,84,86],{"id":85},"step-1-reproduce-the-symptom","Step 1 — Reproduce the symptom",[10,88,89],{},"Write the same small workbook with both engines and read it back:",[46,91,95],{"className":92,"code":93,"language":94,"meta":51,"style":51},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\norders = pd.DataFrame({\"Qty\": [3, 5, 12], \"Price\": [89.0, 45.5, 14.0]})\norders[\"Total\"] = [f\"=A{r}*B{r}\" for r in range(2, len(orders) + 2)]\nfor engine in (\"openpyxl\", \"xlsxwriter\"):\n    orders.to_excel(f\"orders_{engine}.xlsx\", index=False, engine=engine)\n    print(engine, pd.read_excel(f\"orders_{engine}.xlsx\")[\"Total\"].tolist())\n","python",[14,96,97,113,120,177,257,282,323],{"__ignoreMap":51},[55,98,99,103,107,110],{"class":57,"line":58},[55,100,102],{"class":101},"s-kum","import",[55,104,106],{"class":105},"skGVy"," pandas ",[55,108,109],{"class":101},"as",[55,111,112],{"class":105}," pd\n",[55,114,116],{"class":57,"line":115},2,[55,117,119],{"emptyLinePlaceholder":118},true,"\n",[55,121,123,126,129,132,135,138,142,145,148,150,153,156,159,161,164,166,169,171,174],{"class":57,"line":122},3,[55,124,125],{"class":105},"orders ",[55,127,128],{"class":101},"=",[55,130,131],{"class":105}," pd.DataFrame({",[55,133,134],{"class":65},"\"Qty\"",[55,136,137],{"class":105},": [",[55,139,141],{"class":140},"sP0c6","3",[55,143,144],{"class":105},", ",[55,146,147],{"class":140},"5",[55,149,144],{"class":105},[55,151,152],{"class":140},"12",[55,154,155],{"class":105},"], ",[55,157,158],{"class":65},"\"Price\"",[55,160,137],{"class":105},[55,162,163],{"class":140},"89.0",[55,165,144],{"class":105},[55,167,168],{"class":140},"45.5",[55,170,144],{"class":105},[55,172,173],{"class":140},"14.0",[55,175,176],{"class":105},"]})\n",[55,178,180,183,186,189,191,194,197,200,204,207,210,213,215,217,219,222,225,228,231,234,237,240,242,245,248,251,254],{"class":57,"line":179},4,[55,181,182],{"class":105},"orders[",[55,184,185],{"class":65},"\"Total\"",[55,187,188],{"class":105},"] ",[55,190,128],{"class":101},[55,192,193],{"class":105}," [",[55,195,196],{"class":101},"f",[55,198,199],{"class":65},"\"=A",[55,201,203],{"class":202},"sSjpA","{",[55,205,206],{"class":105},"r",[55,208,209],{"class":202},"}",[55,211,212],{"class":65},"*B",[55,214,203],{"class":202},[55,216,206],{"class":105},[55,218,209],{"class":202},[55,220,221],{"class":65},"\"",[55,223,224],{"class":101}," for",[55,226,227],{"class":105}," r ",[55,229,230],{"class":101},"in",[55,232,233],{"class":140}," range",[55,235,236],{"class":105},"(",[55,238,239],{"class":140},"2",[55,241,144],{"class":105},[55,243,244],{"class":140},"len",[55,246,247],{"class":105},"(orders) ",[55,249,250],{"class":101},"+",[55,252,253],{"class":140}," 2",[55,255,256],{"class":105},")]\n",[55,258,260,263,266,268,271,274,276,279],{"class":57,"line":259},5,[55,261,262],{"class":101},"for",[55,264,265],{"class":105}," engine ",[55,267,230],{"class":101},[55,269,270],{"class":105}," (",[55,272,273],{"class":65},"\"openpyxl\"",[55,275,144],{"class":105},[55,277,278],{"class":65},"\"xlsxwriter\"",[55,280,281],{"class":105},"):\n",[55,283,285,288,290,293,295,298,300,303,305,309,311,314,316,318,320],{"class":57,"line":284},6,[55,286,287],{"class":105},"    orders.to_excel(",[55,289,196],{"class":101},[55,291,292],{"class":65},"\"orders_",[55,294,203],{"class":202},[55,296,297],{"class":105},"engine",[55,299,209],{"class":202},[55,301,302],{"class":65},".xlsx\"",[55,304,144],{"class":105},[55,306,308],{"class":307},"sa561","index",[55,310,128],{"class":101},[55,312,313],{"class":140},"False",[55,315,144],{"class":105},[55,317,297],{"class":307},[55,319,128],{"class":101},[55,321,322],{"class":105},"engine)\n",[55,324,326,329,332,334,336,338,340,342,344,347,349],{"class":57,"line":325},7,[55,327,328],{"class":140},"    print",[55,330,331],{"class":105},"(engine, pd.read_excel(",[55,333,196],{"class":101},[55,335,292],{"class":65},[55,337,203],{"class":202},[55,339,297],{"class":105},[55,341,209],{"class":202},[55,343,302],{"class":65},[55,345,346],{"class":105},")[",[55,348,185],{"class":65},[55,350,351],{"class":105},"].tolist())\n",[10,353,354,355,358,359,362],{},"The openpyxl-written file reads as ",[14,356,357],{},"[nan, nan, nan]"," and the XlsxWriter file as ",[14,360,361],{},"[0, 0, 0]",". The second is the more dangerous of the two: zeros look like data, and a downstream sum quietly reports 0 revenue.",[364,365,373,374,373,378,373,382,373,390,373,400,373,411,373,418,373,424,373,430,373,436,373,440,373,445,373,449,373,454,373,459,373,466,373,471,373,475,373,478,373,483,373,486,373,491,373,494,373,499,373,504,373,511,373,516,373,520,373,523,373,529,373,532,373,537,373,540],"svg",{"viewBox":366,"role":367,"ariaLabelledBy":368,"xmlns":371,"style":372},"4 0 752 207","img",[369,370],"nan-why-t","nan-why-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[375,376,377],"title",{"id":369},"What each writer stores next to a formula",[379,380,381],"desc",{"id":370},"Excel and LibreOffice store the formula and its calculated result. XlsxWriter stores the formula with a placeholder result of 0. openpyxl stores the formula with no result. pandas reads the stored result, so it sees the real number, 0, or NaN respectively.",[383,384],"rect",{"x":385,"y":386,"width":387,"height":388,"fill":389},"4","0","752","207","#ffffff",[383,391],{"x":392,"y":393,"width":394,"height":395,"rx":396,"fill":397,"stroke":398,"style":399},"20.0","16.0","228.0","175.0","14","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[401,402,404],"g",{"transform":403},"translate(121.0,29.0) scale(1.083)",[405,406],"path",{"d":407,"fill":408,"stroke":409,"style":410},"M5 12.5l4.5 4.5L19 7","none","var(--teal-ink,#0b6157)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[412,413,417],"text",{"x":414,"y":415,"style":416},"134.0","78.0","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Saved by Excel \u002F LibreOffice",[57,419],{"x1":420,"y1":421,"x2":422,"y2":421,"stroke":398,"style":423},"36.0","91.0","232.0","stroke-width:1px",[412,425,429],{"x":426,"y":427,"style":428},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","formula =A2*B2",[401,431,433],{"transform":432},"translate(38.5,99.5) scale(0.625)",[405,434],{"d":407,"fill":408,"stroke":398,"style":435},"stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[412,437,439],{"x":426,"y":438,"style":428},"137.0","cached result 267",[401,441,443],{"transform":442},"translate(38.5,125.5) scale(0.625)",[405,444],{"d":407,"fill":408,"stroke":398,"style":435},[412,446,448],{"x":426,"y":447,"style":428},"163.0","read_excel: 267",[401,450,452],{"transform":451},"translate(38.5,151.5) scale(0.625)",[405,453],{"d":407,"fill":408,"stroke":398,"style":435},[383,455],{"x":456,"y":393,"width":394,"height":395,"rx":396,"fill":457,"stroke":458,"style":399},"266.0","#fdefd8","var(--gold,#b4740a)",[401,460,462],{"transform":461},"translate(367.0,29.0) scale(1.083)",[405,463],{"d":464,"fill":408,"stroke":465,"style":410},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--gold-ink,#7a4e06)",[412,467,470],{"x":468,"y":415,"style":469},"380.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Written by XlsxWriter",[57,472],{"x1":473,"y1":421,"x2":474,"y2":421,"stroke":458,"style":423},"282.0","478.0",[412,476,429],{"x":477,"y":427,"style":428},"306.0",[401,479,481],{"transform":480},"translate(284.5,99.5) scale(0.625)",[405,482],{"d":464,"fill":408,"stroke":458,"style":435},[412,484,485],{"x":477,"y":438,"style":428},"cached result 0",[401,487,489],{"transform":488},"translate(284.5,125.5) scale(0.625)",[405,490],{"d":464,"fill":408,"stroke":458,"style":435},[412,492,493],{"x":477,"y":447,"style":428},"read_excel: 0",[401,495,497],{"transform":496},"translate(284.5,151.5) scale(0.625)",[405,498],{"d":464,"fill":408,"stroke":458,"style":435},[383,500],{"x":501,"y":393,"width":394,"height":395,"rx":396,"fill":502,"stroke":503,"style":399},"512.0","#fce9e9","var(--danger,#dc2626)",[401,505,507],{"transform":506},"translate(613.0,29.0) scale(1.083)",[405,508],{"d":509,"fill":408,"stroke":510,"style":410},"M6 6l12 12 M18 6L6 18","var(--accent-ink,#be185d)",[412,512,515],{"x":513,"y":415,"style":514},"626.0","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Written by openpyxl",[57,517],{"x1":518,"y1":421,"x2":519,"y2":421,"stroke":503,"style":423},"528.0","724.0",[412,521,429],{"x":522,"y":427,"style":428},"552.0",[401,524,526],{"transform":525},"translate(530.5,99.5) scale(0.625)",[405,527],{"d":509,"fill":408,"stroke":528,"style":435},"var(--accent,#f43f8f)",[412,530,531],{"x":522,"y":438,"style":428},"no cached result",[401,533,535],{"transform":534},"translate(530.5,125.5) scale(0.625)",[405,536],{"d":509,"fill":408,"stroke":528,"style":435},[412,538,539],{"x":522,"y":447,"style":428},"read_excel: NaN",[401,541,543],{"transform":542},"translate(530.5,151.5) scale(0.625)",[405,544],{"d":509,"fill":408,"stroke":528,"style":435},[41,546,548],{"id":547},"step-2-confirm-the-diagnosis","Step 2 — Confirm the diagnosis",[10,550,551],{},"Before changing anything, check that the cells really are formulas without stored results. openpyxl can load a workbook twice — once for formulas, once for cached values — and compare:",[46,553,555],{"className":92,"code":554,"language":94,"meta":51,"style":51},"from openpyxl import load_workbook\n\ndef formulas_without_results(path):\n    f_ws = load_workbook(path).active\n    v_ws = load_workbook(path, data_only=True).active\n    missing, zero = [], []\n    for row_f, row_v in zip(f_ws.iter_rows(), v_ws.iter_rows()):\n        for cf, cv in zip(row_f, row_v):\n            if isinstance(cf.value, str) and cf.value.startswith(\"=\"):\n                if cv.value is None:\n                    missing.append(cf.coordinate)\n                elif cv.value == 0:\n                    zero.append(cf.coordinate)\n    return missing, zero\n\nfor engine in (\"openpyxl\", \"xlsxwriter\"):\n    missing, zero = formulas_without_results(f\"orders_{engine}.xlsx\")\n    print(f\"{engine:10} no result: {missing}  cached 0: {zero}\")\n",[14,556,557,570,574,586,596,617,627,643,659,688,706,712,728,734,743,748,767,792],{"__ignoreMap":51},[55,558,559,562,565,567],{"class":57,"line":58},[55,560,561],{"class":101},"from",[55,563,564],{"class":105}," openpyxl ",[55,566,102],{"class":101},[55,568,569],{"class":105}," load_workbook\n",[55,571,572],{"class":57,"line":115},[55,573,119],{"emptyLinePlaceholder":118},[55,575,576,579,583],{"class":57,"line":122},[55,577,578],{"class":101},"def",[55,580,582],{"class":581},"s_Opv"," formulas_without_results",[55,584,585],{"class":105},"(path):\n",[55,587,588,591,593],{"class":57,"line":179},[55,589,590],{"class":105},"    f_ws ",[55,592,128],{"class":101},[55,594,595],{"class":105}," load_workbook(path).active\n",[55,597,598,601,603,606,609,611,614],{"class":57,"line":259},[55,599,600],{"class":105},"    v_ws ",[55,602,128],{"class":101},[55,604,605],{"class":105}," load_workbook(path, ",[55,607,608],{"class":307},"data_only",[55,610,128],{"class":101},[55,612,613],{"class":140},"True",[55,615,616],{"class":105},").active\n",[55,618,619,622,624],{"class":57,"line":284},[55,620,621],{"class":105},"    missing, zero ",[55,623,128],{"class":101},[55,625,626],{"class":105}," [], []\n",[55,628,629,632,635,637,640],{"class":57,"line":325},[55,630,631],{"class":101},"    for",[55,633,634],{"class":105}," row_f, row_v ",[55,636,230],{"class":101},[55,638,639],{"class":140}," zip",[55,641,642],{"class":105},"(f_ws.iter_rows(), v_ws.iter_rows()):\n",[55,644,646,649,652,654,656],{"class":57,"line":645},8,[55,647,648],{"class":101},"        for",[55,650,651],{"class":105}," cf, cv ",[55,653,230],{"class":101},[55,655,639],{"class":140},[55,657,658],{"class":105},"(row_f, row_v):\n",[55,660,662,665,668,671,674,677,680,683,686],{"class":57,"line":661},9,[55,663,664],{"class":101},"            if",[55,666,667],{"class":140}," isinstance",[55,669,670],{"class":105},"(cf.value, ",[55,672,673],{"class":140},"str",[55,675,676],{"class":105},") ",[55,678,679],{"class":101},"and",[55,681,682],{"class":105}," cf.value.startswith(",[55,684,685],{"class":65},"\"=\"",[55,687,281],{"class":105},[55,689,691,694,697,700,703],{"class":57,"line":690},10,[55,692,693],{"class":101},"                if",[55,695,696],{"class":105}," cv.value ",[55,698,699],{"class":101},"is",[55,701,702],{"class":140}," None",[55,704,705],{"class":105},":\n",[55,707,709],{"class":57,"line":708},11,[55,710,711],{"class":105},"                    missing.append(cf.coordinate)\n",[55,713,715,718,720,723,726],{"class":57,"line":714},12,[55,716,717],{"class":101},"                elif",[55,719,696],{"class":105},[55,721,722],{"class":101},"==",[55,724,725],{"class":140}," 0",[55,727,705],{"class":105},[55,729,731],{"class":57,"line":730},13,[55,732,733],{"class":105},"                    zero.append(cf.coordinate)\n",[55,735,737,740],{"class":57,"line":736},14,[55,738,739],{"class":101},"    return",[55,741,742],{"class":105}," missing, zero\n",[55,744,746],{"class":57,"line":745},15,[55,747,119],{"emptyLinePlaceholder":118},[55,749,751,753,755,757,759,761,763,765],{"class":57,"line":750},16,[55,752,262],{"class":101},[55,754,265],{"class":105},[55,756,230],{"class":101},[55,758,270],{"class":105},[55,760,273],{"class":65},[55,762,144],{"class":105},[55,764,278],{"class":65},[55,766,281],{"class":105},[55,768,770,772,774,777,779,781,783,785,787,789],{"class":57,"line":769},17,[55,771,621],{"class":105},[55,773,128],{"class":101},[55,775,776],{"class":105}," formulas_without_results(",[55,778,196],{"class":101},[55,780,292],{"class":65},[55,782,203],{"class":202},[55,784,297],{"class":105},[55,786,209],{"class":202},[55,788,302],{"class":65},[55,790,791],{"class":105},")\n",[55,793,795,797,799,801,803,805,807,810,812,815,817,820,822,825,827,830,832,834],{"class":57,"line":794},18,[55,796,328],{"class":140},[55,798,236],{"class":105},[55,800,196],{"class":101},[55,802,221],{"class":65},[55,804,203],{"class":202},[55,806,297],{"class":105},[55,808,809],{"class":101},":10",[55,811,209],{"class":202},[55,813,814],{"class":65}," no result: ",[55,816,203],{"class":202},[55,818,819],{"class":105},"missing",[55,821,209],{"class":202},[55,823,824],{"class":65},"  cached 0: ",[55,826,203],{"class":202},[55,828,829],{"class":105},"zero",[55,831,209],{"class":202},[55,833,221],{"class":65},[55,835,791],{"class":105},[10,837,838,839,841,842,846],{},"If the formula cells have no result (or a 0 that cannot be right), this page applies. If they have plausible cached values and pandas still shows ",[14,840,24],{},", the problem is elsewhere — a placeholder string, a merged cell, or the wrong header row — and ",[35,843,845],{"href":844},"\u002Fadvanced-data-transformation-and-cleaning\u002Fhandling-missing-data-in-excel-reports\u002Ffind-and-report-missing-values-in-an-excel-file\u002F","Find and Report Missing Values in an Excel File"," is the better starting point.",[41,848,850],{"id":849},"step-3-fix-1-let-libreoffice-calculate-and-store-the-results","Step 3 — Fix 1: let LibreOffice calculate and store the results",[10,852,853],{},"Opening and saving the file in a spreadsheet engine stores real results next to every formula. LibreOffice does it headlessly:",[46,855,857],{"className":92,"code":856,"language":94,"meta":51,"style":51},"import subprocess\n\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"recalculated\",\n                \"orders_openpyxl.xlsx\"], check=True, capture_output=True)\nprint(pd.read_excel(\"recalculated\u002Forders_openpyxl.xlsx\")[\"Total\"].tolist())\n",[14,858,859,866,870,906,931],{"__ignoreMap":51},[55,860,861,863],{"class":57,"line":58},[55,862,102],{"class":101},[55,864,865],{"class":105}," subprocess\n",[55,867,868],{"class":57,"line":115},[55,869,119],{"emptyLinePlaceholder":118},[55,871,872,875,878,880,883,885,888,890,893,895,898,900,903],{"class":57,"line":122},[55,873,874],{"class":105},"subprocess.run([",[55,876,877],{"class":65},"\"soffice\"",[55,879,144],{"class":105},[55,881,882],{"class":65},"\"--headless\"",[55,884,144],{"class":105},[55,886,887],{"class":65},"\"--convert-to\"",[55,889,144],{"class":105},[55,891,892],{"class":65},"\"xlsx\"",[55,894,144],{"class":105},[55,896,897],{"class":65},"\"--outdir\"",[55,899,144],{"class":105},[55,901,902],{"class":65},"\"recalculated\"",[55,904,905],{"class":105},",\n",[55,907,908,911,913,916,918,920,922,925,927,929],{"class":57,"line":179},[55,909,910],{"class":65},"                \"orders_openpyxl.xlsx\"",[55,912,155],{"class":105},[55,914,915],{"class":307},"check",[55,917,128],{"class":101},[55,919,613],{"class":140},[55,921,144],{"class":105},[55,923,924],{"class":307},"capture_output",[55,926,128],{"class":101},[55,928,613],{"class":140},[55,930,791],{"class":105},[55,932,933,936,939,942,944,946],{"class":57,"line":259},[55,934,935],{"class":140},"print",[55,937,938],{"class":105},"(pd.read_excel(",[55,940,941],{"class":65},"\"recalculated\u002Forders_openpyxl.xlsx\"",[55,943,346],{"class":105},[55,945,185],{"class":65},[55,947,351],{"class":105},[10,949,950,951,954,955,957,958,961,962,39],{},"The recalculated copy reads ",[14,952,953],{},"[267.0, 227.5, 168.0]",", and the formulas are still there for anyone who opens the file. This is the fix to use when the workbook must keep live formulas ",[30,956,679],{}," be read by other programs. One caveat from testing: LibreOffice does not recalculate XlsxWriter files on load, because they already carry (placeholder) results, so it keeps the zeros. Round-trip an XlsxWriter file through openpyxl first (",[14,959,960],{},"load_workbook(p).save(p)"," drops the cached zeros), then convert. For more control — editing and recalculating in one session — see ",[35,963,965],{"href":964},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fautomate-libreoffice-calc-from-python-with-uno\u002F","Automate LibreOffice Calc from Python with UNO",[364,967,373,972,373,975,373,978,373,981,373,985,373,992,373,998,373,1003,373,1007,373,1013,373,1018,373,1022,373,1028,373,1034,373,1038,373,1042,373,1046,373,1050,373,1053,373,1057,373,1064,373,1068,373,1072,373,1075,373,1079,373,1082,373,1085,373,1091,373,1095],{"viewBox":968,"role":367,"ariaLabelledBy":969,"xmlns":371,"style":372},"4 0 752 160",[970,971],"nan-recalc-t","nan-recalc-d",[375,973,974],{"id":970},"Recalculating a generated workbook so readers see numbers",[379,976,977],{"id":971},"An openpyxl-written workbook with formulas but no results is opened and saved by LibreOffice in headless mode, which stores the calculated results. pandas then reads real numbers. XlsxWriter files are first re-saved through openpyxl to drop their cached zeros.",[383,979],{"x":385,"y":386,"width":387,"height":980,"fill":389},"160",[383,982],{"x":392,"y":393,"width":983,"height":984,"rx":152,"fill":502,"stroke":503,"style":399},"153.0","128.0",[401,986,988],{"transform":987},"translate(84.5,37.8) scale(1.000)",[405,989],{"d":990,"fill":408,"stroke":510,"style":991},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[412,993,997],{"x":994,"y":995,"style":996},"96.5","84.2","font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Generated .xlsx",[412,999,1002],{"x":994,"y":1000,"style":1001},"103.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","formulas without",[412,1004,1006],{"x":994,"y":1005,"style":1001},"121.2","results",[57,1008],{"x1":1009,"y1":1010,"x2":1011,"y2":1010,"stroke":1012,"style":399},"178.0","80.0","200.0","var(--brand,#5b5cf0)",[1014,1015],"polygon",{"points":1016,"fill":1017},"204.0,80.0 195.0,85.0 195.0,75.0","#5b5cf0",[383,1019],{"x":1020,"y":393,"width":983,"height":984,"rx":152,"fill":457,"stroke":458,"style":1021},"209.0","stroke-width:2px;stroke-dasharray:6 4",[401,1023,1025],{"transform":1024},"translate(273.5,29.0) scale(1.000)",[405,1026],{"d":1027,"fill":408,"stroke":465,"style":991},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7",[412,1029,1033],{"x":1030,"y":1031,"style":1032},"285.5","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","(XlsxWriter only)",[412,1035,1037],{"x":1030,"y":1036,"style":1032},"93.0","re-save",[412,1039,1041],{"x":1030,"y":1040,"style":1001},"112.5","openpyxl drops",[412,1043,1045],{"x":1030,"y":1044,"style":1001},"130.0","cached 0",[57,1047],{"x1":1048,"y1":1010,"x2":1049,"y2":1010,"stroke":1012,"style":399},"367.0","389.0",[1014,1051],{"points":1052,"fill":1017},"393.0,80.0 384.0,85.0 384.0,75.0",[383,1054],{"x":1055,"y":393,"width":983,"height":984,"rx":152,"fill":1056,"stroke":1012,"style":399},"398.0","#f0f4ff",[401,1058,1060],{"transform":1059},"translate(462.5,37.8) scale(1.000)",[405,1061],{"d":1062,"fill":408,"stroke":1063,"style":991},"M12 9a3 3 0 1 0 .01 0z M12 2.5v3 M12 18.5v3 M2.5 12h3 M18.5 12h3 M5.3 5.3l2.1 2.1 M16.6 16.6l2.1 2.1 M5.3 18.7l2.1-2.1 M16.6 7.4l2.1-2.1","var(--brand-strong,#4338ca)",[412,1065,81],{"x":1066,"y":995,"style":1067},"474.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[412,1069,1071],{"x":1066,"y":1070,"style":1067},"101.8","--convert-to xlsx",[412,1073,1074],{"x":1066,"y":1005,"style":1001},"calculates and stores",[57,1076],{"x1":1077,"y1":1010,"x2":1078,"y2":1010,"stroke":1012,"style":399},"556.0","578.0",[1014,1080],{"points":1081,"fill":1017},"582.0,80.0 573.0,85.0 573.0,75.0",[383,1083],{"x":1084,"y":393,"width":983,"height":984,"rx":152,"fill":397,"stroke":398,"style":399},"587.0",[401,1086,1088],{"transform":1087},"translate(651.5,46.5) scale(1.000)",[405,1089],{"d":1090,"fill":408,"stroke":409,"style":991},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14",[412,1092,20],{"x":1093,"y":1036,"style":1094},"663.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[412,1096,1097],{"x":1093,"y":1040,"style":1001},"267, 227.5, 168",[41,1099,1101],{"id":1100},"step-4-fix-2-calculate-in-pandas-instead","Step 4 — Fix 2: calculate in pandas instead",[10,1103,1104],{},"If the reader is your own code, the simplest fix is not to depend on the formula at all. Read the inputs and repeat the calculation:",[46,1106,1108],{"className":92,"code":1107,"language":94,"meta":51,"style":51},"df = pd.read_excel(\"orders_openpyxl.xlsx\")\ndf[\"Total\"] = df[\"Qty\"] * df[\"Price\"]\nprint(df)\n",[14,1109,1110,1125,1153],{"__ignoreMap":51},[55,1111,1112,1115,1117,1120,1123],{"class":57,"line":58},[55,1113,1114],{"class":105},"df ",[55,1116,128],{"class":101},[55,1118,1119],{"class":105}," pd.read_excel(",[55,1121,1122],{"class":65},"\"orders_openpyxl.xlsx\"",[55,1124,791],{"class":105},[55,1126,1127,1130,1132,1134,1136,1139,1141,1143,1146,1148,1150],{"class":57,"line":115},[55,1128,1129],{"class":105},"df[",[55,1131,185],{"class":65},[55,1133,188],{"class":105},[55,1135,128],{"class":101},[55,1137,1138],{"class":105}," df[",[55,1140,134],{"class":65},[55,1142,188],{"class":105},[55,1144,1145],{"class":101},"*",[55,1147,1138],{"class":105},[55,1149,158],{"class":65},[55,1151,1152],{"class":105},"]\n",[55,1154,1155,1157],{"class":57,"line":122},[55,1156,935],{"class":140},[55,1158,1159],{"class":105},"(df)\n",[10,1161,1162,1163,1167],{},"For simple row formulas this is one line and always correct. For complex models — lookups across sheets, financial functions — translating every formula is work, and the pages in ",[35,1164,1166],{"href":1165},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002F","Excel Formula Equivalents in pandas"," show the pandas version of the common ones. Better still, avoid the round trip: have the job that writes the workbook also hand the DataFrame (or a Parquet copy) to the job that reads it.",[41,1169,1171],{"id":1170},"step-5-fix-3-write-cached-results-when-creating-the-file","Step 5 — Fix 3: write cached results when creating the file",[10,1173,1174,1175,1178],{},"When you control the writer, store the result alongside the formula. XlsxWriter's ",[14,1176,1177],{},"write_formula"," takes the value as its last argument:",[46,1180,1182],{"className":92,"code":1181,"language":94,"meta":51,"style":51},"import xlsxwriter\n\nbook = xlsxwriter.Workbook(\"orders_cached.xlsx\")\nsheet = book.add_worksheet()\nsheet.write_row(0, 0, [\"Qty\", \"Price\", \"Total\"])\nfor i, (qty, price) in enumerate(zip(orders[\"Qty\"], orders[\"Price\"]), start=1):\n    sheet.write_row(i, 0, [qty, price])\n    sheet.write_formula(i, 2, f\"=A{i + 1}*B{i + 1}\", None, qty * price)\nbook.close()\nprint(pd.read_excel(\"orders_cached.xlsx\")[\"Total\"].tolist())\n",[14,1183,1184,1190,1194,1209,1219,1246,1286,1296,1348,1353],{"__ignoreMap":51},[55,1185,1186,1188],{"class":57,"line":58},[55,1187,102],{"class":101},[55,1189,75],{"class":105},[55,1191,1192],{"class":57,"line":115},[55,1193,119],{"emptyLinePlaceholder":118},[55,1195,1196,1199,1201,1204,1207],{"class":57,"line":122},[55,1197,1198],{"class":105},"book ",[55,1200,128],{"class":101},[55,1202,1203],{"class":105}," xlsxwriter.Workbook(",[55,1205,1206],{"class":65},"\"orders_cached.xlsx\"",[55,1208,791],{"class":105},[55,1210,1211,1214,1216],{"class":57,"line":179},[55,1212,1213],{"class":105},"sheet ",[55,1215,128],{"class":101},[55,1217,1218],{"class":105}," book.add_worksheet()\n",[55,1220,1221,1224,1226,1228,1230,1233,1235,1237,1239,1241,1243],{"class":57,"line":259},[55,1222,1223],{"class":105},"sheet.write_row(",[55,1225,386],{"class":140},[55,1227,144],{"class":105},[55,1229,386],{"class":140},[55,1231,1232],{"class":105},", [",[55,1234,134],{"class":65},[55,1236,144],{"class":105},[55,1238,158],{"class":65},[55,1240,144],{"class":105},[55,1242,185],{"class":65},[55,1244,1245],{"class":105},"])\n",[55,1247,1248,1250,1253,1255,1258,1260,1263,1266,1268,1271,1273,1276,1279,1281,1284],{"class":57,"line":284},[55,1249,262],{"class":101},[55,1251,1252],{"class":105}," i, (qty, price) ",[55,1254,230],{"class":101},[55,1256,1257],{"class":140}," enumerate",[55,1259,236],{"class":105},[55,1261,1262],{"class":140},"zip",[55,1264,1265],{"class":105},"(orders[",[55,1267,134],{"class":65},[55,1269,1270],{"class":105},"], orders[",[55,1272,158],{"class":65},[55,1274,1275],{"class":105},"]), ",[55,1277,1278],{"class":307},"start",[55,1280,128],{"class":101},[55,1282,1283],{"class":140},"1",[55,1285,281],{"class":105},[55,1287,1288,1291,1293],{"class":57,"line":325},[55,1289,1290],{"class":105},"    sheet.write_row(i, ",[55,1292,386],{"class":140},[55,1294,1295],{"class":105},", [qty, price])\n",[55,1297,1298,1301,1303,1305,1307,1309,1311,1314,1316,1319,1321,1323,1325,1327,1329,1331,1333,1335,1337,1340,1343,1345],{"class":57,"line":645},[55,1299,1300],{"class":105},"    sheet.write_formula(i, ",[55,1302,239],{"class":140},[55,1304,144],{"class":105},[55,1306,196],{"class":101},[55,1308,199],{"class":65},[55,1310,203],{"class":202},[55,1312,1313],{"class":105},"i ",[55,1315,250],{"class":101},[55,1317,1318],{"class":140}," 1",[55,1320,209],{"class":202},[55,1322,212],{"class":65},[55,1324,203],{"class":202},[55,1326,1313],{"class":105},[55,1328,250],{"class":101},[55,1330,1318],{"class":140},[55,1332,209],{"class":202},[55,1334,221],{"class":65},[55,1336,144],{"class":105},[55,1338,1339],{"class":140},"None",[55,1341,1342],{"class":105},", qty ",[55,1344,1145],{"class":101},[55,1346,1347],{"class":105}," price)\n",[55,1349,1350],{"class":57,"line":661},[55,1351,1352],{"class":105},"book.close()\n",[55,1354,1355,1357,1359,1361,1363,1365],{"class":57,"line":690},[55,1356,935],{"class":140},[55,1358,938],{"class":105},[55,1360,1206],{"class":65},[55,1362,346],{"class":105},[55,1364,185],{"class":65},[55,1366,351],{"class":105},[10,1368,1369,1370,1372,1373,1377],{},"The file now reads ",[14,1371,953],{}," without any recalculation, and Excel shows the same numbers — it recalculates on open anyway. The risk is that the value you compute in Python and the formula disagree; keep both derived from the same expression, and test them against each other with a LibreOffice recalculation in CI. The technique is covered in ",[35,1374,1376],{"href":1375},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fstore-formula-results-with-xlsxwriter\u002F","Store Formula Results with xlsxwriter",". openpyxl has no equivalent: it cannot write a cached value next to a formula.",[41,1379,1381],{"id":1380},"step-6-workbooks-saved-by-excel-with-stale-values","Step 6 — Workbooks saved by Excel with stale values",[10,1383,1384,1385,1388],{},"A related case: the file ",[30,1386,1387],{},"was"," saved by Excel, but with calculation set to manual, so the stored results are old. pandas faithfully reads the stale numbers. Check the workbook's calculation settings:",[46,1390,1392],{"className":92,"code":1391,"language":94,"meta":51,"style":51},"wb = load_workbook(\"recalculated\u002Forders_openpyxl.xlsx\")\nprint(\"calc mode:\", wb.calculation.calcMode, \"| full calc on load:\", wb.calculation.fullCalcOnLoad)\n",[14,1393,1394,1408],{"__ignoreMap":51},[55,1395,1396,1399,1401,1404,1406],{"class":57,"line":58},[55,1397,1398],{"class":105},"wb ",[55,1400,128],{"class":101},[55,1402,1403],{"class":105}," load_workbook(",[55,1405,941],{"class":65},[55,1407,791],{"class":105},[55,1409,1410,1412,1414,1417,1420,1423],{"class":57,"line":115},[55,1411,935],{"class":140},[55,1413,236],{"class":105},[55,1415,1416],{"class":65},"\"calc mode:\"",[55,1418,1419],{"class":105},", wb.calculation.calcMode, ",[55,1421,1422],{"class":65},"\"| full calc on load:\"",[55,1424,1425],{"class":105},", wb.calculation.fullCalcOnLoad)\n",[10,1427,1428,1429,1431,1432,1435,1436,1431,1438,1441,1442,1444,1445,1448,1449,1452,1453,1456],{},"The LibreOffice-saved copy reports ",[14,1430,1339],{}," for ",[14,1433,1434],{},"calcMode"," — the attribute is simply absent, which means automatic — and ",[14,1437,613],{},[14,1439,1440],{},"fullCalcOnLoad",", LibreOffice's request that the next application recalculate on opening. If ",[14,1443,1434],{}," says ",[14,1446,1447],{},"\"manual\"",", the cached values may predate the last edit; recalculate with LibreOffice as in Step 3 before trusting them. Setting ",[14,1450,1451],{},"wb.calculation.fullCalcOnLoad = True"," with openpyxl makes ",[30,1454,1455],{},"Excel"," recalculate when a person opens the file, which helps people but does nothing for pandas.",[41,1458,1460],{"id":1459},"which-fix-to-use","Which fix to use",[10,1462,1463],{},"The three fixes answer different situations, and the deciding question is who reads the file next:",[364,1465,373,1470,373,1473,373,1476,373,1479,373,1483,373,1489,373,1492,373,1496,373,1500,373,1503,373,1506,373,1515,373,1520,373,1524,373,1530,373,1534,373,1538,373,1540,373,1543,373,1547,373,1550,373,1553,373,1558,373,1561,373,1564,373,1566,373,1569,373,1573,373,1576,373,1579,373,1585,373,1588],{"viewBox":1466,"role":367,"ariaLabelledBy":1467,"xmlns":371,"style":372},"4 0 752 272",[1468,1469],"nan-choose-t","nan-choose-d",[375,1471,1472],{"id":1468},"Choosing a fix for formula cells that read as NaN",[379,1474,1475],{"id":1469},"If your own code reads the file, compute the values in pandas. If other programs read it and the formulas must stay live, recalculate with LibreOffice. If you control the writer and the formulas are simple, write cached results with XlsxWriter.",[383,1477],{"x":385,"y":386,"width":387,"height":1478,"fill":389},"272",[383,1480],{"x":1481,"y":393,"width":1482,"height":1031,"rx":152,"fill":1056,"stroke":1012,"style":399},"240.0","280.0",[401,1484,1486],{"transform":1485},"translate(368.0,29.0) scale(1.000)",[405,1487],{"d":1488,"fill":408,"stroke":1063,"style":991},"M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M2.5 20c0-3.6 2.9-6 6.5-6s6.5 2.4 6.5 6 M16 4.5a3.3 3.3 0 0 1 0 6.3 M18 14.3c2.2.7 3.5 2.8 3.5 5.7",[412,1490,1491],{"x":468,"y":1031,"style":1067},"Who reads the workbook next?",[57,1493],{"x1":468,"y1":1494,"x2":468,"y2":1495,"stroke":1012,"style":399},"91.5","111.5",[57,1497],{"x1":1498,"y1":1495,"x2":1499,"y2":1495,"stroke":1012,"style":399},"134.7","625.3",[57,1501],{"x1":1498,"y1":1495,"x2":1498,"y2":1502,"stroke":1012,"style":399},"157.5",[1014,1504],{"points":1505,"fill":1017},"134.7,161.5 129.7,152.5 139.7,152.5",[383,1507],{"x":1508,"y":1509,"width":1510,"height":1511,"rx":1512,"fill":389,"stroke":1513,"style":1514},"82.0","121.5","105.3","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[412,1516,1519],{"x":1498,"y":1517,"style":1518},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","your own code",[383,1521],{"x":392,"y":1522,"width":1523,"height":1036,"rx":152,"fill":397,"stroke":398,"style":399},"163.5","229.3",[401,1525,1527],{"transform":1526},"translate(122.7,176.5) scale(1.000)",[405,1528],{"d":1529,"fill":408,"stroke":409,"style":991},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01",[412,1531,1533],{"x":1498,"y":1532,"style":1094},"223.0","Compute in pandas",[412,1535,1537],{"x":1498,"y":1536,"style":1001},"242.5","no formula round trip",[57,1539],{"x1":468,"y1":1495,"x2":468,"y2":1502,"stroke":1012,"style":399},[1014,1541],{"points":1542,"fill":1017},"380.0,161.5 375.0,152.5 385.0,152.5",[383,1544],{"x":1545,"y":1509,"width":1546,"height":1511,"rx":1512,"fill":389,"stroke":1513,"style":1514},"294.0","172.1",[412,1548,1549],{"x":468,"y":1517,"style":1518},"other tools + live formulas",[383,1551],{"x":1552,"y":1522,"width":1523,"height":1036,"rx":152,"fill":1056,"stroke":1012,"style":399},"265.3",[401,1554,1556],{"transform":1555},"translate(368.0,176.5) scale(1.000)",[405,1557],{"d":1062,"fill":408,"stroke":1063,"style":991},[412,1559,1560],{"x":468,"y":1532,"style":1067},"Recalculate with LibreOffice",[412,1562,1563],{"x":468,"y":1536,"style":1001},"soffice --convert-to",[57,1565],{"x1":1499,"y1":1495,"x2":1499,"y2":1502,"stroke":1012,"style":399},[1014,1567],{"points":1568,"fill":1017},"625.3,161.5 620.3,152.5 630.3,152.5",[383,1570],{"x":1571,"y":1509,"width":1572,"height":1511,"rx":1512,"fill":389,"stroke":1513,"style":1514},"583.5","83.7",[412,1574,1575],{"x":1499,"y":1517,"style":1518},"you write it",[383,1577],{"x":1578,"y":1522,"width":1523,"height":1036,"rx":152,"fill":457,"stroke":458,"style":399},"510.7",[401,1580,1582],{"transform":1581},"translate(613.3,176.5) scale(1.000)",[405,1583],{"d":1584,"fill":408,"stroke":465,"style":991},"M9 8l-4 4 4 4 M15 8l4 4-4 4",[412,1586,1587],{"x":1499,"y":1532,"style":1032},"Cache results",[412,1589,1590],{"x":1499,"y":1536,"style":1001},"write_formula(…, value)",[10,1592,1593],{},"Computing in pandas is the most robust, because there is no second copy of the logic to drift. Recalculation is the most faithful, because the spreadsheet engine evaluates exactly the formulas a person will see. Cached results are the fastest — no extra process — but only as trustworthy as the test that checks the cached numbers against a real recalculation. Many pipelines combine them: compute in pandas, write formulas with cached values for the people who open the file, and run a LibreOffice recalculation in the test suite to prove the two agree.",[41,1595,1597],{"id":1596},"performance-notes","Performance notes",[10,1599,1600,1601,1604],{},"A LibreOffice conversion costs a second or two for process startup plus the calculation itself, so convert files in batches — ",[14,1602,1603],{},"soffice --convert-to xlsx --outdir out *.xlsx"," handles many files in one process — rather than one call per file in a tight loop. Computing in pandas is effectively free next to reading the workbook. Writing cached values with XlsxWriter adds nothing measurable to the write time.",[41,1606,1608],{"id":1607},"common-pitfalls","Common pitfalls",[1610,1611,1612,1620,1626,1636,1642,1652],"ul",{},[1613,1614,1615,1619],"li",{},[1616,1617,1618],"strong",{},"Treating zeros as data."," XlsxWriter's cached 0 looks valid; check formula cells before summing.",[1613,1621,1622,1625],{},[1616,1623,1624],{},"Recalculating XlsxWriter files directly."," LibreOffice keeps their cached zeros; re-save through openpyxl first.",[1613,1627,1628,1635],{},[1616,1629,1630,1631,1634],{},"Reading with ",[14,1632,1633],{},"data_only=True"," and saving."," That replaces formulas with the (missing) cached values permanently.",[1613,1637,1638,1641],{},[1616,1639,1640],{},"Expecting pandas to evaluate formulas."," No pandas engine calculates; they all read stored results.",[1613,1643,1644,1647,1648,1651],{},[1616,1645,1646],{},"Engines that read differently."," ",[14,1649,1650],{},"engine=\"calamine\""," reads the same cached values as openpyxl, so switching engines does not help; only a file with stored results does.",[1613,1653,1654,1657],{},[1616,1655,1656],{},"Copying formulas between workbooks."," A formula copied into a new openpyxl workbook loses its cached result even if the source had one; recalculate the copy before another program reads it.",[41,1659,1661],{"id":1660},"conclusion","Conclusion",[10,1663,1664,1665,1667,1668,1670],{},"pandas reads the result stored next to each formula, and workbooks written by Python have none (openpyxl) or a placeholder 0 (XlsxWriter), which is why formula columns read as ",[14,1666,24],{}," or zeros. Confirm with a two-pass openpyxl check, then either let LibreOffice calculate and store the results, compute the values in pandas, or write cached results with ",[14,1669,1177],{}," when the file is created — and watch for Excel files saved in manual calculation mode.",[41,1672,1674],{"id":1673},"frequently-asked-questions","Frequently asked questions",[10,1676,1677,1680],{},[1616,1678,1679],{},"Why does pandas read_excel return NaN for formula cells?","\npandas reads the cached result stored with each formula. Files written by openpyxl contain formulas without cached results, so the cells read as NaN until the workbook is opened and saved by Excel or LibreOffice.",[10,1682,1683,1686],{},[1616,1684,1685],{},"Why are my formula cells read as 0?","\nThe file was written by XlsxWriter, which stores 0 as the cached result of every formula unless you pass a value to write_formula. Excel shows the right number because it recalculates on opening; pandas reads the stored 0.",[10,1688,1689,1692],{},[1616,1690,1691],{},"How do I make pandas read calculated formula values?","\nRecalculate the workbook in a spreadsheet engine, for example soffice --headless --convert-to xlsx, which stores real results; or compute the values in pandas; or write cached values with XlsxWriter's write_formula when creating the file.",[10,1694,1695,1698],{},[1616,1696,1697],{},"Can pandas evaluate Excel formulas?","\nNo. None of the read_excel engines calculate formulas. They only return the values that a spreadsheet application stored in the file.",[41,1700,1702],{"id":1701},"related","Related",[1610,1704,1705,1711,1718,1725],{},[1613,1706,1707,1708,1710],{},"Up one level: ",[35,1709,38],{"href":37}," — errors and surprises, with fixes.",[1613,1712,1713,1717],{},[35,1714,1716],{"href":1715},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","Read Formula Results with openpyxl data_only"," — the same cached values through openpyxl.",[1613,1719,1720,1724],{},[35,1721,1723],{"href":1722},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-excel-formulas-from-a-pandas-dataframe\u002F","Write Excel Formulas from a pandas DataFrame"," — where these formula columns come from.",[1613,1726,1727,1731],{},[35,1728,1730],{"href":1729},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formulas-showing-as-text-in-excel-output\u002F","Fix Formulas Showing as Text in Excel Output"," — the opposite problem, formulas that never become formulas.",[1733,1734,1735],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":51,"searchDepth":115,"depth":115,"links":1737},[1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750],{"id":43,"depth":115,"text":44},{"id":85,"depth":115,"text":86},{"id":547,"depth":115,"text":548},{"id":849,"depth":115,"text":850},{"id":1100,"depth":115,"text":1101},{"id":1170,"depth":115,"text":1171},{"id":1380,"depth":115,"text":1381},{"id":1459,"depth":115,"text":1460},{"id":1596,"depth":115,"text":1597},{"id":1607,"depth":115,"text":1608},{"id":1660,"depth":115,"text":1661},{"id":1673,"depth":115,"text":1674},{"id":1701,"depth":115,"text":1702},"2026-10-02","pd.read_excel returns NaN — or a suspicious 0 — for every formula cell in a workbook generated by a script, while the same file shows the right numbers in Excel. The cause is a missing cached result, not a bad read. Detect it, then fix it by recalculating with LibreOffice, computing the values in pandas, or writing cached results when the file is created.","md",[1755,1757,1759,1761],{"q":1679,"a":1756},"pandas reads the cached result stored with each formula. Files written by openpyxl contain formulas without cached results, so the cells read as NaN until the workbook is opened and saved by Excel or LibreOffice.",{"q":1685,"a":1758},"The file was written by XlsxWriter, which stores 0 as the cached result of every formula unless you pass a value to write_formula. Excel shows the right number because it recalculates on opening; pandas reads the stored 0.",{"q":1691,"a":1760},"Recalculate the workbook in a spreadsheet engine, for example soffice --headless --convert-to xlsx, which stores real results; or compute the values in pandas; or write cached values with XlsxWriter's write_formula when creating the file.",{"q":1697,"a":1762},"No. None of the read_excel engines calculate formulas. They only return the values that a spreadsheet application stored in the file.","fix formula cells reading as nan in pandas",null,{"breadcrumb":1766},[1767,1770,1773],{"name":1768,"item":1769},"Home","\u002F",{"name":1771,"item":1772},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":38,"item":37},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas",{"title":1776,"description":1777},"Fix Formula Cells Reading as NaN or 0 in pandas read_excel","Why pandas reads formula columns as NaN (openpyxl-written files) or 0 (XlsxWriter files), how to detect missing cached values, and three fixes: LibreOffice recalculation, computing in pandas, and caching results with write_formula.","fix-formula-cells-reading-as-nan-in-pandas","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formula-cells-reading-as-nan-in-pandas\u002Findex",[1781,1782,1783],"troubleshooting","excel-formulas","reading-excel","how-to","SX9LUzq7lsZacOlZ5tVJ0U9N9tMt1H6dulRG9dPQdtU",[1787,1791],{"title":1788,"path":1789,"stem":1790,"children":-1},"Fix Floating-Point Noise Like 0.1 + 0.2 ≠ 0.3 in Excel Output","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-floating-point-noise-in-excel-output","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-floating-point-noise-in-excel-output\u002Findex",{"title":1792,"path":1793,"stem":1794,"children":-1},"Fix Formulas Showing as Text in Excel Output from Python","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formulas-showing-as-text-in-excel-output","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-formulas-showing-as-text-in-excel-output\u002Findex",[1796,1798],{"path":1797,"title":1771},"\u002Fgetting-started-with-python-excel-automation",{"path":1799,"title":38},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[1802,1806,1809,1812,1815,1818],{"path":1803,"title":1804,"kind":1805},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fhandle-permission-denied-when-writing-excel-in-python","Handle Permission Denied When Writing Excel in Python","fix",{"path":1807,"title":1808,"kind":1784},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook","What openpyxl Loses When You Save an Existing Workbook",{"path":1810,"title":1811,"kind":1805},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffix-excel-serial-numbers-showing-instead-of-dates","Fix Excel Serial Numbers Showing Instead of Dates",{"path":1813,"title":1814,"kind":1784},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-daylight-saving-time-in-excel-timestamps","Handle Daylight Saving Time in Excel Timestamps",{"path":1816,"title":1817,"kind":1784},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":1819,"title":1820,"kind":1821},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972065750]