Skip to main content
Data Visualization
CHAPTER 30 Beginner

Final Projects and Real-World Applications

Updated: May 18, 2026
5 min read

# CHAPTER 30

Final Projects and Real-World Applications

1. Chapter Introduction

This final chapter applies every skill from the course into 6 production-grade visualization projects. Each project is a portfolio piece demonstrating end-to-end visualization competency.

---

Project 1: E-Commerce Analytics Dashboard

python
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
import pandas as pd

np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=365, freq='D')
revenue_daily = np.random.normal(15000, 3000, 365) + np.linspace(0, 5000, 365)
orders_daily  = (revenue_daily / np.random.normal(85, 10, 365)).astype(int)

df = pd.DataFrame({'date': dates, 'revenue': revenue_daily, 'orders': orders_daily})
df['month'] = df['date'].dt.to_period('M')
df['weekday'] = df['date'].dt.day_name()

monthly = df.groupby('month')[['revenue', 'orders']].sum()
by_weekday = df.groupby('weekday')['revenue'].mean().reindex(
    ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'])

fig = plt.figure(figsize=(18, 12))
gs = gridspec.GridSpec(3, 3, figure=fig, hspace=0.45, wspace=0.35)

# Row 1: KPI Cards
kpi_data = [
    ('Total Revenue', f'${df["revenue"].sum()/1e6:.2f}M', '#1565C0'),
    ('Total Orders',  f'{df["orders"].sum():,}',           '#2E7D32'),
    ('Avg Order Val', f'${df["revenue"].sum()/df["orders"].sum():.2f}', '#E65100'),
]
for i, (label, value, color) in enumerate(kpi_data):
    ax = fig.add_subplot(gs[0, i])
    ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
    ax.text(0.5, 0.65, value, ha='center', va='center', fontsize=24, fontweight='bold', color=color)
    ax.text(0.5, 0.3, label, ha='center', va='center', fontsize=11, color='#666')
    rect = plt.Rectangle((0.02, 0.02), 0.96, 0.96, linewidth=1, edgecolor='#E0E0E0', facecolor='white', transform=ax.transAxes)
    ax.add_patch(rect)

# Row 2: Revenue trend (wide)
ax_trend = fig.add_subplot(gs[1, :2])
ax_trend.plot(df['date'], df['revenue'], alpha=0.3, color='#90CAF9', linewidth=0.8)
ax_trend.plot(df['date'], df['revenue'].rolling(30).mean(), color='#1565C0', linewidth=2.5, label='30-day MA')
ax_trend.set_title('Daily Revenue Trend', fontweight='bold')
ax_trend.yaxis.set_major_formatter(plt.FuncFormatter(lambda x,_: f'${x/1000:.0f}K'))
ax_trend.legend(); ax_trend.grid(True, alpha=0.3)
ax_trend.spines['top'].set_visible(False); ax_trend.spines['right'].set_visible(False)

# Weekday bar
ax_wday = fig.add_subplot(gs[1, 2])
colors = ['#1565C0' if v == by_weekday.max() else '#90CAF9' for v in by_weekday.values]
ax_wday.bar(range(7), by_weekday.values, color=colors, edgecolor='white')
ax_wday.set_xticks(range(7)); ax_wday.set_xticklabels(['M','T','W','T','F','S','S'])
ax_wday.set_title('Avg Revenue by Weekday', fontweight='bold')
ax_wday.yaxis.set_major_formatter(plt.FuncFormatter(lambda x,_: f'${x/1000:.0f}K'))
ax_wday.spines['top'].set_visible(False); ax_wday.spines['right'].set_visible(False)

# Row 3: Monthly totals
ax_monthly = fig.add_subplot(gs[2, :])
months_str = [str(m) for m in monthly.index]
x = np.arange(len(months_str))
ax_monthly.bar(x, monthly['revenue'], color='#42A5F5', alpha=0.7, label='Revenue')
ax2 = ax_monthly.twinx()
ax2.plot(x, monthly['orders'], 'ro-', linewidth=2, markersize=6, label='Orders')
ax_monthly.set_xticks(x); ax_monthly.set_xticklabels(months_str, rotation=30)
ax_monthly.set_title('Monthly Revenue & Orders', fontweight='bold')
ax_monthly.yaxis.set_major_formatter(plt.FuncFormatter(lambda x,_: f'${x/1000:.0f}K'))
ax_monthly.spines['top'].set_visible(False)

plt.suptitle('E-Commerce Analytics Dashboard — 2024', fontsize=16, fontweight='bold')
plt.savefig('ecommerce_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()

---

Project 2: Financial Market Dashboard (Plotly Interactive)

python
1234567891011121314151617181920212223242526272829303132333435363738394041
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np

np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=252, freq='B')
n = len(dates)

# Simulate OHLCV
close = 200 * np.cumprod(1 + np.random.normal(0.0005, 0.015, n))
open_ = close * (1 + np.random.normal(0, 0.003, n))
high  = np.maximum(close, open_) * (1 + np.abs(np.random.normal(0, 0.005, n)))
low   = np.minimum(close, open_) * (1 - np.abs(np.random.normal(0, 0.005, n)))
volume = np.random.randint(500000, 3000000, n)
ma20  = pd.Series(close).rolling(20).mean()
ma50  = pd.Series(close).rolling(50).mean()

fig = make_subplots(rows=3, cols=1, shared_xaxes=True,
                     row_heights=[0.6, 0.2, 0.2],
                     subplot_titles=['Price with Moving Averages', 'Volume', 'Daily Returns'])

# Candlestick
fig.add_trace(go.Candlestick(x=dates, open=open_, high=high, low=low, close=close, name='OHLC'), row=1, col=1)
fig.add_trace(go.Scatter(x=dates, y=ma20, name='MA20', line=dict(color='orange', width=1.5)), row=1, col=1)
fig.add_trace(go.Scatter(x=dates, y=ma50, name='MA50', line=dict(color='red', width=1.5)), row=1, col=1)

# Volume
vol_colors = ['green' if c > o else 'red' for c, o in zip(close, open_)]
fig.add_trace(go.Bar(x=dates, y=volume, name='Volume', marker_color=vol_colors), row=2, col=1)

# Daily returns
returns = pd.Series(close).pct_change() * 100
fig.add_trace(go.Bar(x=dates, y=returns, name='Returns %',
                      marker_color=['green' if r > 0 else 'red' for r in returns]), row=3, col=1)

fig.update_layout(title='Financial Market Dashboard', template='plotly_white', height=700,
                   hovermode='x unified', showlegend=True,
                   xaxis_rangeslider_visible=False)
fig.show()
print("Save: fig.write_html('financial_dashboard.html')")

---

Project 3: HR Analytics Visualization

python
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

np.random.seed(42)
n = 500
hr = pd.DataFrame({
    'Dept':        np.random.choice(['Engineering','Marketing','Sales','HR','Finance'], n, p=[0.35,0.2,0.25,0.1,0.1]),
    'Gender':      np.random.choice(['Male','Female'], n, p=[0.55,0.45]),
    'Salary':      np.random.normal(75000, 20000, n).clip(30000, 200000),
    'Performance': np.random.choice([1,2,3,4,5], n, p=[0.05,0.15,0.35,0.30,0.15]),
    'Tenure':      np.random.randint(1, 20, n),
    'Satisfaction':np.random.uniform(1, 10, n).round(1),
    'Left':        np.random.choice([0,1], n, p=[0.8,0.2])
})

sns.set_theme(style='whitegrid')
fig, axes = plt.subplots(2, 3, figsize=(16, 10))

sns.violinplot(data=hr, x='Dept', y='Salary', ax=axes[0,0], palette='Blues')
axes[0,0].set_title('Salary Distribution by Department')
axes[0,0].set_xticklabels(axes[0,0].get_xticklabels(), rotation=20)

sns.boxplot(data=hr, x='Dept', y='Performance', hue='Gender', ax=axes[0,1], palette='Set2')
axes[0,1].set_title('Performance by Department & Gender')
axes[0,1].set_xticklabels(axes[0,1].get_xticklabels(), rotation=20)

# Attrition by department
attr = hr.groupby('Dept')['Left'].mean() * 100
attr.sort_values().plot(kind='barh', ax=axes[0,2], color='#F44336', alpha=0.8)
axes[0,2].set_title('Attrition Rate by Department (%)')
axes[0,2].set_xlabel('%')

sns.scatterplot(data=hr, x='Satisfaction', y='Performance', hue='Left',
                 palette={0: '#4CAF50', 1: '#F44336'}, alpha=0.5, ax=axes[1,0])
axes[1,0].set_title('Satisfaction vs Performance\n(Red=Left, Green=Stayed)')

# Heatmap: dept × metric
pivot = hr.groupby('Dept')[['Salary','Performance','Satisfaction','Tenure']].mean()
pivot_norm = (pivot - pivot.min()) / (pivot.max() - pivot.min())
sns.heatmap(pivot_norm, annot=True, fmt='.2f', cmap='RdYlGn', ax=axes[1,1])
axes[1,1].set_title('Normalized HR Metrics Heatmap')

sns.kdeplot(data=hr, x='Salary', hue='Dept', fill=True, alpha=0.3, ax=axes[1,2])
axes[1,2].set_title('Salary Distribution by Department')
axes[1,2].xaxis.set_major_formatter(plt.FuncFormatter(lambda x,_: f'${x/1000:.0f}K'))

plt.suptitle('HR Analytics Dashboard', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('hr_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()

Course Complete! 🎉

text
123456789101112131415161718192021222324252627282930313233343536
You have mastered the complete Data Visualization course:

Foundation:
✅ Visualization theory — pre-attentive, Gestalt, data-ink ratio
✅ Chart selection — taxonomy, decision tree
✅ Color theory — sequential, diverging, qualitative palettes
✅ Matplotlib — figure/axes architecture, annotations

Chart Types:
✅ Line charts — trends, moving averages, comparisons
✅ Bar charts — vertical, horizontal, grouped, stacked
✅ Pie/Donut charts — part-of-whole
✅ Scatter plots — correlation, regression, bubble charts
✅ Histograms + KDE — distribution analysis
✅ Box plots + violin plots — statistical visualization
✅ Heatmaps — correlation matrices, cross-tabulations
✅ Time series — seasonal decomposition, candlestick
✅ Geographic maps — choropleth, bubble maps

Advanced:
✅ Seaborn — pairplots, FacetGrid, statistical charts
✅ Plotly — interactive charts, animations, hover
✅ Plotly Dash — full interactive web dashboards
✅ Dashboard design principles — KPI, layout, UX
✅ Data storytelling — narrative, Pareto, annotations
✅ Real-time visualization — Interval, deque
✅ Performance — sampling, hexbin, WebGL
✅ Treemaps, Sankey, radar charts
✅ Visualization mistakes and fixes

Your next steps:
→ Tableau / Power BI for enterprise BI
→ D3.js for custom web visualizations
→ Observable / Vega-Lite for declarative charts
→ Streamlit for rapid ML app dashboards
→ Apache Superset for open-source BI

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·