data-visualization

Chart types, data aggregation patterns, and recharts usage for the csv-explorer chart builder

7 stars

Best use case

data-visualization is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Chart types, data aggregation patterns, and recharts usage for the csv-explorer chart builder

Teams using data-visualization should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/data-visualization/SKILL.md --create-dirs "https://raw.githubusercontent.com/heldernoid/agentic-build-templates/main/projects/data-analytics/csv-explorer/skills/data-visualization/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/data-visualization/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How data-visualization Compares

Feature / Agentdata-visualizationStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Chart types, data aggregation patterns, and recharts usage for the csv-explorer chart builder

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# data-visualization skill

## Overview

csv-explorer supports three chart types: bar, line, and scatter. Charts are built from column selections and rendered using recharts. The server aggregates data before sending to the client; the client only renders pre-computed data. This keeps the browser fast even on large datasets.

## Chart types

### Bar chart

Use for comparing a numeric measure across categories or discrete X axis values.

- X axis: string or boolean column (categories/groups)
- Y axis: number column (the measure)
- Aggregate: sum, mean, count, min, max (default: sum)
- Optional group column: adds multiple color-coded bar series per X value

Example: Revenue by product category (sum).

### Line chart

Use for showing a numeric measure over a continuous or ordered X axis.

- X axis: date or string column (ordered labels)
- Y axis: number column
- Aggregate: sum, mean, count, min, max (default: sum)
- Optional group column: multiple lines, one per group value

Example: Weekly revenue over Q1 2026 grouped by region.

### Scatter chart

Use for showing the correlation between two numeric columns.

- X axis: number column
- Y axis: number column
- No aggregation; raw row values are used
- `max_points` rows are sampled (default 500, max 1000)

Example: Unit price vs. revenue showing positive correlation.

## Server-side aggregation

The chart data endpoint reads the full CSV file (or up to `max_points` rows for scatter) and aggregates in Node.js.

**Bar/line aggregation algorithm:**

```typescript
// Build a map: xValue -> (groupValue -> y values[])
const groups = new Map<string, Map<string, number[]>>();

for (const row of rows) {
  const x = String(row[x_col] ?? '');
  const y = parseFloat(String(row[y_col]));
  if (isNaN(y)) continue;
  const g = group_col != null ? String(row[group_col] ?? '') : '__default__';
  if (!groups.has(x)) groups.set(x, new Map());
  const xMap = groups.get(x)!;
  if (!xMap.has(g)) xMap.set(g, []);
  xMap.get(g)!.push(y);
}

// Apply aggregate function per (x, group) cell
function applyAgg(values: number[], fn: string): number {
  if (fn === 'sum')   return values.reduce((a, b) => a + b, 0);
  if (fn === 'mean')  return values.reduce((a, b) => a + b, 0) / values.length;
  if (fn === 'count') return values.length;
  if (fn === 'min')   return Math.min(...values);
  if (fn === 'max')   return Math.max(...values);
  return 0;
}
```

**Scatter sampling:**

When `row_count > max_points`, rows are uniformly sampled using a deterministic stride:
```typescript
const stride = Math.floor(row_count / max_points);
const sampled = rows.filter((_, i) => i % stride === 0).slice(0, max_points);
```

## Response format

### Bar/line response

```typescript
{
  labels: ["Electronics", "Furniture", "Accessories"],  // X axis
  series: [
    { name: "North", data: [120000, 45000, 12000] },
    { name: "East",  data: [98000,  38000, 9500] }
  ],
  x_label: "category",
  y_label: "revenue"
}
```

When no `group_col` is provided, `series` has exactly one element with `name: "value"`.

### Scatter response

```typescript
{
  labels: [],   // unused for scatter
  series: [
    {
      name: "unit_price vs revenue",
      data: [
        { x: 149.99, y: 449.97 },
        { x: 89.00,  y: 89.00 },
        ...
      ]
    }
  ],
  x_label: "unit_price",
  y_label: "revenue"
}
```

## recharts integration

**Bar chart component:**

```tsx
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';

// Transform response into recharts data array
const chartData = response.labels.map((label, i) => {
  const point: Record<string, string | number> = { label };
  for (const s of response.series) point[s.name] = s.data[i] as number;
  return point;
});

const COLORS = ['#0891b2', '#2563eb', '#9333ea', '#f97316', '#16a34a'];

<ResponsiveContainer width="100%" height={300}>
  <BarChart data={chartData}>
    <CartesianGrid strokeDasharray="3 3" stroke="#e7e5e4"/>
    <XAxis dataKey="label" tick={{ fontSize: 11 }}/>
    <YAxis tick={{ fontSize: 11 }}/>
    <Tooltip/>
    {response.series.length > 1 && <Legend/>}
    {response.series.map((s, i) => (
      <Bar key={s.name} dataKey={s.name} fill={COLORS[i % COLORS.length]} radius={[4, 4, 0, 0]}/>
    ))}
  </BarChart>
</ResponsiveContainer>
```

**Scatter chart component:**

```tsx
import { ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';

<ResponsiveContainer width="100%" height={300}>
  <ScatterChart>
    <CartesianGrid strokeDasharray="3 3" stroke="#e7e5e4"/>
    <XAxis dataKey="x" name={response.x_label} tick={{ fontSize: 11 }}/>
    <YAxis dataKey="y" name={response.y_label} tick={{ fontSize: 11 }}/>
    <Tooltip cursor={{ strokeDasharray: '3 3' }}/>
    <Scatter data={response.series[0].data as Array<{x:number;y:number}>} fill="#0891b2" fillOpacity={0.6}/>
  </ScatterChart>
</ResponsiveContainer>
```

## PNG export

Use `html2canvas` to capture the chart container div as a PNG:

```typescript
import html2canvas from 'html2canvas';

async function exportChartPng(containerRef: React.RefObject<HTMLDivElement>, filename: string) {
  if (!containerRef.current) return;
  const canvas = await html2canvas(containerRef.current, { backgroundColor: '#ffffff', scale: 2 });
  const link = document.createElement('a');
  link.download = filename;
  link.href = canvas.toDataURL('image/png');
  link.click();
}
```

`scale: 2` produces a 2x resolution image suitable for presentations.

## Axis label formatting

Format large numbers on the Y axis using a compact formatter:

```typescript
function formatYAxis(value: number): string {
  if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;
  if (value >= 1_000)     return `${(value / 1_000).toFixed(0)}K`;
  return String(value);
}
```

Pass as the `tickFormatter` prop on `<YAxis tickFormatter={formatYAxis}/>`.

## Color palette

The default series colors in order:

| Index | Hex | Name |
|-------|-----|------|
| 0 | `#0891b2` | Cyan (primary) |
| 1 | `#2563eb` | Blue |
| 2 | `#9333ea` | Purple |
| 3 | `#f97316` | Orange |
| 4 | `#16a34a` | Green |
| 5 | `#dc2626` | Red |

Cycle with `COLORS[i % COLORS.length]`.

## No-data state

If `response.labels.length === 0` or `response.series.length === 0`, show a placeholder:

```tsx
<div style={{ textAlign: 'center', color: 'var(--text-muted)', padding: '60px 0' }}>
  <svg .../>
  <p>No data returned. Check that the selected columns have non-null numeric values.</p>
</div>
```

## Chart limitations

- Max groups for grouped bar/line: 10. If the group column has more than 10 unique values, only the top 10 by aggregate total are shown, with an "Others" series for the remainder.
- Max X axis labels: 200. Excess labels are dropped from the right.
- Scatter max points: 1,000 (enforced server-side).
- Float precision: Y axis values are rounded to 2 decimal places before sending.

Related Skills

food-database

7
from heldernoid/agentic-build-templates

No description provided.

database-size-monitor

7
from heldernoid/agentic-build-templates

Dashboard for monitoring PostgreSQL and MySQL table sizes over time, with growth tracking, threshold alerts, and snapshot comparison

sqlite-data

7
from heldernoid/agentic-build-templates

Query and inspect SQLite databases used by data tools. Use when you need to directly inspect stored pipeline runs, metrics, or configuration data stored in a SQLite database file. Triggers include "query the database", "inspect SQLite", "check raw data", "what is in the db", or any task requiring direct database access.

data-pipeline-monitor

7
from heldernoid/agentic-build-templates

Track ETL and data pipeline jobs with success/failure status, duration tracking, heartbeat monitoring, and dependency visualization. Use when you need to monitor scheduled jobs, detect failures, track pipeline health over time, or visualize ETL step dependencies. Triggers include "pipeline monitoring", "job tracking", "ETL status", "cron job health", "heartbeat monitor", "pipeline failed", or any task involving monitoring data workflows.

finetune-data-curator

7
from heldernoid/agentic-build-templates

Web app for creating, editing, and validating JSONL fine-tuning datasets. Checks format compliance for OpenAI, Anthropic, and Llama formats, detects duplicates, scores quality, and exports clean datasets.

Skill: Uptime Monitoring

7
from heldernoid/agentic-build-templates

## Overview

Skill: Status Page

7
from heldernoid/agentic-build-templates

## Overview

Skill: unit-conversion

7
from heldernoid/agentic-build-templates

## Overview

Skill: recipe-scaler

7
from heldernoid/agentic-build-templates

## Overview

reading-list

7
from heldernoid/agentic-build-templates

Operate the reading-list API to save, manage, tag, search, and export articles.

email-digest

7
from heldernoid/agentic-build-templates

Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.

websocket-realtime

7
from heldernoid/agentic-build-templates

Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".