Chapter 13: Key Takeaways - Play-by-Play Visualization
Quick Reference Guide
The Core Principle
Play-by-play visualization transforms raw game data into narrative. Each play is a data point; the visualization's job is to reveal the story those data points tell about momentum, key moments, and game flow.
1. Play-by-Play Data Structure
Essential Fields
play = {
# Pre-play state
'quarter': 1,
'time': '10:30',
'down': 2,
'distance': 7,
'yard_line': 35, # 1-99 scale
# Action and result
'play_type': 'pass',
'yards_gained': 12,
# Advanced metrics
'epa': 0.85, # Expected Points Added
'wp_before': 0.52, # Win Probability before
'wp_after': 0.58, # Win Probability after
'wpa': 0.06 # Win Probability Added
}
Yard Line Convention
- 1-50: Own territory (1 = own goal line)
- 51-99: Opponent territory (99 = opponent's goal line)
- Yard line 75 = opponent's 25-yard line
2. Key Metrics
EPA (Expected Points Added)
EPA = EP_after - EP_before
- Positive EPA: Play improved scoring expectancy
- Negative EPA: Play hurt scoring expectancy
- Context-dependent: 3-yard gain can be positive (3rd & 2) or negative (3rd & 8)
WPA (Win Probability Added)
WPA = WP_after - WP_before
- Measures game impact: Same play has more WPA in close game
- Ranges from -1 to +1: Theoretically
- Typical big play: ±5-15%
- Game-changing play: ±15-30%
Success Rate
- 1st down: 40% of distance
- 2nd down: 50% of distance
- 3rd/4th down: 100% of distance (first down)
3. Drive Chart Types
Traditional Drive Chart
- Shows field position progression
- Horizontal representation of the field
- Color-coded by result (TD, FG, punt, turnover)
EPA-Annotated Drive Chart
- Adds value context to each play
- Color scale: Green (positive) → Red (negative)
- Cumulative EPA shows drive value
Multi-Drive Summary
- Stacked horizontal bars
- One row per drive
- Quick comparison of all possessions
4. Win Probability Visualization
Key Design Elements
| Element | Purpose |
|---|---|
| Fill areas | Show which team is favored |
| 50% line | Reference for "even" game |
| Quarter markers | Time context |
| Key play annotations | Identify turning points |
| Team colors | Immediate identification |
Best Practices
- Start at 50% for neutral site games
- Limit annotations to 5-10 key moments
- Use fills to emphasize advantage magnitude
- Show overtime as extension of timeline
5. Situational Analysis
Down × Distance Matrix
| 1-3 | 4-6 | 7-10 | 11+
---------|--------|--------|--------|--------
1st Down | +0.25 | +0.18 | +0.12 | +0.05
2nd Down | +0.30 | +0.15 | +0.02 | -0.15
3rd Down | +0.45 | +0.22 | -0.08 | -0.28
Visualization Guidelines
- Use diverging colormap centered at 0
- Include sample sizes for reliability
- Add cell annotations for exact values
6. Chart Type Quick Reference
| Visualization | Use Case | Key Feature |
|---|---|---|
| Drive chart | Single possession | Field position |
| WP curve | Full game flow | Momentum shifts |
| EPA bar chart | Play-by-play value | Individual contributions |
| Heatmap | Situational analysis | Pattern identification |
| Sequence diagram | Detailed drive review | Full context |
| Waterfall | Cumulative contributions | Running totals |
7. Code Templates
Basic Drive Chart
def create_drive_chart(plays):
fig, ax = plt.subplots(figsize=(14, 4))
# Draw field
ax.axhspan(0.3, 0.7, facecolor='#2e5a1c')
# Plot plays
current_yl = plays[0]['yard_line']
for play in plays:
yards = play['yards_gained']
next_yl = current_yl + yards
ax.plot([current_yl, next_yl], [0.5, 0.5],
linewidth=4, solid_capstyle='round')
current_yl = next_yl
ax.set_xlim(0, 100)
ax.axis('off')
return fig
Win Probability Chart
def create_wp_chart(plays, home_team, away_team):
fig, ax = plt.subplots(figsize=(14, 6))
times = [convert_to_game_time(p) for p in plays]
wps = [p['home_wp'] for p in plays]
ax.fill_between(times, wps, 0.5,
where=[wp >= 0.5 for wp in wps],
color='green', alpha=0.3)
ax.fill_between(times, wps, 0.5,
where=[wp < 0.5 for wp in wps],
color='red', alpha=0.3)
ax.plot(times, wps, linewidth=2)
ax.axhline(0.5, linestyle='--', alpha=0.5)
return fig
EPA Color Function
def epa_color(epa):
if epa >= 1.0:
return '#1a9641' # Big positive
elif epa >= 0.3:
return '#a6d96a' # Positive
elif epa >= -0.3:
return '#ffffbf' # Neutral
elif epa >= -1.0:
return '#fdae61' # Negative
else:
return '#d7191c' # Big negative
8. Audience-Specific Design
Broadcast (5-8 seconds)
- Large, clear numbers
- Minimal text
- Team colors prominent
- Update animations
Coaching Staff (extended study)
- Full detail
- All situational breakdowns
- Links to video
- Print-ready
Social Media (2-3 seconds)
- Single key insight
- Bold visual
- Call to action
- Mobile-optimized (square/vertical)
9. Common Mistakes to Avoid
Drive Charts
- ❌ Too many play labels (cluttered)
- ❌ Inconsistent color scales
- ❌ Missing drive result indicator
- ✅ Clear start/end markers
- ✅ Appropriate detail level
Win Probability
- ❌ Too many annotations
- ❌ No team identification
- ❌ Missing 50% reference
- ✅ Clear fills showing advantage
- ✅ Key moments highlighted
Heatmaps
- ❌ Using sequential colormap for EPA
- ❌ Missing sample sizes
- ❌ Unclear axis labels
- ✅ Diverging colormap centered at 0
- ✅ Cell annotations
10. Pre-Visualization Checklist
Before Creating
- [ ] What story does the data tell?
- [ ] Who is the audience?
- [ ] What is the appropriate detail level?
- [ ] What time frame do viewers have?
During Creation
- [ ] Are colors meaningful?
- [ ] Is there a clear visual hierarchy?
- [ ] Are key moments identified?
- [ ] Is context provided?
Before Publishing
- [ ] Is it accurate?
- [ ] Is it accessible?
- [ ] Does it tell the intended story?
- [ ] Would a non-expert understand it?
Formulas Quick Reference
Game Time Conversion
game_minutes = (quarter - 1) * 15 + (15 - minutes) - seconds/60
EPA from EP Values
epa = ep_after - ep_before
Drive Efficiency
drive_epa_per_play = sum(play_epas) / len(plays)
Success Rate
success_rate = successful_plays / total_plays
Essential Resources
Python Libraries
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.animation import FuncAnimation
import numpy as np
Color Palettes
# EPA diverging
EPA_COLORS = ['#d7191c', '#fdae61', '#ffffbf', '#a6d96a', '#1a9641']
# Drive results
RESULT_COLORS = {
'touchdown': '#2a9d8f',
'field_goal': '#e9c46a',
'turnover': '#e76f51',
'punt': '#8d99ae',
'downs': '#e76f51'
}
Chapter Summary in One Sentence
Play-by-play visualization transforms game data into visual narratives using drive charts, win probability curves, and situational analysis to reveal the story of how games unfold play by play.