Waterfall Chart
Startup Funding Runway Analysis
Cash runway waterfall showing burn rate components and remaining runway.
Output
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch
categories = ['Series A\nFunding', 'Engineering\nTeam', 'Sales &\nMarketing', 'Operations',
'Infrastructure', 'Legal &\nAdmin', 'Revenue\nOffset', 'Remaining\nRunway']
values = [0, -180, -120, -45, -35, -25, 85, 0]
initial = 500
running_total = initial
bottoms, heights, colors = [], [], []
for i, (cat, val) in enumerate(zip(categories, values)):
if 'Series' in cat:
bottoms.append(0)
heights.append(initial)
colors.append('#22c55e')
elif 'Remaining' in cat:
bottoms.append(0)
heights.append(running_total)
colors.append('#3b82f6' if running_total > 100 else '#f59e0b')
elif val > 0:
bottoms.append(running_total)
heights.append(val)
colors.append('#22c55e')
running_total += val
else:
bottoms.append(running_total + val)
heights.append(abs(val))
colors.append('#ef4444')
running_total += val
fig, ax = plt.subplots(figsize=(14, 8), facecolor='#ffffff')
ax.set_facecolor('#ffffff')
x = np.arange(len(categories))
bars = ax.bar(x, heights, bottom=bottoms, color=colors, width=0.65, edgecolor='#e5e7eb', linewidth=1)
for i, (bar, val, bot, height) in enumerate(zip(bars, values, bottoms, heights)):
y_pos = bot + height / 2
if 'Series' in categories[i] or 'Remaining' in categories[i]:
label = f"${height}K"
ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, ha='center', va='center',
fontsize=11, fontweight='bold', color='white')
else:
label = f"+${val}K" if val > 0 else f"-${abs(val)}K"
ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, ha='center', va='center',
fontsize=10, fontweight='bold', color='white')
for i in range(len(x) - 1):
y = initial if i == 0 else bottoms[i] + heights[i]
ax.plot([x[i] + 0.35, x[i+1] - 0.35], [y, y], color='#9ca3af', linestyle='--', linewidth=1.5, alpha=0.7)
ax.set_xlim(-0.6, len(categories) - 0.4)
ax.set_ylim(0, initial * 1.1)
ax.set_xticks(x)
ax.set_xticklabels(categories, fontsize=9, color='#374151')
ax.set_ylabel('Cash ($ Thousands)', fontsize=12, color='#374151', fontweight='500')
ax.set_title('12-Month Cash Runway Analysis', fontsize=16, color='#111827', fontweight='bold', pad=20)
ax.tick_params(axis='y', colors='#374151', labelsize=10)
ax.yaxis.grid(True, linestyle='--', alpha=0.4, color='#e5e7eb')
ax.set_axisbelow(True)
for spine in ax.spines.values():
spine.set_color('#d1d5db')
# Calculate runway in months
monthly_burn = (initial - running_total - 85) / 12 # Net of revenue
runway_months = running_total / monthly_burn if monthly_burn > 0 else 0
ax.annotate(f'Monthly Burn: ${monthly_burn:.0f}K | Runway: {runway_months:.0f} months', xy=(0.98, 0.95), xycoords='axes fraction',
fontsize=10, color='#2563eb', ha='right', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.4', facecolor='#eff6ff', edgecolor='#3b82f6'))
legend_elements = [Patch(facecolor='#22c55e', label='Funding/Revenue'), Patch(facecolor='#ef4444', label='Burn Rate'),
Patch(facecolor='#3b82f6', label='Remaining Cash')]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0, -0.1), ncol=3, fontsize=9,
facecolor='white', edgecolor='#d1d5db', labelcolor='#374151')
plt.tight_layout()
plt.subplots_adjust(bottom=0.15)
plt.show()
Library
Matplotlib
Category
Financial
More Waterfall Chart examples
☕