Waterfall Chart

Marketing ROI Breakdown

Marketing spend attribution waterfall showing channel performance and ROI.

Output
Marketing ROI Breakdown
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch

categories = ['Marketing\nSpend', 'Paid\nSearch', 'Social\nMedia', 'Content\nMarketing', 
              'Email\nCampaigns', 'Events &\nSponsors', 'Attributed\nRevenue']
values = [0, 85, 62, 48, 95, 35, 0]

initial = 150
running_total = 0
bottoms, heights, colors = [], [], []

palette = ['#27D3F5', '#4927F5', '#F5B027', '#6CF527', '#F527B0']

for i, (cat, val) in enumerate(zip(categories, values)):
    if 'Marketing\nSpend' in cat:
        bottoms.append(0)
        heights.append(initial)
        colors.append('#F5276C')
    elif 'Attributed' in cat:
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#6CF527')
    else:
        bottoms.append(running_total)
        heights.append(val)
        colors.append(palette[(i-1) % len(palette)])
        running_total += val

fig, ax = plt.subplots(figsize=(12, 8), facecolor='#ffffff')
ax.set_facecolor('#ffffff')

x = np.arange(len(categories))
bars = ax.bar(x, heights, bottom=bottoms, color=colors, width=0.6, edgecolor='#e5e7eb', linewidth=1)

for i, (bar, val, bot, height) in enumerate(zip(bars, values, bottoms, heights)):
    y_pos = bot + height / 2
    if 'Marketing\nSpend' 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='#374151')
    elif 'Attributed' 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='#0a0a0f')
    else:
        label = f"${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.set_xlim(-0.6, len(categories) - 0.4)
ax.set_ylim(0, max(running_total, initial) * 1.15)
ax.set_xticks(x)
ax.set_xticklabels(categories, fontsize=9, color='#374151')
ax.set_ylabel('Amount ($ Thousands)', fontsize=12, color='#374151', fontweight='500')
ax.set_title('Marketing Channel Attribution & ROI', 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 = ((running_total - initial) / initial) * 100
ax.annotate(f'Marketing ROI: {roi:.0f}% | ROAS: {running_total/initial:.1f}x', 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))

# Add spend reference line
ax.axhline(y=initial, color='#F5276C', linestyle='--', linewidth=1.5, alpha=0.5)
ax.text(len(categories) - 0.5, initial + 5, 'Spend', color='#F5276C', fontsize=9, ha='right')

legend_elements = [Patch(facecolor='#F5276C', label='Marketing Spend'), Patch(facecolor='#27D3F5', label='Channel Revenue'),
                   Patch(facecolor='#6CF527', label='Total Revenue')]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0, -0.1), ncol=3, 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