Show data values in Chart.js bars (version 3) - javascript

There is a thread with many answers on this topic (Show values on top of bars in chart.js), but it's all about version 2.x
getDatasetMeta() has been deprecated:
https://www.chartjs.org/docs/3.0.2/getting-started/v3-migration.html
The "datalabels" plugin has not been ported to 3.x:
https://github.com/chartjs/chartjs-plugin-datalabels
Have you found any working solutions? How can data values be displayed on top of vertical barcharts (or next to horizontal barcharts)?

You can use the beta of the datalabels plugin.
Documentation: https://v2_0_0-rc_1--chartjs-plugin-datalabels.netlify.app/
Script tag: <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0-rc/dist/chartjs-plugin-datalabels.min.js"></script>
Install command: npm i chartjs-plugin-datalabels#next
Live example:
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.3.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0-rc"></script>
<canvas id="myChart" width="850" height="520"></canvas>
<script>
var ctx = document.getElementById('myChart');
Chart.register(ChartDataLabels); // first way of registering the plugin, registers them for all your charts
var myChart = new Chart(ctx, {
type: 'bar',
plugins: [ChartDataLabels], // second way of registering plugin, register plugin for only this chart
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
data: [12, 19, 3, 5, 2, 3],
label: 'Advisor Closed MTD',
backgroundColor: 'rgb(192,111,94)',
barThickness: 25,
datalabels: {
color: '#FFCE56'
}
}],
},
options: {
responsive: false,
plugins: {
datalabels: {
anchor: 'end', // remove this line to get label in middle of the bar
align: 'end',
formatter: (val) => (`${val}%`),
labels: {
value: {
color: 'blue'
}
}
}
}
}
});
</script>

Related

Chart.js: Change lengend colors to array

I have a chart with three datasets (Svelte REPL with code and result) and would like to change the background colors of the boxes corresponding to each set, for example:
let legendColors = ['#dddddd', '#aaaaaa', '#777777'];
After several attempts the closest I got was changing font color, but not even that as array, only a single one. :(
How do I get the boxes of the legend to be in the 3 colors I want?
Thank you in advance for your help!
Edit: I did find something here: What happened to generateLegend() in chartjs 3.0?, but that removes the functionality of the legend (i.e. removing parts of the data).
Edit: Another answer below has running snippet that is simpler to implement which also answers OP's request. My original answer below is more focused on building the legend completely by oneself.
Live Demo. I've found this is fun...
Some points to note:
You need to build the legend yourself, as your colors are not "relevant" to the data you use (that's why by default it is using the colors from dataset "a") (edited as another answer shows such possibility)
As you are using Svelte, in the Demo I used the <style> which binds with the <div> for the legend for styling of the legend.
For people who ain't using Svelte, or are seeking solutions within Chart.js, they should follow the advice from the StackOverflow answer OP linked -- they need to build the legend using the plugins field of 2nd argument when creating a new Chart()
No matter which route to take, to keep the functionality of the legend as OP mentioned, I added a tweaked version of default behaviour of OnClick.
P.S. For (3) we have to further override generateLabels() (here, but may cause meta.controllers._resolveAnimation having problems, which we may still need to override onClick).
P.P.S. When a legend item is clicked, the label is crossed out (strikethrough) as a default behaviour. That is left as a further exercise or another answer. (For Svelte, use Boolean flags to change styles. Alternatively, hack with CSS checked checkbox labels).
You can achieve this in 2 ways, using a custom generateLabels function or by specifying a backgroundcolor in the dataset.
Custom generateLabels:
let legendColors = ['#dddddd', '#aaaaaa'];
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {
plugins: {
legend: {
labels: {
generateLabels: function(chart) {
const datasets = chart.data.datasets;
const {
labels: {
usePointStyle,
pointStyle,
textAlign,
color
}
} = chart.legend.options;
return chart._getSortedDatasetMetas().map((meta, i) => {
const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
const borderWidth = Chart.helpers.toPadding(style.borderWidth);
return {
text: datasets[meta.index].label,
fillStyle: legendColors[i],
fontColor: color,
hidden: !meta.visible,
lineCap: style.borderCapStyle,
lineDash: style.borderDash,
lineDashOffset: style.borderDashOffset,
lineJoin: style.borderJoinStyle,
lineWidth: (borderWidth.width + borderWidth.height) / 4,
strokeStyle: style.borderColor,
pointStyle: pointStyle || style.pointStyle,
rotation: style.rotation,
textAlign: textAlign || style.textAlign,
borderRadius: 0, // TODO: v4, default to style.borderRadius
// Below is extra data used for toggling the datasets
datasetIndex: meta.index
};
}, this);
}
}
}
}
},
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
Adding background color prop in datasets:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink',
pointBackgroundColor: 'pink',
backgroundColor: '#dddddd'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
pointBackgroundColor: 'orange',
backgroundColor: '#aaaaaa'
}
]
},
options: {},
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>

Chart.js Treemap Adding custom text to each rectangle

I am using chart.js to develop a TreeMap. It works great but the issue is each rectangle only shows the value of the data. I want to add some custom text next to the value. How do I achieve this?
var topTags = [
{tag:'python',num:133269},{tag:'javascript',num:109742},{tag:'java',num:65490},{tag:'c#',num:45445},{tag:'html',num:43767},{tag:'android',num:42657},{tag:'reactjs',num:38844},{tag:'php',num:34381},{tag:'sql',num:29996},{tag:'python',num:29942},{tag:'css',num:29654},{tag:'r',num:28319},{tag:'c++',num:27389},{tag:'node.js',num:25415},{tag:'angular',num:24093},{tag:'pandas',num:23826},{tag:'arrays',num:23075},{tag:'jquery',num:18968},{tag:'mysql',num:18863},{tag:'swift',num:17971},{tag:'ios',num:17600},{tag:'json',num:15589},{tag:'laravel',num:15537},{tag:'flutter',num:15201},{tag:'c',num:15195},{tag:'django',num:14748},{tag:'sql',num:12752},{tag:'reactjs',num:10974},{tag:'excel',num:10962},{tag:'list',num:10726},{tag:'regex',num:10676}
];
var canvas = document.getElementById("treemap");
var ctx = canvas.getContext("2d");
var chart = window.chart = new Chart(ctx, {
type: "treemap",
data: {
datasets: [{
tree: topTags,
key: "num",
groups: ['num'],
spacing: 0.5,
borderWidth: 1.5,
fontColor: "black",
borderColor: "grey"
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
tooltips: { enabled: false }
}
});
When running this code, I get the numbers in each rectangle but I need some text to be appended next to the numbers for each rectangle. How do I achieve this?
You can use the formatter options in the labels section:
const options = {
type: 'treemap',
data: {
datasets: [{
label: '# of Votes',
tree: [12, 19, 3, 5, 2, 3],
backgroundColor: 'pink',
labels: {
display: true,
formatter(ctx) {
const data = ctx.chart.data;
return `Custom Text: ${data.datasets[ctx.datasetIndex].tree[ctx.dataIndex]}`;
}
},
}]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-chart-treemap#2.0.1/dist/chartjs-chart-treemap.js"></script>
</body>

React-Chart.js legend onClick function

I'm working on a bar chart with multiple stacked datasets using the react wrapper for Chart.js(https://github.com/reactchartjs/react-chartjs-2).
I've been trying to make the chart show only one dataset at a time, but I'm having trouble coming up with the right function.
I want the chart to start off with all the datasets hidden(this part was easy) and when you click the legend I want the chart to only show only the selected dataset. So when you click one and then another I want the first one to get hidden.
I know I need to use the legend onClick option but I can't figure out how to set it up.
Any help would be appreciated, thanks!
Edit: Here is the chart in question: https://codesandbox.io/s/lucid-river-xhvtd?file=/src/charts/bar_chart.js
You can set all datasets to hide and then only the one clicked to show:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink',
hidden: true
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
hidden: true
},
{
label: '# of People',
data: [3, 1, 15, 4, 9, 12],
borderColor: 'cyan',
hidden: true
}
]
},
options: {
plugins: {
legend: {
onClick: (evt, legendItem, legend) => {
const index = legendItem.datasetIndex;
const ci = legend.chart;
legend.chart.data.datasets.forEach((d, i) => {
ci.hide(i);
d.hidden = true;
})
ci.show(index);
legendItem.hidden = false;
ci.update();
}
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.js"></script>
</body>

Chart.js v3: Tooltip callback doesn't identify clicked dataset of stacked bar chart

In Chart.js v2, the datasetIndex property of ChartTooltipItem[] identifies which segment of a stacked bar chart was clicked. This allowed the tooltip content to be customized for each segment of the stacked bar chart.
In v3, TooltipItem[] provides the datasets but does not identify which one was clicked. There is a datasetIndex field for each TooltipItem, but it just matches the index in TooltipItem[] rather than identify the clicked segment.
Has anyone found a field in the V3 tooltip callback to identified which segment of a stacked bar chart was clicked? Or was this functionality lost in the v3 rewrite?
It just works fine, the only thing that is different is that it seems like in v2 it defaulted to the point mode while now it is using index mode, if you change it back to point it works as expected:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
tooltip: {
mode: 'point',
callbacks: {
beforeBody: (ttItems, x) => {
ttItems.forEach((ttItem) => {
console.log('BeforeBody: ', ttItem.datasetIndex, ttItem.dataIndex)
})
},
afterBody: (ttItems, x) => {
ttItems.forEach((ttItem) => {
console.log('AfterBody: ', ttItem.datasetIndex, ttItem.dataIndex)
})
}
}
}
},
scales: {
y: {
stacked: true
},
x: {
stacked: true
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.1/chart.js"></script>
</body>

How do I remove cartesian axes from chart js?

I am trying to personalize a chart.js. But I can not find how to remove (or hide) the X and Y axes.
I am also interested in not showing data on hover and I would like not to show the reference on the top. I am just starting with chart.js and I only need to do a few graphs.
Thank you :)
This is the graph I currently have
datasets: {
label: "I need help plz",
backgroundColor: gradient,
fill: true,
borderColor: "rgb(0, 50, 100)",
borderWidth: 0.001,
tension: 0.4,
radius: 0,
data: dataset,
},
For removing the references on the top this post was useful Chart.js v2 hide dataset labels
As described in the documentation (https://www.chartjs.org/docs/master/axes/#common-options-to-all-axes) you can set in the options of the scale the display to true or false or 'auto' where auto hides the scale if no dataset is visable that is linked to that axis.
For not showing data on hover you can set the tooltip to enabled: false
Example (y auto display and no x axis):
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1,
backgroundColor: 'red'
}, ]
},
options: {
plugins: {
tooltip: {
enabled: false
}
},
scales: {
y: {
display: 'auto'
},
x: {
display: false
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
</body>

Categories