In my chart, the legend contains multiple series such as A, B, C, and D, and the X-axis contains categories like Red, Green, Blue, and Yellow. When I click on a legend item—for example, series A—the category “Red,” which only contains data for series A, automatically disappears from the X-axis as expected since it no longer has any associated data.
However, for another category like “Green,” which only contains data for series B and is positioned in the middle, clicking on series B in the legend does not remove “Green” from the X-axis even though it no longer has any valid data. I would like to understand why this inconsistency is occurring and how to ensure that X-axis labels without any remaining data are always removed consistently.
Hi Varsha,Could you please share the JavaScript code for this scenario? When a legend item is unchecked, any category whose total becomes zero across all visible series should be completely removed from the chart. Right?
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Major trophies for some English teams',
align: 'left'
xAxis: {
categories: ['Arsenal', 'Chelsea', 'Liverpool', 'Manchester United'],
labels: {
useHTML: true
}
yAxis: {
min: 0,
text: 'Count trophies'
stackLabels: {
enabled: true
legend: {
align: 'left',
x: 70,
verticalAlign: 'top',
y: 70,
floating: true,
borderWidth: 1
plotOptions: {
series: {
events: {
legendItemClick: function () {
const chart = this.chart;
// Wait until visibility toggles
setTimeout(() => {
const visibleSeries = chart.series.filter(s => s.visible);
const categoryTotals = [];
// Initialize per category total = 0
for (let i = 0; i < chart.xAxis[0].categories.length; i++) {
categoryTotals[i] = 0;
// Sum visible values per category
visibleSeries.forEach(series => {
series.yData.forEach((v, idx) => {
categoryTotals[idx] += v;
});
// Update X-axis labels based on totals
chart.xAxis[0].setCategories(
chart.xAxis[0].categories.map((cat, idx) =>
categoryTotals[idx] > 0 ? cat : "" // hide by empty label
)
);
}, 0);
return true; // allow default toggle
column: {
stacking: 'normal',
dataLabels: {
series: [
{ name: 'BPL', data: [0, 0, 1, 13] },
{ name: 'FA Cup', data: [14, 0, 8, 12] },
{ name: 'CL', data: [0, 2, 6, 3] }
]
After hiding all the legend items and enabling them again, bars with null values are reappearing on the chart.
Hi Varsha, Can yo please try this code
const originalCategories = ['Arsenal', 'Chelsea', 'Liverpool', 'Manchester United'];
const originalData = {
'BPL': [0, 0, 1, 13],
'FA Cup': [14, 0, 8, 12],
'CL': [0, 2, 6, 3]
};
categories: originalCategories.slice()
title: { text: 'Count trophies' },
stackLabels: { enabled: true }
// Compute totals for each original category
const totals = originalCategories.map((_, catIndex) => {
return visibleSeries.reduce((sum, s) => {
return sum + originalData[s.name][catIndex];
// Build a list of categories to KEEP
const keepIndexes = totals
.map((t, i) => (t > 0 ? i : -1))
.filter(i => i !== -1);
// Build new categories
const newCategories = keepIndexes.map(i => originalCategories[i]);
chart.xAxis[0].setCategories(newCategories, false);
// Update each series with filtered data
chart.series.forEach(series => {
const filteredData = keepIndexes.map(i => originalData[series.name][i]);
series.setData(filteredData, false);
chart.redraw();
return true;
dataLabels: { enabled: true }
{ name: 'BPL', data: originalData['BPL'].slice() },
{ name: 'FA Cup', data: originalData['FA Cup'].slice() },
{ name: 'CL', data: originalData['CL'].slice() }
Hi @Varsha A
The inconsistency happens because empty labels only hide text but keep the tick. To remove X-axis labels consistently, you need to filter out categories with zero totals and update both categories and series data, instead of replacing them with "".
I updated the code so categories with zero values are fully removed from the X-axis. Is this what you had in mind? Hope it helps!
// Save original categories and series data for full restoration
const originalSeriesData = [
[0, 0, 1, 13], // BPL
[14, 0, 8, 12], // FA Cup
[0, 2, 6, 3] // CL
];
categories: [...originalCategories],
if (visibleSeries.length === chart.series.length) {
// Case 1: All series are visible → restore original data and categories
chart.series.forEach((series, idx) => {
series.setData([...originalSeriesData[idx]], false);
chart.xAxis[0].setCategories([...originalCategories], false);
} else {
// Case 2: Some series are hidden → filter categories with non-zero totals
const categoryTotals = originalCategories.map((_, idx) => {
return visibleSeries.reduce((sum, series) => sum + (series.options.data[idx] || 0), 0);
// Collect indexes of categories that still have data
const validIndexes = categoryTotals
.map((val, idx) => (val > 0 ? idx : -1))
.filter(idx => idx !== -1);
// Build new categories list
const newCategories = validIndexes.map(idx => originalCategories[idx]);
const newData = validIndexes.map(i => originalSeriesData[idx][i]);
series.setData(newData, false);
// Update X-axis categories
// Redraw chart after updates
return true; // Allow default toggle behavior
{ name: 'BPL', data: [...originalSeriesData[0]] },
{ name: 'FA Cup', data: [...originalSeriesData[1]] },
{ name: 'CL', data: [...originalSeriesData[2]] }