A force-directed tree lays out a hierarchy as linked bubbles that push apart until they settle. This one holds the coffee flavor wheel, 85 flavors in nine families, in a view you can zoom and pan.
A big tree squeezed into one view turns into a cloud of dots. Zooming lets the whole structure stay on screen while people move in on one branch to read its names, which suits taxonomies and catalogs with a hundred items or more.
Built with amCharts 5, a JavaScript library. The JavaScript includes your theme and renderer (canvas or SVG); the JSON also follows the changes you make with the controls.
npm install @amcharts/amcharts5. See Getting started.
The same chart as a JSON config. Chart Maker reads and writes this format, the library's JSON parser turns it into a chart, and the <am5-chart> element puts it on a page with no code."type" is the class to create and "settings" what you would pass to its new() in code; "properties" fill in its parts, lists such as series and axes or templates such as columns.template; "refs" holds objects used in more than one place ("#series-0" stands for the one named series-0); a string starting with "@" takes a value from another object, such as "@series.get('fill')".
A complete page. Save it as an .html file and open it in a browser.
Paste this into an AI coding assistant to build the chart from scratch. More in amCharts & AI.
// Create root element
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
var root = am5.Root.new("chartdiv");
// Set themes
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root),
am5themes_Responsive.new(root)
]);
var data = {
value: 0,
children: [
{
name: "Floral",
children: [
{
name: "Black Tea",
value: 1
},
{
name: "Floral",
children: [
{
name: "Chamomile",
value: 1
},
{
name: "Rose",
value: 1
},
{
name: "Jasmine",
value: 1
}
]
}
]
},
{
name: "Fruity",
children: [
{
name: "Berry",
children: [
{
name: "Blackberry",
value: 1
},
{
name: "Raspberry",
value: 1
},
{
name: "Blueberry",
value: 1
},
{
name: "Strawberry",
value: 1
}
]
},
{
name: "Dried Fruit",
children: [
{
name: "Raisin",
value: 1
},
{
name: "Prune",
value: 1
}
]
},
{
name: "Other Fruit",
children: [
{
name: "Coconut",
value: 1
},
{
name: "Cherry",
value: 1
},
{
name: "Pomegranate",
value: 1
},
{
name: "Pineapple",
value: 1
},
{
name: "Grape",
value: 1
},
{
name: "Apple",
value: 1
},
{
name: "Peach",
value: 1
},
{
name: "Pear",
value: 1
}
]
},
{
name: "Citrus Fruit",
children: [
{
name: "Grapefruit",
value: 1
},
{
name: "Orange",
value: 1
},
{
name: "Lemon",
value: 1
},
{
name: "Lime",
value: 1
}
]
}
]
},
{
name: "Sour/Fermented",
children: [
{
name: "Sour",
children: [
{
name: "Sour Aromatics",
value: 1
},
{
name: "Acetic Acid",
value: 1
},
{
name: "Butyric Acid",
value: 1
},
{
name: "Isovaleric Acid",
value: 1
},
{
name: "Citric Acid",
value: 1
},
{
name: "Malic Acid",
value: 1
}
]
},
{
name: "Alcohol/Fermented",
children: [
{
name: "Winey",
value: 1
},
{
name: "Whiskey",
value: 1
},
{
name: "Fermented",
value: 1
},
{
name: "Overripe",
value: 1
}
]
}
]
},
{
name: "Green/Vegetative",
children: [
{
name: "Olive Oil",
value: 1
},
{
name: "Raw",
value: 1
},
{
name: "Green/Vegetative",
children: [
{
name: "Under-ripe",
value: 1
},
{
name: "Peapod",
value: 1
},
{
name: "Fresh",
value: 1
},
{
name: "Dark Green",
value: 1
},
{
name: "Vegetative",
value: 1
},
{
name: "Hay-like",
value: 1
},
{
name: "Herb-like",
value: 1
}
]
},
{
name: "Beany",
value: 1
}
]
},
{
name: "Other",
children: [
{
name: "Papery/Musty",
children: [
{
name: "Stale",
value: 1
},
{
name: "Cardboard",
value: 1
},
{
name: "Papery",
value: 1
},
{
name: "Woody",
value: 1
},
{
name: "Moldy/Damp",
value: 1
},
{
name: "Musty/Dusty",
value: 1
},
{
name: "Musty/Earthy",
value: 1
},
{
name: "Animalic",
value: 1
},
{
name: "Meaty Brothy",
value: 1
},
{
name: "Phenolic",
value: 1
}
]
},
{
name: "Chemical",
children: [
{
name: "Bitter",
value: 1
},
{
name: "Salty",
value: 1
},
{
name: "Medicinal",
value: 1
},
{
name: "Petroleum",
value: 1
},
{
name: "Skunky",
value: 1
},
{
name: "Rubber",
value: 1
}
]
}
]
},
{
name: "Roasted",
children: [
{
name: "Pipe Tobacco",
value: 1
},
{
name: "Tobacco",
value: 1
},
{
name: "Burnt",
children: [
{
name: "Acrid",
value: 1
},
{
name: "Ashy",
value: 1
},
{
name: "Smoky",
value: 1
},
{
name: "Brown, Roast",
value: 1
}
]
},
{
name: "Cereal",
children: [
{
name: "Grain",
value: 1
},
{
name: "Malt",
value: 1
}
]
}
]
},
{
name: "Spices",
children: [
{
name: "Pungent",
value: 1
},
{
name: "Pepper",
value: 1
},
{
name: "Brown Spice",
children: [
{
name: "Anise",
value: 1
},
{
name: "Nutmeg",
value: 1
},
{
name: "Cinnamon",
value: 1
},
{
name: "Clove",
value: 1
}
]
}
]
},
{
name: "Nutty/Cocoa",
children: [
{
name: "Nutty",
children: [
{
name: "Peanuts",
value: 1
},
{
name: "Hazelnut",
value: 1
},
{
name: "Almond",
value: 1
}
]
},
{
name: "Cocoa",
children: [
{
name: "Chocolate",
value: 1
},
{
name: "Dark Chocolate",
value: 1
}
]
}
]
},
{
name: "Sweet",
children: [
{
name: "Brown Sugar",
children: [
{
name: "Molasses",
value: 1
},
{
name: "Maple Syrup",
value: 1
},
{
name: "Caramelized",
value: 1
},
{
name: "Honey",
value: 1
}
]
},
{
name: "Vanilla",
value: 1
},
{
name: "Vanillin",
value: 1
},
{
name: "Overall Sweet",
value: 1
},
{
name: "Sweet Aromatics",
value: 1
}
]
}
]
};
var chart = root.container.children.push(
am5.SerialChartContainer.new(root, {
width: am5.p100, // the container fills the whole chart div
height: am5.p100
})
);
chart.zoomableContainer.setAll({
wheelable: true, // the mouse wheel zooms in on the tree
pinchZoom: true // and so does pinching on a touch screen
});
var zoomTools = chart.set("zoomTools", am5.ZoomTools.new(root, {})); // zoom in, zoom out and reset buttons
// Create series
// https://www.amcharts.com/docs/v5/charts/hierarchy/#Adding
var series = chart.series.push(am5hierarchy.ForceDirected.new(root, {
maskContent:false, //!important with zoomable containers
singleBranchOnly: false, // opening one branch leaves the others open
downDepth: 2, // a click on a node opens two levels below it
// leave out the nameless top node: the flavor groups start the tree
topDepth: 1,
initialDepth: 3, // three levels on load, from the flavor groups down
valueField: "value",
categoryField: "name",
childDataField: "children",
idField: "name",
linkWithField: "linkWith",
// nodes push each other apart less and are pulled to the center harder than by default
manyBodyStrength: -10,
centerStrength: 0.8
}));
series.get("colors").setAll({
step: 2 // every second color of the set, so neighbors differ more
});
series.links.template.set("strength", 0.5); // links hold their nodes more loosely than the default 0.9
// names shrink as far as needed to fit their circle instead of hiding
series.labels.template.set("minScale", 0);
// A soft shadow under each circle
series.circles.template.setAll({
shadowColor: am5.color(0x000000), // a black shadow...
shadowOpacity: 0.3, // ...at 30%...
shadowBlur: 6, // ...blurred 6px...
shadowOffsetX: 2, // ...and moved 2px right and down
shadowOffsetY: 2
});
// Every flavor counts as 1, so the tooltip shows just the name
series.nodes.template.set("tooltipText", "{category}");
series.data.setAll([data]);
series.set("selectedDataItem", series.dataItems[0]); // start at the top node, so the whole tree shows
// Make stuff animate on load
series.appear(1000, 100);
{
"type": "SerialChartContainer",
"settings": {
"width": {
"type": "Percent",
"value": 100
},
"height": {
"type": "Percent",
"value": 100
},
"zoomTools": {
"type": "ZoomTools"
}
},
"properties": {
"series": [
"#series-0"
],
"zoomableContainer": {
"settings": {
"wheelable": true,
"pinchZoom": true
}
}
},
"refs": [
{
"data-0": [
{
"value": 0,
"children": [
{
"name": "Floral",
"children": [
{
"name": "Black Tea",
"value": 1
},
{
"name": "Floral",
"children": [
{
"name": "Chamomile",
"value": 1
},
{
"name": "Rose",
"value": 1
},
{
"name": "Jasmine",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Fruity",
"children": [
{
"name": "Berry",
"children": [
{
"name": "Blackberry",
"value": 1
},
{
"name": "Raspberry",
"value": 1
},
{
"name": "Blueberry",
"value": 1
},
{
"name": "Strawberry",
"value": 1
}
],
"__parse": true
},
{
"name": "Dried Fruit",
"children": [
{
"name": "Raisin",
"value": 1
},
{
"name": "Prune",
"value": 1
}
],
"__parse": true
},
{
"name": "Other Fruit",
"children": [
{
"name": "Coconut",
"value": 1
},
{
"name": "Cherry",
"value": 1
},
{
"name": "Pomegranate",
"value": 1
},
{
"name": "Pineapple",
"value": 1
},
{
"name": "Grape",
"value": 1
},
{
"name": "Apple",
"value": 1
},
{
"name": "Peach",
"value": 1
},
{
"name": "Pear",
"value": 1
}
],
"__parse": true
},
{
"name": "Citrus Fruit",
"children": [
{
"name": "Grapefruit",
"value": 1
},
{
"name": "Orange",
"value": 1
},
{
"name": "Lemon",
"value": 1
},
{
"name": "Lime",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Sour/Fermented",
"children": [
{
"name": "Sour",
"children": [
{
"name": "Sour Aromatics",
"value": 1
},
{
"name": "Acetic Acid",
"value": 1
},
{
"name": "Butyric Acid",
"value": 1
},
{
"name": "Isovaleric Acid",
"value": 1
},
{
"name": "Citric Acid",
"value": 1
},
{
"name": "Malic Acid",
"value": 1
}
],
"__parse": true
},
{
"name": "Alcohol/Fermented",
"children": [
{
"name": "Winey",
"value": 1
},
{
"name": "Whiskey",
"value": 1
},
{
"name": "Fermented",
"value": 1
},
{
"name": "Overripe",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Green/Vegetative",
"children": [
{
"name": "Olive Oil",
"value": 1
},
{
"name": "Raw",
"value": 1
},
{
"name": "Green/Vegetative",
"children": [
{
"name": "Under-ripe",
"value": 1
},
{
"name": "Peapod",
"value": 1
},
{
"name": "Fresh",
"value": 1
},
{
"name": "Dark Green",
"value": 1
},
{
"name": "Vegetative",
"value": 1
},
{
"name": "Hay-like",
"value": 1
},
{
"name": "Herb-like",
"value": 1
}
],
"__parse": true
},
{
"name": "Beany",
"value": 1
}
],
"__parse": true
},
{
"name": "Other",
"children": [
{
"name": "Papery/Musty",
"children": [
{
"name": "Stale",
"value": 1
},
{
"name": "Cardboard",
"value": 1
},
{
"name": "Papery",
"value": 1
},
{
"name": "Woody",
"value": 1
},
{
"name": "Moldy/Damp",
"value": 1
},
{
"name": "Musty/Dusty",
"value": 1
},
{
"name": "Musty/Earthy",
"value": 1
},
{
"name": "Animalic",
"value": 1
},
{
"name": "Meaty Brothy",
"value": 1
},
{
"name": "Phenolic",
"value": 1
}
],
"__parse": true
},
{
"name": "Chemical",
"children": [
{
"name": "Bitter",
"value": 1
},
{
"name": "Salty",
"value": 1
},
{
"name": "Medicinal",
"value": 1
},
{
"name": "Petroleum",
"value": 1
},
{
"name": "Skunky",
"value": 1
},
{
"name": "Rubber",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Roasted",
"children": [
{
"name": "Pipe Tobacco",
"value": 1
},
{
"name": "Tobacco",
"value": 1
},
{
"name": "Burnt",
"children": [
{
"name": "Acrid",
"value": 1
},
{
"name": "Ashy",
"value": 1
},
{
"name": "Smoky",
"value": 1
},
{
"name": "Brown, Roast",
"value": 1
}
],
"__parse": true
},
{
"name": "Cereal",
"children": [
{
"name": "Grain",
"value": 1
},
{
"name": "Malt",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Spices",
"children": [
{
"name": "Pungent",
"value": 1
},
{
"name": "Pepper",
"value": 1
},
{
"name": "Brown Spice",
"children": [
{
"name": "Anise",
"value": 1
},
{
"name": "Nutmeg",
"value": 1
},
{
"name": "Cinnamon",
"value": 1
},
{
"name": "Clove",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Nutty/Cocoa",
"children": [
{
"name": "Nutty",
"children": [
{
"name": "Peanuts",
"value": 1
},
{
"name": "Hazelnut",
"value": 1
},
{
"name": "Almond",
"value": 1
}
],
"__parse": true
},
{
"name": "Cocoa",
"children": [
{
"name": "Chocolate",
"value": 1
},
{
"name": "Dark Chocolate",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
},
{
"name": "Sweet",
"children": [
{
"name": "Brown Sugar",
"children": [
{
"name": "Molasses",
"value": 1
},
{
"name": "Maple Syrup",
"value": 1
},
{
"name": "Caramelized",
"value": 1
},
{
"name": "Honey",
"value": 1
}
],
"__parse": true
},
{
"name": "Vanilla",
"value": 1
},
{
"name": "Vanillin",
"value": 1
},
{
"name": "Overall Sweet",
"value": 1
},
{
"name": "Sweet Aromatics",
"value": 1
}
],
"__parse": true
}
],
"__parse": true
}
]
},
{
"series-0": {
"type": "ForceDirected",
"settings": {
"maskContent": false,
"singleBranchOnly": false,
"downDepth": 2,
"topDepth": 1,
"initialDepth": 3,
"valueField": "value",
"categoryField": "name",
"childDataField": "children",
"idField": "name",
"linkWithField": "linkWith",
"manyBodyStrength": -10,
"centerStrength": 0.8,
"selectedDataItem": "@self.dataItems.0",
"colors": {
"type": "ColorSet",
"settings": {
"step": 2,
"passOptions": {
"hue": 0.05,
"saturation": 0,
"lightness": 0
},
"colors": [
{
"type": "Color",
"value": "#67b7dc"
},
{
"type": "Color",
"value": "#6794dc"
},
{
"type": "Color",
"value": "#6771dc"
},
{
"type": "Color",
"value": "#8067dc"
},
{
"type": "Color",
"value": "#a367dc"
},
{
"type": "Color",
"value": "#c767dc"
},
{
"type": "Color",
"value": "#dc67ce"
},
{
"type": "Color",
"value": "#dc67ab"
},
{
"type": "Color",
"value": "#dc6788"
},
{
"type": "Color",
"value": "#dc6967"
},
{
"type": "Color",
"value": "#dc8c67"
},
{
"type": "Color",
"value": "#dcaf67"
},
{
"type": "Color",
"value": "#dcd267"
},
{
"type": "Color",
"value": "#c3dc67"
},
{
"type": "Color",
"value": "#a0dc67"
},
{
"type": "Color",
"value": "#7ddc67"
},
{
"type": "Color",
"value": "#67dc75"
}
],
"reuse": false,
"startIndex": 0,
"stateAnimationDuration": 600
}
}
},
"properties": {
"data": "#data-0",
"labels": {
"properties": {
"template": {
"settings": {
"minScale": 0
}
}
}
},
"links": {
"properties": {
"template": {
"settings": {
"strength": 0.5
}
}
}
},
"nodes": {
"properties": {
"template": {
"settings": {
"tooltipText": "{category}"
}
}
}
},
"circles": {
"properties": {
"template": {
"settings": {
"shadowColor": {
"type": "Color",
"value": "#000000"
},
"shadowOpacity": 0.3,
"shadowBlur": 6,
"shadowOffsetX": 2,
"shadowOffsetY": 2
}
}
}
}
}
}
}
]
}