Wouter Bosch
Wouter Bosch

Reputation: 97

Chart.js V4 Toggle each bar in chart while having different labels under each bar. How?

I am trying to create a barchart with several different datasets but I'm struggling with getting labels below each bar. This is what I currently have. enter image description here

I want to have labels below the bars as well, not just in the legend. Below is my data var.

{
    "labels": [
        ""
    ],
    "datasets": [
        {
            "label": "testname1",
            "borderColor": "rgba(254, 112, 150, 1)",
            "backgroundColor": "rgba(254, 112, 150, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                58
            ]
        },
        {
            "label": "testname2",
            "borderColor": "rgba(54, 215, 232, 1)",
            "backgroundColor": "rgba(54, 215, 232, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                60
            ]
        },
        {
            "label": "testname3",
            "borderColor": "rgba(6, 185, 157, 1)",
            "backgroundColor": "rgba(6, 185, 157, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                21
            ]
        },
        {
            "label": "testname4",
            "borderColor": "rgba(242, 197, 124, 1)",
            "backgroundColor": "rgba(242, 197, 124, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                35
            ]
        },
        {
            "label": "testname5",
            "borderColor": "rgba(54,70,82, 1)",
            "backgroundColor": "rgba(54,70,82, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                32
            ]
        },
        {
            "label": "testname6",
            "borderColor": "rgba(68, 94, 147, 1)",
            "backgroundColor": "rgba(68, 94, 147, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname7",
            "borderColor": "rgba(143, 57, 133, 1)",
            "backgroundColor": "rgba(143, 57, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                5
            ]
        },
        {
            "label": "testname8",
            "borderColor": "rgba(255, 209, 102, 1)",
            "backgroundColor": "rgba(255, 209, 102, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                0
            ]
        },
        {
            "label": "testname9",
            "borderColor": "rgba(67, 129, 193, 1)",
            "backgroundColor": "rgba(67, 129, 193, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                42
            ]
        },
        {
            "label": "testname10",
            "borderColor": "rgba(135, 61, 72, 1)",
            "backgroundColor": "rgba(135, 61, 72, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                76
            ]
        },
        {
            "label": "testname11",
            "borderColor": "rgba(42, 71, 71, 1)",
            "backgroundColor": "rgba(42, 71, 71, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname12",
            "borderColor": "rgba(237, 191, 133, 1)",
            "backgroundColor": "rgba(237, 191, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                34
            ]
        },
        {
            "label": "testname13",
            "borderColor": "rgba(187, 40, 55, 1)",
            "backgroundColor": "rgba(187, 40, 55, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                59
            ]
        },
        {
            "label": "testname14",
            "borderColor": "rgba(115, 92, 221, 1)",
            "backgroundColor": "rgba(115, 92, 221, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                98
            ]
        },
        {
            "label": "testname15",
            "borderColor": "rgba(144, 0, 179, 1)",
            "backgroundColor": "rgba(144, 0, 179, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                64
            ]
        }
    ]
}

This is my options

{
    "scales": {
        "y": {
            "ticks": {
                "display": true
            }
        },
        "x": {
            "display": false
        }
    },
    "plugins": {
        "legend": {
            "display": {
                "displayLegend": true
            },
            "position": "top"
        },
        "tooltip": {
            "callbacks": {}
        },
        "elements": {
            "point": {
                "radius": 0
            }
        }
    }
}

I can manage to add the labels below the columns if I make it all 1 dataset but then all columns are the same color and you cant toggle them. I also tried this link Chart.js manipulate each bar in chart with different labels. But this is for version two of chartjs and doesnt work in the current version anymore. The paths in the beforelayout plugin keep returning cant set on undefined and when I did find xAxes in the chart object it was undefined.

Does anyone know how to get labels under my barchart columns without making it all one dataset?

Upvotes: 1

Views: 60

Answers (1)

kikon
kikon

Reputation: 8495

You can add a supplemental x axis, and set the labels of that axis to the labels of the visible datasets in the afterTickToLabelConversion callback of that axis.

The configuration of that axis may look like this:

   x_dataset_labels: {
      type: "linear",
      min: 0,
      max: 1,
      afterTickToLabelConversion(scale){
         const chart = scale.chart;
         const visible = Array.from({length: chart.data.datasets.length},
               (_, i)=>!chart.getDatasetMeta(i).hidden ? i : false).filter(vis => vis!==false),
            nVisible = visible.length;
         scale.ticks = Array.from({length: nVisible}, (_, i) => ({
            value: (i+0.5)/nVisible, label: chart.data.datasets[visible[i]].label || ''
         }));
      },
      offset: false
   }

A snippet with the data and options in the question and this axis added:

const data = {
    "labels": [
        ""
    ],
    "datasets": [
        {
            "label": "testname1",
            "borderColor": "rgba(254, 112, 150, 1)",
            "backgroundColor": "rgba(254, 112, 150, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                58
            ]
        },
        {
            "label": "testname2",
            "borderColor": "rgba(54, 215, 232, 1)",
            "backgroundColor": "rgba(54, 215, 232, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                60
            ]
        },
        {
            "label": "testname3",
            "borderColor": "rgba(6, 185, 157, 1)",
            "backgroundColor": "rgba(6, 185, 157, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                21
            ]
        },
        {
            "label": "testname4",
            "borderColor": "rgba(242, 197, 124, 1)",
            "backgroundColor": "rgba(242, 197, 124, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                35
            ]
        },
        {
            "label": "testname5",
            "borderColor": "rgba(54,70,82, 1)",
            "backgroundColor": "rgba(54,70,82, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                32
            ]
        },
        {
            "label": "testname6",
            "borderColor": "rgba(68, 94, 147, 1)",
            "backgroundColor": "rgba(68, 94, 147, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname7",
            "borderColor": "rgba(143, 57, 133, 1)",
            "backgroundColor": "rgba(143, 57, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                5
            ]
        },
        {
            "label": "testname8",
            "borderColor": "rgba(255, 209, 102, 1)",
            "backgroundColor": "rgba(255, 209, 102, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                0
            ]
        },
        {
            "label": "testname9",
            "borderColor": "rgba(67, 129, 193, 1)",
            "backgroundColor": "rgba(67, 129, 193, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                42
            ]
        },
        {
            "label": "testname10",
            "borderColor": "rgba(135, 61, 72, 1)",
            "backgroundColor": "rgba(135, 61, 72, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                76
            ]
        },
        {
            "label": "testname11",
            "borderColor": "rgba(42, 71, 71, 1)",
            "backgroundColor": "rgba(42, 71, 71, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname12",
            "borderColor": "rgba(237, 191, 133, 1)",
            "backgroundColor": "rgba(237, 191, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                34
            ]
        },
        {
            "label": "testname13",
            "borderColor": "rgba(187, 40, 55, 1)",
            "backgroundColor": "rgba(187, 40, 55, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                59
            ]
        },
        {
            "label": "testname14",
            "borderColor": "rgba(115, 92, 221, 1)",
            "backgroundColor": "rgba(115, 92, 221, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                98
            ]
        },
        {
            "label": "testname15",
            "borderColor": "rgba(144, 0, 179, 1)",
            "backgroundColor": "rgba(144, 0, 179, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                64
            ]
        }
    ]
};

const options = {
    "scales": {
        "y": {
            "ticks": {
                "display": true
            }
        },
        "x": {
            "display": false
        },
        x_dataset_labels: {
            type: "linear",
            min: 0,
            max: 1,
            afterTickToLabelConversion(scale){
                const chart = scale.chart;
                const visible = Array.from({length: chart.data.datasets.length},
                        (_, i)=>!chart.getDatasetMeta(i).hidden ? i : false).filter(vis => vis!==false),
                    nVisible = visible.length;
                scale.ticks = Array.from({length: nVisible}, (_, i) => ({
                    value: (i+0.5)/nVisible, label: chart.data.datasets[visible[i]].label || ''
                }));
            },
            offset: false
        }
    },
    "plugins": {
        "legend": {
            "display": {
                "displayLegend": true
            },
            "position": "top"
        },
        "tooltip": {
            "callbacks": {}
        },
        "elements": {
            "point": {
                "radius": 0
            }
        }
    }
};

new Chart("myChart", {type: "bar", data, options});
<div style="height:70vh">
    <canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

The same, with the addition of axis implemented as in a plugin, that also has some options for grid and tick marks:

const data = {
    "labels": [
        ""
    ],
    "datasets": [
        {
            "label": "testname1",
            "borderColor": "rgba(254, 112, 150, 1)",
            "backgroundColor": "rgba(254, 112, 150, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                58
            ]
        },
        {
            "label": "testname2",
            "borderColor": "rgba(54, 215, 232, 1)",
            "backgroundColor": "rgba(54, 215, 232, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                60
            ]
        },
        {
            "label": "testname3",
            "borderColor": "rgba(6, 185, 157, 1)",
            "backgroundColor": "rgba(6, 185, 157, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                21
            ]
        },
        {
            "label": "testname4",
            "borderColor": "rgba(242, 197, 124, 1)",
            "backgroundColor": "rgba(242, 197, 124, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                35
            ]
        },
        {
            "label": "testname5",
            "borderColor": "rgba(54,70,82, 1)",
            "backgroundColor": "rgba(54,70,82, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                32
            ]
        },
        {
            "label": "testname6",
            "borderColor": "rgba(68, 94, 147, 1)",
            "backgroundColor": "rgba(68, 94, 147, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname7",
            "borderColor": "rgba(143, 57, 133, 1)",
            "backgroundColor": "rgba(143, 57, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                5
            ]
        },
        {
            "label": "testname8",
            "borderColor": "rgba(255, 209, 102, 1)",
            "backgroundColor": "rgba(255, 209, 102, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                0
            ]
        },
        {
            "label": "testname9",
            "borderColor": "rgba(67, 129, 193, 1)",
            "backgroundColor": "rgba(67, 129, 193, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                42
            ]
        },
        {
            "label": "testname10",
            "borderColor": "rgba(135, 61, 72, 1)",
            "backgroundColor": "rgba(135, 61, 72, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                76
            ]
        },
        {
            "label": "testname11",
            "borderColor": "rgba(42, 71, 71, 1)",
            "backgroundColor": "rgba(42, 71, 71, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                75
            ]
        },
        {
            "label": "testname12",
            "borderColor": "rgba(237, 191, 133, 1)",
            "backgroundColor": "rgba(237, 191, 133, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                34
            ]
        },
        {
            "label": "testname13",
            "borderColor": "rgba(187, 40, 55, 1)",
            "backgroundColor": "rgba(187, 40, 55, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                59
            ]
        },
        {
            "label": "testname14",
            "borderColor": "rgba(115, 92, 221, 1)",
            "backgroundColor": "rgba(115, 92, 221, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                98
            ]
        },
        {
            "label": "testname15",
            "borderColor": "rgba(144, 0, 179, 1)",
            "backgroundColor": "rgba(144, 0, 179, 1)",
            "borderWidth": 1,
            "categoryPercentage": 1,
            "data": [
                64
            ]
        }
    ]
};

const options = {
    "scales": {
        "y": {
            "ticks": {
                "display": true
            }
        },
        "x": {
            "display": false
        }
    },
    "plugins": {
        "legend": {
            "display": {
                "displayLegend": true
            },
            "position": "top"
        },
        "tooltip": {
            "callbacks": {}
        },
        "elements": {
            "point": {
                "radius": 0
            }
        },
        one_bar_datasets_x_labels: {
            tickLength: 8,
            color: 'rgba(0, 0, 0, 0.3)',
            gridVisible: true,
            gridLineDash: [5, 5]
        }
    }
};

const pluginOneBarDatasetsXLabels = {
    id: 'one_bar_datasets_x_labels',
    beforeInit(chart, _, options){
        chart.options.scales.x_dataset_labels = {}
        chart.options.scales.x_dataset_labels.type = 'linear';
        chart.options.scales.x_dataset_labels.min = 0;
        chart.options.scales.x_dataset_labels.max = 1;
        chart.options.scales.x_dataset_labels.offset = false;
        chart.options.scales.x_dataset_labels.grid = {};
        chart.options.scales.x_dataset_labels.grid.display = !!options.gridVisible;
        if(options.tickLength || options.color){
            chart.options.scales.x_dataset_labels.grid.tickLength = options.tickLength || 0;
            chart.options.scales.x_dataset_labels.grid.color = options.color || 'rgba(0,0,0,0.1)';
        }
        if(options.gridLineDash){
            chart.options.scales.x_dataset_labels.border = {};
            chart.options.scales.x_dataset_labels.border.dash = options.gridLineDash;
        }
        chart.options.scales.x_dataset_labels.afterTickToLabelConversion = function(scale){
            const visible = Array.from({length: scale.chart.data.datasets.length},
                    (_, i)=>!scale.chart.getDatasetMeta(i).hidden ? i : false).filter(vis => vis!==false),
                nVisible = visible.length;
            scale.ticks = Array.from({length: nVisible}, (_, i) => ({
                value: (i+0.5)/nVisible, label: scale.chart.data.datasets[visible[i]].label || ''
            }));
        }
    }
}

new Chart("myChart", {type: "bar", data, options, plugins: [pluginOneBarDatasetsXLabels]});
<div style="height:70vh">
    <canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

Upvotes: 1

Related Questions