Mercury SkillsMercury Skills
v1.0.0 cosmicstack-labs

Data Storytelling for Slides

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

View source0 downloads
data-storytellingdata-vizchartspresentationsanalytics

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#

LevelChart SelectionNarrative IntegrationVisual DesignAudience Impact
1: Raw DataDefault chart type, no thoughtNo story — just numbersDefault Excel/Sheets colorsConfusing, ignored
2: Basic ChartAppropriate chart typeChart title describes takeawayBrand colors, clean labelsUnderstood but forgettable
3: AnnotatedRight chart for the questionKey points highlighted with annotationsCustom colors, callouts, footnotesRemembered, shareable
4: NarrativeMulti-chart flow tells a storyData + text + visuals in harmonyPurposeful design, progressive disclosureDrives action and decisions
5: ImmersiveInteractive explorationData narrative with branching pathsCinematic, animated, multi-perspectiveChanges 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#

  1. Chart junk: 3D effects, excessive gridlines, clip art, and useless decorations that distract from the data.
  2. Wrong chart type: Using pie charts for 12 categories, or line charts for categorical data. Match chart to data relationship.
  3. Missing context: Showing a metric without a comparison (period-over-period, vs. target, vs. industry). Data alone is meaningless.
  4. No narrative: Charts displayed without explanation or insight. The audience is left to figure it out themselves.
  5. Data overload: Too many metrics, too many data points, too many charts. One insight per slide. Prioritize ruthlessly.
  6. Misleading scales: Truncated Y-axes, inconsistent scales across comparison charts, or dual axes that imply false correlation.
  7. No source attribution: Data without a source is untrustworthy. Always cite where numbers come from.
  8. Highlighting everything: Making all bars in a chart different colors. If everything is highlighted, nothing is.
  9. 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.

More in Presentation

View all →