Hierarchy node colors
This tutorial looks at various ways we can control coloring of hierarchy nodes.
Auto-assigned colors
Section titled “Auto-assigned colors”A series will automatically assign a unique color to each root node as well as all the first-level nodes from its own color set.
Deeper level nodes will inherit their colors from parent nodes.
Should we want to, we can override the whole list of colors by either setting it directly on series color set, creating a quick theme, or a reusable full theme, e.g.:
series.get("colors").setAll({ colors: [ am5.color(0x095256), am5.color(0x087f8c), am5.color(0x5aaa95), am5.color(0x86a873), am5.color(0xbb9f06) ], step: 1});series.get("colors").setAll({ colors: [ am5.color(0x095256), am5.color(0x087f8c), am5.color(0x5aaa95), am5.color(0x86a873), am5.color(0xbb9f06) ], step: 1});Manual colors
Section titled “Manual colors”Note about data
Section titled “Note about data”Before we explore the dynamic node coloring options, and important note.
Series data needs to be set after all the other configuration options for the series.
Setting data before adapters or template fields, will cause the those to be ignored.
Via adapters
Section titled “Via adapters”It’s possible to use custom functions (adapters) to determine color for each node’s elements, like circles or rectangles.
Adapters are functions that are run whenever color (or any other setting) is requested for an element. They have a chance of modifying the value.
We can use them to apply custom colors for series elements:
| Hierarchy type | Visual elements |
|---|---|
ForceDirected |
circles, outerCircles, links |
Pack |
circles |
Partition |
rectangles |
Sunburst |
slices |
Tree |
circles, outerCircles, links |
Treemap |
rectangles |
For example, the following will change fill color for node circles, and outline to outer circles on a force-directed series to red:
series.circles.template.adapters.add("fill", function(fill, target) { return am5.color(0xff0000);});
series.outerCircles.template.adapters.add("stroke", function(fill, target) { return am5.color(0xff0000);});series.circles.template.adapters.add("fill", function(fill, target) { return am5.color(0xff0000);});
series.outerCircles.template.adapters.add("stroke", function(fill, target) { return am5.color(0xff0000);});Adapters can also contain custom code to selectively return values according to some logic.
E.g. the following will color treemap node rectangles red if value is lower than 100, and green if it’s 100 or above:
series.rectangles.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("value") > 100) { return am5.color(0xb30000); } else { return am5.color(0x50b300); }});series.rectangles.template.adapters.add("fill", function(fill, target) { if (target.dataItem.get("value") > 100) { return am5.color(0xb30000); } else { return am5.color(0x50b300); }});In the above code we are accessing data item of the node (passed in via target parameter) to determine its value.
Via data
Section titled “Via data”We can also specify fill and other colors, as well as any other setting value, via data using template fields.
In short, template field allows specifying field in data that holds setting values for the node.
Using it we can bind fill and stroke settings of an element to data:
series.circles.template.setAll({ templateField: "nodeSettings"});
series.data.setAll([{ name: "Root", value: 0, children: [{ name: "A", value: 89, nodeSettings: { fill: am5.color(0x297373) } }, { name: "B", value: 55, nodeSettings: { fill: am5.color(0x946B49) } }, { name: "C", value: 66, nodeSettings: { fill: am5.color(0xFF621F) } }]}]);series.circles.template.setAll({ templateField: "nodeSettings"});
series.data.setAll([{ name: "Root", value: 0, children: [{ name: "A", value: 89, nodeSettings: { fill: am5.color(0x297373) } }, { name: "B", value: 55, nodeSettings: { fill: am5.color(0x946B49) } }, { name: "C", value: 66, nodeSettings: { fill: am5.color(0xFF621F) } }]}]);Via heat rules
Section titled “Via heat rules”Heat rules is an excellent way to automatically apply a range of setting values, e.g. fill color, based on the node’s value within range of values in the whole series.
We can use values in series’ valueField for heat rules, or we can use a set of completely different values via customValueField:
let series = container.children.push( am5hierarchy.Treemap.new(root, { singleBranchOnly: false, downDepth: 1, upDepth: -1, initialDepth: 2, valueField: "value", customValueField: "heatValue", categoryField: "name", childDataField: "children", nodePaddingOuter: 0, nodePaddingInner: 0, calculateAggregates: true }));
series.events.on("datavalidated", function() { let min = Infinity; let max = 0; series.nodes.each(function(node) { var dataItem = node.dataItem; if (dataItem.get("customValue") > max) { max = dataItem.get("customValue"); } if (dataItem.get("customValue") < min) { min = dataItem.get("customValue"); } });
series.set("heatRules", [{ target: series.rectangles.template, dataField: "customValue", min: am5.color(0xF53D3D), max: am5.color(0x0056F5), minValue: min, maxValue: max, key: "fill" }]);});var series = container.children.push( am5hierarchy.Treemap.new(root, { singleBranchOnly: false, downDepth: 1, upDepth: -1, initialDepth: 2, valueField: "value", customValueField: "heatValue", categoryField: "name", childDataField: "children", nodePaddingOuter: 0, nodePaddingInner: 0, calculateAggregates: true }));
// Calculate min and max values in dataseries.events.on("datavalidated", function() { var min = Infinity; var max = 0; series.nodes.each(function(node) { var dataItem = node.dataItem; if (dataItem.get("customValue") > max) { max = dataItem.get("customValue"); } if (dataItem.get("customValue") < min) { min = dataItem.get("customValue"); } });
series.set("heatRules", [{ target: series.rectangles.template, dataField: "customValue", min: am5.color(0xF53D3D), max: am5.color(0x0056F5), minValue: min, maxValue: max, key: "fill" }]);});