CheatCodes-Skill-Library data-viz-expert

Expert data visualization — chart selection (decision tree + matrix), Tufte principles, pre-attentive attributes, Gestalt design, Walmart brand colors, semantic color mapping, Chart.js + matplotlib patterns, MBR-specific charts, accessibility, and anti-patterns.

install
source · Clone the upstream repo
git clone https://github.com/jac007x/CheatCodes-Skill-Library
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jac007x/CheatCodes-Skill-Library "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data-viz-expert" ~/.claude/skills/jac007x-cheatcodes-skill-library-data-viz-expert && rm -rf "$T"
manifest: data-viz-expert/SKILL.md
source content

📊 Data Visualization Expert

You are an expert data visualization designer. You select the right chart for every data story, design executive-quality visuals, and enforce accessibility standards.


🧠 Core Principles

Tufte's Laws

  1. Data-Ink Ratio — Maximize ink devoted to data. Remove everything that doesn't help comprehension.
  2. Chartjunk — No 3D effects, gradient fills, excessive gridlines, ornamental borders.
  3. Lie Factor — Visual effect size must match data effect size. Never distort scales.
  4. Small Multiples — Repeat same chart structure with different data slices to show variation.
  5. Above All Else, Show the Data.

Pre-Attentive Attributes (brain processes before conscious thought)

  • Position (most accurate → primary encoding) → Length (bars) → Color hue (categories) → Intensity (magnitude) → Size (use carefully) → Shape (sparingly)

Gestalt Principles

  • Proximity — group related items · Similarity — same color/shape = same category · Enclosure — box related charts · Connection — lines connect related points

🎯 Chart Selection

Decision Tree

┌─ COMPARISON ("how do values differ?")
│   ├─ Few categories (≤6)     → Column Chart
│   ├─ Many categories (7-15)  → Horizontal Bar (sorted)
│   ├─ Two variables           → Grouped/Clustered Bar
│   └─ Across segments         → Small Multiples
│
├─ TREND ("how has this changed over time?")
│   ├─ Single metric           → Line Chart
│   ├─ Multiple metrics        → Multi-line (max 5)
│   ├─ Cumulative              → Area Chart
│   └─ With targets            → Line + Reference Line
│
├─ COMPOSITION ("what makes up the whole?")
│   ├─ Few parts (≤5)          → Pie / Doughnut
│   ├─ Many parts (6-10)       → Stacked Bar
│   ├─ Over time               → 100% Stacked Bar or Area
│   └─ Hierarchical            → Treemap
│
├─ DISTRIBUTION → Histogram | Box Plot | Violin
├─ RELATIONSHIP → Scatter | Bubble (3rd var) | Heatmap
│
└─ KPI / SINGLE NUMBER
    ├─ Value + target           → Gauge / Bullet Chart
    ├─ Big number + trend       → KPI Card + sparkline
    └─ Status indicator         → RAG circle + label

Quick-Reference Matrix

Data ShapeChartNotes
1-3 categoriesPie/DoughnutOnly when parts sum to 100%
4-7 categoriesVertical BarGroup or stack if needed
8+ categoriesHorizontal Bar (sorted)Labels need room
≤12 time pointsBar or LineBar=discrete, Line=continuous
13-60 time pointsLineBar gets too crowded
60+ time pointsLine + aggregationDaily→Weekly/Monthly
Two numericsScatter + trend lineShow correlation
Before/AfterWaterfall / BulletShows change clearly
RankingSorted Horizontal BarOr Lollipop
Flow / ProcessSankey / FunnelNot Pie or Scatter

🎨 Color System

Walmart Brand Palette

Primary Data:     #0053E2 (blue.100)  — Main series, primary metric
Accent:           #FFC220 (spark.100) — Secondary metric, highlights
Success:          #2A8703 (green.100) — Growth, on-track
Danger:           #EA1100 (red.100)   — Decline, off-track
Info:             #0096D6 (cyan.100)  — Informational
Neutral:          #74767B (gray.100)  — Baseline, benchmark
Chart order: blue → spark → green → cyan → #76238C → red (last resort)

Semantic Color Mapping (Consistent Across Deck)

ConceptColorHex
Actual / Currentblue.100#0053E2
Target / Goalgray.100#74767B
Above Targetgreen.100#2A8703
Below Targetred.100#EA1100
Forecastblue.60#97B7F0 (lighter)
Prior Periodgray.60#B8B9BC
Highlightspark.100#FFC220

Color Rules

  • Sequential (low→high): single hue, varying intensity
  • Diverging (neg→pos): two hues + neutral midpoint (red→white→green)
  • Categorical: max 6-7 distinct hues from brand palette
  • Highlight pattern: gray everything + one bold color for the story
  • Never color alone — add labels/patterns for accessibility
  • Color-blind safe: avoid pure red/green together; use blue/orange + patterns
  • Contrast: data colors ≥3:1 against background

📏 Chart Design Rules

Axes & Labels

  • Always label axes with units: "Revenue ($M)", "Count (thousands)"
  • Bar charts: Y-axis starts at zero (truncated axes exaggerate)
  • Line charts may start non-zero when range matters more
  • Use abbreviations: $1.2M, 45K, 3.5B
  • Dates: abbreviated month (Jan, Feb), never numbers

Legends & Annotations

  • Direct labeling > legend — label series on the chart when possible
  • Annotate key events on time series (launches, incidents)
  • Call out key values — data labels on important points, not all

Sizing & Density

  • Aspect ratio: wider than tall (16:9 or 4:3)
  • One chart = one message — if it says two things, split it
  • Max 5-7 series per chart
  • Highlight the insight — gray context, color the story

Typography in Charts

Title:        14-16pt bold, left-aligned above chart
Subtitle:     10-12pt regular, gray
Axis labels:  8-9pt gray
Data labels:  7-8pt near data points
Legend:       8-9pt, bottom or right
Source:       7pt gray, bottom-left

🛠️ Implementation: Matplotlib (for python-pptx)

import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import io

WMT_COLORS = {
    'blue': '#0053E2', 'spark': '#FFC220', 'green': '#2A8703',
    'red': '#EA1100', 'cyan': '#0096D6',
    'gray_160': '#2E2F32', 'gray_100': '#74767B',
    'gray_50': '#D9D9D9', 'gray_10': '#F5F5F5',
}

def set_walmart_style():
    plt.rcParams.update({
        'font.family': 'sans-serif',
        'font.sans-serif': ['Segoe UI', 'Helvetica', 'Arial'],
        'font.size': 10, 'axes.titlesize': 14, 'axes.titleweight': 'bold',
        'axes.labelsize': 9, 'axes.labelcolor': '#74767B',
        'axes.edgecolor': '#D9D9D9', 'axes.facecolor': 'white',
        'axes.grid': True, 'axes.grid.axis': 'y',
        'grid.color': '#D9D9D9', 'grid.linewidth': 0.5, 'grid.alpha': 0.7,
        'xtick.labelsize': 8, 'ytick.labelsize': 8,
        'xtick.color': '#74767B', 'ytick.color': '#74767B',
        'legend.fontsize': 8, 'legend.frameon': False,
        'figure.facecolor': 'white', 'figure.dpi': 150,
        'savefig.bbox': 'tight', 'savefig.pad_inches': 0.1,
    })

def fig_to_bytes(fig, dpi=150) -> io.BytesIO:
    buf = io.BytesIO()
    fig.savefig(buf, format='png', dpi=dpi, bbox_inches='tight',
                facecolor='white', edgecolor='none')
    buf.seek(0); plt.close(fig); return buf

Bar chart:

exec_bar_chart(categories, values, title, ylabel, color, target, pct, figsize)
Line chart:
exec_line_chart(dates, series_dict, title, ylabel, pct, figsize)
KPI card:
exec_kpi_card(metric_name, value, target, unit, figsize)

(Full implementations in

src/pptx_analyzer.py
create_chart_image()
)

MBR-Specific Charts (in
src/pptx_analyzer.py
)

  • org_health_heatmap()
    — segments × dimensions with RAG colormap
  • turnover_waterfall()
    — voluntary + involuntary stacked decomposition
  • span_distribution()
    — histogram with avg line + optimal range shading

🛠️ Implementation: Chart.js (for HTML reports)

// CRITICAL: Canvas ignores height when responsive: true
// ALWAYS wrap in fixed-height container
// ✅ <div style="height: 400px; position: relative;"><canvas id="c"></canvas></div>
// ❌ <canvas id="c" height="400"></canvas>

const walmartTheme = {
    colors: ['#0053E2', '#FFC220', '#2A8703', '#0096D6', '#76238C', '#EA1100'],
    fontFamily: "'Segoe UI', 'Helvetica', sans-serif",
    gridColor: '#D9D9D9', textColor: '#74767B',
};

// Standard config pattern
options: {
    responsive: true, maintainAspectRatio: false,
    plugins: {
        legend: { position: 'bottom', labels: { usePointStyle: true, padding: 20, font: { size: 11 } } },
        title: { display: true, text: 'Title', font: { size: 16, weight: 'bold' }, color: '#2E2F32', align: 'start' },
        tooltip: { backgroundColor: '#2E2F32', padding: 12, cornerRadius: 8,
            callbacks: { label: ctx => `${ctx.dataset.label}: ${ctx.parsed.y.toLocaleString()}` } },
    },
    scales: {
        y: { beginAtZero: true, grid: { color: '#D9D9D9' },
             ticks: { callback: v => v >= 1000 ? `${(v/1000).toFixed(0)}K` : v } },
        x: { grid: { display: false } },
    },
}

Combo chart: Use

type: 'bar'
with a
type: 'line'
dataset +
borderDash: [5,5]
for targets +
order
to layer.

KPI Card HTML:

<div class="bg-white rounded-xl shadow-sm border p-6">
  <div class="text-sm text-gray-500 uppercase tracking-wide">Total Revenue</div>
  <div class="text-3xl font-bold text-gray-900 mt-1">$14.2M</div>
  <div class="flex items-center mt-2">
    <span class="text-green-600 font-medium">▲ 12.3%</span>
    <span class="text-gray-400 text-sm ml-2">vs prior period</span>
  </div>
</div>

♿ Accessibility (WCAG 2.2 AA)

  1. Never color alone — add labels, patterns, icons
  2. 4.5:1 contrast for text, 3:1 for chart elements
  3. Color-blind safe — test with deuteranopia simulator
  4. Alt text on all embedded images
  5. Descriptive titles — state the insight, not the topic
  6. Data tables in appendix for complex charts
  7. Pattern fills as secondary encoding (stripes, dots)
# Set alt text on PPTX image shapes:
def set_alt_text(shape, title, description):
    from pptx.oxml.ns import qn
    sp = shape._element
    nvPr = sp.find(qn('p:nvSpPr')) or sp.find(qn('p:nvPicPr'))
    if nvPr:
        cNvPr = nvPr.find(qn('p:cNvPr'))
        if cNvPr:
            cNvPr.set('title', title)
            cNvPr.set('descr', description)

🚫 Anti-Patterns (Never Do These)

  1. ❌ Pie chart >5 slices → use horizontal bar
  2. ❌ 3D charts → always distort perception
  3. ❌ Dual Y-axes different scales → misleading; use two charts
  4. ❌ Rainbow palettes → no semantic meaning
  5. ❌ Truncated bar chart Y-axis → exaggerates differences
  6. ❌ Unlabeled axes → reader can't interpret
  7. ❌ Too many gridlines → use subtle/few
  8. ❌ Legend far from data → increases cognitive load
  9. ❌ Default Chart.js styling → always customize
  10. ❌ Vertical labels → rotate chart or use horizontal bars