Pivot Charts Tutorial
This guide shows you how to turn your pivot table data into charts using @mindfiredigital/pivothead-analytics. By the end you will have a working chart in your project.
Step 1 — Install the package
npm install @mindfiredigital/pivothead-analytics
What happens after install
The package runs a postinstall setup prompt automatically in your terminal:
┌──────────────────────────────────────────────────────┐
│ @mindfiredigital/pivothead-analytics Setup │
└──────────────────────────────────────────────────────┘
Which charting library would you like to install?
[1] Chart.js Lightweight, easy to use, browser-first charting
[2] Apache ECharts Feature-rich, interactive charts for complex data
[3] Plotly.js Scientific & statistical charts, great for data science
[4] D3.js Maximum flexibility with custom SVG-based rendering
Enter number(s) separated by commas (e.g. 1 or 1,3),
or press Enter to skip and install manually later.
>
Type a number and press Enter. The script:
- Detects your package manager (npm / pnpm / yarn / bun) automatically
- Installs the chosen library for you — no separate install command needed
- Writes
.pivothead-analytics.jsonto your project root soChartEngineknows which library to use at runtime - Handles monorepo workspace roots automatically (adds
-w/-Wflag when needed)
You only need one library. Chart.js is the best starting point.
| # | Library | Best for |
|---|---|---|
| 1 | Chart.js (recommended) | Standard charts, lightweight apps |
| 2 | Apache ECharts | Feature-rich interactive dashboards |
| 3 | Plotly | Scientific / statistical / 3D charts |
| 4 | D3 | Fully custom SVG-based charts |
CI / non-interactive environments
In CI pipelines or any environment without an interactive terminal, the prompt is skipped automatically. Install your chosen library manually and set the PIVOTHEAD_LIBRARY environment variable so ChartEngine can detect it at runtime:
# Install the library
npm install chart.js
# Tell ChartEngine which one to use (add to your .env or CI environment)
PIVOTHEAD_LIBRARY=chartjs
Valid values: chartjs · echarts · plotly · d3
To suppress the prompt entirely in any environment:
PIVOTHEAD_SKIP_SETUP=true npm install @mindfiredigital/pivothead-analytics
Monorepo projects
If you are in a pnpm / yarn / npm workspaces monorepo, the postinstall detects it and passes the correct workspace flag (-w / -W) when installing the charting library. No extra configuration needed.
If you install from a workspace package rather than the root, run the install from that package's directory or target it explicitly:
# pnpm
pnpm add @mindfiredigital/pivothead-analytics chart.js --filter my-app
# yarn
yarn workspace my-app add @mindfiredigital/pivothead-analytics chart.js
The .pivothead-analytics.json file
After a successful interactive install, a config file is written to your project root:
{
"library": "chartjs",
"installedLibraries": ["chartjs"],
"generatedAt": "2025-01-01T00:00:00.000Z"
}
ChartEngine reads this file at startup to auto-detect which renderer to use. You can:
- Commit it — keeps the choice in version control so teammates don't need to re-run setup
- Gitignore it — teammates will be prompted on their first install instead
If you skipped the prompt and installed manually, create this file yourself or rely on the PIVOTHEAD_LIBRARY env var instead.
Step 2 — Prepare your data and PivotEngine
ChartEngine reads data from a PivotEngine. Set yours up first:
import { PivotEngine } from '@mindfiredigital/pivothead';
const data = [
{ region: 'North', product: 'Laptops', revenue: 45000 },
{ region: 'North', product: 'Phones', revenue: 32000 },
{ region: 'South', product: 'Laptops', revenue: 38000 },
{ region: 'South', product: 'Phones', revenue: 41000 },
{ region: 'East', product: 'Laptops', revenue: 52000 },
{ region: 'East', product: 'Phones', revenue: 28000 },
];
const config = {
rows: [{ uniqueName: 'region', caption: 'Region' }],
columns: [{ uniqueName: 'product', caption: 'Product' }],
measures: [{ uniqueName: 'revenue', caption: 'Revenue', aggregation: 'sum' }],
};
const engine = new PivotEngine(data, config);
Step 3 — Add a container element
Add a <div> where the chart will be drawn. Give it a fixed size.
<div id="myChart" style="width: 600px; height: 400px;"></div>
Step 4 — Create ChartEngine and render
Import your charting library and pass it directly to ChartEngine. This is required in any bundler-based project (Vite, webpack, etc.) because bundlers use ES modules — require() is not available at runtime.
import { Chart, registerables } from 'chart.js';
import { ChartEngine } from '@mindfiredigital/pivothead-analytics';
// Required: register all Chart.js components
Chart.register(...registerables);
// Pass the Chart object in — this is the key step
const chartEngine = new ChartEngine(engine, { chartInstance: Chart });
// Render a column chart
chartEngine.column({
container: '#myChart',
style: { title: 'Revenue by Region' },
});
That's it — your chart is on screen.
Step 5 — Pick a specific chart type
Replace column with any of these convenience methods:
chartEngine.column({ container: '#chart' }); // vertical bars
chartEngine.bar({ container: '#chart' }); // horizontal bars
chartEngine.line({ container: '#chart' }); // line chart
chartEngine.area({ container: '#chart' }); // area chart
chartEngine.pie({ container: '#chart' }); // pie chart
chartEngine.doughnut({ container: '#chart' }); // doughnut chart
chartEngine.scatter({ container: '#chart' }); // scatter plot
chartEngine.heatmap({ container: '#chart' }); // heatmap grid
chartEngine.stackedColumn({ container: '#chart' }); // stacked columns
chartEngine.stackedBar({ container: '#chart' }); // stacked bars
chartEngine.histogram({ container: '#chart' }); // frequency histogram
chartEngine.funnel({ container: '#chart' }); // funnel stages
chartEngine.combo({ container: '#chart' }); // bar + line combo
Let the engine pick the best chart automatically
Not sure which chart fits your data? Use auto():
chartEngine.auto({
container: '#myChart',
style: { title: 'Auto-selected Chart' },
});
The engine checks your data structure (dimensions, measures, cardinality) and picks the most suitable chart type.
To see the recommendations before rendering:
const recommendations = chartEngine.recommend();
// Each recommendation has: type, score (0–1), reason
recommendations.forEach(rec => {
console.log(`${rec.type}: ${Math.round(rec.score * 100)}% — ${rec.reason}`);
});
// Render the top recommendation
chartEngine.renderRecommendation(recommendations[0], '#myChart');
Styling your chart
Pass a style object to any render call:
chartEngine.column({
container: '#myChart',
style: {
title: 'Revenue by Region',
subtitle: 'Q1 2025',
showLegend: true,
legendPosition: 'bottom', // 'top' | 'bottom' | 'left' | 'right'
showGrid: true,
animated: true,
colorScheme: 'vibrant', // see colour palette list below
},
});
Available colour palettes
tableau10 (default) · colorBlind · categorical · pastel · vibrant ·
sequentialBlues · sequentialGreens · sequentialReds · sequentialOranges · sequentialPurples ·
divergingRedBlue · divergingRedGreen · divergingPurpleGreen
Use colorBlind when accessibility matters.
Custom colours
chartEngine.column({
container: '#myChart',
style: {
colors: ['#6366f1', '#ec4899', '#22c55e', '#fb923c'],
},
});
Format values
Display numbers as currency, percentages, or compact notation:
chartEngine.column({
container: '#myChart',
format: {
valueFormat: 'currency', // 'number' | 'currency' | 'percent' | 'compact'
currency: 'USD',
locale: 'en-US',
decimals: 0,
},
});
Filter what the chart shows
const chartService = chartEngine.getChartService();
// Show only specific rows, limit to top 5
chartService.setFilters({
selectedMeasure: 'revenue',
selectedRows: ['North', 'South'],
limit: 5,
});
// Refresh the chart to reflect the new filters
chartEngine.updateAllCharts();
// Get available options (useful for building filter dropdowns)
const options = chartService.getAvailableFilterOptions();
// options.measures → [{ uniqueName: 'revenue', caption: 'Revenue' }]
// options.rows → ['North', 'South', 'East']
// options.columns → ['Laptops', 'Phones']
// Remove all filters
chartService.resetFilters();
Switching chart types on the fly
Destroy the old chart, then render a new one in the same container:
function switchChart(newType) {
chartEngine.destroyChart('#myChart');
chartEngine.render({
container: '#myChart',
type: newType,
style: { title: 'Sales Overview', animated: true },
});
}
document.getElementById('chartType').addEventListener('change', e => {
switchChart(e.target.value);
});
Exporting charts
// Download as image or document
await chartEngine.exportAsPng('#myChart', 'sales-report');
await chartEngine.exportAsSvg('#myChart', 'sales-vector');
await chartEngine.exportAsPdf('#myChart', 'sales-document');
// Download the underlying data
await chartEngine.exportAsCsv('#myChart', 'chart-data');
await chartEngine.exportAsJson('#myChart', 'chart-data');
// Get a Blob to upload or email
const blob = await chartEngine.getChartBlob('#myChart', 'png');
Using a different rendering library
Import your chosen library and pass it as the matching instance option:
// ECharts
import * as echarts from 'echarts';
const chartEngine = new ChartEngine(engine, { echartsInstance: echarts });
// Plotly
import Plotly from 'plotly.js-dist';
const chartEngine = new ChartEngine(engine, { plotlyInstance: Plotly });
// D3
import * as d3 from 'd3';
const chartEngine = new ChartEngine(engine, { d3Instance: d3 });
Cleanup
Always dispose the engine when you are done (e.g., on page navigation):
chartEngine.dispose();
This destroys all active charts and unsubscribes from PivotEngine updates.
Complete working example
import { Chart, registerables } from 'chart.js';
import { PivotEngine } from '@mindfiredigital/pivothead';
import { ChartEngine } from '@mindfiredigital/pivothead-analytics';
// 1. Register Chart.js components
Chart.register(...registerables);
// 2. Data + pivot config
const data = [
{ region: 'North', product: 'Laptops', revenue: 45000 },
{ region: 'South', product: 'Laptops', revenue: 38000 },
{ region: 'East', product: 'Phones', revenue: 28000 },
];
const engine = new PivotEngine(data, {
rows: [{ uniqueName: 'region', caption: 'Region' }],
columns: [{ uniqueName: 'product', caption: 'Product' }],
measures: [{ uniqueName: 'revenue', caption: 'Revenue', aggregation: 'sum' }],
});
// 3. Chart engine — pass chartInstance so it works in any bundler (Vite, webpack, etc.)
const chartEngine = new ChartEngine(engine, {
chartInstance: Chart,
defaultStyle: { colorScheme: 'tableau10', animated: true, showLegend: true },
defaultFormat: { valueFormat: 'currency', currency: 'USD' },
});
// 3. Get recommendations and render the best one
const best = chartEngine.getBestRecommendation();
console.log('Rendering:', best.type, '—', best.reason);
chartEngine.renderRecommendation(best, '#mainChart');
// 4. Export on button click
document.getElementById('exportBtn').addEventListener('click', async () => {
await chartEngine.exportAsPng('#mainChart', 'dashboard');
});
// 5. Cleanup
window.addEventListener('beforeunload', () => {
chartEngine.dispose();
});
Next steps
- Analytics API Reference — Full method signatures and types
- Core Concepts — Understanding PivotEngine configuration