data-viz
AI-First Data Visualization
Philosophy
Build production-quality interactive data interfaces with modern component libraries — no vendor lock-in, embeddable anywhere. When no tool is specified, build code-first. When the user explicitly names a BI tool, use it — only suggest code-first if they ask for options or hit a technical blocker.
Technology Stack
Full API patterns & code: references/component-guide.md
Framework Priority
- React + Tailwind — Default when JSX/TSX supported
- HTML + CSS + Vanilla JS — Fallback (use D3 or Chart.js)
- Python (Plotly/Dash) — Python-only environments only
Library Selection
| Library | Best For |
|---|---|
| shadcn/ui charts | Default first choice — general dashboards, most chart types |
| Recharts | Line, bar, area, composed, radar — fine-grained control |
| Tremor | KPI cards, metric displays, full dashboard layouts |
| Nivo | Heatmaps, treemaps, choropleth, calendar, Sankey, funnel |
| visx | Bespoke custom viz — D3-level control with React |
| D3.js | Force-directed graphs, DAGs, maps — maximum flexibility |
| Victory | When animation quality matters most |
Supporting: Tailwind CSS · Radix UI · Framer Motion · Lucide React · date-fns · Papaparse · lodash
Building a Visualization
Step 1: Understand the Data Story
Before code, identify: What question does the data answer? Who is the audience (exec → KPIs only, analyst → drill-down, public → narrative)? What's the ONE key insight? Design around it.
Step 2: Choose Chart Type
| Data Relationship | Chart Type | Library |
|---|---|---|
| Trend over time | Line, Area | shadcn/Recharts |
| Category comparison | Bar (horizontal if many) | shadcn/Recharts |
| Part of whole | Donut, Treemap | shadcn/Nivo |
| Distribution | Histogram, Box, Violin | Nivo/visx |
| Correlation | Scatter, Bubble | Recharts/visx |
| Geographic | Choropleth, Dot map | Nivo/D3 |
| Hierarchical | Treemap, Sunburst | Nivo |
| Flow / Process | Sankey, Funnel | Nivo/D3 |
| Single KPI | Metric card, Gauge, Sparkline | Tremor/shadcn |
| Multi-metric overview | Dashboard grid of cards | Tremor + shadcn |
| Ranking | Horizontal bar, Bar list | Tremor |
| Column/model lineage | Force-directed DAG | D3 |
| Pipeline dependencies | Hierarchical tree, DAG | D3/Nivo |
| Multi-dimensional quality | Radar/Spider | Recharts |
| Activity density over time | Calendar heatmap | Nivo |
| Incremental change breakdown | Waterfall | Recharts (custom) |
Step 3: Build the Interface
Start from this layout — remove what the data doesn't need:
┌─────────────────────────────────────────┐
│ Header: Title + Description + Date Range│
├─────────────────────────────────────────┤
│ KPI Row: 3-5 metric cards + sparklines │
├─────────────────────────────────────────┤
│ Primary Visualization (largest chart) │
├──────────────────┬──────────────────────┤
│ Secondary Chart │ Supporting Chart/Tbl │
├──────────────────┴──────────────────────┤
│ Detail Table (sortable, filterable) │
└─────────────────────────────────────────┘
A single insight might just be one chart with a headline and annotation. Scale complexity to audience.
Step 4: Design Principles
- Data-ink ratio: Remove chartjunk — unnecessary gridlines, redundant labels, decorative borders
- Color with purpose: Encode meaning (red=bad, green=good, blue=neutral). Max 5-7 colors. Single-hue gradient for sequential data
- Typography hierarchy: Title → subtitle (muted) → axis labels (small) → data labels
- Responsive:
min-h-[VALUE]on all charts. Grid stacks on mobile - Animation: Entry transitions only,
duration-300toduration-500. Never continuous - Accessibility:
aria-labelon charts, WCAG AA contrast, don't rely on color alone - Dynamic color safety: When colors come from external sources (brand palettes, category maps, API data, user config), never apply them directly as text color without a contrast check. Dark colors are invisible on dark card backgrounds. Safe pattern: use the external color only for non-text elements (left border, dot, underline); always use the standard text color (white /
var(--text)) for the label itself. If color-coded text is required, apply a minimum lightness floor:color: hsl(from brandColor h s max(l, 60%)) - Icon semantics: Verify every icon matches its label's actual meaning, not just its visual shape. Common traps: using a rising-trend icon (📈) for metrics where lower is better (latency, error rate, cost); using achievement icons (🏆) for plain counts. When in doubt, use a neutral descriptive icon over a thematic one that could mislead
Step 5: Interactivity & Annotations
Priority: Tooltips (every chart) → Filtering → Sorting → Drill-down → Cross-filtering → Export → Annotations
Annotations turn charts into stories. Mark: inflection points, threshold crossings (amber), external events (indigo/red), anomalies (red), achievements (green). Limit 3 per chart. Implementation: references/component-guide.md → Annotation Patterns.
Step 6: Tell the Story
- Headline states insight: "Revenue grew 23% QoQ, driven by enterprise" — not "Q3 Revenue Chart"
- Annotate key moments directly on chart
- Contextual comparisons: vs. prior period, vs. target, vs. benchmark
- Progressive disclosure: Overview first — detail on demand
Environment-Specific Guidance
| Environment | Approach |
|---|---|
| Claude Artifacts | React (JSX), single file, default export. Available: recharts, lodash, d3, lucide-react, shadcn via @/components/ui/*, Tailwind |
| Claude Code / Terminal | Vite + React + Tailwind. Add shadcn/ui + Recharts. Structure: src/components/charts/, src/components/cards/, src/data/ |
| Python / Jupyter | Plotly for charts, Plotly Dash for dashboards |
| Cursor / Bolt / other IDEs | Match existing framework. Prefer shadcn/ui if present |
Anti-Patterns
- Screenshot/static charts — build interactive components
- Defaulting to BI tools unprompted — build code-first when no tool specified
- Default matplotlib — always customize in Python
- Rainbow palettes — use deliberate, meaningful colors
- 3D charts — almost never appropriate
- Pie charts > 5 slices — use horizontal bar
- Unlabeled dual y-axes — use two separate charts
- Truncated bar axes — always start at zero
- Filtering or mapping over a field not confirmed to exist in the data export — an undefined field in
.filter()or.map()produces empty arrays or NaN silently, not an error; always validate the exported schema matches what the chart code consumes
Pre-Delivery Checklist
Before marking a dashboard complete:
- Every tab / view activated — all charts render (no blank canvases, no unexpected 0–1 axes)
- Every field referenced in chart/filter code confirmed present in the data export
- All text readable on its background — check explicitly when colors come from external data
- All icons match their label's meaning
- Tooltips appear on hover for every chart
- No chart silently receives an empty dataset — add a visible empty state or console warning
- Mobile: grid stacks correctly, no body-level horizontal overflow
More from altimateai/altimate-code
schema-migration
Analyze DDL migrations for data loss risks — type narrowing, missing defaults, dropped constraints, breaking column changes. Use before applying schema changes to production.
3dbt-unit-tests
Generate dbt unit tests automatically for any model. Analyzes SQL logic (CASE/WHEN, JOINs, window functions, NULLs), creates type-correct mock inputs from manifest schema, and assembles complete YAML. Use when a user says "generate tests", "add unit tests", "test this model", or "test coverage" for dbt models.
3dbt-test
Add schema tests, unit tests, and data quality checks to dbt models. Use when validating data integrity, adding test definitions to schema.yml, writing unit tests, or practicing test-driven development in dbt. Powered by altimate-dbt.
2dbt-docs
Document dbt models and columns in schema.yml with business context — model descriptions, column definitions, and doc blocks. Use when adding or improving documentation for discoverability. Powered by altimate-dbt.
2sql-review
Pre-merge SQL quality gate — lint 26 anti-patterns, grade readability/performance A-F, validate syntax, and scan for injection threats. Use before committing or reviewing SQL changes.
2dbt-troubleshoot
Debug dbt errors — compilation failures, runtime database errors, test failures, wrong data, and performance issues. Use when something is broken, producing wrong results, or failing to build. Powered by altimate-dbt.
2