mcpbeat

Data Storytelling

cosmicstack-labs/data-storytelling

Data Storytelling for Slides: Charts, graphs, data visualization, and narrative techniques for presenting data in presentations

6k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
365
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/cosmicstack-labs/mercury-agent-skills --skill data-storytelling

The instruction itself

38 sections, as written by the author

Data Storytelling for Slides

Turn raw data into compelling visual narratives that audiences understand, remember, and act on.

Core Principles

1. Data Without Story Is Just Numbers

A chart without context is meaningless. Every data point should serve a narrative: "Revenue grew 40% because we launched the mobile app" is a story. "Revenue was $1.2M" is just a number.

2. Show the Relationship, Not Just the Data

The best data slides reveal relationships: cause and effect, before and after, actual vs. target, you vs. competition. Comparison is the foundation of insight.

3. Maximize the Data-Ink Ratio

Remove anything in a chart that isn't data or essential context. Gridlines, borders, 3D effects, excessive labels — eliminate noise. Every pixel should either inform or guide.

4. The Audience Should Arrive at the Insight in 5 Seconds

If a viewer can't understand the key takeaway within 5 seconds, the visualization has failed. Pre-attentive attributes (color, size, position) should make the insight immediately obvious.


Data Storytelling Maturity Model

| Level | Chart Selection | Narrative Integration | Visual Design | Audience Impact |

|-------|----------------|---------------------|---------------|----------------|

| 1: Raw Data | Default chart type, no thought | No story — just numbers | Default Excel/Sheets colors | Confusing, ignored |

| 2: Basic Chart | Appropriate chart type | Chart title describes takeaway | Brand colors, clean labels | Understood but forgettable |

| 3: Annotated | Right chart for the question | Key points highlighted with annotations | Custom colors, callouts, footnotes | Remembered, shareable |

| 4: Narrative | Multi-chart flow tells a story | Data + text + visuals in harmony | Purposeful design, progressive disclosure | Drives action and decisions |

| 5: Immersive | Interactive exploration | Data narrative with branching paths | Cinematic, animated, multi-perspective | Changes behavior, memorable |

Target: Level 3 for internal dashboards and reports. Level 4 for investor and executive presentations.


Chart Selection Guide

Choosing the Right Chart Type

| Data Relationship     | Recommended Chart          | Why                            |
|-----------------------|----------------------------|--------------------------------|
| Comparison over time  | Line chart                 | Shows trends, continuity       |
| Part of a whole       | Bar chart (stacked) or pie | Shows composition (limit to 5) |
| Ranking               | Horizontal bar chart       | Easy to compare lengths        |
| Distribution          | Histogram or box plot      | Shows spread and outliers      |
| Correlation           | Scatter plot               | Reveals relationships          |
| Composition change    | Stacked area chart         | Shows parts over time          |
| Flow / Funnel         | Sankey or funnel chart     | Shows conversion and drop-off  |
| Geographic            | Map (choropleth)           | Spatial patterns               |
| Progress to goal      | Bullet chart / gauge       | Actual vs. target              |
| Relationship network  | Network / node diagram     | Connections and clusters       |

Chart Decision Flowchart

What do you want to show?

1. Change over time? → Line chart or area chart
2. Compare categories? → Bar chart (horizontal for many categories)
3. Show composition? → Stacked bar (preferred) or pie chart (≤5 slices)
4. Distribution of data? → Histogram or box plot
5. Relationship between variables? → Scatter plot (add trend line)
6. Part-to-whole over time? → Stacked area chart
7. Progress to goal? → Bullet chart or progress bar
8. Flow between stages? → Sankey diagram or funnel
9. Geographic patterns? → Map visualization

When NOT to Use Pie Charts

Avoid pie charts when:
- You have more than 5 categories (use stacked bar instead)
- You need precise comparisons (bars are better)
- The slices are similar in size (hard to distinguish)
- You want to show trends over time (use stacked area)

Only use pie charts when:
- You want to show part-of-whole with 2-4 categories
- The differences are obvious (e.g., 80% vs 20%)
- The audience needs a quick, intuitive understanding

Actionable Guidance

Telling a Story with Data

# The Three-Act Data Story

## ACT 1: Context
- What's the situation?
- What are we measuring and why?
- What's the time frame?

## ACT 2: The Insight
- What changed? (The "aha" moment)
- Why did it change? (Cause explanation)
- How significant is it? (Magnitude)

## ACT 3: Implication
- What should we do about it?
- What happens if we don't act?
- What's the expected outcome?

The Data-Narrative Template

# Data story template structure

data_story = {
    "headline": "Revenue Grew 40% After Mobile Launch",  # The takeaway
    "context": {
        "before": "Revenue was flat at $2M/month for 6 months",
        "catalyst": "Mobile app launched in March 2024",
        "after": "Revenue accelerated to $2.8M/month by June"
    },
    "evidence": {
        "primary_chart": "Line chart showing revenue trajectory",
        "supporting_data": "Mobile now accounts for 35% of all orders",
        "statistical_significance": "p < 0.01, R² = 0.89"
    },
    "implication": {
        "action": "Double down on mobile features and marketing",
        "projection": "Projecting $4M/month by Q4 at current growth",
        "risk": "Competitors also investing in mobile"
    }
}

def format_data_slide(story_dict):
    """Generate a structured data slide from a story dictionary."""
    slide = f"""
    # {story_dict['headline']}
    
    **Context**: {story_dict['context']['before']}
    → {story_dict['context']['catalyst']}
    → {story_dict['context']['after']}
    
    [CHART: {story_dict['evidence']['primary_chart']}]
    
    **Key Insight**: {story_dict['evidence']['supporting_data']}
    
    **Action**: {story_dict['implication']['action']}
    """
    return slide

Data-Ink Ratio

What Is Data-Ink?

Data-Ink = The ink (pixels) used to display data
Non-Data-Ink = Decorative elements, gridlines, borders, backgrounds

Data-Ink Ratio = Data-Ink / Total Ink Used in Visualization

Goal: Maximize the data-ink ratio (remove non-data ink without losing context)

Before and After: Improving Data-Ink Ratio

❌ POOR (Low data-ink ratio):
- 3D bar chart with shadows and gradients
- Background color with gradient
- Thick gridlines every interval
- Heavy borders around everything
- Decorative clip art
- Drop shadows on data points
- Excessive axis labels

✅ GOOD (High data-ink ratio):
- Flat, 2D design
- Minimal or no background fill
- Thin, light gridlines (or none)
- No chart borders
- Data points stand out with color
- Labels only where necessary
- Clean typography

Applying Data-Ink Principle

# Concept: Removing non-data ink from a matplotlib chart

import matplotlib.pyplot as plt
import numpy as np

# Sample data
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
revenue = [120, 145, 160, 185, 210, 245]

# BAD: Low data-ink ratio
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# Bad chart
ax1.bar(months, revenue, color="skyblue", edgecolor="black", linewidth=1.5)
ax1.set_title("Bad: Low Data-Ink Ratio", fontsize=16, fontweight="bold")
ax1.set_facecolor("#f0f0f0")  # Useless background
ax1.grid(True, axis="y", alpha=0.8, linewidth=1.5)  # Heavy gridlines
ax1.spines["top"].set_visible(True)
ax1.spines["right"].set_visible(True)
ax1.spines["left"].set_linewidth(2)
ax1.spines["bottom"].set_linewidth(2)
# Lots of wasted ink

# Good chart
ax2.bar(months, revenue, color="#2B6CB0", width=0.6)
ax2.set_title("Good: High Data-Ink Ratio", fontsize=16, fontweight="bold")
ax2.set_facecolor("white")
ax2.grid(False)  # No gridlines
ax2.spines["top"].set_visible(False)
ax2.spines["right"].set_visible(False)
ax2.spines["left"].set_color("#CBD5E0")
ax2.spines["bottom"].set_color("#CBD5E0")
ax2.tick_params(colors="#4A5568")
# Every pixel serves the data

plt.tight_layout()

Pre-Attentive Attributes

What Are Pre-Attentive Attributes?

Pre-attentive attributes are visual properties that the brain processes in under 500 milliseconds — before conscious attention. Use them to direct the audience's eye to the most important insight instantly.

Key Pre-Attentive Attributes (ranked by effectiveness):

| Attribute    | Best Used For                     | Example                              |
|--------------|-----------------------------------|--------------------------------------|
| Color (hue)  | Highlighting a specific category  | One bar in red, others in gray       |
| Intensity    | Showing magnitude or importance   | Darker shade = higher value          |
| Size         | Showing quantity or hierarchy     | Larger circle = more users           |
| Position     | Showing ranking or sequence       | Top of list = highest ranked         |
| Orientation  | Showing difference or grouping    | Angled element vs. straight          |
| Shape        | Categorizing different types      | Circles for product, squares for service |
| Motion       | Showing change or urgency         | Animated growth (use sparingly)      |

The Highlighting Technique

# Using pre-attentive attributes to highlight key data

import matplotlib.pyplot as plt
import numpy as np

def highlight_bar_chart(categories, values, highlight_index, 
                         highlight_color="#E53E3E", 
                         default_color="#CBD5E0"):
    """
    Create a bar chart where one bar is highlighted using color.
    This uses the pre-attentive attribute of color (hue) to direct attention.
    """
    colors = [highlight_color if i == highlight_index else default_color 
              for i in range(len(categories))]
    
    fig, ax = plt.subplots(figsize=(10, 6))
    bars = ax.bar(categories, values, color=colors, width=0.6)
    
    # Remove clutter
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["left"].set_color("#E2E8F0")
    ax.spines["bottom"].set_color("#E2E8F0")
    ax.grid(False)
    
    # Add value labels
    for bar, value in zip(bars, values):
        ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 1,
                f"{value}", ha="center", va="bottom", 
                fontsize=12, fontweight="bold" if value == max(values) else "normal",
                color="#2D3748")
    
    ax.set_title("Revenue by Channel", fontsize=16, fontweight="bold", pad=20)
    return fig

# Example
categories = ["Direct", "Organic", "Paid Ads", "Social", "Referral"]
values = [45, 120, 85, 60, 40]
# Highlight the highest value (Organic)
# chart = highlight_bar_chart(categories, values, highlight_index=1)

Dashboard Slide Design

Dashboard Structure for Presentations

Executive Dashboard Layout:

┌──────────────────────────────────────────────────┐
│ HEADER: Key Metric + Trend (Large, Center)       │
│ [KPI: $1.2M ARR]  [↑ 40% YoY]                   │
├──────────┬──────────┬──────────┬─────────────────┤
│ KPI 1    │ KPI 2    │ KPI 3    │ KPI 4           │
│ Revenue  │ Users    │ Retention│ NPS             │
│ $X       │ X,XXX    │ XX%      │ XX              │
│ ↑ X%     │ ↑ X%     │ ↓ X%     │ → X pts         │
├──────────┴──────────┴──────────┴─────────────────┤
│ Main Chart Area (largest real estate)            │
│ [Line chart showing trend over time]             │
│                                                   │
├──────────────────────────────────────────────────┤
│ Supporting Detail / Breakdown                    │
│ [Secondary chart or table]                        │
└──────────────────────────────────────────────────┘

KPI Presentation Patterns

## KPI Slide Patterns

### Single KPI (Hero Metric)
[Large Number]         → $1,200,000
[Label]                → Annual Recurring Revenue
[Trend Arrow]          → ↑ 40% year-over-year
[Sparkline]            → [Mini line chart showing trend]
[Context]              → "On track to hit $2M by Q4"

### Multiple KPIs (Dashboard Style)
| Metric       | Value     | Trend | vs Target | Sparkline |
|--------------|-----------|-------|-----------|-----------|
| ARR          | $1.2M     | ↑ 40% | ✓ On track| [mini ln] |
| Active Users | 45,000    | ↑ 22% | ✓ Ahead   | [mini ln] |
| Churn Rate   | 3.2%      | ↓ 0.5%| ⚠ Watch   | [mini ln] |
| NPS          | 62        | ↑ 5pts| ✓ Good    | [mini ln] |

### Waterfall KPI
[Starting Point] → [Change 1] → [Change 2] → [Change 3] = [Result]

Annotated Charts

Annotation Styles

Five Essential Annotation Types:

1. **Callout Box**: Highlight a specific point with a text box + arrow
   - Use for: Key inflection points, record highs/lows

2. **Trend Line**: A line showing the overall direction
   - Use for: Emphasizing growth despite fluctuations

3. **Threshold Line**: A horizontal/vertical line marking a target
   - Use for: Showing progress toward a goal

4. **Data Label**: Direct label on a specific data point
   - Use for: The MOST important point only (not all points)

5. **Comparative Callout**: "vs. Industry Average" label
   - Use for: Contextualizing performance

Annotation Best Practices

DO:
- Annotate ONE key insight per chart
- Use arrows or lines to clearly connect annotation to data point
- Keep annotations short (8-12 words max)
- Use a contrasting color for the annotation
- Place annotations in empty space (not over data)

DON'T:
- Annotate every interesting point (overwhelming)
- Use annotations that explain what's already obvious
- Make annotations larger than the data itself
- Forget to include units or context

Annotated Chart Example

# Creating an annotated chart for presentations

import matplotlib.pyplot as plt
import numpy as np

def annotated_revenue_chart():
    """Create a line chart with strategic annotations."""
    months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
    revenue = [200, 210, 205, 220, 260, 300, 320, 350, 380, 420, 460, 510]
    
    fig, ax = plt.subplots(figsize=(12, 6))
    
    # Main line
    ax.plot(months, revenue, color="#2B6CB0", linewidth=2.5, zorder=2)
    ax.fill_between(range(len(months)), revenue, alpha=0.1, color="#2B6CB0")
    
    # Annotation 1: Product launch inflection point
    ax.annotate(
        "Mobile App\nLaunch",  # Label
        xy=(4, 260),          # Point being annotated
        xytext=(2, 350),      # Where to place the text
        fontsize=12, fontweight="bold", color="#E53E3E",
        arrowprops=dict(arrowstyle="->", color="#E53E3E", linewidth=2),
        bbox=dict(boxstyle="round,pad=0.3", facecolor="white", edgecolor="#E53E3E")
    )
    
    # Annotation 2: Key result
    ax.annotate(
        "Record: $510K\n↑ 155% YoY",
        xy=(11, 510),
        xytext=(9, 540),
        fontsize=12, fontweight="bold", color="#38A169",
        arrowprops=dict(arrowstyle="->", color="#38A169", linewidth=2),
        bbox=dict(boxstyle="round,pad=0.3", facecolor="white", edgecolor="#38A169")
    )
    
    # Clean design
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["left"].set_color("#CBD5E0")
    ax.spines["bottom"].set_color("#CBD5E0")
    ax.grid(True, alpha=0.3, axis="y")
    ax.tick_params(colors="#4A5568")
    
    ax.set_title("Monthly Revenue — $510K in Record December", 
                 fontsize=16, fontweight="bold", pad=20)
    ax.set_ylabel("Revenue ($K)", fontsize=12, color="#4A5568")
    
    return fig

Avoiding Misleading Visuals

Common Data Visualization Traps

| Trap                   | Why It's Misleading                          | How to Fix                              |
|------------------------|----------------------------------------------|-----------------------------------------|
| Truncated Y-Axis       | Exaggerates small differences                | Start axis at 0 (or clearly mark break) |
| 3D Charts              | Distorts proportions, hard to read           | Use flat 2D charts                      |
| Cherry-picked timeframe | Shows favorable data, hides full picture    | Show full timeline                      |
| Dual axes manipulation | Makes unrelated trends look correlated       | Use separate charts or clarify          |
| Pie chart with 10+ slices | Tiny slices are unreadable                 | Aggregate into "Other" or use bar chart |
| Area charts not starting at 0 | Exaggerates growth                      | Always start area charts at 0           |
| Color misuse           | Red = bad, green = good (cultural bias)     | Use color consistently, add labels      |
| Inconsistent scales    | Makes comparison impossible                  | Use the same scale for related charts   |
| No baseline            | Changes look bigger/smaller than reality     | Always include a comparison baseline    |
| Selectively omitted data | Hides context, skews perception           | Show all relevant data, mark outliers   |

The Y-Axis Rule

Bar charts and area charts MUST start at zero.
Line charts CAN have a non-zero baseline but should indicate it.

✅ Bar chart starting at 0:   [||||||||||]  = 100%
❌ Bar chart starting at 80:  [|||]         = Looks like 15% but is actually 80%

Exception: Line charts for small fluctuations (e.g., stock prices) 
can zoom in — but clearly mark the axis break or use a sparkline.

Data Sources & Citations on Slides

Citation Format

Required elements for data citations on slides:
1. Source name (organization, publication)
2. Publication date or data collection period
3. URL or DOI (if public)
4. Methodology note (if relevant)

Format: "Source: [Organization], [Year]. [URL]"

Examples:
- "Source: Gartner, 2024. gartner.com/market-report"
- "Source: Internal data, Jan-Dec 2024 (n=10,000 users)"
- "Source: US Census Bureau, 2023. census.gov/data"

Citation Placement

- Place citations at the bottom of the slide (footer area)
- Use 10-12pt font in a neutral color (gray)
- Keep consistent position on every slide with data
- For critical numbers, include the citation on the same slide
- For sensitive data, mark: "Source: [Company] Internal Data — Confidential"

Interactive vs Static Data Slides

When to Use Each

| Context                  | Recommendation          | Reason                              |
|--------------------------|-------------------------|-------------------------------------|
| Live presentation        | Static chart            | Audience doesn't interact anyway    |
| Email / PDF              | Static + summary table  | Reader can't click                  |
| Board meeting            | Static + printed backup | Focus on discussion                 |
| Executive review         | Static with drill-downs | PDF with appendix                   |
| Data room / due diligence| Interactive dashboard   | Investors want to explore           |
| Internal weekly report   | Interactive preferred   | Team needs to filter and slice      |
| Conference presentation  | Static (high impact)    | One message, perfectly framed       |

Static Chart Best Practices

For static slides (presentations, PDFs):
- Include the key insight in the title (not "Revenue by Quarter" but "Revenue Grew 40%")
- Add minimal annotations directly on the chart
- Include a "source" and "methodology" footnote
- Show the data table alongside if precision matters
- Use callouts for the 1-2 most important data points

Common Mistakes

  • Chart junk: 3D effects, excessive gridlines, clip art, and useless decorations that distract from the data.
  • Wrong chart type: Using pie charts for 12 categories, or line charts for categorical data. Match chart to data relationship.
  • Missing context: Showing a metric without a comparison (period-over-period, vs. target, vs. industry). Data alone is meaningless.
  • No narrative: Charts displayed without explanation or insight. The audience is left to figure it out themselves.
  • Data overload: Too many metrics, too many data points, too many charts. One insight per slide. Prioritize ruthlessly.
  • Misleading scales: Truncated Y-axes, inconsistent scales across comparison charts, or dual axes that imply false correlation.
  • No source attribution: Data without a source is untrustworthy. Always cite where numbers come from.
  • Highlighting everything: Making all bars in a chart different colors. If everything is highlighted, nothing is.
  • Small fonts on charts: Axis labels, legends, and annotations too small to read when projected. Minimum 12pt for any chart text.

10. No takeaway title: A chart titled "Revenue by Quarter" tells me what it is, not what I should learn. Use insight-driven titles.

How to use it

Copy the folder

Take cosmicstack-labs/data-storytelling from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.