data-visualization
Data Visualization
Build effective, accessible charts and graphs for data-driven applications.
Instructions
- Choose the right chart type - Match visualization to data relationships
- Keep it simple - Avoid chart junk and unnecessary decoration
- Use color purposefully - Semantic colors, accessible palettes
- Label clearly - Axes, legends, and data points should be readable
- Make it accessible - Screen reader support and keyboard navigation
Chart Type Selection
| Data Relationship | Chart Type |
|---|---|
| Trend over time | Line chart |
| Comparison | Bar chart |
| Part of whole | Pie/Donut chart |
| Distribution | Histogram |
| Correlation | Scatter plot |
| Ranking | Horizontal bar |
| Geographic | Map |
Recharts (Recommended)
Basic Line Chart
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
const data = [
{ month: 'Jan', revenue: 4000 },
{ month: 'Feb', revenue: 3000 },
{ month: 'Mar', revenue: 5000 },
{ month: 'Apr', revenue: 4500 },
{ month: 'May', revenue: 6000 },
];
function RevenueChart() {
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis dataKey="month" stroke="#6b7280" fontSize={12} />
<YAxis stroke="#6b7280" fontSize={12} tickFormatter={(v) => `$${v / 1000}k`} />
<Tooltip
formatter={(value: number) => [`$${value.toLocaleString()}`, 'Revenue']}
contentStyle={{ borderRadius: '8px', border: '1px solid #e5e7eb' }}
/>
<Line
type="monotone"
dataKey="revenue"
stroke="#2563eb"
strokeWidth={2}
dot={{ fill: '#2563eb', strokeWidth: 2 }}
activeDot={{ r: 6 }}
/>
</LineChart>
</ResponsiveContainer>
);
}
Multi-Line Chart with Legend
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
function ComparisonChart({ data }) {
return (
<ResponsiveContainer width="100%" height={400}>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="thisYear" stroke="#2563eb" name="This Year" />
<Line type="monotone" dataKey="lastYear" stroke="#9ca3af" name="Last Year" strokeDasharray="5 5" />
</LineChart>
</ResponsiveContainer>
);
}
Bar Chart
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
function SalesChart({ data }) {
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis dataKey="category" />
<YAxis />
<Tooltip />
<Bar dataKey="sales" fill="#2563eb" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
);
}
Pie/Donut Chart
import { PieChart, Pie, Cell, ResponsiveContainer, Legend, Tooltip } from 'recharts';
const COLORS = ['#2563eb', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'];
function CategoryPieChart({ data }) {
return (
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={100}
paddingAngle={2}
dataKey="value"
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
>
{data.map((entry, index) => (
<Cell key={entry.name} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
<Legend />
</PieChart>
</ResponsiveContainer>
);
}
Sparklines
import { LineChart, Line, ResponsiveContainer } from 'recharts';
function Sparkline({ data, color = '#2563eb', height = 40 }) {
return (
<ResponsiveContainer width="100%" height={height}>
<LineChart data={data}>
<Line
type="monotone"
dataKey="value"
stroke={color}
strokeWidth={2}
dot={false}
/>
</LineChart>
</ResponsiveContainer>
);
}
// Usage in KPI card
function KPICardWithSparkline({ title, value, trend }) {
return (
<div className="bg-white p-4 rounded-lg shadow">
<div className="text-sm text-gray-500">{title}</div>
<div className="text-2xl font-bold">{value}</div>
<div className="mt-2 h-10">
<Sparkline data={trend} />
</div>
</div>
);
}
Real-Time Charts
function RealTimeChart() {
const [data, setData] = useState<{ time: string; value: number }[]>([]);
useEffect(() => {
const interval = setInterval(() => {
setData((prev) => {
const newPoint = {
time: new Date().toLocaleTimeString(),
value: Math.random() * 100,
};
const updated = [...prev, newPoint];
// Keep last 20 points
return updated.slice(-20);
});
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
<XAxis dataKey="time" />
<YAxis domain={[0, 100]} />
<Line
type="monotone"
dataKey="value"
stroke="#2563eb"
isAnimationActive={false}
dot={false}
/>
</LineChart>
</ResponsiveContainer>
);
}
Accessible Charts
function AccessibleChart({ data, title, description }) {
return (
<div role="img" aria-label={title} aria-describedby="chart-desc">
<p id="chart-desc" className="sr-only">{description}</p>
{/* Visual chart */}
<ResponsiveContainer width="100%" height={300}>
<BarChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<Bar dataKey="value" fill="#2563eb" />
</BarChart>
</ResponsiveContainer>
{/* Data table for screen readers */}
<table className="sr-only">
<caption>{title}</caption>
<thead>
<tr>
<th>Category</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{data.map((item) => (
<tr key={item.name}>
<td>{item.name}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
Color Palettes
// Categorical (distinct items)
const categorical = ['#2563eb', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4'];
// Sequential (low to high)
const sequential = ['#dbeafe', '#93c5fd', '#3b82f6', '#1d4ed8', '#1e3a8a'];
// Diverging (negative to positive)
const diverging = ['#ef4444', '#fca5a5', '#fef3c7', '#86efac', '#22c55e'];
// Status colors
const status = {
success: '#22c55e',
warning: '#f59e0b',
error: '#ef4444',
info: '#3b82f6',
};
Chart.js Integration
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend } from 'chart.js';
import { Line } from 'react-chartjs-2';
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
function ChartJSLine({ data }) {
const chartData = {
labels: data.map(d => d.label),
datasets: [{
label: 'Revenue',
data: data.map(d => d.value),
borderColor: '#2563eb',
backgroundColor: 'rgba(37, 99, 235, 0.1)',
fill: true,
tension: 0.4,
}],
};
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
},
scales: {
y: { beginAtZero: true },
},
};
return (
<div style={{ height: 300 }}>
<Line data={chartData} options={options} />
</div>
);
}
Best Practices
- Start Y-axis at zero for bar charts (prevents misleading comparisons)
- Use consistent colors across related charts
- Limit data points - aggregate if too dense
- Add context - show comparisons, targets, benchmarks
- Format numbers - use abbreviations for large numbers (1.2M not 1,200,000)
- Test color blindness - use patterns or labels as backup
When to Use
- Analytics dashboards
- Financial reports
- Performance monitoring
- Scientific data display
- Business intelligence tools
- Marketing metrics
Notes
- Recharts is best for React integration and customization
- Chart.js is lighter but less React-native
- D3.js offers maximum control but steeper learning curve
- Consider SVG export for print/sharing
More from housegarofalo/claude-code-base
mobile-pwa
Build Progressive Web Apps with offline support, push notifications, and native-like experiences. Covers service workers, Web App Manifest, caching strategies, IndexedDB, background sync, and installability. Use for mobile-first web apps, offline-capable applications, and app-like experiences.
5svelte-kit
Expert guidance for SvelteKit 2 with Svelte 5 runes, server-side rendering, and modern patterns. Covers $state, $derived, $effect, form actions, load functions, and API routes. Use for SvelteKit applications, Svelte 5 runes, and full-stack Svelte development.
5matter-thread
>
5vitest
Fast Vite-native unit testing framework for JavaScript/TypeScript. ESM-first, Jest-compatible API, with instant HMR. Use for modern frontend testing, Vue/React/Svelte testing, or fast test execution. Triggers on vitest, vite test, vue test, svelte test.
5vite
Build modern frontend applications with Vite. Covers project setup, plugins, configuration, environment variables, and build optimization. Use for React, Vue, Svelte development with fast HMR and optimized production builds.
5security-auditor-agent
Comprehensive security audit agent that performs systematic vulnerability assessment, threat modeling, and security compliance checks. Covers OWASP Top 10, dependency scanning, secret detection, infrastructure security, and compliance frameworks. Use for security audits, penetration test preparation, compliance assessments, or security hardening initiatives.
4