[{"data":1,"prerenderedAt":3374},["ShallowReactive",2],{"doc:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python":3,"surround:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python":3339,"ancestors:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python":3348,"children:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python":3353,"related:\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python":3354},{"id":4,"title":5,"body":6,"dateModified":3306,"datePublished":3306,"description":3307,"extension":3308,"faq":3309,"keyword":3318,"kind":3319,"meta":3320,"navigation":95,"path":3329,"seo":3330,"slug":3332,"stem":3333,"topics":3334,"type":3337,"__hash__":3338},"docs\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python\u002Findex.md","Build a Break-Even Analysis in Excel with Python",{"type":7,"value":8,"toc":3295},"minimark",[9,19,24,53,60,64,67,534,546,728,732,735,1754,1774,1778,1781,2451,2458,2626,2630,2970,2977,3181,3185,3223,3227,3230,3234,3240,3246,3252,3258,3262,3291],[10,11,12,13,18],"p",{},"\"How many do we need to sell to cover our costs?\" is one of the first questions asked about any product, price change or new location, and the break-even analysis that answers it is a few lines of arithmetic: fixed costs divided by the contribution each unit makes. The value of building it as a workbook is that people can then change the price, the unit cost or the fixed costs and see the answer move — so the arithmetic should live in Excel formulas, with Python laying out the model and checking it. This page builds that workbook with openpyxl: an inputs block, the single-product break-even, margin of safety, a break-even for several products sold in a mix, a sensitivity grid showing break-even volume across prices and unit costs, and a cost-volume-profit chart. LibreOffice recalculates the workbook so every formula can be compared with the same figures computed in pandas. It belongs to ",[14,15,17],"a",{"href":16},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002F","Building Finance and Operations Reports",".",[20,21,23],"h2",{"id":22},"prerequisites","Prerequisites",[25,26,31],"pre",{"className":27,"code":28,"language":29,"meta":30,"style":30},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas\n","bash","",[32,33,34],"code",{"__ignoreMap":30},[35,36,39,43,47,50],"span",{"class":37,"line":38},"line",1,[35,40,42],{"class":41},"sMTad","pip",[35,44,46],{"class":45},"srMev"," install",[35,48,49],{"class":45}," openpyxl",[35,51,52],{"class":45}," pandas\n",[10,54,55,56,59],{},"LibreOffice (",[32,57,58],{},"soffice",") is used only to recalculate the workbook for the checks. The example is a small manufacturer of three products with shared fixed costs of 240,000 a year and a sales forecast of 26,000 units.",[20,61,63],{"id":62},"step-1-the-figures-computed-in-pandas-first","Step 1 — The figures, computed in pandas first",[10,65,66],{},"Compute the answers in Python before building any formulas, so the workbook has something to be checked against:",[25,68,72],{"className":69,"code":70,"language":71,"meta":30,"style":30},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nFIXED = 240_000\nproducts = pd.DataFrame({\"Product\": [\"Standard\", \"Plus\", \"Pro\"], \"Price\": [18.0, 29.0, 52.0],\n                         \"Variable cost\": [11.0, 16.5, 27.0], \"Forecast units\": [14_000, 8_000, 4_000]})\nproducts[\"Contribution\"] = products[\"Price\"] - products[\"Variable cost\"]\nproducts[\"CM ratio\"] = products[\"Contribution\"] \u002F products[\"Price\"]\nproducts[\"Mix\"] = products[\"Forecast units\"] \u002F products[\"Forecast units\"].sum()\n\nwacm = (products[\"Contribution\"] * products[\"Mix\"]).sum()          # weighted average contribution per unit\nbe_units = FIXED \u002F wacm\nproducts[\"Break-even units\"] = be_units * products[\"Mix\"]\nbe_revenue = (products[\"Break-even units\"] * products[\"Price\"]).sum()\nforecast_revenue = (products[\"Forecast units\"] * products[\"Price\"]).sum()\nmargin_of_safety = (forecast_revenue - be_revenue) \u002F forecast_revenue\nprint(products.round(3).to_string(index=False))\nprint(f\"weighted contribution {wacm:.4f}; break-even {be_units:,.0f} units, revenue {be_revenue:,.0f}; margin of safety {margin_of_safety:.1%}\")\n","python",[32,73,74,90,97,110,166,210,242,269,296,301,330,347,370,393,415,436,463],{"__ignoreMap":30},[35,75,76,80,84,87],{"class":37,"line":38},[35,77,79],{"class":78},"s-kum","import",[35,81,83],{"class":82},"skGVy"," pandas ",[35,85,86],{"class":78},"as",[35,88,89],{"class":82}," pd\n",[35,91,93],{"class":37,"line":92},2,[35,94,96],{"emptyLinePlaceholder":95},true,"\n",[35,98,100,104,107],{"class":37,"line":99},3,[35,101,103],{"class":102},"sP0c6","FIXED",[35,105,106],{"class":78}," =",[35,108,109],{"class":102}," 240_000\n",[35,111,113,116,119,122,125,128,131,134,137,139,142,145,148,150,153,155,158,160,163],{"class":37,"line":112},4,[35,114,115],{"class":82},"products ",[35,117,118],{"class":78},"=",[35,120,121],{"class":82}," pd.DataFrame({",[35,123,124],{"class":45},"\"Product\"",[35,126,127],{"class":82},": [",[35,129,130],{"class":45},"\"Standard\"",[35,132,133],{"class":82},", ",[35,135,136],{"class":45},"\"Plus\"",[35,138,133],{"class":82},[35,140,141],{"class":45},"\"Pro\"",[35,143,144],{"class":82},"], ",[35,146,147],{"class":45},"\"Price\"",[35,149,127],{"class":82},[35,151,152],{"class":102},"18.0",[35,154,133],{"class":82},[35,156,157],{"class":102},"29.0",[35,159,133],{"class":82},[35,161,162],{"class":102},"52.0",[35,164,165],{"class":82},"],\n",[35,167,169,172,174,177,179,182,184,187,189,192,194,197,199,202,204,207],{"class":37,"line":168},5,[35,170,171],{"class":45},"                         \"Variable cost\"",[35,173,127],{"class":82},[35,175,176],{"class":102},"11.0",[35,178,133],{"class":82},[35,180,181],{"class":102},"16.5",[35,183,133],{"class":82},[35,185,186],{"class":102},"27.0",[35,188,144],{"class":82},[35,190,191],{"class":45},"\"Forecast units\"",[35,193,127],{"class":82},[35,195,196],{"class":102},"14_000",[35,198,133],{"class":82},[35,200,201],{"class":102},"8_000",[35,203,133],{"class":82},[35,205,206],{"class":102},"4_000",[35,208,209],{"class":82},"]})\n",[35,211,213,216,219,222,224,227,229,231,234,236,239],{"class":37,"line":212},6,[35,214,215],{"class":82},"products[",[35,217,218],{"class":45},"\"Contribution\"",[35,220,221],{"class":82},"] ",[35,223,118],{"class":78},[35,225,226],{"class":82}," products[",[35,228,147],{"class":45},[35,230,221],{"class":82},[35,232,233],{"class":78},"-",[35,235,226],{"class":82},[35,237,238],{"class":45},"\"Variable cost\"",[35,240,241],{"class":82},"]\n",[35,243,245,247,250,252,254,256,258,260,263,265,267],{"class":37,"line":244},7,[35,246,215],{"class":82},[35,248,249],{"class":45},"\"CM ratio\"",[35,251,221],{"class":82},[35,253,118],{"class":78},[35,255,226],{"class":82},[35,257,218],{"class":45},[35,259,221],{"class":82},[35,261,262],{"class":78},"\u002F",[35,264,226],{"class":82},[35,266,147],{"class":45},[35,268,241],{"class":82},[35,270,272,274,277,279,281,283,285,287,289,291,293],{"class":37,"line":271},8,[35,273,215],{"class":82},[35,275,276],{"class":45},"\"Mix\"",[35,278,221],{"class":82},[35,280,118],{"class":78},[35,282,226],{"class":82},[35,284,191],{"class":45},[35,286,221],{"class":82},[35,288,262],{"class":78},[35,290,226],{"class":82},[35,292,191],{"class":45},[35,294,295],{"class":82},"].sum()\n",[35,297,299],{"class":37,"line":298},9,[35,300,96],{"emptyLinePlaceholder":95},[35,302,304,307,309,312,314,316,319,321,323,326],{"class":37,"line":303},10,[35,305,306],{"class":82},"wacm ",[35,308,118],{"class":78},[35,310,311],{"class":82}," (products[",[35,313,218],{"class":45},[35,315,221],{"class":82},[35,317,318],{"class":78},"*",[35,320,226],{"class":82},[35,322,276],{"class":45},[35,324,325],{"class":82},"]).sum()          ",[35,327,329],{"class":328},"s-wDw","# weighted average contribution per unit\n",[35,331,333,336,338,341,344],{"class":37,"line":332},11,[35,334,335],{"class":82},"be_units ",[35,337,118],{"class":78},[35,339,340],{"class":102}," FIXED",[35,342,343],{"class":78}," \u002F",[35,345,346],{"class":82}," wacm\n",[35,348,350,352,355,357,359,362,364,366,368],{"class":37,"line":349},12,[35,351,215],{"class":82},[35,353,354],{"class":45},"\"Break-even units\"",[35,356,221],{"class":82},[35,358,118],{"class":78},[35,360,361],{"class":82}," be_units ",[35,363,318],{"class":78},[35,365,226],{"class":82},[35,367,276],{"class":45},[35,369,241],{"class":82},[35,371,373,376,378,380,382,384,386,388,390],{"class":37,"line":372},13,[35,374,375],{"class":82},"be_revenue ",[35,377,118],{"class":78},[35,379,311],{"class":82},[35,381,354],{"class":45},[35,383,221],{"class":82},[35,385,318],{"class":78},[35,387,226],{"class":82},[35,389,147],{"class":45},[35,391,392],{"class":82},"]).sum()\n",[35,394,396,399,401,403,405,407,409,411,413],{"class":37,"line":395},14,[35,397,398],{"class":82},"forecast_revenue ",[35,400,118],{"class":78},[35,402,311],{"class":82},[35,404,191],{"class":45},[35,406,221],{"class":82},[35,408,318],{"class":78},[35,410,226],{"class":82},[35,412,147],{"class":45},[35,414,392],{"class":82},[35,416,418,421,423,426,428,431,433],{"class":37,"line":417},15,[35,419,420],{"class":82},"margin_of_safety ",[35,422,118],{"class":78},[35,424,425],{"class":82}," (forecast_revenue ",[35,427,233],{"class":78},[35,429,430],{"class":82}," be_revenue) ",[35,432,262],{"class":78},[35,434,435],{"class":82}," forecast_revenue\n",[35,437,439,442,445,448,451,455,457,460],{"class":37,"line":438},16,[35,440,441],{"class":102},"print",[35,443,444],{"class":82},"(products.round(",[35,446,447],{"class":102},"3",[35,449,450],{"class":82},").to_string(",[35,452,454],{"class":453},"sa561","index",[35,456,118],{"class":78},[35,458,459],{"class":102},"False",[35,461,462],{"class":82},"))\n",[35,464,466,468,471,474,477,481,484,487,490,493,495,498,501,503,506,508,511,513,515,518,520,523,526,528,531],{"class":37,"line":465},17,[35,467,441],{"class":102},[35,469,470],{"class":82},"(",[35,472,473],{"class":78},"f",[35,475,476],{"class":45},"\"weighted contribution ",[35,478,480],{"class":479},"sSjpA","{",[35,482,483],{"class":82},"wacm",[35,485,486],{"class":78},":.4f",[35,488,489],{"class":479},"}",[35,491,492],{"class":45},"; break-even ",[35,494,480],{"class":479},[35,496,497],{"class":82},"be_units",[35,499,500],{"class":78},":,.0f",[35,502,489],{"class":479},[35,504,505],{"class":45}," units, revenue ",[35,507,480],{"class":479},[35,509,510],{"class":82},"be_revenue",[35,512,500],{"class":78},[35,514,489],{"class":479},[35,516,517],{"class":45},"; margin of safety ",[35,519,480],{"class":479},[35,521,522],{"class":82},"margin_of_safety",[35,524,525],{"class":78},":.1%",[35,527,489],{"class":479},[35,529,530],{"class":45},"\"",[35,532,533],{"class":82},")\n",[10,535,536,537,541,542,545],{},"Each product's ",[538,539,540],"em",{},"contribution"," is what a unit leaves after its own variable costs, available to pay the fixed costs. With several products sharing fixed costs there is no single break-even until you fix the ",[538,543,544],{},"mix",": here 54% Standard, 31% Plus and 15% Pro, as in the forecast. The weighted average contribution per unit sold in that mix is 11.46, so the business breaks even at about 20,940 units — 11,275 Standard, 6,443 Plus and 3,221 Pro — or 557,315 of revenue. Forecast revenue is 692,000, 19.5% above break-even, which is the margin of safety: how far sales can fall short before the business makes a loss.",[547,548,556,557,556,561,556,565,556,573,556,583,556,594,556,601,556,606,556,610,556,616,556,621,556,625,556,632,556,637,556,640,556,643,556,647,556,650,556,655,556,662,556,667,556,670,556,673,556,677,556,680,556,683,556,689,556,692,556,695,556,698,556,702,556,705,556,710,556,717,556,722,556,725],"svg",{"viewBox":549,"role":550,"ariaLabelledBy":551,"xmlns":554,"style":555},"4 0 752 142","img",[552,553],"be-flow-t","be-flow-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  ",[558,559,560],"title",{"id":552},"From prices and costs to the break-even point",[562,563,564],"desc",{"id":553},"Price less variable cost gives each product's contribution. Weighting contributions by the sales mix gives an average contribution per unit. Fixed costs divided by that average give break-even units, which split by the mix and priced give break-even revenue. Comparing with forecast revenue gives the margin of safety.",[566,567],"rect",{"x":568,"y":569,"width":570,"height":571,"fill":572},"4","0","752","142","#ffffff",[566,574],{"x":575,"y":576,"width":577,"height":578,"rx":579,"fill":580,"stroke":581,"style":582},"20.0","16.0","115.2","110.5","12","#e7ebef","var(--line,#cdd5e6)","stroke-width:2px",[584,585,587],"g",{"transform":586},"translate(65.6,29.0) scale(1.000)",[588,589],"path",{"d":590,"fill":591,"stroke":592,"style":593},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[595,596,600],"text",{"x":597,"y":598,"style":599},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Contribution",[595,602,605],{"x":597,"y":603,"style":604},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","price − variable",[595,607,609],{"x":597,"y":608,"style":604},"112.5","cost",[37,611],{"x1":612,"y1":613,"x2":614,"y2":613,"stroke":615,"style":582},"140.2","71.2","162.2","var(--brand,#5b5cf0)",[617,618],"polygon",{"points":619,"fill":620},"166.2,71.2 157.2,76.2 157.2,66.2","#5b5cf0",[566,622],{"x":623,"y":576,"width":577,"height":578,"rx":579,"fill":624,"stroke":615,"style":582},"171.2","#f0f4ff",[584,626,628],{"transform":627},"translate(216.8,29.0) scale(1.000)",[588,629],{"d":630,"fill":591,"stroke":631,"style":593},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--brand-strong,#4338ca)",[595,633,636],{"x":634,"y":598,"style":635},"228.8","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Weighted by",[595,638,544],{"x":634,"y":639,"style":635},"93.0",[595,641,642],{"x":634,"y":608,"style":604},"11.46 per unit",[37,644],{"x1":645,"y1":613,"x2":646,"y2":613,"stroke":615,"style":582},"291.4","313.4",[617,648],{"points":649,"fill":620},"317.4,71.2 308.4,76.2 308.4,66.2",[566,651],{"x":652,"y":576,"width":577,"height":578,"rx":579,"fill":653,"stroke":654,"style":582},"322.4","#d9f4f1","var(--teal,#0f9488)",[584,656,658],{"transform":657},"translate(368.0,29.0) scale(1.000)",[588,659],{"d":660,"fill":591,"stroke":661,"style":593},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--teal-ink,#0b6157)",[595,663,666],{"x":664,"y":598,"style":665},"380.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Break-even",[595,668,669],{"x":664,"y":639,"style":665},"units",[595,671,672],{"x":664,"y":608,"style":604},"fixed ÷ 11.46",[37,674],{"x1":675,"y1":613,"x2":676,"y2":613,"stroke":615,"style":582},"442.6","464.6",[617,678],{"points":679,"fill":620},"468.6,71.2 459.6,76.2 459.6,66.2",[566,681],{"x":682,"y":576,"width":577,"height":578,"rx":579,"fill":653,"stroke":654,"style":582},"473.6",[584,684,686],{"transform":685},"translate(519.2,29.0) scale(1.000)",[588,687],{"d":688,"fill":591,"stroke":661,"style":593},"M4 20h16 M4 20V4 M6 16l4-5 4 3 6-7",[595,690,666],{"x":691,"y":598,"style":665},"531.2",[595,693,694],{"x":691,"y":639,"style":665},"revenue",[595,696,697],{"x":691,"y":608,"style":604},"units × prices",[37,699],{"x1":700,"y1":613,"x2":701,"y2":613,"stroke":615,"style":582},"593.8","615.8",[617,703],{"points":704,"fill":620},"619.8,71.2 610.8,76.2 610.8,66.2",[566,706],{"x":707,"y":576,"width":577,"height":578,"rx":579,"fill":708,"stroke":709,"style":582},"624.8","#fdefd8","var(--gold,#b4740a)",[584,711,713],{"transform":712},"translate(670.4,29.0) scale(1.000)",[588,714],{"d":715,"fill":591,"stroke":716,"style":593},"M5 12.5l4.5 4.5L19 7","var(--gold-ink,#7a4e06)",[595,718,721],{"x":719,"y":598,"style":720},"682.4","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Margin of",[595,723,724],{"x":719,"y":639,"style":720},"safety",[595,726,727],{"x":719,"y":608,"style":604},"vs forecast",[20,729,731],{"id":730},"step-2-the-model-sheet-with-live-formulas","Step 2 — The model sheet with live formulas",[10,733,734],{},"Write the inputs as values and everything else as formulas that refer to them. Inputs are shaded so readers know which cells they may change:",[25,736,738],{"className":69,"code":737,"language":71,"meta":30,"style":30},"from openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill\n\nwb = Workbook()\nws = wb.active\nws.title = \"Model\"\nINPUT = PatternFill(\"solid\", fgColor=\"FFF4CE\")\nws[\"A1\"], ws[\"A1\"].font = \"Break-even analysis\", Font(size=14, bold=True)\nws[\"A3\"], ws[\"B3\"] = \"Fixed costs (per year)\", FIXED\nws[\"B3\"].fill = INPUT\nheaders = [\"Product\", \"Price\", \"Variable cost\", \"Forecast units\", \"Contribution\", \"CM ratio\", \"Mix\", \"Break-even units\", \"Break-even revenue\"]\nfor col, h in enumerate(headers, start=1):\n    ws.cell(5, col, h).font = Font(bold=True)\nfirst, last = 6, 6 + len(products) - 1\nfor i, p in enumerate(products.itertuples(index=False), start=first):\n    ws.cell(i, 1, p.Product)\n    for col, value in zip((2, 3, 4), (p.Price, p._2, p._3)):\n        ws.cell(i, col, value).fill = INPUT\n    ws.cell(i, 5, f\"=B{i}-C{i}\")\n    ws.cell(i, 6, f\"=E{i}\u002FB{i}\")\n    ws.cell(i, 7, f\"=D{i}\u002FSUM($D${first}:$D${last})\")\n    ws.cell(i, 8, f\"=$B$11*G{i}\")\n    ws.cell(i, 9, f\"=H{i}*B{i}\")\nsummary = [(\"Weighted contribution per unit\", f\"=SUMPRODUCT(E{first}:E{last},G{first}:G{last})\", \"0.0000\"),\n           (\"Break-even units (all products)\", \"=B3\u002FB10\", \"#,##0\"),\n           (\"Break-even revenue\", f\"=SUM(I{first}:I{last})\", \"#,##0\"),\n           (\"Forecast revenue\", f\"=SUMPRODUCT(B{first}:B{last},D{first}:D{last})\", \"#,##0\"),\n           (\"Margin of safety\", \"=(B13-B12)\u002FB13\", \"0.0%\"),\n           (\"Forecast profit\", f\"=SUMPRODUCT(E{first}:E{last},D{first}:D{last})-B3\", \"#,##0\")]\nfor r, (label, formula, fmt) in enumerate(summary, start=10):\n    ws.cell(r, 1, label).font = Font(bold=True)\n    ws.cell(r, 2, formula).number_format = fmt\nfor col, fmt in zip(\"BCDEFGHI\", [\"0.00\", \"0.00\", \"#,##0\", \"0.00\", \"0.0%\", \"0.0%\", \"#,##0\", \"#,##0\"]):\n    for r in range(first, last + 1):\n        ws[f\"{col}{r}\"].number_format = fmt\nws.column_dimensions[\"A\"].width = 32\nfor col in \"BCDEFGHI\":\n    ws.column_dimensions[col].width = 15\n",[32,739,740,753,765,769,779,789,799,824,868,892,906,953,981,1005,1034,1064,1074,1104,1114,1148,1181,1227,1252,1286,1350,1371,1408,1464,1484,1538,1562,1585,1600,1654,1678,1710,1727,1743],{"__ignoreMap":30},[35,741,742,745,748,750],{"class":37,"line":38},[35,743,744],{"class":78},"from",[35,746,747],{"class":82}," openpyxl ",[35,749,79],{"class":78},[35,751,752],{"class":82}," Workbook\n",[35,754,755,757,760,762],{"class":37,"line":92},[35,756,744],{"class":78},[35,758,759],{"class":82}," openpyxl.styles ",[35,761,79],{"class":78},[35,763,764],{"class":82}," Font, PatternFill\n",[35,766,767],{"class":37,"line":99},[35,768,96],{"emptyLinePlaceholder":95},[35,770,771,774,776],{"class":37,"line":112},[35,772,773],{"class":82},"wb ",[35,775,118],{"class":78},[35,777,778],{"class":82}," Workbook()\n",[35,780,781,784,786],{"class":37,"line":168},[35,782,783],{"class":82},"ws ",[35,785,118],{"class":78},[35,787,788],{"class":82}," wb.active\n",[35,790,791,794,796],{"class":37,"line":212},[35,792,793],{"class":82},"ws.title ",[35,795,118],{"class":78},[35,797,798],{"class":45}," \"Model\"\n",[35,800,801,804,806,809,812,814,817,819,822],{"class":37,"line":244},[35,802,803],{"class":102},"INPUT",[35,805,106],{"class":78},[35,807,808],{"class":82}," PatternFill(",[35,810,811],{"class":45},"\"solid\"",[35,813,133],{"class":82},[35,815,816],{"class":453},"fgColor",[35,818,118],{"class":78},[35,820,821],{"class":45},"\"FFF4CE\"",[35,823,533],{"class":82},[35,825,826,829,832,835,837,840,842,845,848,851,853,856,858,861,863,866],{"class":37,"line":271},[35,827,828],{"class":82},"ws[",[35,830,831],{"class":45},"\"A1\"",[35,833,834],{"class":82},"], ws[",[35,836,831],{"class":45},[35,838,839],{"class":82},"].font ",[35,841,118],{"class":78},[35,843,844],{"class":45}," \"Break-even analysis\"",[35,846,847],{"class":82},", Font(",[35,849,850],{"class":453},"size",[35,852,118],{"class":78},[35,854,855],{"class":102},"14",[35,857,133],{"class":82},[35,859,860],{"class":453},"bold",[35,862,118],{"class":78},[35,864,865],{"class":102},"True",[35,867,533],{"class":82},[35,869,870,872,875,877,880,882,884,887,889],{"class":37,"line":298},[35,871,828],{"class":82},[35,873,874],{"class":45},"\"A3\"",[35,876,834],{"class":82},[35,878,879],{"class":45},"\"B3\"",[35,881,221],{"class":82},[35,883,118],{"class":78},[35,885,886],{"class":45}," \"Fixed costs (per year)\"",[35,888,133],{"class":82},[35,890,891],{"class":102},"FIXED\n",[35,893,894,896,898,901,903],{"class":37,"line":303},[35,895,828],{"class":82},[35,897,879],{"class":45},[35,899,900],{"class":82},"].fill ",[35,902,118],{"class":78},[35,904,905],{"class":102}," INPUT\n",[35,907,908,911,913,916,918,920,922,924,926,928,930,932,934,936,938,940,942,944,946,948,951],{"class":37,"line":332},[35,909,910],{"class":82},"headers ",[35,912,118],{"class":78},[35,914,915],{"class":82}," [",[35,917,124],{"class":45},[35,919,133],{"class":82},[35,921,147],{"class":45},[35,923,133],{"class":82},[35,925,238],{"class":45},[35,927,133],{"class":82},[35,929,191],{"class":45},[35,931,133],{"class":82},[35,933,218],{"class":45},[35,935,133],{"class":82},[35,937,249],{"class":45},[35,939,133],{"class":82},[35,941,276],{"class":45},[35,943,133],{"class":82},[35,945,354],{"class":45},[35,947,133],{"class":82},[35,949,950],{"class":45},"\"Break-even revenue\"",[35,952,241],{"class":82},[35,954,955,958,961,964,967,970,973,975,978],{"class":37,"line":349},[35,956,957],{"class":78},"for",[35,959,960],{"class":82}," col, h ",[35,962,963],{"class":78},"in",[35,965,966],{"class":102}," enumerate",[35,968,969],{"class":82},"(headers, ",[35,971,972],{"class":453},"start",[35,974,118],{"class":78},[35,976,977],{"class":102},"1",[35,979,980],{"class":82},"):\n",[35,982,983,986,989,992,994,997,999,1001,1003],{"class":37,"line":372},[35,984,985],{"class":82},"    ws.cell(",[35,987,988],{"class":102},"5",[35,990,991],{"class":82},", col, h).font ",[35,993,118],{"class":78},[35,995,996],{"class":82}," Font(",[35,998,860],{"class":453},[35,1000,118],{"class":78},[35,1002,865],{"class":102},[35,1004,533],{"class":82},[35,1006,1007,1010,1012,1015,1017,1020,1023,1026,1029,1031],{"class":37,"line":395},[35,1008,1009],{"class":82},"first, last ",[35,1011,118],{"class":78},[35,1013,1014],{"class":102}," 6",[35,1016,133],{"class":82},[35,1018,1019],{"class":102},"6",[35,1021,1022],{"class":78}," +",[35,1024,1025],{"class":102}," len",[35,1027,1028],{"class":82},"(products) ",[35,1030,233],{"class":78},[35,1032,1033],{"class":102}," 1\n",[35,1035,1036,1038,1041,1043,1045,1048,1050,1052,1054,1057,1059,1061],{"class":37,"line":417},[35,1037,957],{"class":78},[35,1039,1040],{"class":82}," i, p ",[35,1042,963],{"class":78},[35,1044,966],{"class":102},[35,1046,1047],{"class":82},"(products.itertuples(",[35,1049,454],{"class":453},[35,1051,118],{"class":78},[35,1053,459],{"class":102},[35,1055,1056],{"class":82},"), ",[35,1058,972],{"class":453},[35,1060,118],{"class":78},[35,1062,1063],{"class":82},"first):\n",[35,1065,1066,1069,1071],{"class":37,"line":438},[35,1067,1068],{"class":82},"    ws.cell(i, ",[35,1070,977],{"class":102},[35,1072,1073],{"class":82},", p.Product)\n",[35,1075,1076,1079,1082,1084,1087,1090,1093,1095,1097,1099,1101],{"class":37,"line":465},[35,1077,1078],{"class":78},"    for",[35,1080,1081],{"class":82}," col, value ",[35,1083,963],{"class":78},[35,1085,1086],{"class":102}," zip",[35,1088,1089],{"class":82},"((",[35,1091,1092],{"class":102},"2",[35,1094,133],{"class":82},[35,1096,447],{"class":102},[35,1098,133],{"class":82},[35,1100,568],{"class":102},[35,1102,1103],{"class":82},"), (p.Price, p._2, p._3)):\n",[35,1105,1107,1110,1112],{"class":37,"line":1106},18,[35,1108,1109],{"class":82},"        ws.cell(i, col, value).fill ",[35,1111,118],{"class":78},[35,1113,905],{"class":102},[35,1115,1117,1119,1121,1123,1125,1128,1130,1133,1135,1138,1140,1142,1144,1146],{"class":37,"line":1116},19,[35,1118,1068],{"class":82},[35,1120,988],{"class":102},[35,1122,133],{"class":82},[35,1124,473],{"class":78},[35,1126,1127],{"class":45},"\"=B",[35,1129,480],{"class":479},[35,1131,1132],{"class":82},"i",[35,1134,489],{"class":479},[35,1136,1137],{"class":45},"-C",[35,1139,480],{"class":479},[35,1141,1132],{"class":82},[35,1143,489],{"class":479},[35,1145,530],{"class":45},[35,1147,533],{"class":82},[35,1149,1151,1153,1155,1157,1159,1162,1164,1166,1168,1171,1173,1175,1177,1179],{"class":37,"line":1150},20,[35,1152,1068],{"class":82},[35,1154,1019],{"class":102},[35,1156,133],{"class":82},[35,1158,473],{"class":78},[35,1160,1161],{"class":45},"\"=E",[35,1163,480],{"class":479},[35,1165,1132],{"class":82},[35,1167,489],{"class":479},[35,1169,1170],{"class":45},"\u002FB",[35,1172,480],{"class":479},[35,1174,1132],{"class":82},[35,1176,489],{"class":479},[35,1178,530],{"class":45},[35,1180,533],{"class":82},[35,1182,1184,1186,1189,1191,1193,1196,1198,1200,1202,1205,1207,1210,1212,1215,1217,1220,1222,1225],{"class":37,"line":1183},21,[35,1185,1068],{"class":82},[35,1187,1188],{"class":102},"7",[35,1190,133],{"class":82},[35,1192,473],{"class":78},[35,1194,1195],{"class":45},"\"=D",[35,1197,480],{"class":479},[35,1199,1132],{"class":82},[35,1201,489],{"class":479},[35,1203,1204],{"class":45},"\u002FSUM($D$",[35,1206,480],{"class":479},[35,1208,1209],{"class":82},"first",[35,1211,489],{"class":479},[35,1213,1214],{"class":45},":$D$",[35,1216,480],{"class":479},[35,1218,1219],{"class":82},"last",[35,1221,489],{"class":479},[35,1223,1224],{"class":45},")\"",[35,1226,533],{"class":82},[35,1228,1230,1232,1235,1237,1239,1242,1244,1246,1248,1250],{"class":37,"line":1229},22,[35,1231,1068],{"class":82},[35,1233,1234],{"class":102},"8",[35,1236,133],{"class":82},[35,1238,473],{"class":78},[35,1240,1241],{"class":45},"\"=$B$11*G",[35,1243,480],{"class":479},[35,1245,1132],{"class":82},[35,1247,489],{"class":479},[35,1249,530],{"class":45},[35,1251,533],{"class":82},[35,1253,1255,1257,1260,1262,1264,1267,1269,1271,1273,1276,1278,1280,1282,1284],{"class":37,"line":1254},23,[35,1256,1068],{"class":82},[35,1258,1259],{"class":102},"9",[35,1261,133],{"class":82},[35,1263,473],{"class":78},[35,1265,1266],{"class":45},"\"=H",[35,1268,480],{"class":479},[35,1270,1132],{"class":82},[35,1272,489],{"class":479},[35,1274,1275],{"class":45},"*B",[35,1277,480],{"class":479},[35,1279,1132],{"class":82},[35,1281,489],{"class":479},[35,1283,530],{"class":45},[35,1285,533],{"class":82},[35,1287,1289,1292,1294,1297,1300,1302,1304,1307,1309,1311,1313,1316,1318,1320,1322,1325,1327,1329,1331,1334,1336,1338,1340,1342,1344,1347],{"class":37,"line":1288},24,[35,1290,1291],{"class":82},"summary ",[35,1293,118],{"class":78},[35,1295,1296],{"class":82}," [(",[35,1298,1299],{"class":45},"\"Weighted contribution per unit\"",[35,1301,133],{"class":82},[35,1303,473],{"class":78},[35,1305,1306],{"class":45},"\"=SUMPRODUCT(E",[35,1308,480],{"class":479},[35,1310,1209],{"class":82},[35,1312,489],{"class":479},[35,1314,1315],{"class":45},":E",[35,1317,480],{"class":479},[35,1319,1219],{"class":82},[35,1321,489],{"class":479},[35,1323,1324],{"class":45},",G",[35,1326,480],{"class":479},[35,1328,1209],{"class":82},[35,1330,489],{"class":479},[35,1332,1333],{"class":45},":G",[35,1335,480],{"class":479},[35,1337,1219],{"class":82},[35,1339,489],{"class":479},[35,1341,1224],{"class":45},[35,1343,133],{"class":82},[35,1345,1346],{"class":45},"\"0.0000\"",[35,1348,1349],{"class":82},"),\n",[35,1351,1353,1356,1359,1361,1364,1366,1369],{"class":37,"line":1352},25,[35,1354,1355],{"class":82},"           (",[35,1357,1358],{"class":45},"\"Break-even units (all products)\"",[35,1360,133],{"class":82},[35,1362,1363],{"class":45},"\"=B3\u002FB10\"",[35,1365,133],{"class":82},[35,1367,1368],{"class":45},"\"#,##0\"",[35,1370,1349],{"class":82},[35,1372,1374,1376,1378,1380,1382,1385,1387,1389,1391,1394,1396,1398,1400,1402,1404,1406],{"class":37,"line":1373},26,[35,1375,1355],{"class":82},[35,1377,950],{"class":45},[35,1379,133],{"class":82},[35,1381,473],{"class":78},[35,1383,1384],{"class":45},"\"=SUM(I",[35,1386,480],{"class":479},[35,1388,1209],{"class":82},[35,1390,489],{"class":479},[35,1392,1393],{"class":45},":I",[35,1395,480],{"class":479},[35,1397,1219],{"class":82},[35,1399,489],{"class":479},[35,1401,1224],{"class":45},[35,1403,133],{"class":82},[35,1405,1368],{"class":45},[35,1407,1349],{"class":82},[35,1409,1411,1413,1416,1418,1420,1423,1425,1427,1429,1432,1434,1436,1438,1441,1443,1445,1447,1450,1452,1454,1456,1458,1460,1462],{"class":37,"line":1410},27,[35,1412,1355],{"class":82},[35,1414,1415],{"class":45},"\"Forecast revenue\"",[35,1417,133],{"class":82},[35,1419,473],{"class":78},[35,1421,1422],{"class":45},"\"=SUMPRODUCT(B",[35,1424,480],{"class":479},[35,1426,1209],{"class":82},[35,1428,489],{"class":479},[35,1430,1431],{"class":45},":B",[35,1433,480],{"class":479},[35,1435,1219],{"class":82},[35,1437,489],{"class":479},[35,1439,1440],{"class":45},",D",[35,1442,480],{"class":479},[35,1444,1209],{"class":82},[35,1446,489],{"class":479},[35,1448,1449],{"class":45},":D",[35,1451,480],{"class":479},[35,1453,1219],{"class":82},[35,1455,489],{"class":479},[35,1457,1224],{"class":45},[35,1459,133],{"class":82},[35,1461,1368],{"class":45},[35,1463,1349],{"class":82},[35,1465,1467,1469,1472,1474,1477,1479,1482],{"class":37,"line":1466},28,[35,1468,1355],{"class":82},[35,1470,1471],{"class":45},"\"Margin of safety\"",[35,1473,133],{"class":82},[35,1475,1476],{"class":45},"\"=(B13-B12)\u002FB13\"",[35,1478,133],{"class":82},[35,1480,1481],{"class":45},"\"0.0%\"",[35,1483,1349],{"class":82},[35,1485,1487,1489,1492,1494,1496,1498,1500,1502,1504,1506,1508,1510,1512,1514,1516,1518,1520,1522,1524,1526,1528,1531,1533,1535],{"class":37,"line":1486},29,[35,1488,1355],{"class":82},[35,1490,1491],{"class":45},"\"Forecast profit\"",[35,1493,133],{"class":82},[35,1495,473],{"class":78},[35,1497,1306],{"class":45},[35,1499,480],{"class":479},[35,1501,1209],{"class":82},[35,1503,489],{"class":479},[35,1505,1315],{"class":45},[35,1507,480],{"class":479},[35,1509,1219],{"class":82},[35,1511,489],{"class":479},[35,1513,1440],{"class":45},[35,1515,480],{"class":479},[35,1517,1209],{"class":82},[35,1519,489],{"class":479},[35,1521,1449],{"class":45},[35,1523,480],{"class":479},[35,1525,1219],{"class":82},[35,1527,489],{"class":479},[35,1529,1530],{"class":45},")-B3\"",[35,1532,133],{"class":82},[35,1534,1368],{"class":45},[35,1536,1537],{"class":82},")]\n",[35,1539,1541,1543,1546,1548,1550,1553,1555,1557,1560],{"class":37,"line":1540},30,[35,1542,957],{"class":78},[35,1544,1545],{"class":82}," r, (label, formula, fmt) ",[35,1547,963],{"class":78},[35,1549,966],{"class":102},[35,1551,1552],{"class":82},"(summary, ",[35,1554,972],{"class":453},[35,1556,118],{"class":78},[35,1558,1559],{"class":102},"10",[35,1561,980],{"class":82},[35,1563,1565,1568,1570,1573,1575,1577,1579,1581,1583],{"class":37,"line":1564},31,[35,1566,1567],{"class":82},"    ws.cell(r, ",[35,1569,977],{"class":102},[35,1571,1572],{"class":82},", label).font ",[35,1574,118],{"class":78},[35,1576,996],{"class":82},[35,1578,860],{"class":453},[35,1580,118],{"class":78},[35,1582,865],{"class":102},[35,1584,533],{"class":82},[35,1586,1588,1590,1592,1595,1597],{"class":37,"line":1587},32,[35,1589,1567],{"class":82},[35,1591,1092],{"class":102},[35,1593,1594],{"class":82},", formula).number_format ",[35,1596,118],{"class":78},[35,1598,1599],{"class":82}," fmt\n",[35,1601,1603,1605,1608,1610,1612,1614,1617,1620,1623,1625,1627,1629,1631,1633,1635,1637,1639,1641,1643,1645,1647,1649,1651],{"class":37,"line":1602},33,[35,1604,957],{"class":78},[35,1606,1607],{"class":82}," col, fmt ",[35,1609,963],{"class":78},[35,1611,1086],{"class":102},[35,1613,470],{"class":82},[35,1615,1616],{"class":45},"\"BCDEFGHI\"",[35,1618,1619],{"class":82},", [",[35,1621,1622],{"class":45},"\"0.00\"",[35,1624,133],{"class":82},[35,1626,1622],{"class":45},[35,1628,133],{"class":82},[35,1630,1368],{"class":45},[35,1632,133],{"class":82},[35,1634,1622],{"class":45},[35,1636,133],{"class":82},[35,1638,1481],{"class":45},[35,1640,133],{"class":82},[35,1642,1481],{"class":45},[35,1644,133],{"class":82},[35,1646,1368],{"class":45},[35,1648,133],{"class":82},[35,1650,1368],{"class":45},[35,1652,1653],{"class":82},"]):\n",[35,1655,1657,1659,1662,1664,1667,1670,1673,1676],{"class":37,"line":1656},34,[35,1658,1078],{"class":78},[35,1660,1661],{"class":82}," r ",[35,1663,963],{"class":78},[35,1665,1666],{"class":102}," range",[35,1668,1669],{"class":82},"(first, last ",[35,1671,1672],{"class":78},"+",[35,1674,1675],{"class":102}," 1",[35,1677,980],{"class":82},[35,1679,1681,1684,1686,1688,1690,1693,1696,1699,1701,1703,1706,1708],{"class":37,"line":1680},35,[35,1682,1683],{"class":82},"        ws[",[35,1685,473],{"class":78},[35,1687,530],{"class":45},[35,1689,480],{"class":479},[35,1691,1692],{"class":82},"col",[35,1694,1695],{"class":479},"}{",[35,1697,1698],{"class":82},"r",[35,1700,489],{"class":479},[35,1702,530],{"class":45},[35,1704,1705],{"class":82},"].number_format ",[35,1707,118],{"class":78},[35,1709,1599],{"class":82},[35,1711,1713,1716,1719,1722,1724],{"class":37,"line":1712},36,[35,1714,1715],{"class":82},"ws.column_dimensions[",[35,1717,1718],{"class":45},"\"A\"",[35,1720,1721],{"class":82},"].width ",[35,1723,118],{"class":78},[35,1725,1726],{"class":102}," 32\n",[35,1728,1730,1732,1735,1737,1740],{"class":37,"line":1729},37,[35,1731,957],{"class":78},[35,1733,1734],{"class":82}," col ",[35,1736,963],{"class":78},[35,1738,1739],{"class":45}," \"BCDEFGHI\"",[35,1741,1742],{"class":82},":\n",[35,1744,1746,1749,1751],{"class":37,"line":1745},38,[35,1747,1748],{"class":82},"    ws.column_dimensions[col].width ",[35,1750,118],{"class":78},[35,1752,1753],{"class":102}," 15\n",[10,1755,1756,1757,1760,1761,1764,1765,1768,1769,1773],{},"The break-even units in ",[32,1758,1759],{},"B11"," divide fixed costs by the weighted contribution in ",[32,1762,1763],{},"B10",", and each product's share in column H is that total times its mix. Change Pro's price in ",[32,1766,1767],{},"B8"," and its contribution, the weighted average, every break-even figure and the margin of safety all follow. Laying out inputs and formulas this way is covered more generally in ",[14,1770,1772],{"href":1771},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frun-what-if-scenarios-on-an-excel-model-with-python\u002F","Run What-If Scenarios on an Excel Model with Python",", which also shows how to drive such a model's inputs from Python.",[20,1775,1777],{"id":1776},"step-3-a-sensitivity-grid-and-a-cvp-chart","Step 3 — A sensitivity grid and a CVP chart",[10,1779,1780],{},"A single break-even number hides how sensitive it is. A grid of break-even volumes across a range of prices and variable costs for the main product — each cell a formula — shows it at a glance; a cost-volume-profit chart shows where revenue overtakes total cost:",[25,1782,1784],{"className":69,"code":1783,"language":71,"meta":30,"style":30},"from openpyxl.chart import Reference, ScatterChart, Series\n\nsens = wb.create_sheet(\"Sensitivity\")\nsens[\"A1\"] = \"Break-even units (all products) by Standard price (across) and Standard variable cost (down)\"\nprices = [16, 17, 18, 19, 20]\ncosts = [10.0, 10.5, 11.0, 11.5, 12.0]\nfor j, price in enumerate(prices, start=2):\n    sens.cell(3, j, price).font = Font(bold=True)\nfor i, cost in enumerate(costs, start=4):\n    sens.cell(i, 1, cost).font = Font(bold=True)\n    for j, _ in enumerate(prices, start=2):\n        col = sens.cell(3, j).column_letter\n        weighted = (f\"(({col}$3-$A{i})*Model!$G$6\"\n                    f\"+SUMPRODUCT(Model!$E$7:$E${last},Model!$G$7:$G${last}))\")\n        sens.cell(i, j, f\"=Model!$B$3\u002F{weighted}\").number_format = \"#,##0\"\n\ncvp = wb.create_sheet(\"CVP\")\ncvp.append([\"Units\", \"Revenue\", \"Total cost\", \"Fixed cost\"])\nfor n, units in enumerate(range(0, 40_001, 5_000), start=2):\n    cvp.append([units, f\"={units}*Model!$B$13\u002FSUM(Model!$D$6:$D${last})\",\n                f\"=Model!$B$3+{units}*(Model!$B$13\u002FSUM(Model!$D$6:$D${last})-Model!$B$10)\", \"=Model!$B$3\"])\nchart = ScatterChart()\nchart.title, chart.x_axis.title, chart.y_axis.title = \"Cost-volume-profit\", \"Units sold (forecast mix)\", \"Amount\"\nxs = Reference(cvp, min_col=1, min_row=2, max_row=cvp.max_row)\nfor col in (2, 3, 4):\n    s = Series(Reference(cvp, min_col=col, min_row=1, max_row=cvp.max_row), xs, title_from_data=True)\n    s.marker.symbol = \"none\"\n    chart.series.append(s)\nchart.x_axis.delete = chart.y_axis.delete = False\nchart.width, chart.height = 18, 9\ncvp.add_chart(chart, \"F2\")\nwb.save(\"break_even.xlsx\")\n",[32,1785,1786,1798,1802,1817,1831,1865,1898,1920,1942,1964,1986,2007,2022,2055,2083,2110,2114,2128,2154,2194,2224,2257,2267,2287,2323,2345,2386,2396,2401,2416,2431,2441],{"__ignoreMap":30},[35,1787,1788,1790,1793,1795],{"class":37,"line":38},[35,1789,744],{"class":78},[35,1791,1792],{"class":82}," openpyxl.chart ",[35,1794,79],{"class":78},[35,1796,1797],{"class":82}," Reference, ScatterChart, Series\n",[35,1799,1800],{"class":37,"line":92},[35,1801,96],{"emptyLinePlaceholder":95},[35,1803,1804,1807,1809,1812,1815],{"class":37,"line":99},[35,1805,1806],{"class":82},"sens ",[35,1808,118],{"class":78},[35,1810,1811],{"class":82}," wb.create_sheet(",[35,1813,1814],{"class":45},"\"Sensitivity\"",[35,1816,533],{"class":82},[35,1818,1819,1822,1824,1826,1828],{"class":37,"line":112},[35,1820,1821],{"class":82},"sens[",[35,1823,831],{"class":45},[35,1825,221],{"class":82},[35,1827,118],{"class":78},[35,1829,1830],{"class":45}," \"Break-even units (all products) by Standard price (across) and Standard variable cost (down)\"\n",[35,1832,1833,1836,1838,1840,1843,1845,1848,1850,1853,1855,1858,1860,1863],{"class":37,"line":168},[35,1834,1835],{"class":82},"prices ",[35,1837,118],{"class":78},[35,1839,915],{"class":82},[35,1841,1842],{"class":102},"16",[35,1844,133],{"class":82},[35,1846,1847],{"class":102},"17",[35,1849,133],{"class":82},[35,1851,1852],{"class":102},"18",[35,1854,133],{"class":82},[35,1856,1857],{"class":102},"19",[35,1859,133],{"class":82},[35,1861,1862],{"class":102},"20",[35,1864,241],{"class":82},[35,1866,1867,1870,1872,1874,1877,1879,1882,1884,1886,1888,1891,1893,1896],{"class":37,"line":212},[35,1868,1869],{"class":82},"costs ",[35,1871,118],{"class":78},[35,1873,915],{"class":82},[35,1875,1876],{"class":102},"10.0",[35,1878,133],{"class":82},[35,1880,1881],{"class":102},"10.5",[35,1883,133],{"class":82},[35,1885,176],{"class":102},[35,1887,133],{"class":82},[35,1889,1890],{"class":102},"11.5",[35,1892,133],{"class":82},[35,1894,1895],{"class":102},"12.0",[35,1897,241],{"class":82},[35,1899,1900,1902,1905,1907,1909,1912,1914,1916,1918],{"class":37,"line":244},[35,1901,957],{"class":78},[35,1903,1904],{"class":82}," j, price ",[35,1906,963],{"class":78},[35,1908,966],{"class":102},[35,1910,1911],{"class":82},"(prices, ",[35,1913,972],{"class":453},[35,1915,118],{"class":78},[35,1917,1092],{"class":102},[35,1919,980],{"class":82},[35,1921,1922,1925,1927,1930,1932,1934,1936,1938,1940],{"class":37,"line":271},[35,1923,1924],{"class":82},"    sens.cell(",[35,1926,447],{"class":102},[35,1928,1929],{"class":82},", j, price).font ",[35,1931,118],{"class":78},[35,1933,996],{"class":82},[35,1935,860],{"class":453},[35,1937,118],{"class":78},[35,1939,865],{"class":102},[35,1941,533],{"class":82},[35,1943,1944,1946,1949,1951,1953,1956,1958,1960,1962],{"class":37,"line":298},[35,1945,957],{"class":78},[35,1947,1948],{"class":82}," i, cost ",[35,1950,963],{"class":78},[35,1952,966],{"class":102},[35,1954,1955],{"class":82},"(costs, ",[35,1957,972],{"class":453},[35,1959,118],{"class":78},[35,1961,568],{"class":102},[35,1963,980],{"class":82},[35,1965,1966,1969,1971,1974,1976,1978,1980,1982,1984],{"class":37,"line":303},[35,1967,1968],{"class":82},"    sens.cell(i, ",[35,1970,977],{"class":102},[35,1972,1973],{"class":82},", cost).font ",[35,1975,118],{"class":78},[35,1977,996],{"class":82},[35,1979,860],{"class":453},[35,1981,118],{"class":78},[35,1983,865],{"class":102},[35,1985,533],{"class":82},[35,1987,1988,1990,1993,1995,1997,1999,2001,2003,2005],{"class":37,"line":332},[35,1989,1078],{"class":78},[35,1991,1992],{"class":82}," j, _ ",[35,1994,963],{"class":78},[35,1996,966],{"class":102},[35,1998,1911],{"class":82},[35,2000,972],{"class":453},[35,2002,118],{"class":78},[35,2004,1092],{"class":102},[35,2006,980],{"class":82},[35,2008,2009,2012,2014,2017,2019],{"class":37,"line":349},[35,2010,2011],{"class":82},"        col ",[35,2013,118],{"class":78},[35,2015,2016],{"class":82}," sens.cell(",[35,2018,447],{"class":102},[35,2020,2021],{"class":82},", j).column_letter\n",[35,2023,2024,2027,2029,2032,2034,2037,2039,2041,2043,2046,2048,2050,2052],{"class":37,"line":372},[35,2025,2026],{"class":82},"        weighted ",[35,2028,118],{"class":78},[35,2030,2031],{"class":82}," (",[35,2033,473],{"class":78},[35,2035,2036],{"class":45},"\"((",[35,2038,480],{"class":479},[35,2040,1692],{"class":82},[35,2042,489],{"class":479},[35,2044,2045],{"class":45},"$3-$A",[35,2047,480],{"class":479},[35,2049,1132],{"class":82},[35,2051,489],{"class":479},[35,2053,2054],{"class":45},")*Model!$G$6\"\n",[35,2056,2057,2060,2063,2065,2067,2069,2072,2074,2076,2078,2081],{"class":37,"line":395},[35,2058,2059],{"class":78},"                    f",[35,2061,2062],{"class":45},"\"+SUMPRODUCT(Model!$E$7:$E$",[35,2064,480],{"class":479},[35,2066,1219],{"class":82},[35,2068,489],{"class":479},[35,2070,2071],{"class":45},",Model!$G$7:$G$",[35,2073,480],{"class":479},[35,2075,1219],{"class":82},[35,2077,489],{"class":479},[35,2079,2080],{"class":45},"))\"",[35,2082,533],{"class":82},[35,2084,2085,2088,2090,2093,2095,2098,2100,2102,2105,2107],{"class":37,"line":417},[35,2086,2087],{"class":82},"        sens.cell(i, j, ",[35,2089,473],{"class":78},[35,2091,2092],{"class":45},"\"=Model!$B$3\u002F",[35,2094,480],{"class":479},[35,2096,2097],{"class":82},"weighted",[35,2099,489],{"class":479},[35,2101,530],{"class":45},[35,2103,2104],{"class":82},").number_format ",[35,2106,118],{"class":78},[35,2108,2109],{"class":45}," \"#,##0\"\n",[35,2111,2112],{"class":37,"line":438},[35,2113,96],{"emptyLinePlaceholder":95},[35,2115,2116,2119,2121,2123,2126],{"class":37,"line":465},[35,2117,2118],{"class":82},"cvp ",[35,2120,118],{"class":78},[35,2122,1811],{"class":82},[35,2124,2125],{"class":45},"\"CVP\"",[35,2127,533],{"class":82},[35,2129,2130,2133,2136,2138,2141,2143,2146,2148,2151],{"class":37,"line":1106},[35,2131,2132],{"class":82},"cvp.append([",[35,2134,2135],{"class":45},"\"Units\"",[35,2137,133],{"class":82},[35,2139,2140],{"class":45},"\"Revenue\"",[35,2142,133],{"class":82},[35,2144,2145],{"class":45},"\"Total cost\"",[35,2147,133],{"class":82},[35,2149,2150],{"class":45},"\"Fixed cost\"",[35,2152,2153],{"class":82},"])\n",[35,2155,2156,2158,2161,2163,2165,2167,2170,2172,2174,2176,2179,2181,2184,2186,2188,2190,2192],{"class":37,"line":1116},[35,2157,957],{"class":78},[35,2159,2160],{"class":82}," n, units ",[35,2162,963],{"class":78},[35,2164,966],{"class":102},[35,2166,470],{"class":82},[35,2168,2169],{"class":102},"range",[35,2171,470],{"class":82},[35,2173,569],{"class":102},[35,2175,133],{"class":82},[35,2177,2178],{"class":102},"40_001",[35,2180,133],{"class":82},[35,2182,2183],{"class":102},"5_000",[35,2185,1056],{"class":82},[35,2187,972],{"class":453},[35,2189,118],{"class":78},[35,2191,1092],{"class":102},[35,2193,980],{"class":82},[35,2195,2196,2199,2201,2204,2206,2208,2210,2213,2215,2217,2219,2221],{"class":37,"line":1150},[35,2197,2198],{"class":82},"    cvp.append([units, ",[35,2200,473],{"class":78},[35,2202,2203],{"class":45},"\"=",[35,2205,480],{"class":479},[35,2207,669],{"class":82},[35,2209,489],{"class":479},[35,2211,2212],{"class":45},"*Model!$B$13\u002FSUM(Model!$D$6:$D$",[35,2214,480],{"class":479},[35,2216,1219],{"class":82},[35,2218,489],{"class":479},[35,2220,1224],{"class":45},[35,2222,2223],{"class":82},",\n",[35,2225,2226,2229,2232,2234,2236,2238,2241,2243,2245,2247,2250,2252,2255],{"class":37,"line":1183},[35,2227,2228],{"class":78},"                f",[35,2230,2231],{"class":45},"\"=Model!$B$3+",[35,2233,480],{"class":479},[35,2235,669],{"class":82},[35,2237,489],{"class":479},[35,2239,2240],{"class":45},"*(Model!$B$13\u002FSUM(Model!$D$6:$D$",[35,2242,480],{"class":479},[35,2244,1219],{"class":82},[35,2246,489],{"class":479},[35,2248,2249],{"class":45},")-Model!$B$10)\"",[35,2251,133],{"class":82},[35,2253,2254],{"class":45},"\"=Model!$B$3\"",[35,2256,2153],{"class":82},[35,2258,2259,2262,2264],{"class":37,"line":1229},[35,2260,2261],{"class":82},"chart ",[35,2263,118],{"class":78},[35,2265,2266],{"class":82}," ScatterChart()\n",[35,2268,2269,2272,2274,2277,2279,2282,2284],{"class":37,"line":1254},[35,2270,2271],{"class":82},"chart.title, chart.x_axis.title, chart.y_axis.title ",[35,2273,118],{"class":78},[35,2275,2276],{"class":45}," \"Cost-volume-profit\"",[35,2278,133],{"class":82},[35,2280,2281],{"class":45},"\"Units sold (forecast mix)\"",[35,2283,133],{"class":82},[35,2285,2286],{"class":45},"\"Amount\"\n",[35,2288,2289,2292,2294,2297,2300,2302,2304,2306,2309,2311,2313,2315,2318,2320],{"class":37,"line":1288},[35,2290,2291],{"class":82},"xs ",[35,2293,118],{"class":78},[35,2295,2296],{"class":82}," Reference(cvp, ",[35,2298,2299],{"class":453},"min_col",[35,2301,118],{"class":78},[35,2303,977],{"class":102},[35,2305,133],{"class":82},[35,2307,2308],{"class":453},"min_row",[35,2310,118],{"class":78},[35,2312,1092],{"class":102},[35,2314,133],{"class":82},[35,2316,2317],{"class":453},"max_row",[35,2319,118],{"class":78},[35,2321,2322],{"class":82},"cvp.max_row)\n",[35,2324,2325,2327,2329,2331,2333,2335,2337,2339,2341,2343],{"class":37,"line":1352},[35,2326,957],{"class":78},[35,2328,1734],{"class":82},[35,2330,963],{"class":78},[35,2332,2031],{"class":82},[35,2334,1092],{"class":102},[35,2336,133],{"class":82},[35,2338,447],{"class":102},[35,2340,133],{"class":82},[35,2342,568],{"class":102},[35,2344,980],{"class":82},[35,2346,2347,2350,2352,2355,2357,2359,2362,2364,2366,2368,2370,2372,2374,2377,2380,2382,2384],{"class":37,"line":1373},[35,2348,2349],{"class":82},"    s ",[35,2351,118],{"class":78},[35,2353,2354],{"class":82}," Series(Reference(cvp, ",[35,2356,2299],{"class":453},[35,2358,118],{"class":78},[35,2360,2361],{"class":82},"col, ",[35,2363,2308],{"class":453},[35,2365,118],{"class":78},[35,2367,977],{"class":102},[35,2369,133],{"class":82},[35,2371,2317],{"class":453},[35,2373,118],{"class":78},[35,2375,2376],{"class":82},"cvp.max_row), xs, ",[35,2378,2379],{"class":453},"title_from_data",[35,2381,118],{"class":78},[35,2383,865],{"class":102},[35,2385,533],{"class":82},[35,2387,2388,2391,2393],{"class":37,"line":1410},[35,2389,2390],{"class":82},"    s.marker.symbol ",[35,2392,118],{"class":78},[35,2394,2395],{"class":45}," \"none\"\n",[35,2397,2398],{"class":37,"line":1466},[35,2399,2400],{"class":82},"    chart.series.append(s)\n",[35,2402,2403,2406,2408,2411,2413],{"class":37,"line":1486},[35,2404,2405],{"class":82},"chart.x_axis.delete ",[35,2407,118],{"class":78},[35,2409,2410],{"class":82}," chart.y_axis.delete ",[35,2412,118],{"class":78},[35,2414,2415],{"class":102}," False\n",[35,2417,2418,2421,2423,2426,2428],{"class":37,"line":1540},[35,2419,2420],{"class":82},"chart.width, chart.height ",[35,2422,118],{"class":78},[35,2424,2425],{"class":102}," 18",[35,2427,133],{"class":82},[35,2429,2430],{"class":102},"9\n",[35,2432,2433,2436,2439],{"class":37,"line":1564},[35,2434,2435],{"class":82},"cvp.add_chart(chart, ",[35,2437,2438],{"class":45},"\"F2\"",[35,2440,533],{"class":82},[35,2442,2443,2446,2449],{"class":37,"line":1587},[35,2444,2445],{"class":82},"wb.save(",[35,2447,2448],{"class":45},"\"break_even.xlsx\"",[35,2450,533],{"class":82},[10,2452,2453,2454,2457],{},"Each sensitivity cell recomputes the weighted contribution with that cell's price and cost for Standard, keeps Plus and Pro as in the model, and divides fixed costs by it. On the chart, revenue and total cost are straight lines in volume at the forecast mix — average price per unit, and fixed cost plus average variable cost per unit — and they cross at the break-even volume; the flat fixed-cost line shows how much of total cost does not move with volume. The chart's axes need ",[32,2455,2456],{},"delete = False"," to appear in recent Excel versions.",[547,2459,556,2465,556,2468,556,2471,556,2475,556,2480,556,2486,556,2489,556,2493,556,2499,556,2504,556,2508,556,2512,556,2515,556,2519,556,2521,556,2525,556,2528,556,2532,556,2536,556,2540,556,2544,556,2548,556,2552,556,2556,556,2560,556,2564,556,2568,556,2572,556,2575,556,2578,556,2581,556,2584,556,2587,556,2590,556,2593,556,2596,556,2599,556,2602,556,2605,556,2608,556,2611,556,2614,556,2617,556,2620,556,2623],{"viewBox":2460,"role":550,"ariaLabelledBy":2461,"xmlns":554,"style":2464},"4 0 748 280",[2462,2463],"be-cvp-t","be-cvp-d","width:100%;max-width:748px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[558,2466,2467],{"id":2462},"Revenue and total cost against volume",[562,2469,2470],{"id":2463},"Revenue rises from zero at about 26.62 per unit at the forecast mix. Total cost starts at the 240,000 of fixed costs and rises at about 15.15 per unit. The lines cross at about 20,940 units, the break-even point; above that, the gap between them is profit.",[566,2472],{"x":568,"y":569,"width":2473,"height":2474,"fill":572},"748","280",[566,2476],{"x":2477,"y":152,"width":2478,"height":2478,"rx":447,"fill":624,"stroke":615,"style":2479},"64.0","14.0","stroke-width:1.5px",[595,2481,2485],{"x":2482,"y":2483,"style":2484},"84.0","29.5","font-size:12px;font-weight:600;fill:var(--text,#172033);text-anchor:start","Revenue (k)",[566,2487],{"x":2488,"y":152,"width":2478,"height":2478,"rx":447,"fill":624,"stroke":615,"style":2479},"185.9",[595,2490,2492],{"x":2491,"y":2483,"style":2484},"205.9","Total cost (k)",[37,2494],{"x1":2495,"y1":2496,"x2":2497,"y2":2496,"stroke":581,"style":2498},"53.4","242.0","736.0","stroke-width:1px",[595,2500,569],{"x":2501,"y":2502,"style":2503},"30.7","246.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle",[37,2505],{"x1":2495,"y1":2506,"x2":2497,"y2":2506,"stroke":581,"style":2507},"178.7","stroke-width:1px;stroke-dasharray:5 4",[595,2509,2511],{"x":2501,"y":2510,"style":2503},"182.7","500",[37,2513],{"x1":2495,"y1":2514,"x2":2497,"y2":2514,"stroke":581,"style":2507},"115.3",[595,2516,2518],{"x":2501,"y":2517,"style":2503},"119.3","1k",[37,2520],{"x1":2495,"y1":162,"x2":2497,"y2":162,"stroke":581,"style":2507},[595,2522,2524],{"x":2501,"y":2523,"style":2503},"56.0","1.5k",[37,2526],{"x1":2495,"y1":2496,"x2":2497,"y2":2496,"stroke":2527,"style":2479},"var(--muted,#5b6780)",[595,2529,569],{"x":2530,"y":2531,"style":604},"91.3","260.0",[595,2533,2535],{"x":2534,"y":2531,"style":604},"167.2","5k",[595,2537,2539],{"x":2538,"y":2531,"style":604},"243.0","10k",[595,2541,2543],{"x":2542,"y":2531,"style":604},"318.9","15k",[595,2545,2547],{"x":2546,"y":2531,"style":604},"394.7","20k",[595,2549,2551],{"x":2550,"y":2531,"style":604},"470.6","25k",[595,2553,2555],{"x":2554,"y":2531,"style":604},"546.4","30k",[595,2557,2559],{"x":2558,"y":2531,"style":604},"622.2","35k",[595,2561,2563],{"x":2562,"y":2531,"style":604},"698.1","40k",[588,2565],{"d":2566,"fill":591,"stroke":615,"style":2567},"M91.3,242.0 L167.2,225.1 L243.0,208.3 L318.9,191.4 L394.7,174.6 L470.6,157.7 L546.4,140.9 L622.2,124.0 L698.1,107.2","stroke-width:2.5px;stroke-linejoin:round;stroke-linecap:round",[2569,2570],"circle",{"cx":2530,"cy":2496,"r":2571,"fill":572,"stroke":615,"style":582},"4.0",[2569,2573],{"cx":2534,"cy":2574,"r":2571,"fill":572,"stroke":615,"style":582},"225.1",[2569,2576],{"cx":2538,"cy":2577,"r":2571,"fill":572,"stroke":615,"style":582},"208.3",[2569,2579],{"cx":2542,"cy":2580,"r":2571,"fill":572,"stroke":615,"style":582},"191.4",[2569,2582],{"cx":2546,"cy":2583,"r":2571,"fill":572,"stroke":615,"style":582},"174.6",[2569,2585],{"cx":2550,"cy":2586,"r":2571,"fill":572,"stroke":615,"style":582},"157.7",[2569,2588],{"cx":2554,"cy":2589,"r":2571,"fill":572,"stroke":615,"style":582},"140.9",[2569,2591],{"cx":2558,"cy":2592,"r":2571,"fill":572,"stroke":615,"style":582},"124.0",[2569,2594],{"cx":2562,"cy":2595,"r":2571,"fill":572,"stroke":615,"style":582},"107.2",[588,2597],{"d":2598,"fill":591,"stroke":615,"style":2567},"M91.3,211.6 L167.2,202.0 L243.0,192.4 L318.9,182.8 L394.7,173.2 L470.6,163.6 L546.4,154.0 L622.2,144.4 L698.1,134.8",[2569,2600],{"cx":2530,"cy":2601,"r":2571,"fill":572,"stroke":615,"style":582},"211.6",[2569,2603],{"cx":2534,"cy":2604,"r":2571,"fill":572,"stroke":615,"style":582},"202.0",[2569,2606],{"cx":2538,"cy":2607,"r":2571,"fill":572,"stroke":615,"style":582},"192.4",[2569,2609],{"cx":2542,"cy":2610,"r":2571,"fill":572,"stroke":615,"style":582},"182.8",[2569,2612],{"cx":2546,"cy":2613,"r":2571,"fill":572,"stroke":615,"style":582},"173.2",[2569,2615],{"cx":2550,"cy":2616,"r":2571,"fill":572,"stroke":615,"style":582},"163.6",[2569,2618],{"cx":2554,"cy":2619,"r":2571,"fill":572,"stroke":615,"style":582},"154.0",[2569,2621],{"cx":2558,"cy":2622,"r":2571,"fill":572,"stroke":615,"style":582},"144.4",[2569,2624],{"cx":2562,"cy":2625,"r":2571,"fill":572,"stroke":615,"style":582},"134.8",[20,2627,2629],{"id":2628},"step-4-recalculate-and-check-against-pandas","Step 4 — Recalculate and check against pandas",[25,2631,2633],{"className":69,"code":2632,"language":71,"meta":30,"style":30},"import subprocess\nfrom openpyxl import load_workbook\n\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"calc\", \"break_even.xlsx\"], check=True, capture_output=True)\ncalc = load_workbook(\"calc\u002Fbreak_even.xlsx\", data_only=True)\nm = calc[\"Model\"]\nchecks = {\"weighted contribution\": (m[\"B10\"].value, wacm), \"break-even units\": (m[\"B11\"].value, be_units),\n          \"break-even revenue\": (m[\"B12\"].value, be_revenue), \"margin of safety\": (m[\"B14\"].value, margin_of_safety)}\nfor name, (excel, python) in checks.items():\n    print(f\"{name:\u003C22} Excel {excel:>12,.4f}   pandas {python:>12,.4f}   {'ok' if abs(excel - python) \u003C 1e-6 else 'MISMATCH'}\")\ns = calc[\"Sensitivity\"]\nprint(\"sensitivity at price 18, cost 11:\", round(s[\"D6\"].value), \"| at price 16, cost 12:\", round(s[\"B8\"].value), \"| at 20, 10:\", round(s[\"F4\"].value))\n",[32,2634,2635,2642,2653,2657,2714,2738,2753,2786,2810,2822,2905,2918],{"__ignoreMap":30},[35,2636,2637,2639],{"class":37,"line":38},[35,2638,79],{"class":78},[35,2640,2641],{"class":82}," subprocess\n",[35,2643,2644,2646,2648,2650],{"class":37,"line":92},[35,2645,744],{"class":78},[35,2647,747],{"class":82},[35,2649,79],{"class":78},[35,2651,2652],{"class":82}," load_workbook\n",[35,2654,2655],{"class":37,"line":99},[35,2656,96],{"emptyLinePlaceholder":95},[35,2658,2659,2662,2665,2667,2670,2672,2675,2677,2680,2682,2685,2687,2690,2692,2694,2696,2699,2701,2703,2705,2708,2710,2712],{"class":37,"line":112},[35,2660,2661],{"class":82},"subprocess.run([",[35,2663,2664],{"class":45},"\"soffice\"",[35,2666,133],{"class":82},[35,2668,2669],{"class":45},"\"--headless\"",[35,2671,133],{"class":82},[35,2673,2674],{"class":45},"\"--convert-to\"",[35,2676,133],{"class":82},[35,2678,2679],{"class":45},"\"xlsx\"",[35,2681,133],{"class":82},[35,2683,2684],{"class":45},"\"--outdir\"",[35,2686,133],{"class":82},[35,2688,2689],{"class":45},"\"calc\"",[35,2691,133],{"class":82},[35,2693,2448],{"class":45},[35,2695,144],{"class":82},[35,2697,2698],{"class":453},"check",[35,2700,118],{"class":78},[35,2702,865],{"class":102},[35,2704,133],{"class":82},[35,2706,2707],{"class":453},"capture_output",[35,2709,118],{"class":78},[35,2711,865],{"class":102},[35,2713,533],{"class":82},[35,2715,2716,2719,2721,2724,2727,2729,2732,2734,2736],{"class":37,"line":168},[35,2717,2718],{"class":82},"calc ",[35,2720,118],{"class":78},[35,2722,2723],{"class":82}," load_workbook(",[35,2725,2726],{"class":45},"\"calc\u002Fbreak_even.xlsx\"",[35,2728,133],{"class":82},[35,2730,2731],{"class":453},"data_only",[35,2733,118],{"class":78},[35,2735,865],{"class":102},[35,2737,533],{"class":82},[35,2739,2740,2743,2745,2748,2751],{"class":37,"line":212},[35,2741,2742],{"class":82},"m ",[35,2744,118],{"class":78},[35,2746,2747],{"class":82}," calc[",[35,2749,2750],{"class":45},"\"Model\"",[35,2752,241],{"class":82},[35,2754,2755,2758,2760,2763,2766,2769,2772,2775,2778,2780,2783],{"class":37,"line":244},[35,2756,2757],{"class":82},"checks ",[35,2759,118],{"class":78},[35,2761,2762],{"class":82}," {",[35,2764,2765],{"class":45},"\"weighted contribution\"",[35,2767,2768],{"class":82},": (m[",[35,2770,2771],{"class":45},"\"B10\"",[35,2773,2774],{"class":82},"].value, wacm), ",[35,2776,2777],{"class":45},"\"break-even units\"",[35,2779,2768],{"class":82},[35,2781,2782],{"class":45},"\"B11\"",[35,2784,2785],{"class":82},"].value, be_units),\n",[35,2787,2788,2791,2793,2796,2799,2802,2804,2807],{"class":37,"line":271},[35,2789,2790],{"class":45},"          \"break-even revenue\"",[35,2792,2768],{"class":82},[35,2794,2795],{"class":45},"\"B12\"",[35,2797,2798],{"class":82},"].value, be_revenue), ",[35,2800,2801],{"class":45},"\"margin of safety\"",[35,2803,2768],{"class":82},[35,2805,2806],{"class":45},"\"B14\"",[35,2808,2809],{"class":82},"].value, margin_of_safety)}\n",[35,2811,2812,2814,2817,2819],{"class":37,"line":298},[35,2813,957],{"class":78},[35,2815,2816],{"class":82}," name, (excel, python) ",[35,2818,963],{"class":78},[35,2820,2821],{"class":82}," checks.items():\n",[35,2823,2824,2827,2829,2831,2833,2835,2838,2841,2843,2846,2848,2851,2854,2856,2859,2861,2863,2865,2867,2870,2873,2876,2879,2882,2884,2887,2890,2893,2896,2899,2901,2903],{"class":37,"line":303},[35,2825,2826],{"class":102},"    print",[35,2828,470],{"class":82},[35,2830,473],{"class":78},[35,2832,530],{"class":45},[35,2834,480],{"class":479},[35,2836,2837],{"class":82},"name",[35,2839,2840],{"class":78},":\u003C22",[35,2842,489],{"class":479},[35,2844,2845],{"class":45}," Excel ",[35,2847,480],{"class":479},[35,2849,2850],{"class":82},"excel",[35,2852,2853],{"class":78},":>12,.4f",[35,2855,489],{"class":479},[35,2857,2858],{"class":45},"   pandas ",[35,2860,480],{"class":479},[35,2862,71],{"class":82},[35,2864,2853],{"class":78},[35,2866,489],{"class":479},[35,2868,2869],{"class":479},"   {",[35,2871,2872],{"class":45},"'ok'",[35,2874,2875],{"class":78}," if",[35,2877,2878],{"class":102}," abs",[35,2880,2881],{"class":82},"(excel ",[35,2883,233],{"class":78},[35,2885,2886],{"class":82}," python) ",[35,2888,2889],{"class":78},"\u003C",[35,2891,2892],{"class":102}," 1e-6",[35,2894,2895],{"class":78}," else",[35,2897,2898],{"class":45}," 'MISMATCH'",[35,2900,489],{"class":479},[35,2902,530],{"class":45},[35,2904,533],{"class":82},[35,2906,2907,2910,2912,2914,2916],{"class":37,"line":332},[35,2908,2909],{"class":82},"s ",[35,2911,118],{"class":78},[35,2913,2747],{"class":82},[35,2915,1814],{"class":45},[35,2917,241],{"class":82},[35,2919,2920,2922,2924,2927,2929,2932,2935,2938,2941,2944,2946,2948,2950,2953,2955,2958,2960,2962,2964,2967],{"class":37,"line":349},[35,2921,441],{"class":102},[35,2923,470],{"class":82},[35,2925,2926],{"class":45},"\"sensitivity at price 18, cost 11:\"",[35,2928,133],{"class":82},[35,2930,2931],{"class":102},"round",[35,2933,2934],{"class":82},"(s[",[35,2936,2937],{"class":45},"\"D6\"",[35,2939,2940],{"class":82},"].value), ",[35,2942,2943],{"class":45},"\"| at price 16, cost 12:\"",[35,2945,133],{"class":82},[35,2947,2931],{"class":102},[35,2949,2934],{"class":82},[35,2951,2952],{"class":45},"\"B8\"",[35,2954,2940],{"class":82},[35,2956,2957],{"class":45},"\"| at 20, 10:\"",[35,2959,133],{"class":82},[35,2961,2931],{"class":102},[35,2963,2934],{"class":82},[35,2965,2966],{"class":45},"\"F4\"",[35,2968,2969],{"class":82},"].value))\n",[10,2971,2972,2973,18],{},"Every model figure matches the pandas calculation, and the sensitivity cell for today's price and cost (18 and 11) reproduces the model's 20,940 units. The corners of the grid show the spread: if Standard's price fell to 16 while its cost rose to 12, the business would need about 24,375 units to break even — leaving a thin margin below the 26,000 forecast — while a price of 20 with a cost of 10 brings break-even down to about 18,353. That range, not the single number, is what makes the analysis useful in a pricing discussion. The verification technique is described in ",[14,2974,2976],{"href":2975},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python\u002F","Recalculate Excel Formulas Without Excel in Python",[547,2978,556,2984,556,2987,556,2990,556,2995,556,3000,556,3004,556,3010,556,3014,556,3018,556,3022,556,3026,556,3030,556,3034,556,3037,556,3041,556,3045,556,3049,556,3053,556,3057,556,3059,556,3063,556,3065,556,3067,556,3069,556,3071,556,3073,556,3075,556,3077,556,3079,556,3081,556,3083,556,3085,556,3088,556,3090,556,3093,556,3095,556,3099,556,3101,556,3103,556,3105,556,3107,556,3109,556,3111,556,3113,556,3117,556,3120,556,3123,556,3125,556,3128,556,3130,556,3132,556,3134,556,3136,556,3138,556,3141,556,3143,556,3145,556,3147,556,3149,556,3151,556,3154,556,3156,556,3159,556,3161,556,3165,556,3167,556,3169,556,3171,556,3173,556,3175,556,3177,556,3179],{"viewBox":2979,"role":550,"ariaLabelledBy":2980,"xmlns":554,"style":2983},"155 0 449 168",[2981,2982],"be-sens-t","be-sens-d","width:100%;max-width:449px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[558,2985,2986],{"id":2981},"Break-even units by Standard price and variable cost",[562,2988,2989],{"id":2982},"Rows are Standard variable costs from 10.00 to 12.00 and columns are prices from 16 to 20. Today's case, price 18 and cost 11, needs about 20,940 units. A price of 16 with a cost of 12 needs about 24,375; a price of 20 with a cost of 10 needs about 18,353.",[566,2991],{"x":2992,"y":569,"width":2993,"height":2994,"fill":572},"155","449","168",[566,2996],{"x":2997,"y":576,"width":2998,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"171.6","32.0","24.0",[566,3001],{"x":3002,"y":576,"width":3003,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"203.6","93.1",[595,3005,3009],{"x":3006,"y":3007,"style":3008},"250.1","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[566,3011],{"x":3012,"y":576,"width":3013,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"296.7","68.0",[595,3015,3017],{"x":3016,"y":3007,"style":3008},"330.6","B",[566,3019],{"x":3020,"y":576,"width":3021,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"364.6","44.0",[595,3023,3025],{"x":3024,"y":3007,"style":3008},"386.6","C",[566,3027],{"x":3028,"y":576,"width":3029,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"408.6","69.8",[595,3031,3033],{"x":3032,"y":3007,"style":3008},"443.5","D",[566,3035],{"x":3036,"y":576,"width":3021,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"478.5",[595,3038,3040],{"x":3039,"y":3007,"style":3008},"500.5","E",[566,3042],{"x":3043,"y":576,"width":3044,"height":2999,"rx":569,"fill":580,"stroke":581,"style":2498},"522.5","66.0",[595,3046,3048],{"x":3047,"y":3007,"style":3008},"555.4","F",[566,3050],{"x":2997,"y":3051,"width":2998,"height":3052,"rx":569,"fill":580,"stroke":581,"style":2498},"40.0","28.0",[595,3054,977],{"x":3055,"y":3056,"style":3008},"187.6","59.0",[566,3058],{"x":3002,"y":3051,"width":3003,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3060,3062],{"x":3006,"y":3056,"style":3061},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","cost \\ price",[566,3064],{"x":3012,"y":3051,"width":3013,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3066,1842],{"x":3016,"y":3056,"style":3061},[566,3068],{"x":3020,"y":3051,"width":3021,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3070,1847],{"x":3024,"y":3056,"style":3061},[566,3072],{"x":3028,"y":3051,"width":3029,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3074,1852],{"x":3032,"y":3056,"style":3061},[566,3076],{"x":3036,"y":3051,"width":3021,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3078,1857],{"x":3039,"y":3056,"style":3061},[566,3080],{"x":3043,"y":3051,"width":3044,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3082,1862],{"x":3047,"y":3056,"style":3061},[566,3084],{"x":2997,"y":3013,"width":2998,"height":3052,"rx":569,"fill":580,"stroke":581,"style":2498},[595,3086,1092],{"x":3055,"y":3087,"style":3008},"87.0",[566,3089],{"x":3002,"y":3013,"width":3003,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3091,3092],{"x":3006,"y":3087,"style":3061},"10.00",[566,3094],{"x":3012,"y":3013,"width":3013,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3096,3098],{"x":3016,"y":3087,"style":3097},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","…",[566,3100],{"x":3020,"y":3013,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3102,3098],{"x":3024,"y":3087,"style":3097},[566,3104],{"x":3028,"y":3013,"width":3029,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3106,3098],{"x":3032,"y":3087,"style":3097},[566,3108],{"x":3036,"y":3013,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3110,3098],{"x":3039,"y":3087,"style":3097},[566,3112],{"x":3043,"y":3013,"width":3044,"height":3052,"rx":569,"fill":653,"stroke":654,"style":2479},[595,3114,3116],{"x":3047,"y":3087,"style":3115},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","18,353",[566,3118],{"x":2997,"y":3119,"width":2998,"height":3052,"rx":569,"fill":580,"stroke":581,"style":2498},"96.0",[595,3121,447],{"x":3055,"y":3122,"style":3008},"115.0",[566,3124],{"x":3002,"y":3119,"width":3003,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3126,3127],{"x":3006,"y":3122,"style":3061},"11.00",[566,3129],{"x":3012,"y":3119,"width":3013,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3131,3098],{"x":3016,"y":3122,"style":3097},[566,3133],{"x":3020,"y":3119,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3135,3098],{"x":3024,"y":3122,"style":3097},[566,3137],{"x":3028,"y":3119,"width":3029,"height":3052,"rx":569,"fill":653,"stroke":654,"style":2479},[595,3139,3140],{"x":3032,"y":3122,"style":3115},"20,940",[566,3142],{"x":3036,"y":3119,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3144,3098],{"x":3039,"y":3122,"style":3097},[566,3146],{"x":3043,"y":3119,"width":3044,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3148,3098],{"x":3047,"y":3122,"style":3097},[566,3150],{"x":2997,"y":2592,"width":2998,"height":3052,"rx":569,"fill":580,"stroke":581,"style":2498},[595,3152,568],{"x":3055,"y":3153,"style":3008},"143.0",[566,3155],{"x":3002,"y":2592,"width":3003,"height":3052,"rx":569,"fill":624,"stroke":615,"style":2479},[595,3157,3158],{"x":3006,"y":3153,"style":3061},"12.00",[566,3160],{"x":3012,"y":2592,"width":3013,"height":3052,"rx":569,"fill":708,"stroke":709,"style":2479},[595,3162,3164],{"x":3016,"y":3153,"style":3163},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","24,375",[566,3166],{"x":3020,"y":2592,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3168,3098],{"x":3024,"y":3153,"style":3097},[566,3170],{"x":3028,"y":2592,"width":3029,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3172,3098],{"x":3032,"y":3153,"style":3097},[566,3174],{"x":3036,"y":2592,"width":3021,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3176,3098],{"x":3039,"y":3153,"style":3097},[566,3178],{"x":3043,"y":2592,"width":3044,"height":3052,"rx":569,"fill":572,"stroke":581,"style":2498},[595,3180,3098],{"x":3047,"y":3153,"style":3097},[20,3182,3184],{"id":3183},"common-pitfalls","Common pitfalls",[3186,3187,3188,3196,3202,3208,3214],"ul",{},[3189,3190,3191,3195],"li",{},[3192,3193,3194],"strong",{},"Hard-coded results."," Write formulas that refer to input cells so the model stays live.",[3189,3197,3198,3201],{},[3192,3199,3200],{},"Ignoring the mix."," Several products have no break-even until the mix is fixed.",[3189,3203,3204,3207],{},[3192,3205,3206],{},"One number instead of a range."," Add a sensitivity grid.",[3189,3209,3210,3213],{},[3192,3211,3212],{},"Unchecked formulas."," Recalculate and compare with an independent calculation.",[3189,3215,3216,3219,3220,3222],{},[3192,3217,3218],{},"Hidden chart axes."," Set ",[32,3221,2456],{}," on openpyxl chart axes.",[20,3224,3226],{"id":3225},"conclusion","Conclusion",[10,3228,3229],{},"Compute contribution, the mix-weighted contribution, break-even units and revenue and the margin of safety in pandas, then write the same model to Excel as shaded inputs and formulas that refer to them, add a sensitivity grid of break-even volumes across prices and costs and a cost-volume-profit chart, and recalculate with LibreOffice to confirm that every formula agrees with Python. The result is a model people can use to answer their own \"what if\" questions.",[20,3231,3233],{"id":3232},"frequently-asked-questions","Frequently asked questions",[10,3235,3236,3239],{},[3192,3237,3238],{},"How do I calculate break-even units in Python?","\nDivide fixed costs by contribution per unit, which is price minus variable cost; for several products use the contribution weighted by the sales mix.",[10,3241,3242,3245],{},[3192,3243,3244],{},"How do I calculate break-even for multiple products?","\nFix a sales mix, compute the weighted average contribution per unit, divide fixed costs by it for total units, and split those units by the mix.",[10,3247,3248,3251],{},[3192,3249,3250],{},"What is the margin of safety?","\nThe share by which forecast sales exceed break-even sales, (forecast revenue − break-even revenue) ÷ forecast revenue.",[10,3253,3254,3257],{},[3192,3255,3256],{},"How do I make the Excel model update when inputs change?","\nWrite the inputs as values and every calculation as a formula referring to them, rather than writing the computed results.",[20,3259,3261],{"id":3260},"related","Related",[3186,3263,3264,3270,3277,3284],{},[3189,3265,3266,3267,3269],{},"Up one level: ",[14,3268,17],{"href":16}," — finance reports from Python.",[3189,3271,3272,3276],{},[14,3273,3275],{"href":3274},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-product-margin-report\u002F","Build a Product Margin Report"," — margins by product.",[3189,3278,3279,3283],{},[14,3280,3282],{"href":3281},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report\u002F","Build a Budget vs Actual Variance Report"," — comparing against plan.",[3189,3285,3286,3290],{},[14,3287,3289],{"href":3288},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002Fadd-a-combo-chart-with-a-secondary-axis-in-openpyxl\u002F","Add a Combo Chart with a Secondary Axis in openpyxl"," — more chart options.",[3292,3293,3294],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":30,"searchDepth":92,"depth":92,"links":3296},[3297,3298,3299,3300,3301,3302,3303,3304,3305],{"id":22,"depth":92,"text":23},{"id":62,"depth":92,"text":63},{"id":730,"depth":92,"text":731},{"id":1776,"depth":92,"text":1777},{"id":2628,"depth":92,"text":2629},{"id":3183,"depth":92,"text":3184},{"id":3225,"depth":92,"text":3226},{"id":3232,"depth":92,"text":3233},{"id":3260,"depth":92,"text":3261},"2026-10-02","Build a live break-even workbook from Python: contribution margin, break-even units and revenue and margin of safety as Excel formulas driven by input cells, a multi-product break-even based on the sales mix, a price-by-cost sensitivity grid, and a cost-volume-profit chart, all checked against the same figures computed in pandas.","md",[3310,3312,3314,3316],{"q":3238,"a":3311},"Divide fixed costs by contribution per unit, which is price minus variable cost; for several products use the contribution weighted by the sales mix.",{"q":3244,"a":3313},"Fix a sales mix, compute the weighted average contribution per unit, divide fixed costs by it for total units, and split those units by the mix.",{"q":3250,"a":3315},"The share by which forecast sales exceed break-even sales, (forecast revenue − break-even revenue) ÷ forecast revenue.",{"q":3256,"a":3317},"Write the inputs as values and every calculation as a formula referring to them, rather than writing the computed results.","break-even analysis in excel with python",null,{"breadcrumb":3321},[3322,3324,3327],{"name":3323,"item":262},"Home",{"name":3325,"item":3326},"Automating Reporting Workflows with Python and Excel","\u002Fautomating-reporting-workflows\u002F",{"name":3328,"item":16},"Building Finance and Operations Reports in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python",{"title":5,"description":3331},"Break-even analysis workbook with openpyxl: input cells, contribution margin and break-even formulas, margin of safety, sales-mix break-even for several products, a sensitivity grid and a CVP chart, verified with LibreOffice.","build-a-break-even-analysis-in-excel-with-python","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-break-even-analysis-in-excel-with-python\u002Findex",[3335,3336],"report-layouts","excel-formulas","how-to","-Z9oHzGvC2xTL36ifrZQL6UI_aGb3Va-Q_HQmJArRLU",[3340,3344],{"title":3341,"path":3342,"stem":3343,"children":-1},"Build a Bill of Materials Cost Rollup","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-bill-of-materials-cost-rollup","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-bill-of-materials-cost-rollup\u002Findex",{"title":3345,"path":3346,"stem":3347,"children":-1},"Build a Budget vs Actual Variance Report in Excel with Python","\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report","automating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report\u002Findex",[3349,3351],{"path":3350,"title":3328},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports",{"path":3352,"title":3325},"\u002Fautomating-reporting-workflows",[],[3355,3359,3362,3365,3368,3371],{"path":3356,"title":3357,"kind":3358},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards","Building Multi-Sheet Excel Dashboards","guide",{"path":3360,"title":3361,"kind":3337},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-data-dictionary-sheet-to-an-excel-report","Add a Data Dictionary Sheet to an Excel Report",{"path":3363,"title":3364,"kind":3337},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-kpi-summary-block-to-an-excel-dashboard","Add a KPI Summary Block to an Excel Dashboard",{"path":3366,"title":3367,"kind":3337},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-a-table-of-contents-sheet-with-hyperlinks-in-excel","Add a Table of Contents Sheet with Hyperlinks in Excel",{"path":3369,"title":3370,"kind":3337},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-slicer-style-filters-to-an-excel-dashboard","Add a Dropdown Filter That Drives an Excel Dashboard",{"path":3372,"title":3373,"kind":3337},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-summary-sheet-to-excel-report-python","Add a Summary Sheet to an Excel Report with Python",1790972119263]