Waterfall Chart

Revenue to Net Income Breakdown

Dark-themed waterfall chart showing the breakdown from gross revenue to net income including costs, expenses, and taxes.

Output
Revenue to Net Income Breakdown
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch

# Financial data (in millions)
categories = ['Gross\nRevenue', 'Discounts', 'Net\nRevenue', 'COGS', 'Gross\nProfit', 
              'OpEx', 'EBITDA', 'D&A', 'Interest', 'Taxes', 'Net\nIncome']
values = [0, -45, 0, -280, 0, -165, 0, -35, -18, -42, 0]

# Calculate positions for waterfall
initial = 850
running_total = initial
bottoms = []
heights = []
colors = []

for i, (cat, val) in enumerate(zip(categories, values)):
    if cat == 'Gross\nRevenue':
        bottoms.append(0)
        heights.append(initial)
        colors.append('#27D3F5')
    elif cat in ['Net\nRevenue', 'Gross\nProfit', 'EBITDA']:
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#F5B027')
    elif cat == 'Net\nIncome':
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#6CF527')
    else:
        bottoms.append(running_total + val)
        heights.append(abs(val))
        colors.append('#F5276C')
        running_total += val

# Create figure with extra space for legend
fig, ax = plt.subplots(figsize=(14, 8), facecolor='#0a0a0f')
ax.set_facecolor('#0a0a0f')

x = np.arange(len(categories))
bars = ax.bar(x, heights, bottom=bottoms, color=colors, width=0.65, edgecolor='#1e293b', 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 ['Gross\nRevenue', 'Net\nRevenue', 'Gross\nProfit', 'EBITDA', 'Net\nIncome']:
        label = f"${height}M"
        fontcolor = '#0a0a0f' if height > 200 else 'white'
    else:
        label = f"-${abs(val)}M"
        fontcolor = 'white'
    ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, 
            ha='center', va='center', fontsize=9, fontweight='bold', color=fontcolor)

# Connect bars with lines
for i in range(len(x) - 1):
    if categories[i] in ['Gross\nRevenue', 'Net\nRevenue', 'Gross\nProfit', 'EBITDA']:
        y = heights[i]
    else:
        y = bottoms[i]
    ax.plot([x[i] + 0.35, x[i+1] - 0.35], [y, y], 
            color='#475569', linestyle='--', linewidth=1.5, alpha=0.7)

# Styling
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='#e2e8f0')
ax.set_ylabel('Value ($ Millions)', fontsize=12, color='#e2e8f0', fontweight='500')
ax.set_title('Revenue to Net Income Waterfall', fontsize=16, color='white', fontweight='bold', pad=20)

ax.tick_params(axis='y', colors='#e2e8f0', labelsize=10)
ax.yaxis.grid(True, linestyle='--', alpha=0.3, color='#334155')
ax.set_axisbelow(True)

for spine in ax.spines.values():
    spine.set_color('#334155')

# Legend outside plot
legend_elements = [
    Patch(facecolor='#27D3F5', label='Starting Revenue'),
    Patch(facecolor='#F5B027', label='Subtotals'),
    Patch(facecolor='#F5276C', label='Deductions'),
    Patch(facecolor='#6CF527', label='Net Income')
]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0, -0.12), 
          ncol=4, fontsize=9, facecolor='#1e293b', edgecolor='#334155', labelcolor='white')

plt.tight_layout()
plt.subplots_adjust(bottom=0.18)
plt.show()
Library

Matplotlib

Category

Financial

Did this help you?

Support PyLucid to keep it free & growing

Support