Gauge Chart

Campaign ROI Meter

Marketing return on investment with pink accent

Output
Campaign ROI Meter
Python
import matplotlib.pyplot as plt
from matplotlib.patches import Wedge, Circle, Polygon
import numpy as np

# Data
roi = 3.2  # 320% return
max_roi = 5.0
value = (roi / max_roi) * 100

# Colors - Light theme
bg_color = '#ffffff'
track_color = '#f3f4f6'
arc_color = '#F527B0'
text_color = '#1f2937'
dim_color = '#9ca3af'

start_angle, end_angle = -30, 210
sweep = end_angle - start_angle

fig, ax = plt.subplots(figsize=(10, 8), facecolor=bg_color)
ax.set_facecolor(bg_color)
ax.set_xlim(-1.4, 1.4)
ax.set_ylim(-0.5, 1.4)
ax.set_aspect('equal')
ax.axis('off')

# Track
ax.add_patch(Wedge((0.01, -0.01), 1.0, start_angle, end_angle, width=0.15,
                   facecolor='#000000', edgecolor='none', alpha=0.03))
ax.add_patch(Wedge((0, 0), 1.0, start_angle, end_angle, width=0.15,
                   facecolor=track_color, edgecolor='none'))

# Break-even line at 1.0x
be_pct = 1.0 / max_roi
be_ang = np.radians(end_angle - be_pct * sweep)
ax.plot([0.86*np.cos(be_ang), 1.02*np.cos(be_ang)],
        [0.86*np.sin(be_ang), 1.02*np.sin(be_ang)], 
        color='#d1d5db', linewidth=2, linestyle='--')

# Value arc
value_pct = value / 100
value_angle = start_angle + (1 - value_pct) * sweep
for r_off, w_off, alpha in [(0.03, 0.04, 0.15), (0.015, 0.02, 0.35), (0, 0, 0.95)]:
    ax.add_patch(Wedge((0, 0), 1.0 + r_off, value_angle, end_angle,
                       width=0.15 + w_off, facecolor=arc_color, edgecolor='none', alpha=alpha))

# Ticks with ROI labels
labels = ['0x', '1x', '2.5x', '5x']
positions = [0, 0.2, 0.5, 1.0]
for pct, label in zip(positions, labels):
    angle = np.radians(end_angle - pct * sweep)
    ax.plot([0.87*np.cos(angle), 0.80*np.cos(angle)], 
            [0.87*np.sin(angle), 0.80*np.sin(angle)], color='#d1d5db', linewidth=2)
    ax.text(0.72*np.cos(angle), 0.72*np.sin(angle), label,
            fontsize=10, color=dim_color, ha='center', va='center')

# Needle
needle_angle = np.radians(end_angle - value_pct * sweep)
nx, ny = 0.62 * np.cos(needle_angle), 0.62 * np.sin(needle_angle)
perp = needle_angle + np.pi/2
bx1, by1 = 0.035 * np.cos(perp), 0.035 * np.sin(perp)

ax.add_patch(Polygon([(nx+0.01, ny-0.01), (bx1+0.01, by1-0.01), (-bx1+0.01, -by1-0.01)],
                     facecolor='#000000', edgecolor='none', alpha=0.1))
ax.add_patch(Polygon([(nx, ny), (bx1, by1), (-bx1, -by1)], facecolor=text_color, edgecolor='none'))

# Hub
ax.add_patch(Circle((0.01, -0.01), 0.09, facecolor='#000000', edgecolor='none', alpha=0.08))
for r, c, a in [(0.10, arc_color, 0.2), (0.08, '#ffffff', 1), (0.06, arc_color, 0.9)]:
    ax.add_patch(Circle((0, 0), r, facecolor=c, edgecolor='none', alpha=a))

# Text
ax.text(0, -0.22, f'{roi}x', fontsize=52, fontweight='bold', color=text_color, ha='center', va='center')
ax.text(0, -0.40, 'RETURN', fontsize=13, color=dim_color, ha='center', va='center', fontweight='500')
ax.text(0, -0.56, '$320K from $100K', fontsize=13, color=arc_color, ha='center', va='center', fontweight='600')
ax.text(0, 1.22, 'Marketing ROI', fontsize=18, fontweight='bold', color=text_color, ha='center', va='center')

plt.tight_layout()
plt.show()
Library

Matplotlib

Category

Part-to-Whole

Did this help you?

Support PyLucid to keep it free & growing

Support