Coffee Math: The Visualization
In a previous post, I did the math on whether buying an espresso machine actually saves money compared to Melbourne cafe prices. The numbers were clear but dry – tables of dollar amounts and break-even months. Let’s turn those numbers into charts.
This post takes the same data – a Breville Barista Pro at $1,000, a La Marzocco Linea Micra + Niche Zero at $7,678, and Melbourne flat whites at $6 each – and visualizes the break-even story with Python.
The Data
Show codeHide code
1import matplotlib.pyplot as plt
2import pandas as pd
3import numpy as np
4
5# Core cost data from the original analysis
6CAFE_PRICE = 6.00 # AUD per flat white
7BREVILLE_UPFRONT = 1000 # AUD (machine + accessories)
8LAMARZOCCO_UPFRONT = 7678 # AUD (machine + grinder + accessories)
9LEARNING_CURVE = 120 # AUD wasted coffee while learning
10
11# Annual running costs at 2 coffees/day
12BEANS_ANNUAL = 1050
13MILK_ANNUAL = 275
14MAINTENANCE_ANNUAL = 245
15RUNNING_ANNUAL = BEANS_ANNUAL + MILK_ANNUAL + MAINTENANCE_ANNUAL # $1,570
16
17# matplotlib styling
18LABEL_COLOR = "#444444"
19GRID_COLOR = "#cccccc"
20plt.rcParams.update({
21 "figure.facecolor": "white",
22 "axes.facecolor": "white",
23 "axes.edgecolor": LABEL_COLOR,
24 "axes.labelcolor": LABEL_COLOR,
25 "xtick.color": LABEL_COLOR,
26 "ytick.color": LABEL_COLOR,
27 "text.color": LABEL_COLOR,
28 "legend.edgecolor": LABEL_COLOR,
29})Cumulative Cost Over Time
The key question is simple: at what point does the money you save on cafe coffees exceed what you spent on the machine and running costs? Here’s how the three options compare over three years.
Show codeHide code
1months = np.arange(0, 37)
2coffees_per_day = 2
3days_per_month = 30.44 # average
4
5cafe_cumulative = CAFE_PRICE * coffees_per_day * days_per_month * months
6
7breville_cumulative = (
8 BREVILLE_UPFRONT
9 + LEARNING_CURVE
10 + (RUNNING_ANNUAL / 12) * months
11)
12breville_cumulative[0] = BREVILLE_UPFRONT # upfront only at month 0
13
14lamarzocco_cumulative = (
15 LAMARZOCCO_UPFRONT
16 + LEARNING_CURVE
17 + (RUNNING_ANNUAL / 12) * months
18)
19lamarzocco_cumulative[0] = LAMARZOCCO_UPFRONT
20
21fig, ax = plt.subplots(figsize=(8, 4))
22
23ax.plot(months, cafe_cumulative, label="Cafe ($6/flat white)", color="#e07a5f", linewidth=2)
24ax.plot(months, breville_cumulative, label="Breville Barista Pro", color="#3d85c6", linewidth=2)
25ax.plot(months, lamarzocco_cumulative, label="La Marzocco + Niche Zero", color="#81b29a", linewidth=2)
26
27# Mark break-even points
28breville_be = 4.3
29lamarzocco_be = 33.6 # ~2.8 years
30ax.axvline(x=breville_be, color="#3d85c6", linestyle="--", alpha=0.5)
31ax.axvline(x=lamarzocco_be, color="#81b29a", linestyle="--", alpha=0.5)
32
33ax.annotate(
34 "Breville\nbreak-even\n4.3 mo",
35 xy=(breville_be, CAFE_PRICE * coffees_per_day * days_per_month * breville_be),
36 xytext=(breville_be + 3, 4000),
37 fontsize=8,
38 color="#3d85c6",
39 arrowprops=dict(arrowstyle="->", color="#3d85c6", lw=0.8),
40)
41ax.annotate(
42 "La Marzocco\nbreak-even\n~2.8 yr",
43 xy=(lamarzocco_be, CAFE_PRICE * coffees_per_day * days_per_month * lamarzocco_be),
44 xytext=(lamarzocco_be - 10, 9000),
45 fontsize=8,
46 color="#81b29a",
47 arrowprops=dict(arrowstyle="->", color="#81b29a", lw=0.8),
48)
49
50ax.set_xlabel("Months")
51ax.set_ylabel("Cumulative Cost (AUD)")
52ax.legend(framealpha=0.5)
53ax.grid(True, alpha=0.2, color=GRID_COLOR)
54ax.set_xlim(0, 36)
55ax.set_ylim(0, None)
56
57plt.tight_layout()
58plt.show()
Cumulative cost comparison over 36 months at 2 coffees per day. The Breville breaks even at 4.3 months; the La Marzocco at about 2.8 years.
The Breville line crosses below the cafe line remarkably fast. By month five, you’re already saving money. The La Marzocco setup takes nearly three years to pay off, but once it does, the savings accumulate at the same rate.
Break-Even by Consumption
How much coffee you drink changes the equation dramatically. Here’s how break-even times shift across different consumption levels.
Show codeHide code
1def break_even_months(upfront, daily_coffees):
2 """Calculate months to break even."""
3 monthly_cafe = CAFE_PRICE * daily_coffees * 30.44
4 monthly_home = (RUNNING_ANNUAL / 12) * (daily_coffees / 2) # scale running cost
5 monthly_savings = monthly_cafe - monthly_home
6 if monthly_savings <= 0:
7 return float("inf")
8 return (upfront + LEARNING_CURVE) / monthly_savings
9
10rows = []
11for daily in [1, 2, 3]:
12 b_months = break_even_months(BREVILLE_UPFRONT, daily)
13 l_months = break_even_months(LAMARZOCCO_UPFRONT, daily)
14
15 def fmt(m):
16 if m >= 12:
17 return f"{m / 12:.1f} years"
18 return f"{m:.1f} months"
19
20 rows.append({
21 "Daily Coffees": daily,
22 "Breville Barista Pro": fmt(b_months),
23 "La Marzocco + Niche Zero": fmt(l_months),
24 })
25
26df_breakeven = pd.DataFrame(rows)
27print(df_breakeven.to_html(index=False, justify="left"))| Daily Coffees | Breville Barista Pro | La Marzocco + Niche Zero |
|---|---|---|
| 1 | 9.6 months | 5.5 years |
| 2 | 4.8 months | 2.8 years |
| 3 | 3.2 months | 1.8 years |
At three coffees a day, even the premium La Marzocco setup pays for itself in under two years.
Running Cost Breakdown
Where does the $1,570 annual running cost actually go? Beans dominate, which makes sense – 13 kilograms of specialty coffee a year is a lot of beans.
Show codeHide code
1categories = ["Beans", "Milk", "Maintenance\n& Utilities"]
2costs = [BEANS_ANNUAL, MILK_ANNUAL, MAINTENANCE_ANNUAL]
3colors = ["#e07a5f", "#3d85c6", "#81b29a"]
4
5fig, ax = plt.subplots(figsize=(8, 3))
6
7bars = ax.barh(categories, costs, color=colors, height=0.5)
8
9for bar, cost in zip(bars, costs):
10 ax.text(
11 bar.get_width() + 20,
12 bar.get_y() + bar.get_height() / 2,
13 f"${cost:,}",
14 va="center",
15 fontsize=10,
16 color=LABEL_COLOR,
17 )
18
19ax.set_xlabel("Annual Cost (AUD)")
20ax.set_xlim(0, max(costs) * 1.2)
21ax.grid(True, axis="x", alpha=0.2, color=GRID_COLOR)
22ax.invert_yaxis()
23
24plt.tight_layout()
25plt.show()
Annual running cost breakdown for home espresso at 2 coffees per day. Beans account for two-thirds of the ongoing cost.
The Break-Even Formula
Here’s the math if you want to tweak the numbers for your own setup. Swap in your machine cost, local cafe price, and daily consumption to see your personal break-even point.
1# The break-even formula
2machine_cost = 1000 # your upfront cost in AUD
3cafe_price = 6.00 # your local flat white price
4daily_coffees = 2 # how many you drink per day
5running_cost_per_coffee = 2.15 # home espresso cost per cup
6
7monthly_cafe_spend = cafe_price * daily_coffees * 30.44
8monthly_home_spend = running_cost_per_coffee * daily_coffees * 30.44
9monthly_savings = monthly_cafe_spend - monthly_home_spend
10
11break_even = machine_cost / monthly_savings
12print(f"Break-even: {break_even:.1f} months")Break-even: 4.3 months
Equipment Comparison
Putting it all together – here’s a side-by-side comparison factoring in upfront cost, ongoing expenses, and long-term savings.
Show codeHide code
1breville_5yr_savings = (CAFE_PRICE * 2 * 365.25 * 5) - (BREVILLE_UPFRONT + RUNNING_ANNUAL * 5)
2lamarzocco_5yr_savings = (CAFE_PRICE * 2 * 365.25 * 5) - (LAMARZOCCO_UPFRONT + RUNNING_ANNUAL * 5)
3
4df_comparison = pd.DataFrame({
5 "": ["Breville Barista Pro", "La Marzocco + Niche Zero"],
6 "Upfront Cost": ["$1,000", "$7,678"],
7 "Annual Running": ["$1,570", "$1,570"],
8 "Break-even (2 cups/day)": ["4.3 months", "2.8 years"],
9 "Expected Lifespan": ["5-7 years", "10-20 years"],
10 "5-Year Savings": [f"${breville_5yr_savings:,.0f}", f"${lamarzocco_5yr_savings:,.0f}"],
11})
12print(df_comparison.to_html(index=False, justify="left"))| Upfront Cost | Annual Running | Break-even (2 cups/day) | Expected Lifespan | 5-Year Savings | |
|---|---|---|---|---|---|
| Breville Barista Pro | $1,000 | $1,570 | 4.3 months | 5-7 years | $13,065 |
| La Marzocco + Niche Zero | $7,678 | $1,570 | 2.8 years | 10-20 years | $6,387 |
The Bottom Line
The charts make the story clearer than raw numbers ever could. That steep cafe spending line climbing away from the much flatter home espresso lines is hard to argue with. At Melbourne’s current $6 flat whites, even the premium setup eventually makes financial sense – and the Breville pays for itself before winter is over.
The real takeaway is in the running cost breakdown: beans are the biggest ongoing expense by far. If you want to optimise your home espresso costs, shopping around for beans is where the money is.