Highcharts Cookbook
Some Handy JS
functions
Format Large Numbers with Suffixes (K, M, B, T) in Human-readable Format
function formatNumber(num) {
const suffixes = ['', 'K', 'M', 'B', 'T'];
let suffixIndex = 0;
while (num >= 1000 && suffixIndex < suffixes.length - 1) {
num /= 1000;
suffixIndex++;
}
return num.toFixed(2) + suffixes[suffixIndex];
}
Format Percentage in Human-readable Format
function formatPercentage(num) {
return (num * 100).toFixed(2) + '%';
}
Important
all data source are in column i.e. tabular format .csv
e.g.:
Country | Industry | Funding |
---|---|---|
Australia | Image Generation | 31000000 |
Canada | Artificial Intelligence | 445000000 |
Canada | Autonomous Vehicles | 84000000 |
France | Artificial Intelligence | 528000000 |
France | Image Editing | 64000000 |
Treemap with 2 Levels Drilldown
embed highcharts figure like below
<figure class="highcharts-figure">
<div id="container"></div>
<p class="highcharts-description">
Chart showing stacked columns with grouping, allowing specific series to
be stacked on the same column. Stacking is often used to visualize
data that accumulates to a sum.
</p>
</figure>
Read .csv
file and convert to json using d3.js
v7
const response = await d3.csv('data/data.csv');
which generates the following output:
[
{ "Country": "USA", "Industry": "Tech", "Funding": 1000000 },
{ "Country": "USA", "Industry": "Healthcare", "Funding": 750000 },
{ "Country": "China", "Industry": "Manufacturing", "Funding": 2000000 },
{ "Country": "China", "Industry": "Tech", "Funding": 1500000 }
]
[
{
"id": "id_0_0",
"name": "Image Generation",
"parent": "id_0"
},
{
"id": "id_0_0_0",
"name": "Value",
"parent": "id_0_0",
"value": 31000000
},
{
"id": "id_0",
"name": "Australia",
"color": "#2caffe",
"value": 31000000
},
]
(async () => {
// const data = await fetch(
// 'https://www.highcharts.com/samples/data/world-mortality.json'
// ).then(response => response.json());
const response = await d3.csv('data/data_treemap-2-levels-drilldown.csv');
console.log(response);
function convertToTreemapData(input_data, level_1_col, level_2_col, value_col, aggregation_type = 'sum') {
const points = [];
const data = {};
let col1I = 0;
let col2I = 0;
for (const row of input_data) {
console.log(row);
const col1 = row[level_1_col];
const col2 = row[level_2_col];
const val = Number(row[value_col]);
console.log(col1, col2, val);
if (!data[col1]) {
data[col1] = {};
}
if (!data[col1][col2]) {
data[col1][col2] = [];
}
data[col1][col2].push(val);
}
for (const col1 in data) {
const col1P = {
id: 'id_' + col1I,
name: col1,
color: Highcharts.getOptions().colors[col1I]
};
let col1Val = 0;
let col2Count = 0;
for (const col2 in data[col1]) {
const col2P = {
id: col1P.id + '_' + col2I,
name: col2,
parent: col1P.id
};
points.push(col2P);
const values = data[col1][col2];
let aggregatedValue;
switch (aggregation_type) {
case 'avg':
aggregatedValue = values.reduce((a, b) => a + b, 0) / values.length;
break;
default: // 'sum'
aggregatedValue = values.reduce((a, b) => a + b, 0);
}
const valueP = {
id: col2P.id + '_0',
name: 'Value',
parent: col2P.id,
value: Math.round(aggregatedValue)
};
col1Val += valueP.value;
points.push(valueP);
col2I++;
col2Count++;
}
if (aggregation_type === 'avg') {
col1P.value = Math.round(col1Val / col2Count);
} else {
col1P.value = Math.round(col1Val);
}
points.push(col1P);
col1I++;
}
console.log(points);
return points;
}
const treemapData = convertToTreemapData(response, 'Country', 'Industry', 'Funding', 'sum');
console.log(treemapData);
function formatNumber(num) {
const suffixes = ['', 'K', 'M', 'B', 'T'];
let suffixIndex = 0;
while (num >= 1000 && suffixIndex < suffixes.length - 1) {
num /= 1000;
suffixIndex++;
}
return num.toFixed(2) + suffixes[suffixIndex];
}
function formatPercentage(num) {
return (num * 100).toFixed(2) + '%';
}
Highcharts.chart('container-treemap-2-levels-drilldown', {
series: [{
name: 'Regions',
type: 'treemap',
layoutAlgorithm: 'squarified',
allowDrillToNode: true,
animationLimit: 1000,
dataLabels: {
enabled: false
},
levels: [{
level: 1,
dataLabels: {
enabled: true
},
borderWidth: 3,
levelIsConstant: false
}, {
level: 1,
dataLabels: {
style: {
fontSize: '14px'
}
}
}],
accessibility: {
exposeAsGroupOnly: true
},
data: treemapData
}],
subtitle: {
text: 'Click points to drill down. Source: <a href="https://www.forbes.com/lists/ai50/">Forbes 2024 AI 50 List</a>.',
align: 'left'
},
title: {
text: 'Forbes 2024 AI 50 List',
align: 'left'
},
tooltip: {
useHTML: true,
formatter: function() {
const point = this.point;
console.log(point);
// calculate percentage of total
const totalParent = point.node.parentNode.childrenTotal;
const percentage = point.value / totalParent;
const formattedPercentage = formatPercentage(percentage);
return this.point.name + ': <b>$' + formatNumber(this.point.value) + ' (' + formattedPercentage + ')</b>'
}
},
});
})();
basically it set the level 1 as the parent and level 2 as the child, and the value is the funding, the field
parent
indicate the parent of the level 2