I'm making a Vertical Bar Chart using react-chartjs-2.
and I have array of lots of float numbers stored.
I tried to use chartjs callback option to display only the last value on a graph.
But the value in the callback is an integer, so I can't take the value I want.
for example,
const xAsisData = [ 1.11, 4.23, 7.34, ... , 403.78 ] // includes hundreds
scales: {
x: {
ticks: {
autoSkip: false,
callback: (value) => {
// if value === last ? value : null
// ! but last value is 309, not 403.78
},
},
Is there any other option I can use?
You get the index and ticks array as well in your callback so you can just check if the index is not the final one like so:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
y: {
ticks: {
callback: (val, i, ticks) => (i < ticks.length - 1 ? val : null) // Replace null by empty string to still show the gridLine
}
}
}
}
}
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>
What is the best approach to display the data in a chart?
To begin, my application has an empty array that receives objects.
// location where the users are storage
let usersList = [];
// these are the information from an user
const newUser = {
name:`${user.name.first} ${user.name.last}`,
social: Math.floor(Math.random() * 1000 )
}
So, by the end of my code, I have the chart, everything is working but with dummy data.
const myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], // should get the usersList.name
datasets: [{
label: ' Views per channel ',
data: [12, 10, 3, 5, 2, 3], // // should get the usersList.social
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
Ideally, I would need to change the labels to have the name of each user, and the data to have the social of each user. My initial thought was a for loop, but I remember that ES6 has array destructuring.
I am not sure how to approach the problem, do you have any insight?
Thank you very much.
You can use the Array.map() method on the usersList to create the arrays that contain the desired attributes of the users.
Your code would have to be changed as follows:
data: {
labels: usersList.map(u => u.name),
datasets: [{
label: ' Views per channel ',
data: usersList.map(u => u.social),
borderWidth: 1
}]
}
I have a flask app that utilizes chart.js,
live app can viewed here: https://flaskapp.gullp.repl.co/
I'm trying to pull the clicked value from the chart and put it into a variable that resides outside of the chart function.
Here is my chart logic:
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: /* {{ labels }}*/ ['Big Home', 'Medium Home', 'Small Home'] ,
datasets: [{
label: 'count per label',
data: /*{{ values }} */ [3,2,1]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
//below allows you to click the chart and get the respective value. you will pass this value to python
,onClick: function(c,i) {
e = i[0];
//console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
// console.log(x_value);
//console.log(y_value);
console.log('you clicked the graph, now the x value is = ' + x_value)
console.log('since you clicked, this is the chart clicked data = ' + JSON.stringify(chart_clicked_data) )
document.querySelectorAll("tr").forEach((tr, i) => {
if(i === 0){
// skip column names
return
}
if(tr.children[0].innerText != x_value){
tr.style.display = 'none';
}else {
tr.style.display = 'table-row';
}
})
}
}
});
Here is my code trying to extract the x-value:
var chart_clicked_data = { 'score' : myChart.options.x_value}
console.log('this is the json chart clicked data that we want to pass back to flask = ' + JSON.stringify(chart_clicked_data) )
seems like this is not doing the trick:
myChart.config.options.x_value
when i check the console after i click the value, its not showing to be picking up.
entire live code here:
https://repl.it/join/rbkobiqi-gullp
Add an variable outside of your chartFunctions, set that variable in the click handler and then use it
let xVal = ''
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
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
onClick: function(c, i) {
e = i[0];
//console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
// console.log(x_value);
//console.log(y_value);
console.log('you clicked the graph, now the x value is = ' + x_value)
xVal = x_value
},
scales: {
yAxes: [{
ticks: {
reverse: false
}
}]
}
}
}
document.getElementById('temp').addEventListener('click', () => {
console.log('X val: ', xVal);
alert('X val: ' + xVal)
})
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
canvas {
background-color: #eee;
}
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<button id="temp">
show pressed X value
</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js" integrity="sha512-hZf9Qhp3rlDJBvAKvmiG+goaaKRZA6LKUO35oK6EsM0/kjPK32Yw7URqrq3Q+Nvbbt8Usss+IekL7CRn83dYmw==" crossorigin="anonymous"></script>
</body>
I wish to pass values of an array to the data and label fields of the chart.js dataset.
Here the code from success of ajax call made to fetch json data. I fetch the json data and store it into an array.
Data = jQuery.parseJSON(result);
var count = Data.length;
var counter = 0;
while(count > 0) {
LabelResult[counter] =[Data[counter].TIME];
counter++;
count --;
}
Now i wish to use this label values into the labels filed.
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: [LabelResult],
datasets: [{
label: '# of Votes',
data: [DataResult],
borderWidth: 1
}]
}
});
But there seems some issue and the data is not getting rendered on the chart
LabelResult is an array, change
labels: [LabelResult]
to
labels: LabelResult
Also:
data: [DataResult]
to
data: DataResult
Like:
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: LabelResult,
datasets: [{
label: '# of Votes',
data: DataResult,
borderWidth: 1
}]
}
});
I think you could try to remove some brackets.
while(count > 0){
LabelResult[counter] = Data[counter].TIME; // here removed brackets
counter++;
count --;
}
and
data: {
labels: LabelResult, // here removed brackets
datasets: [{
label: '# of Votes',
data: DataResult, // here removed brackets
borderWidth: 1
}]
},
I hope that will works.
I've just started working with Chart.js, and I am getting very frustrated very quickly. I have my stacked bar chart working, but I can't get the click "events" to work.
I have found a comment on GitHub by nnnick from Chart.js stating to use the function getBarsAtEvent, even though this function cannot be found in the Chart.js documentation at all (go ahead, do a search for it). The documentation does mention the getElementsAtEvent function of the chart reference, but that is for Line Charts only.
I set an event listener (the right way) on my canvas element:
canv.addEventListener('click', handleClick, false);
...yet in my handleClick function, chart.getBarsAtEvent is undefined!
Now, in the Chart.js document, there is a statement about a different way to register the click event for the bar chart. It is much different than nnnick's comment on GitHub from 2 years ago.
In the Global Chart Defaults you can set an onClick function for your chart. I added an onClick function to my chart configuration, and it did nothing...
So, how the heck do I get the on-click-callback to work for my bar chart?!
Any help would be greatly appreciated. Thanks!
P.S.: I am not using the master build from GitHub. I tried, but it kept screaming that require is undefined and I was not ready to include CommonJS just so that I could use this chart library. I would rather write my own dang charts. Instead, I downloaded and am using the Standard Build version that I downloaded straight from the link at the top of the documentation page.
EXAMPLE: Here is an example of the configuration I am using:
var chart_config = {
type: 'bar',
data: {
labels: ['One', 'Two', 'Three'],
datasets: [
{
label: 'Dataset 1',
backgroundColor: '#848484',
data: [4, 2, 6]
},
{
label: 'Dataset 2',
backgroundColor: '#848484',
data: [1, 6, 3]
},
{
label: 'Dataset 3',
backgroundColor: '#848484',
data: [7, 5, 2]
}
]
},
options: {
title: {
display: false,
text: 'Stacked Bars'
},
tooltips: {
mode: 'label'
},
responsive: true,
maintainAspectRatio: false,
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: true
}
]
},
onClick: handleClick
}
};
I managed to find the answer to my question by looking through the Chart.js source code.
Provided at line 3727 of Chart.js, Standard Build, is the method .getElementAtEvent. This method returns me the "chart element" that was clicked on. There is sufficent data here to determine what data to show in a drill-down view of the dataset clicked on.
On the first index of the array returned by chart.getElementAtEvent is a value _datasetIndex. This value shows the index of the dataset that was clicked on.
The specific bar that was clicked on, I believe, is noted by the value _index. In my example in my question, _index would point to One in chart_config.data.labels.
My handleClick function now looks like this:
function handleClick(evt)
{
var activeElement = chart.getElementAtEvent(evt);
..where chart is the reference of the chart created by chart.js when doing:
chart = new Chart(canv, chart_config);
The specific set of data that was selected by the click can therefore be found as:
chart_config.data.datasets[activeElement[0]._datasetIndex].data[activeElement[0]._index];
And there you have it. I now have a datapoint that I can build a query from to display the data of the bar that was clicked on.
AUGUST 7TH, 2021. UPDATE
There is now a method for what we are looking for. Take a look at here
Hi this is the click event under options which is getting values from x and y-axis
onClick: function(c,i) {
e = i[0];
console.log(e._index)
var x_value = this.data.labels[e._index];
var y_value = this.data.datasets[0].data[e._index];
console.log(x_value);
console.log(y_value);
}
I found this solution at https://github.com/valor-software/ng2-charts/issues/489
public chartClicked(e: any): void {
if (e.active.length > 0) {
const chart = e.active[0]._chart;
const activePoints = chart.getElementAtEvent(e.event);
if ( activePoints.length > 0) {
// get the internal index of slice in pie chart
const clickedElementIndex = activePoints[0]._index;
const label = chart.data.labels[clickedElementIndex];
// get value by index
const value = chart.data.datasets[0].data[clickedElementIndex];
console.log(clickedElementIndex, label, value)
}
}
}
You can use onClick like this.
var worstCells3GBoxChart = new Chart(ctx, {
type: 'bar',
data: {
labels: lbls,
datasets: [{
label: 'Worst Cells by 3G',
data: datas,
backgroundColor: getColorsUptoArray('bg', datas.length),
borderColor: getColorsUptoArray('br', datas.length),
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
onClick: function (e) {
debugger;
var activePointLabel = this.getElementsAtEvent(e)[0]._model.label;
alert(activePointLabel);
}
}
});
Chartjs V3.4.1
This is what worked for me in v3, after looking at solutions for older versions:
const onClick = (event, clickedElements) => {
if (clickedElements.length === 0) return
const { dataIndex, raw } = clickedElements[0].element.$context
const barLabel = event.chart.data.labels[dataIndex]
...
}
raw is the value of the clicked bar.
barLabel is the label of the clicked bar.
You need to pass the onClick to the bar chart config:
const barConfig = {
...
options: {
responsive: true,
onClick,
...
}
}
Well done! This seems to return the data value being charted though, which in many cases might be possible to appear more than once, thus making it unclear what was clicked on.
This will return the actual data label of the bar being clicked on. I found this more useful when drilling down into a category.
chart_config.data.labels[activeElement[0]._index]
I was able to make this work in another way.
Might not be supported, but sometimes, I find that neither the label nor the value is adequate to get me the necessary information to populate a drill-through.
So what I did was add a custom set of attributes to the data:
var ctx = document.getElementById("cnvMyChart").getContext("2d");
if(theChart != null) {theChart.destroy();}
theChart = new Chart(ctx, {
type: typ,
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datakeys: ["thefirstone","thesecondone","thethirdone","thefourthone","thefifthone","thesixthone"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
...etc
Then when I need to push the drillthrough key into another ajax call, I was able to get it with this:
var theDrillThroughKey = theChart.config.data.datakeys[activePoints[0]._index];
So I'm really not sure that it's appropriate to be adding custom elements into the data for the Chart, but it's working so far in Chrome, IE and Firefox. I needed to be able to put more information into the drillthrough than I really wanted displayed.
Example of the full thing: https://wa.rrdsb.com/chartExamples
Thoughts?
I had the same problem with multiple datasets, and used this workaround:
var clickOnChart = function(dataIndex){
...
}
var lastHoveredIndex = null;
var chart_options = {
...
tooltips: {
...
callbacks: {
label: function(tooltipItem, chart) {
var index = tooltipItem.datasetIndex;
var value = chart.datasets[index].data[0];
var label = chart.datasets[index].label;
lastHoveredIndex = index;
return value + "€";
}
}
},
onClick:function(e, items){
if ( items.length == 0 ) return; //Clicked outside any bar.
clickOnChart(lastHoveredIndex);
}
}
Let's say that you declared a chart using a method like so:
window.myBar = new Chart({chart_name}, {
type: xxx,
data: xxx,
events: ["click"],
options: {
...
}
});
A good way of declaring onclick events would involve listening for the canvas click, like so:
({chart_name}.canvas).onclick = function(evt) {
var activePoints = myBar.getElementsAtEvent(evt);
// let's say you wanted to perform different actions based on label selected
if (activePoints[0]._model.label == "label you are looking for") { ... }
}
In the chart options for Chart.js v3.5.1 which is latest
Check below sample code
let enterpriseChartOptions = {
responsive:true,
maintainAspectRatio: false,
onClick: (c,i) => {
console.log('Get the underlying label for click,', c.chart.config._config.data.labels[i[0].index]);
},
plugins: {
title:{
text:'Enterprise Dashboard (Health Status of 10 stores) updated every 30 minutes',
fontSize:20
},
},
scales: {
x: {
display: true,
type: 'category',
position: 'right',
ticks: {
padding: 8,
},
},
y: {
display: true,
ticks: {
callback: function(val, index) {
// Show the label
return val < 1 ? "All good" : (val < 2 && val >=1) ? "Warning": val === 2 ? "Critical" : "";
},
//color: 'red',
stepSize: 1,
padding: 8
}
}
},
layout: {
padding: {
left: 20,
right: 20,
top: 25,
bottom: 0
}
},
};
var employeeDetailsCtx = document.getElementById("employee-details").getContext("2d");
var employee_details_data = {
labels: ["Late Present", "On Leave", "Training", "Tour"],
datasets: [{
label: "Officer",
backgroundColor: "#5A8DEE",
data: [
...
]
}, {
label: "Staff",
backgroundColor: "#4BC0C0",
data: [
...
]
}]
};
var myoption = {
tooltips: {
enabled: true
},
hover: {
animationDuration: 1
},
onClick: function (evt, i) {
var activePoint = employeeDetailsBarChart.getElementAtEvent(evt)[0];
var data = activePoint._chart.data;
var datasetIndex = activePoint._datasetIndex;
var label = data.datasets[datasetIndex].label;
var value = data.datasets[datasetIndex].data[activePoint._index];
e = i[0];
var x_value = this.data.labels[e._index];
console.log(x_value)
console.log(label)
console.log(value)
},
animation: {
duration: 1,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.textAlign = 'center';
ctx.fillStyle = "rgba(0, 0, 0, 1)";
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
}
};
var employeeDetailsBarChart = new Chart(employeeDetailsCtx, {
type: 'bar',
data: employee_details_data,
options: myoption
});