Change value from 0 to something on tooltip only - chart.js

I'm using chartjs with Bootstrap 4, on version 2.6.0.
Everything is working fine, except that I'm trying to replace an information when value is 0 on tooltip to not voted yet
I've tried a lot, and can't figure it out.
Graph picture
Can you help me?
There's an image attached that illustrates.
The value should still be zero inside the Graph, but I need to translate this information on the tooltip when the value is 0.
My code already has this information:
tooltips: {
custom: function(tooltip) {
if (!tooltip) return;
// disable displaying the color box;
tooltip.displayColors = false;
},
callbacks: {
title: function(tooltipItem, data) {
return this._data.labels[tooltipItem[0].index];
}
}
},
Thanks a lot.
Edit: Here is the second image after the suggested fix.

I'm not good with it but this will get it done. You might have to work it differently. But if you put how you are creating your chart then I can make it an exact match. Essentially you will want this:
callbacks: {
title: function(tooltipItem, data) {
return this._data.labels[tooltipItem[0].index];
},
label: function(tooltipItem, data){
var lab = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
return lab === 0 ? "Não Avaliado" : "Avaliação Geral: " + lab;
}
}

Related

how to show text inside a chart - pie and doughnut?

I have tried a lot of it, but nothing seems to be working as expected.
I need to show the text inside the pie chart.
For the above, I tried using chartjs-plugin-datalabels but then used a formatter to change a value to a value with a percentage.
formatter: function(value:any, context:Context) {
return Math.floor(value) + '%';
},
But that affected both the data point (i.e: [11,200] is by data, I only need to add a percentage to the first data point and not to the second. Show 11% and 200.)
Code:
import ChartDataLabels,{Context} from 'chartjs-plugin-datalabels';
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);
export const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value:any, context:Context) {
return Math.floor(value) + '%';
},
color:"white",
font: {
size: 16,
weight:'bold'
}
},
title: {
display: true,
},
legend: {
display: false,
},
},
};
function MyChart(){
return(
<Pie data={dataChart} options={options} />
)
}
In the above code options in the Pie, the component shows a typescript error while using chartjs-plugin-datalabels library.
The expected type comes from property 'options' which is declared here on type 'IntrinsicAttributes & Omit<ChartProps<"doughnut", number[], unknown>, "type"> & { ref?: ForwardedRef<ChartJSOrUndefined<"doughnut", number[], unknown>> | undefined; }'
2: I need to show text in the center of a Doughnut chart but seems impossible with the library and reactchartjs2 don't have a feature to show text in charts. Tried a possible solution at Add text inside the Doughnut chart of the React-Chartjs-2 box to react but none helped.

Angular CharJS option tooltip label did not work

I have a component code like below
changeData() {
const changedData = this.getData();
this.chartData = Object.assign({}, changedData);
this.lineTooltips = this.getLineTooltips();
this.chartOptions = {
tooltips: {
enabled: true,
callbacks: {
label: function(tooltipItem, data) {
return (data.tooltips[tooltipItem.index]).split('#');
},
}
}
}
}
and also HTML file
<div class="chartStyle">
<p-chart type="line" [data]="chartData" responsive="true" [options]="chartOptions" (onDataSelect)="selectData($event)"></p-chart>
The chart can load the line and data, but I hover to each item on the chart, the callback function did not work to load tooltip.
If you log data.tooltips you will see its undefined, and since you try to read things from it it will throw an error and not draw anything.
Looking at the documentation I think you have to replace data.tooltips with data.datasets. (https://www.chartjs.org/docs/latest/configuration/tooltip.html#label-callback)
The best thing you can do is just log both tooltipItem and data and go through the objects to see how you can combine them to get to the point you need and then insert that in your callback.

Chart.js sync legend toggle on multiple charts

There are solutions to using legend onClick to toggle on/off visibility of (all other) datasets on the clicked chart, but I needed a way to sync this toggle on multiple charts if they have the same label/legend. For example, I have 6 charts presenting different information about the same data. However, not all the charts have all the datasets. One may have 5 datasets, another has 3 and so on. And they may not show up in the same order either.
The goal was to be able to click a legend item on one chart, and that same item be toggled on all the charts.
Since I did not find an existing solution, I'm posting this.
To do this, I put all the charts in a global var and loop through them to match dataset by legendItem.text instead of legendItem.datasetindex, since the label may or may not exist or even be in the same index position on other charts.
Here's how I create/replace the multiple charts: https://stackoverflow.com/a/51882403/1181367
And here's the legend onClick toggle solution:
var config = {
type: type,
data: {
labels: labels,
datasets: datasets
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
legend: {
position: 'right',
onClick: function (e, legendItem) {
var text = legendItem.text;
Object.keys(charts).forEach(function (id) {
// loop through the charts
var ci = charts[id].chart
var cindex = (function () {
var match = null;
ci.legend.legendItems.forEach(function (item) {
if (item.text == text) {
// get index for legend.text that matches clicked legend.text
match = item.datasetIndex;
}
});
return match;
})();
if (cindex !== null) {
// if there's a match
var alreadyHidden = (ci.getDatasetMeta(cindex).hidden === null) ? false : ci.getDatasetMeta(cindex).hidden;
ci.data.datasets.forEach(function (e, i) {
var meta = ci.getDatasetMeta(i);
if (i !== cindex) {
if (!alreadyHidden) {
meta.hidden = meta.hidden === null ? !meta.hidden : null;
} else if (meta.hidden === null) {
meta.hidden = true;
}
} else if (i === cindex) {
meta.hidden = null;
}
});
ci.update();
}
});
}
}
}
};
After using Chris's answer here https://stackoverflow.com/a/51920456/671140 I created a simplified solution.
var config = {
type: type,
data: {
labels: labels,
datasets: datasets
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
legend: {
position: 'right',
onClick: function (e, legendItem) {
var text = legendItem.text;
Object.keys(charts).forEach(function (id) {
// loop through the charts
var ci = charts[id].chart
ci.legend.legendItems.forEach(function (item) {
if (item.text == text) {
ci.options.legend.onClick.call(chart.legend, null, item);
ci.update();
}
});
});
}
}
}
};
The benefit of using this solution is that it will call any custom onClick() handlers that have been added to any of the chart legends.
If anyone's looking for a way to sync a pie chart legend with a line chart legend, try this (it should also work just fine if the charts are the same type, too):
onClick: function(e, legendItem) {
// Save name of clicked label, for later comparison
var legendName = legendItem.text;
// Iterate through global charts array
Object.keys(myCharts).forEach(function(id) {
// Assign shorthand variable to address chart easier
var chrt = myCharts[id];
// Determine chart type
var chartType = chrt.config.type;
// Iterate through each legend in the chart
chrt.legend.legendItems.forEach(function(item) {
// If legend name matches clicked label
if (item.text == legendName) {
if (chartType == 'pie') { // If pie chart
if (chrt.getDatasetMeta(0).data[item.index].hidden === true) chrt.getDatasetMeta(0).data[item.index].hidden = false;
else if (chrt.getDatasetMeta(0).data[item.index].hidden === false) chrt.getDatasetMeta(0).data[item.index].hidden = true;
} else if (chartType == 'line') { // If line chart
if (chrt.getDatasetMeta(item.datasetIndex).hidden === true) chrt.getDatasetMeta(item.datasetIndex).hidden = null;
else if (chrt.getDatasetMeta(item.datasetIndex).hidden === null) chrt.getDatasetMeta(item.datasetIndex).hidden = true;
}
// Trigger chart update
chrt.update();
}
});
});
Place this onClick function in the legend section of the options, just like you can see in the other answers.
My line chart was a day-to-day trend, while the pie chart compared totals across the entire range.
The chart's labels must be identically named for this to work, of course.
Like the other solutions, you must store both charts in one, global variable, like:
window.myCharts['pieChart1']
window.myCharts['lineChart1']
Since hiding datasets, and getting their indexes within the whole dataset, is different depending on the chart type, this function will check the chart type and act accordingly.
Also notice that for pie charts, the "hidden" setting is either true or false, but for line charts, it's either true or null (thanks, chart.js).
I'm sure you can expand this for other chart types, but I've only bothered setting it up for 'line' and 'pie' charts.
If someone is looking for this, here is the working solution:
onClick: function (e, legendItem, legend) {
var text = legendItem.text;
Object.keys(charts).forEach(function (id) {
var ci = charts[id]
ci.legend.legendItems.forEach(function (item) {
if (item.text == text) {
if (ci.data.datasets[item.datasetIndex].hidden == true) {
ci.data.datasets[item.datasetIndex].hidden = false;
} else {
ci.data.datasets[item.datasetIndex].hidden = true;
}
}
});
ci.update();
});
}

How to display stack label/name?

In this wonderful sample, we know blue and red belong to stack: 'Stack 0'. There are some old questions related in SO, after a year what's the simplest way to display 'Stack 0' and 'Stack 1' inside the chart?
I found the datalabels plugin the easiest to use and quite simple to install: https://github.com/chartjs/chartjs-plugin-datalabels
A quick demo is here:
https://chartjs-plugin-datalabels.netlify.com/samples/charts/bar.html
Edit: Oh I see you want to actually just label the data with what it represents, and not the value. You may still be able to do this by providing a formatter function as an option. https://chartjs-plugin-datalabels.netlify.com/formatting . In this case, you'd override the data to just display the label. The label data might be in the context.
Like David said you can use chartjs-plugin-datalabels with a implementation like this:
plugins: {
datalabels: {
align: 'start',
anchor: 'start',
color: 'black',
formatter: function(value, context) {
let ds = context.chart.data.datasets
// check if it's the first ds
if(ds[context.datasetIndex - 1]) {
// check if the ds is in the same stack as the ds before
if(ds[context.datasetIndex - 1].stack == ds[context.datasetIndex].stack) {
return ''
} else {
return ds[context.datasetIndex].stack;
}
} else {
return ds[context.datasetIndex].stack;
}
}
}
}

I want to hide the label in a tooltip because it shows undefined

I am using chart.js to show a line chart. How can I hide a tooltip label for a chart.js line chart? The label in the tooltip is showing undefined so I want to hide the label (please see the screenshot)?
Perhaps there is a way to modify tooltip where I can show only the legends value in tooltip? My code is as follows:
myLine = new Chart(ctx).Line(lineChartData, {
type: 'line',
responsive: true,
scaleShowGridLines : false,
bezierCurve : false,
animationEasing: "linear",
tooltipEvents: ["mousemove", "touchstart", "touchmove"],
showTooltips: true,
scaleLineColor: "rgba(0,0,0,.8)",
});
Just set the tooltipTitleFontSize to 0 in your options.
Preview
Script
myLine = new Chart(ctx).Line(lineChartData, {
...
tooltipTitleFontSize: 0
});
I know I am late, but I guess it still has merit to add this one.
check this : https://stackoverflow.com/a/44632748/12061669
It uses a function to hide the title:
options:{
tooltips:{
callbacks:{
title: ()=>{}
}
}
}
Setting the title's font size to zero is not ideal as you will still see an (ugly) extra space on top of the tooltip, as if the title line is still there - which honestly is what you'd expect.
Instead, I used Yumin Gui's answer but had to return null for it to work:
`
tooltips: {
callbacks: {
title: () => null,
},
},
The result is exactly as in the pie charts (which does not have a title in its default tooltips).
To hide the tooltip title/label, it should be added in the options object for that chart as follows:
options: {
plugins: {
tooltip: {
callbacks: {
title : () => null // or function () { return null; }
}
}
}
}
Do refer to the documentation to understand better that it should be handled with a custom callback function, and it is not a config that can be set in options directly.
The accepted answer won't work in newer versions of chart.js, as Aman said in comments, what you can use now is this:
tooltips: { titleFontSize: 0 }
Example:
var bar_chart = document.getElementById('bar_canvas').getContext('2d');
window.myBar = new Chart(bar_chart, {
type: 'bar',
data: bar_chart_data,
options: {
tooltips: {
titleFontSize: 0,
bodyFontSize: 14,
}
}
});