Waterfall Chart

Dividend Distribution Breakdown

Shareholder returns waterfall showing dividend allocation and retained earnings.

Output
Dividend Distribution Breakdown
Python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Patch

categories = ['Net\nIncome', 'Statutory\nReserve', 'Capital\nReserve', 'Preferred\nDividends', 
              'Common\nDividends', 'Share\nBuybacks', 'Retained\nEarnings']
values = [0, -25, -15, -18, -85, -45, 0]

initial = 320
running_total = initial
bottoms, heights, colors = [], [], []

palette = ['#F5B027', '#F54927', '#F5276C', '#4927F5', '#27D3F5']

for i, (cat, val) in enumerate(zip(categories, values)):
    if cat == 'Net\nIncome':
        bottoms.append(0)
        heights.append(initial)
        colors.append('#6CF527')
    elif 'Retained' in cat:
        bottoms.append(0)
        heights.append(running_total)
        colors.append('#27D3F5')
    else:
        bottoms.append(running_total + val)
        heights.append(abs(val))
        colors.append(palette[(i-1) % len(palette)])
        running_total += val

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

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

for i, (bar, val, bot, height) in enumerate(zip(bars, values, bottoms, heights)):
    y_pos = bot + height / 2
    if categories[i] == 'Net\nIncome' or 'Retained' in categories[i]:
        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='#0a0a0f' if height > 100 else 'white')
    else:
        label = 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='white')

for i in range(len(x) - 1):
    y = initial if i == 0 else bottoms[i]
    ax.plot([x[i] + 0.35, x[i+1] - 0.35], [y, y], color='#475569', linestyle='--', linewidth=1.5, alpha=0.7)

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('Amount ($ Millions)', fontsize=12, color='#e2e8f0', fontweight='500')
ax.set_title('Net Income Distribution to Shareholders', 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')

payout = initial - running_total
payout_ratio = (payout / initial) * 100
ax.annotate(f'Payout Ratio: {payout_ratio:.0f}% | Retention: {100-payout_ratio:.0f}%', xy=(0.98, 0.95), xycoords='axes fraction',
            fontsize=10, color='#F5B027', ha='right', fontweight='bold',
            bbox=dict(boxstyle='round,pad=0.4', facecolor='#1e293b', edgecolor='#F5B027', alpha=0.9))

legend_elements = [Patch(facecolor='#6CF527', label='Net Income'), Patch(facecolor='#F5B027', label='Distributions'),
                   Patch(facecolor='#27D3F5', label='Retained Earnings')]
ax.legend(handles=legend_elements, loc='upper left', bbox_to_anchor=(0, -0.1), ncol=3, fontsize=9,
          facecolor='#1e293b', edgecolor='#334155', labelcolor='white')

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