data-visualization

Build mathematically correct, visually prominent data visualizations for time-series charts. Use this skill when creating charts with mathematical overlays (trendlines, patterns, indicators), fixing v

SKILL.md

GitHub

Data Visualization Skill

Focus: Mathematical correctness and visual prominence for time-series charts with overlays (trendlines, patterns, indicators).

When to use this skill:

  • Building charts with mathematical overlays (trendlines, moving averages, regressions)
  • Fixing visual artifacts (wavy lines at gaps, domain mismatches)
  • Validating chart correctness (progressive evidence)
  • Implementing pattern overlays (flags, wedges, triangles, H&S)
  • Working with Chart.js, D3.js, Recharts, or similar frameworks

When NOT to use this skill:

  • Aesthetic UI design (use frontend-design skill)
  • Telegram-specific UI patterns (use telegram-uiux skill)
  • General React/TypeScript patterns (use telegram-uiux skill)

Quick Reference

Problem: Trendlines appear wavy at weekend gaps Solution: Use timestamp-based regression (not index-based) → MATHEMATICAL-CORRECTNESS.md

Problem: Pattern overlays hard to see on chart Solution: Use shaded regions + bold lines + layer ordering → VISUAL-HIERARCHY.md

Problem: Custom polygon fill doesn't render in Chart.js Solution: Use framework's dataset-to-dataset fill feature → FRAMEWORK-PATTERNS.md

Problem: Chart works with perfect data but crashes on real data Solution: Test with edge cases (gaps, nulls, holidays) → VALIDATION.md


Decision Tree

User request involves data visualization?
├─ YES → Continue
└─ NO → Use different skill

Mathematical overlays (trendlines, patterns)?
├─ YES → Use this skill
└─ NO → Consider frontend-design (if aesthetic focus)

Problem type?
├─ Visual artifacts (wavy lines, curvature)
│  └─ Check: Domain compatibility [MATHEMATICAL-CORRECTNESS.md]
├─ Low visibility (patterns hard to see)
│  └─ Check: Visual hierarchy [VISUAL-HIERARCHY.md]
├─ Framework issues (custom code not working)
│  └─ Check: Framework patterns [FRAMEWORK-PATTERNS.md]
├─ Correctness validation (how to verify?)
│  └─ Check: Progressive validation [VALIDATION.md]
└─ General implementation
   └─ Read all sections for comprehensive approach

Core Principles

1. Visual Prominence Through Layering

Pattern: Shaded regions (fills) + bold trendlines + layer ordering

Why: Simple lines blend into busy charts; shaded areas create immediate recognition

See: VISUAL-HIERARCHY.md for opacity guidelines, layering strategy, Chart.js implementation


2. Domain Compatibility for Mathematical Correctness

Pattern: Regression domain must match visualization axis domain

Why: Domain mismatch creates visual artifacts (wavy lines at irregular spacing)

See: MATHEMATICAL-CORRECTNESS.md for timestamp vs index, testing strategy, common mismatches


3. Framework-Native Over Custom Solutions

Pattern: Use framework's built-in features instead of custom implementations

Why: Native features are tested, documented, maintained; custom solutions fragile

See: FRAMEWORK-PATTERNS.md for Chart.js patterns, research workflow, when custom is acceptable


4. Edge Cases Reveal Mathematical Bugs

Pattern: Test with irregular data (weekend gaps, holidays, nulls)

Why: Regular spacing hides domain mismatches; irregular spacing reveals bugs

See: VALIDATION.md for edge case examples, testing checklist, validation workflow


5. Progressive Evidence for UI Validation

Pattern: Validate through layers: visual → code → edge cases → mathematical

Why: Visual appearance alone doesn't prove correctness; need multiple validation levels

See: VALIDATION.md for 4-layer validation, evidence hierarchy, validation matrix


Workflow

Phase 1: Plan Implementation

  1. Understand requirements: What visualization? What overlays?
  2. Research framework: Does Chart.js/D3 have built-in feature?
  3. Choose approach: Native feature vs custom (prefer native)
  4. Identify domain: What's the X-axis? (time, categories, continuous)

Phase 2: Implement Visualization

  1. Start with data layer: Render base chart (candlesticks, line, etc.)
  2. Add mathematical overlays: Trendlines, patterns, indicators
  3. Apply visual hierarchy: Layer ordering (fills behind, lines front)
  4. Tune prominence: Adjust opacity (25-30% for web), line width (3px)

Phase 3: Validate Correctness

  1. Layer 1 (Visual): Does it look right? Take screenshots
  2. Layer 2 (Code): Using framework correctly? Review patterns
  3. Layer 3 (Edge): Test with weekend gaps, holidays, nulls
  4. Layer 4 (Math): Verify algorithm correctness (domain match?)

Phase 4: Debug Issues

If wavy lines:

  • Check domain compatibility (timestamp vs index regression)
  • Test with weekend gap data
  • Verify Chart.js axis type (type: 'time')

If low visibility:

  • Add shaded fill regions (25-30% opacity)
  • Increase line width (3px)
  • Apply layer ordering (order: 1,2,3)

If framework issues:

  • Research native features (dataset-to-dataset fill)
  • Check documentation examples
  • Prefer configuration over code

Common Patterns

Pattern: Timestamp-Based Regression

Use when: Continuous time axis (Chart.js type: 'time')

function fitLinearTrendline(points) {
    const n = points.length;

    // Use timestamps (p.x), not indices (i)
    const sumX = points.reduce((sum, p) => sum + p.x, 0);
    const sumXY = points.reduce((sum, p) => sum + p.x * p.y, 0);
    const sumX2 = points.reduce((sum, p) => sum + p.x * p.x, 0);

    const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
    const intercept = (sumY - slope * sumX) / n;

    return points.map(p => ({
        x: p.x,
        y: slope * p.x + intercept  // Timestamp-based
    }));
}

See: MATHEMATICAL-CORRECTNESS.md


Pattern: Shaded Region with Layering

Use when: Overlaying patterns on busy charts

const datasets = [];

// Layer 3: Fill area (behind)
datasets.push({
    label: 'Pattern Area',
    data: polygonPoints,
    backgroundColor: 'rgba(38, 166, 154, 0.25)',  // 25% opacity
    fill: true,
    borderColor: 'transparent',
    order: 3,  // Behind
    pointRadius: 0
});

// Layer 2: Trendline (front)
datasets.push({
    label: 'Trendline',
    data: trendlinePoints,
    borderColor: '#26A69A',
    borderWidth: 3,  // Bold
    fill: false,
    order: 2,  // Front
    pointRadius: 0
});

// Layer 1: Data (highest priority)
datasets.push({
    type: 'candlestick',
    data: ohlcData,
    order: 1  // Front-most
});

See: VISUAL-HIERARCHY.md


Pattern: Dataset-to-Dataset Fill (Chart.js)

Use when: Filling area between two lines

const datasets = [];

// Draw lower boundary first
const lowerIndex = datasets.length;
datasets.push({
    label: 'Support',
    data: lowerLine,
    borderColor: '#26A69A',
    fill: false,
    order: 2
});

// Draw upper boundary with fill TO lower
datasets.push({
    label: 'Resistance',
    data: upperLine,
    borderColor: '#26A69A',
    backgroundColor: 'rgba(38, 166, 154, 0.25)',
    fill: lowerIndex,  // Fill to support dataset (Chart.js native)
    order: 2
});

See: FRAMEWORK-PATTERNS.md


Pattern: Edge Case Testing

Use when: Validating mathematical correctness

// Test data with weekend gap
const testData = [
    { x: Date.parse('2024-01-01'), y: 100 },  // Mon
    { x: Date.parse('2024-01-02'), y: 102 },  // Tue
    { x: Date.parse('2024-01-03'), y: 104 },  // Wed
    // Weekend gap (Thu-Sun missing)
    { x: Date.parse('2024-01-08'), y: 106 },  // Mon (5 days later!)
    { x: Date.parse('2024-01-09'), y: 108 },  // Tue
];

const trendline = fitLinearTrendline(testData);

// Validation: Line should stay straight
// If wavy → domain mismatch bug

See: VALIDATION.md


Anti-Patterns

❌ Index-Based Regression on Time Axis

// BAD: Using array indices on continuous time axis
const sumX = points.reduce((sum, p, i) => sum + i, 0);
return { x: p.x, y: slope * i + intercept };
// Result: Wavy lines at weekend gaps

Fix: Use timestamp-based regression → MATHEMATICAL-CORRECTNESS.md


❌ Custom Polygon Fill (Chart.js)

// BAD: Concatenating reversed arrays
const polygon = [...upperLine, ...lowerLine.reverse()];
datasets.push({ data: polygon, fill: true });
// Result: Doesn't render correctly in Chart.js

Fix: Use dataset-to-dataset fill → FRAMEWORK-PATTERNS.md


❌ Visual-Only Validation

// BAD: Stopping at "looks good"
console.log('Screenshot looks good! Ship it!');
// Missing: Code review, edge cases, math verification

Fix: Progressive validation (4 layers) → VALIDATION.md


❌ Same Layer Order for All Elements

// BAD: Random rendering order
datasets.push({ order: 1 });  // Fill
datasets.push({ order: 1 });  // Line
datasets.push({ order: 1 });  // Data
// Result: Unpredictable z-index

Fix: Explicit layering (1=data, 2=lines, 3=fills) → VISUAL-HIERARCHY.md


Integration with Other Skills

Complements:

  • frontend-design: Aesthetic UI design (this skill: technical correctness)
  • telegram-uiux: Telegram-specific patterns (this skill: general data viz)
  • testing-workflow: General testing (this skill: visualization-specific validation)

References:

  • See docs/frontend/UI_PRINCIPLES.md for comprehensive principles
  • See .claude/implementations/2026-01-05-shaded-pattern-visualization.md for implementation case study
  • See .claude/implementations/2026-01-05-proper-pattern-trendlines-all-types.md for pattern-specific details

Real-World Example

Problem: Chart pattern trendlines appeared wavy at weekends, user feedback "I don't like the look"

Root causes:

  1. Visual: Simple thin lines blended into chart (low contrast)
  2. Mathematical: Index-based regression on continuous time axis (domain mismatch)

Solutions applied:

  1. Visual: Shaded regions (25% opacity) + bold lines (3px) + layer ordering
  2. Mathematical: Timestamp-based regression (domain match)
  3. Validation: Tested with weekend gap data (edge cases)

Outcome: ✅ Patterns 3-5x more visible, ✅ Straight lines across gaps, ✅ Professional appearance

See: .claude/evolution/2026-01-05-data-visualization-principles.md for full case study


Quick Checklist

Before implementation:

  • Research framework features (Chart.js docs, examples)
  • Identify axis domain (time, categories, continuous)
  • Plan layer ordering (data=1, lines=2, fills=3)

During implementation:

  • Use framework-native features (dataset-to-dataset fill)
  • Match regression domain to axis domain (timestamps for time axis)
  • Apply visual hierarchy (shaded regions, bold lines)

After implementation:

  • Visual validation (screenshot, looks right?)
  • Code review (framework patterns correct?)
  • Edge case testing (weekend gaps, nulls, holidays)
  • Mathematical verification (domain match, formula correct?)

See detailed documentation:


Last Updated: 2026-01-05 Version: 1.0.0 Source: Distilled from candlestick chart pattern visualization work