Waterfall Chart
Project ROI Breakdown
Investment return waterfall showing project costs, benefits, and net ROI.
Output
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch
categories = ['Initial\nInvestment', 'Implementation\nCosts', 'Training', 'Revenue\nIncrease',
'Cost\nSavings', 'Efficiency\nGains', 'Maintenance', 'Net\nROI']
values = [0, -85, -25, 180, 95, 65, -45, 0]
initial = 0
running_total = initial
bottoms, heights, colors = [], [], []
for i, (cat, val) in enumerate(zip(categories, values)):
if 'Initial' in cat:
bottoms.append(0)
heights.append(250) # Initial investment as reference
colors.append('#F5276C')
running_total = -250
elif 'Net' in cat:
bottoms.append(0 if running_total > 0 else running_total)
heights.append(abs(running_total))
colors.append('#6CF527' if running_total > 0 else '#F5276C')
elif val > 0:
if running_total < 0:
bottoms.append(running_total)
else:
bottoms.append(running_total)
heights.append(val)
colors.append('#27F5B0')
running_total += val
else:
bottoms.append(running_total + val)
heights.append(abs(val))
colors.append('#F54927')
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)
labels_val = [-250, -85, -25, 180, 95, 65, -45, running_total]
for i, (bar, val, bot, height) in enumerate(zip(bars, labels_val, bottoms, heights)):
y_pos = bot + height / 2
if i == 0:
label = f"-${abs(val)}K"
elif i == len(categories) - 1:
label = f"${val}K" if val > 0 else f"-${abs(val)}K"
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='#374151')
ax.axhline(y=0, color='#9ca3af', linestyle='-', linewidth=1)
ax.set_xlim(-0.6, len(categories) - 0.4)
ax.set_ylim(min(bottoms) * 1.1, max(b + h for b, h in zip(bottoms, heights)) * 1.1)
ax.set_xticks(x)
ax.set_xticklabels(categories, fontsize=9, color='#374151')
ax.set_ylabel('Value ($ Thousands)', fontsize=12, color='#374151', fontweight='500')
ax.set_title('Project Investment ROI Analysis', fontsize=16, color='#374151', fontweight='bold', pad=20)
ax.tick_params(axis='y', colors='#e2e8f0', labelsize=10)
ax.yaxis.grid(True, linestyle='--', alpha=0.3, color='#e5e7eb')
ax.set_axisbelow(True)
for spine in ax.spines.values():
spine.set_color('#334155')
roi_pct = (running_total / 250) * 100
ax.annotate(f'ROI: {roi_pct:.0f}% | Payback: 14 months', xy=(0.98, 0.95), xycoords='axes fraction',
fontsize=11, color='#6CF527', ha='right', fontweight='bold',
bbox=dict(boxstyle='round,pad=0.4', facecolor='white', edgecolor='#6CF527', alpha=0.9))
legend_elements = [Patch(facecolor='#F5276C', label='Investment'), Patch(facecolor='#F54927', label='Costs'),
Patch(facecolor='#27F5B0', label='Benefits'), Patch(facecolor='#6CF527', label='Net ROI')]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0, -0.1), ncol=4, fontsize=9,
facecolor='white', edgecolor='#e5e7eb', labelcolor='#374151')
plt.tight_layout()
plt.subplots_adjust(bottom=0.15)
plt.show()
Library
Matplotlib
Category
Financial
More Waterfall Chart examples
☕