Waterfall Chart

Free Cash Flow Bridge Analysis

FCF waterfall bridging from net income through operating and investing activities.

Output
Free Cash Flow Bridge Analysis
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch

# FCF bridge (in millions)
categories = ['Net\nIncome', 'D&A', 'Stock-Based\nComp', 'Working\nCapital', 
              'Deferred\nTaxes', 'CapEx', 'Acquisitions', 'Free\nCash Flow']
values = [0, 85, 42, -38, 15, -120, -45, 0]

# Calculate running total
initial = 280
running_total = initial
bottoms = []
heights = []
colors = []

for i, (cat, val) in enumerate(zip(categories, values)):
    if cat == 'Net\nIncome':
        bottoms.append(0)
        heights.append(initial)
        colors.append('#276CF5')
    elif cat == 'Free\nCash Flow':
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#6CF527' if running_total > 0 else '#F5276C')
    elif val > 0:
        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('#F5276C')
        running_total += val

# Create figure
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)

# Add value labels
for i, (bar, val, bot, height) in enumerate(zip(bars, values, bottoms, heights)):
    y_pos = bot + height / 2
    if categories[i] in ['Net\nIncome', 'Free\nCash Flow']:
        label = f"${height}M"
        ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, 
                ha='center', va='center', fontsize=11, fontweight='bold', color='#374151')
    else:
        label = f"+${val}M" if val > 0 else f"-${abs(val)}M"
        ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, 
                ha='center', va='center', fontsize=10, fontweight='bold', color='#374151')

# Connect bars
for i in range(len(x) - 1):
    if i == 0:
        y = initial
    else:
        y = 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)

# Styling
ax.set_xlim(-0.6, len(categories) - 0.4)
ax.set_ylim(0, max(bottoms[i] + heights[i] for i in range(len(heights))) * 1.1)
ax.set_xticks(x)
ax.set_xticklabels(categories, fontsize=10, color='#374151')
ax.set_ylabel('Value ($ Millions)', fontsize=12, color='#374151', fontweight='500')
ax.set_title('Free Cash Flow Bridge: Net Income to FCF', 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')

# Legend outside plot
legend_elements = [
    Patch(facecolor='#276CF5', label='Net Income'),
    Patch(facecolor='#27F5B0', label='Non-Cash Add-backs'),
    Patch(facecolor='#F5276C', label='Cash Uses'),
    Patch(facecolor='#6CF527', label='Free Cash Flow')
]
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

Did this help you?

Support PyLucid to keep it free & growing

Support