Day 24: Data Storytelling & Dashboards
✅ Today you will learn
- Story structure: context → insight → action
- Know your audience: CEO vs manager vs analyst
- Chart makeover: declutter and highlight
- KPI cards and a one-page dashboard
- Write headlines that state the finding
🏢 In the real world
Two analysts find the same thing: monthly-contract customers churn 5× more. One sends a 20-chart notebook; nobody reads it. The other sends one slide: “Monthly plans lose 44% of customers – a ₹100 discount for the 600 riskiest customers could add about ₹7 lakh a year.” Guess who gets promoted. Storytelling is the last mile of data science.
The story structure
| Audience | Wants | Give them |
|---|---|---|
| CEO | Decision in 1 minute | One headline, 3 KPIs, 1 recommendation |
| Manager | What to change in their team | 3–4 charts with drill-down by region/product |
| Analyst / tech | How you did it | Method, assumptions, notebook link |
Chart makeover: before and after
import pandas as pd
import matplotlib.pyplot as plt
t = pd.read_csv("telecom_churn.csv")
r = (t.groupby("contract")["churn"].apply(lambda c: (c == "Yes").mean()) * 100).round(1)
fig, ax = plt.subplots(1, 2, figsize=(12, 4.2))
# BEFORE: default pie, no message
ax[0].pie(r, labels=r.index, autopct="%1.1f%%", shadow=True, explode=[0.05] * 3)
ax[0].set_title("Churn by contract")
# AFTER: sorted bars, one highlight, insight title, direct labels
r = r.sort_values()
colors = ["#cbd5e1", "#cbd5e1", "#dc2626"]
bars = ax[1].barh(r.index, r.values, color=colors)
ax[1].bar_label(bars, labels=[f"{v:.0f}%" for v in r.values], padding=4, fontsize=11, fontweight="bold")
ax[1].set_title("Monthly-plan customers churn ~5× more than two-year customers", loc="left", fontsize=11)
ax[1].spines[["top", "right", "bottom"]].set_visible(False); ax[1].set_xticks([])
plt.tight_layout(); plt.show()
Pie charts of rates; 3D effects; rainbow colours; titles like “Chart 3”; too many decimals (29.137%); showing every chart you made instead of the three that matter.
Put a rupee value on the insight
import pandas as pd
t = pd.read_csv("telecom_churn.csv")
monthly = t[t["contract"] == "Monthly"]
churners = (monthly["churn"] == "Yes").sum()
avg_bill = monthly["monthly_charges"].mean()
lost_per_year = churners * avg_bill * 12
print(f"Monthly-plan churners: {churners} | avg bill ₹{avg_bill:.0f}")
print(f"Revenue lost per year ≈ ₹{lost_per_year / 1e5:.1f} lakh")
saved = 0.25 * churners # assumption: the offer keeps 1 in 4 churners
gain = saved * avg_bill * 12
cost_all = len(monthly) * 100 * 12 # ₹100/month off for EVERY monthly customer
cost_target = 600 * 100 * 12 # only the 600 highest-risk customers (model, Day 58)
print(f"Revenue kept if 25% are saved: ₹{gain / 1e5:.1f} lakh")
print(f"Offer to everyone: cost ₹{cost_all / 1e5:.1f} lakh → net ₹{(gain - cost_all) / 1e5:+.1f} lakh")
print(f"Offer to top 600: cost ₹{cost_target / 1e5:.1f} lakh → net ₹{(gain - cost_target) / 1e5:+.1f} lakh")Notice the twist: a discount for everyone loses money, a targeted one earns it. The 25% save-rate is an assumption, so say so on the slide and propose a small test first (Day 31). Honest numbers build trust.
A one-page dashboard
import pandas as pd
import matplotlib.pyplot as plt
t = pd.read_csv("telecom_churn.csv")
t["churned"] = t["churn"] == "Yes"
fig = plt.figure(figsize=(12, 7.2))
gs = fig.add_gridspec(3, 4, height_ratios=[0.55, 1, 1], hspace=0.55, wspace=0.35)
kpis = [("Customers", f"{len(t):,}"), ("Churn rate", f"{t['churned'].mean() * 100:.1f}%"),
("Avg bill", f"₹{t['monthly_charges'].mean():.0f}"), ("Complaints/cust", f"{t['complaints'].mean():.2f}")]
for i, (name, val) in enumerate(kpis):
a = fig.add_subplot(gs[0, i]); a.axis("off")
a.add_patch(plt.Rectangle((0, 0), 1, 1, color="#eef2ff", transform=a.transAxes))
a.text(0.5, 0.62, val, ha="center", fontsize=20, fontweight="bold", color="#3730a3")
a.text(0.5, 0.22, name, ha="center", fontsize=10, color="#475569")
a1 = fig.add_subplot(gs[1:, :2])
r = t.groupby("contract")["churned"].mean().sort_values() * 100
a1.barh(r.index, r, color=["#cbd5e1", "#cbd5e1", "#dc2626"]); a1.set_title("Churn % by contract", loc="left")
a2 = fig.add_subplot(gs[1, 2:])
tg = pd.cut(t["tenure_months"], [0, 6, 12, 24, 48, 72], labels=["0-6", "7-12", "13-24", "25-48", "49-72"])
(t.groupby(tg, observed=True)["churned"].mean() * 100).plot(ax=a2, marker="o", color="#4f46e5"); a2.set_title("Churn % falls with tenure", loc="left"); a2.set_xlabel("")
a3 = fig.add_subplot(gs[2, 2:])
cp = t["complaints"].clip(upper=4).map(lambda c: "4+" if c == 4 else str(c)) # group rare 4,5,6… together
(t.groupby(cp)["churned"].mean() * 100).plot(kind="bar", ax=a3, color="#f59e0b", rot=0); a3.set_title("Each complaint raises churn", loc="left"); a3.set_xlabel("complaints")
fig.suptitle("TeleOne churn dashboard – act on new, monthly, complaining customers", fontsize=14, fontweight="bold", x=0.02, ha="left")
plt.show()
Headlines that work
Weak (topic)
- Churn by contract
- Monthly revenue 2024
- Ratings analysis
Strong (finding)
- Monthly plans churn 5× more
- Oct–Nov earned 27% of 2024 revenue
- Power banks get the most 1–3 star ratings
If you had one slide and one minute with the CEO, what would it say? Write that first – then build only the charts that support it.
🏅 Job skills unlocked today
Practice tasks
🏋️ Practice – do it yourself
Show solution
import pandas as pd, matplotlib.pyplot as plt
s = pd.read_csv("sales_data.csv")
s["revenue"] = s["quantity"] * s["unit_price"] * (1 - s["discount"])
c = (s.groupby("category")["revenue"].sum() / s["revenue"].sum() * 100).sort_values()
fig, ax = plt.subplots(figsize=(7, 3.2))
b = ax.barh(c.index, c, color=["#cbd5e1"] * 4 + ["#4f46e5"])
ax.bar_label(b, labels=[f"{v:.0f}%" for v in c], padding=3)
ax.set_title("Electronics alone brings over half of revenue", loc="left"); ax.set_xticks([])
ax.spines[["top", "right", "bottom"]].set_visible(False); plt.show()
Quick quiz
🧠 Quick Quiz – test yourself
Interview corner
💼 Interview Corner
How do you present findings to a non-technical audience?
Lead with the answer, not the method: one headline with a number, the business impact in rupees, a recommended action, and two or three clean charts. Keep technical details in an appendix and avoid jargon like p-values unless asked.
What makes a good dashboard?
A clear purpose and audience, KPIs at the top, the most important chart largest and top-left, consistent colours, filters only where needed, and it loads fast. Fewer charts, each answering a question.
Summary
- Context → insight → impact → action.
- Declutter, sort, highlight one thing, write finding titles.
- Put a rupee value on insights and state assumptions.
- Dashboard: KPI row, key chart large, supporting charts small.
Day 25: Mini project – student performance analysis with a complete visual report.
