Customize Data Points in Treemap and Sunburst Charts Using JavaScript
Overview
Treemap and Sunburst charts display the same kind of hierarchical data, but they use different layouts. A Treemap draws the hierarchy as nested rectangles whose areas represent leaf values. A Sunburst draws it as concentric rings: top-level groups are near the center, and leaf categories are on the outer ring.
In Aspose.Slides for Node.js via Java, each numeric value is a ChartDataPoint. Its ChartDataPoint.getDataPointLevels method provides access to the leaf and its parent groups. This article explains that mapping and shows how to create and format both chart types from the same sample data.


Understand Categories, Data Points, and Levels
The sample used below has three category levels and one numeric series:
| Branch | Stem | Leaf | Revenue |
|---|---|---|---|
| Consumer | Computers | Laptops | 12 |
| Consumer | Computers | Desktops | 8 |
| Consumer | Mobile | Phones | 15 |
| Consumer | Mobile | Tablets | 6 |
| Business | Services | Consulting | 10 |
| Business | Services | Support | 7 |
| Business | Software | Licenses | 11 |
| Business | Software | Subscriptions | 14 |
Each row creates one leaf category and one data point. The category grouping levels describe the path from that leaf to its parents. For the first row, the path is Consumer > Computers > Laptops.
The indexes returned by ChartDataPoint.getDataPointLevels run from the leaf upward:
getDataPointLevels() index |
Logical level | Treemap representation | Sunburst representation |
|---|---|---|---|
0 |
Leaf | Value rectangle | Outer-ring segment |
1 |
Stem | Parent rectangle or header | Middle-ring segment |
2 |
Branch | Top-level rectangle or header | Inner-ring segment |
This order is the same for both chart types even though their visual layouts differ. A parent segment is shared by several leaves. To format it, use the corresponding level of the first data point in that group. For example, the Consumer branch starts with the Laptops point, while the Software stem starts with the Licenses point. Keeping references to those points is clearer and safer than using unexplained expressions such as dataPoints.get_Item(0) or dataPoints.get_Item(6).
Create and Customize Both Chart Types
The following complete example creates a Treemap on the first slide and a Sunburst on the second slide. It builds the hierarchy, displays the value for Tablets, applies fixed colors to selected levels, formats a branch label, and saves the presentation.
const presentation = new aspose.slides.Presentation();
try {
const worksheetIndex = 0;
const leafLevelIndex = 0;
const stemLevelIndex = 1;
const branchLevelIndex = 2;
const branchNames = [
"Consumer", "Consumer", "Consumer", "Consumer",
"Business", "Business", "Business", "Business"
];
const stemNames = [
"Computers", "Computers", "Mobile", "Mobile",
"Services", "Services", "Software", "Software"
];
const leafNames = [
"Laptops", "Desktops", "Phones", "Tablets",
"Consulting", "Support", "Licenses", "Subscriptions"
];
const revenues = [12, 8, 15, 6, 10, 7, 11, 14];
const dataPointCount = leafNames.length;
const chartTypes = [
aspose.slides.ChartType.Treemap,
aspose.slides.ChartType.Sunburst
];
const chartCount = chartTypes.length;
const layoutSlide = presentation.getLayoutSlides().get_Item(0);
for (let chartIndex = 0; chartIndex < chartCount; chartIndex++) {
const chartType = chartTypes[chartIndex];
let slide;
if (chartIndex === 0) {
slide = presentation.getSlides().get_Item(0);
} else {
slide = presentation.getSlides().addEmptySlide(layoutSlide);
}
const chart = slide.getShapes().addChart(chartType, 40, 40, 640, 440);
chart.setTitle(false);
chart.setLegend(false);
const chartData = chart.getChartData();
chartData.getCategories().clear();
chartData.getSeries().clear();
const workbook = chartData.getChartDataWorkbook();
workbook.clear(worksheetIndex);
// Add the leaf categories. A grouping item is set only when a new group begins;
// the following categories remain in that group until another item is set.
for (let dataIndex = 0; dataIndex < dataPointCount; dataIndex++) {
const rowIndex = dataIndex + 1;
const leafName = leafNames[dataIndex];
const categoryCell = workbook.getCell(worksheetIndex, rowIndex, 2, leafName);
const category = chartData.getCategories().add(categoryCell);
const stemName = stemNames[dataIndex];
const startsNewStem = dataIndex === 0 || stemName !== stemNames[dataIndex - 1];
if (startsNewStem) {
category.getGroupingLevels().setGroupingItem(stemLevelIndex, stemName);
}
const branchName = branchNames[dataIndex];
const startsNewBranch = dataIndex === 0 || branchName !== branchNames[dataIndex - 1];
if (startsNewBranch) {
category.getGroupingLevels().setGroupingItem(branchLevelIndex, branchName);
}
}
const seriesNameCell = workbook.getCell(worksheetIndex, 0, 3, "Revenue");
const series = chartData.getSeries().add(seriesNameCell, chartType);
series.getLabels().getDefaultDataLabelFormat().setShowCategoryName(true);
let laptopsDataPoint = null;
let tabletsDataPoint = null;
let licensesDataPoint = null;
for (let dataIndex = 0; dataIndex < dataPointCount; dataIndex++) {
const rowIndex = dataIndex + 1;
const leafName = leafNames[dataIndex];
const revenue = revenues[dataIndex];
const valueCell = workbook.getCell(worksheetIndex, rowIndex, 3, revenue);
let dataPoint;
if (chartType === aspose.slides.ChartType.Treemap) {
dataPoint = series.getDataPoints().addDataPointForTreemapSeries(valueCell);
} else {
dataPoint = series.getDataPoints().addDataPointForSunburstSeries(valueCell);
}
if (leafName === "Laptops") {
laptopsDataPoint = dataPoint;
} else if (leafName === "Tablets") {
tabletsDataPoint = dataPoint;
} else if (leafName === "Licenses") {
licensesDataPoint = dataPoint;
}
}
// Show the category and value on the Tablets leaf.
const tabletsLeafLevel = tabletsDataPoint.getDataPointLevels().get_Item(leafLevelIndex);
const tabletsLabelFormat = tabletsLeafLevel.getLabel().getDataLabelFormat();
tabletsLabelFormat.setShowCategoryName(true);
tabletsLabelFormat.setShowValue(true);
tabletsLabelFormat.setSeparator("\n");
tabletsLabelFormat.setNumberFormat("$0");
// Format the Consumer branch through the first leaf in that branch.
const consumerBranchLevel = laptopsDataPoint.getDataPointLevels().get_Item(branchLevelIndex);
const consumerBranchFill = consumerBranchLevel.getFormat().getFill();
const consumerBranchColor = java.newInstanceSync("java.awt.Color", 31, 78, 121);
consumerBranchFill.setFillType(java.newByte(aspose.slides.FillType.Solid));
consumerBranchFill.getSolidFillColor().setColor(consumerBranchColor);
const consumerLabelFormat = consumerBranchLevel.getLabel().getDataLabelFormat();
consumerLabelFormat.setShowCategoryName(true);
consumerLabelFormat.setShowSeriesName(false);
const consumerLabelTextFill = consumerLabelFormat.getTextFormat().getPortionFormat().getFillFormat();
const whiteColor = java.getStaticFieldValue("java.awt.Color", "WHITE");
consumerLabelTextFill.setFillType(java.newByte(aspose.slides.FillType.Solid));
consumerLabelTextFill.getSolidFillColor().setColor(whiteColor);
// Format the Software stem through the first leaf in that stem.
const softwareStemLevel = licensesDataPoint.getDataPointLevels().get_Item(stemLevelIndex);
const softwareStemFill = softwareStemLevel.getFormat().getFill();
const softwareStemColor = java.newInstanceSync("java.awt.Color", 112, 173, 71);
softwareStemFill.setFillType(java.newByte(aspose.slides.FillType.Solid));
softwareStemFill.getSolidFillColor().setColor(softwareStemColor);
// ParentLabelLayout affects Treemap parent labels; Sunburst uses ring segments.
if (chartType === aspose.slides.ChartType.Treemap) {
series.setParentLabelLayout(aspose.slides.ParentLabelLayoutType.Overlapping);
}
}
presentation.save("hierarchical-charts.pptx", aspose.slides.SaveFormat.Pptx);
} finally {
presentation.dispose();
}
The category cells and value cells use the same worksheet row, so their collection positions remain aligned. When you work with an existing chart rather than creating one, inspect the category rows first and store named references to the data points and levels you intend to format.
Behavior and Practical Considerations
Treemap and Sunburst Differences
- A Treemap uses area to communicate value and nested rectangles to communicate hierarchy. The ChartSeries.setParentLabelLayout method controls how parent labels appear in this chart type.
- A Sunburst uses angle to communicate value and ring depth to communicate hierarchy. ChartSeries.setParentLabelLayout does not control its ring labels.
- Both chart types use the same category grouping levels and the same leaf-to-parent order returned by ChartDataPoint.getDataPointLevels, so the data-building and level-formatting code can be shared.
- Parent values are calculated from their descendant leaves. Do not add separate numeric points for branches or stems.
Sorting and Segment Order
The chart layout engine determines the final placement of rectangles and ring segments. Arrange related category rows together before adding them, but do not rely on a specific rectangle position or start angle. If sequence carries meaning, include it in the labels or use a chart type with an explicit category axis.
Theme and Fixed Colors
Unformatted chart levels inherit colors from the presentation theme. The example uses explicit RGB fills for predictable output. If the chart should follow theme changes, use scheme colors instead of fixed RGB values and avoid overriding every level. Also check label contrast after changing a branch or stem fill.
Labels and Available Space
PowerPoint may hide or truncate labels when a segment is too small. Increasing the chart size, shortening category names, or showing fewer label fields usually produces a clearer result. A label can combine the category name, series name, and value through DataLabelFormat, but enabling every field often makes hierarchical charts difficult to read.
Export and Rendering
Saving to PPTX keeps the chart editable. When Aspose.Slides renders the presentation to PDF or an image, the supported fills and label settings are rendered with the chart. Font substitution and small differences in available layout space can change line wrapping or label visibility, so install the required fonts and verify important export targets.
FAQ
Why does changing a parent level affect several leaves?
A branch or stem is a shared visual segment. Its ChartDataPointLevel can be reached through a descendant leaf, but the formatting belongs to the shared parent segment rather than only to that leaf.
Why is a data label missing?
First enable the required fields on the label’s DataLabelFormat object. Then check whether the segment has enough space. Treemap parent-label layout, chart dimensions, label length, font size, and the number of enabled fields all affect whether a label can be displayed.
Can I set the exact order or coordinates of segments?
You can control the source-row order and keep each group contiguous, but you cannot assign exact Treemap rectangles or Sunburst angles. The chart layout engine calculates them from the hierarchy, values, and available space.
Why do colors change after the presentation theme changes?
Theme-based fills are designed to follow the presentation palette. Apply explicit RGB colors to the levels that must remain fixed, or keep scheme colors when adapting to a new theme is preferred.
Will custom formatting be preserved in PDF and image exports?
Yes, supported chart fills and label settings are included during rendering. For consistent results across systems, make the required fonts available and test the final export size because label fitting is layout-dependent.