Waterfall Chart

Product Line Profitability Analysis

Waterfall showing profit contribution breakdown by product line with margin analysis.

Output
Product Line Profitability Analysis
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch

# Product line profitability (in thousands)
categories = ['Total\nRevenue', 'Enterprise\nSoftware', 'Cloud\nServices', 'Hardware', 
              'Support\nContracts', 'Professional\nServices', 'COGS', 'OpEx', 'Net\nProfit']
values = [0, 85, 120, 45, 65, 35, -180, -95, 0]

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

for i, (cat, val) in enumerate(zip(categories, values)):
    if cat == 'Total\nRevenue':
        total_rev = sum(v for v in values[1:6])
        bottoms.append(0)
        heights.append(total_rev)
        colors.append('#27D3F5')
        running_total = total_rev
    elif cat == 'Net\nProfit':
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#6CF527' if running_total > 0 else '#F5276C')
    elif val > 0:
        running_total -= val
        bottoms.append(running_total)
        heights.append(val)
        colors.append('#F5B027')
    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] == 'Total\nRevenue':
        label = f"${height}K"
    elif categories[i] == 'Net\nProfit':
        label = f"${height}K"
    else:
        label = f"+${val}K" if val > 0 else f"-${abs(val)}K"
    
    color = '#0a0a0f' if height > 80 else 'white'
    ax.text(bar.get_x() + bar.get_width()/2, y_pos, label, 
            ha='center', va='center', fontsize=10, fontweight='bold', color=color)

# 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=9, color='#374151')
ax.set_ylabel('Value ($ Thousands)', fontsize=12, color='#374151', fontweight='500')
ax.set_title('Product Line Profitability Breakdown', 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='#27D3F5', label='Total Revenue'),
    Patch(facecolor='#F5B027', label='Revenue Streams'),
    Patch(facecolor='#F5276C', label='Costs'),
    Patch(facecolor='#6CF527', label='Net Profit')
]
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