Chart JS - Bubble Chart is not getting rendered when loaded Dynamically - chart.js

I would be glad if anyone can help me fix the problem i'm facing with Chart Js's Bubble Chart.
I am loading the chart dynamically based on change in drop down selection.
switch case is as below:
case "bar":
case "bubble":
case "line":
return {
type: value,
data: {
labels: labels,
datasets: [
{
data: data,
fill: false,
backgroundColor: colorCodes.chartBackGroundColor,
borderWidth: 1,
borderColor: colorCodes.chartGraphBorderColor,
hoverBorderWidth: 2
}
]
},
options: {
title: {
display: false
},
legend: {
display: false
},
layout: {
padding: 20
},
responsive: true,
maintainAspectRatio: false,
hover: {
animationDuration: 0
},
tooltips: {
enabled: false
},
animation: {
"duration": 1,
"onComplete": function () {
if (data.length > 0) {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize,
Chart.defaults.global.defaultFontStyle,
Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = data[index];
ctx.fillText(data, bar._model.x, bar._model.y);
});
});
}
}
},
scales: {
scaleOverride: true,
yAxes: [
{
scaleLabel: {
display: true,
labelString: chartTypeAndLabelConfig.yAxis.title,
fontSize: 20,
fontColor: "#1c969c"
},
display: true,
gridLines: {
display: true,
borderDash: [4, 2]
},
ticks: {
beginAtZero: true
}
}
],
xAxes: [
{
scaleLabel: {
display: true,
labelString: chartTypeAndLabelConfig.xAxis.title,
fontSize: 20,
fontColor: "#1c969c"
},
gridLines: {
display: false
}
}
]
}
}
};
the returned config is stored into a variable "chartConfig" and then the chart is created as below:
var chart = new Chart(ctx, chartConfig);
When dropdown is changed from bar to line or line to bar the chart is rendered, when i try to select bubble, i see same values plotted against x-axis and y-axis without any bubbles in the chart.
Example:
data = [1,2,3,4,5];
labels = [a,b,c,d,e];
when dropdown option for bubble is selected i get the chart rendered as:
When rendering chart dynamically, i'm also destroying the previously rendered chart and then rendering the chart based on the new config i get.
Is there anything i'm missing here?

I think the issue is that you need to convert the data into a format supported by bubble charts. For line and bar charts data can be integers or floats but for bubble charts they need to be Objects with a specified 'x', 'y' and 'r' (radius) value.
So for example to display a data in a bubble graph at point (1,4) with a radius of 10, you'll specify it as:
{x: 1, y: 4, r: 10}
One way of doing this could be to call a helper function before creating a bubble chart or storing a copy of the data as an Object to be used only for bubble charts. It really depends on how you've set up your project and if you are concerned about the number of computations carried out or not. Hope this helps!
Documentation for Chart.js Bubble Chart Data Structure

Related

ChartJS 'Line chartjs' does not show output in NodeRED?

My requirement is to output 2 y-axis chart with real-time data readings in NodeRED. I have installed ChartJS package in NodeRED and now according to the documentation of the package there should be PATH, Title, X-Axis, Y-Axis, Payload. But I couldn't find the Payload tab anywhere in the Line Chartjs node?
Ref : https://www.npmjs.com/package/node-red-contrib-chartjs
So I assumed that I have to add the code which belonged to Payload inside a function node before the Line Chartjs node.
What I have tried : (my function node)
var left = {payload : msg.payload.readResults[0].v };
var right = {payload : msg.payload.readResults[1].v };
//return [[left,right]];
const labels = [1,2,3,4,5,6,7,8,9,10];
const data = {
labels: labels,
datasets: [
{
label: 'Dataset 1',
data: left,
borderColor: '#ff0000',
backgroundColor: '#ff0000',
yAxisID: 'leftCamber',
},
{
label: 'Dataset 2',
data: right,
borderColor: '#0000ff',
backgroundColor: '#0000ff',
yAxisID: 'rightCamber',
}
]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
interaction: {
mode: 'index',
intersect: false,
},
stacked: false,
plugins: {
title: {
display: true,
text: 'Chart.js Line Chart - Multi Axis'
}
},
scales: {
leftCamber: {
type: 'linear',
display: true,
position: 'left',
},
rightCamber: {
type: 'linear',
display: true,
position: 'right',
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
},
}
},
};
const actions = [
{
name: 'CamberGraph',
handler(chart) {
chart.data.datasets.forEach(dataset => {
dataset.data = chart.data.labels.length
});
chart.update();
}
},
];
Here I have tried to get the 2 HTTP outputs I've named as left and right as my datasets(2 y-axis) vs hardcoded x-axis(1 through 10) which will be Footage later on.
PS : I have returned the left and right using return statement and it's outputting the values as I expected.
Currently I do not get any output in my debug window as well as in my ChartJS Line Chart when I inject the node. Using what I've tried so far can anybody show where I've done wrong or add/remove anything to make the graph work?
Thank you!

why the main and axis title does not show in chart.js

I have the following code to make a chart with chart.js but the main and axis title just does not work. Also I have put the legend to the bottom but does not work. Can anybody tell why it is not working?
let dataSize = 30;
let readings = new Array(dataSize);
const data = {
// X axis labels
labels: new Array(dataSize),
datasets: [{
//label: 'My Input', // chart label
data: readings, // the data to chart
//borderColor: '#272323', // line color (lavender)
backgroundColor: 'rgba(123, 83, 252, 80)',
borderColor: "rgba(255, 0, 0,1)",
borderWidth: 1.2,
pointBorderColor: "rgba(255, 0, 0, 1)",
pointRadius: 0.2 // point size
}]
};
const config = {
type: 'line', // type of chart
data: data, // the data
options: {
animation: false, // remove animation to speed drawing up
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'Tarrif'
},
legend:{
position: 'bottom'
},
scales: { // axis ranges:
y: {
//type: 'linear',
scaleLabel: {
display: true,
labelString: 'X axis Title'
},
min: 0,
max: 260,
gridLines: {
display: true,
drawBorder: false //hide the chart edge line
}
},
x:[{
gridLines: {
display: false
},
scaleLabel: {
display: true,
labelString: 'X axis Title'
},
min:0
}]
}
}
};
Below is screenshot of my graph:
I followed the advice here:
In Chart.js set chart title, name of x axis and y axis?
thanks
First of all don't use an array for your X scales, all the scales need to be defined as objects. Second you are placing the options in the wrong part, it has to be configured in the title namespace like so:
scales: {
y: {
title: {
display: true,
text: 'yTitle'
}
},
x: {
title: {
display: true,
text: 'xTitle'
}
}
}

Chartjs Datasets overlapping and z-index

I have the below Chart implemented using chart.js version 3.x.
https://jsfiddle.net/Lxya0u98/12/
I have multiple datasets in my charts to achieve the behavior I want.
I am facing an issue with the datasets overlapping. In the chart, I have end of the blue color line overlapping with the green color dot dataset. Is there a way to avoid this issue?
I have the below two datasets:
// Data set for the Big Dot
{
showLine: false,
borderWidth: 0,
lineTension: 0,
borderColor: colorVal,
backgroundColor: colorVal,
pointBackgroundColor: colorVal,
pointBorderColor: colorVal,
pointBorderWidth: 2,
pointRadius: 15,
};
// Data set for the Connecting Lines
{
showLine: true,
lineTension: 0,
borderWidth: 5,
borderColor: colorVal,
pointRadius: 0,
pointBorderWidth: 0,
spanGaps: true,
};
Is there a Z-Index for the Datasets so that they appear on top of the previous one in the stack?
The option dataset.order has similar effect as the z-index.
Datasets with higher order are drawn first
Datasets with no or lower order are drawn last, hence appear on top
Therefore, adding order: 1 to your line datasets should solve the problem.
var newDataLine = {
...
order: 1
};
Instead of defining multiple datasets, you could proceed as follows:
First convert your line chart into a scatter chart.
Then draw the lines directly on the canvas using the Plugin Core API. The API offers a range of hooks that may be used for performing custom code. You can use the beforeDraw hook to draw connection lines of different colors between data points and to the open end of the chart.
Note that you have to define xAxes.ticks.max in order to obtain the open end line at the right of the chart.
Please take a look at below runnable code snippet and see how it works.
new Chart('line-chart', {
type: "scatter",
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
var dataset = chart.data.datasets[0];
var y = yAxis.getPixelForValue(0);
dataset.data.forEach((value, index) => {
var xFrom = xAxis.getPixelForValue(value.x);
var xTo;
if (index + 1 < dataset.data.size) {
xTo = xAxis.getPixelForValue(dataset.data[index + 1].x);
} else {
xTo = xAxis.right;
}
ctx.strokeStyle = dataset.backgroundColor[index];
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(xFrom, y);
ctx.lineTo(xTo, y);
ctx.stroke();
});
ctx.restore();
}
}],
data: {
datasets: [{
data: [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 0 }
],
backgroundColor: ['red', 'blue', 'green'],
borderColor: ['red', 'blue', 'green'],
pointRadius: 8,
pointHoverRadius: 8,
}],
},
options: {
layout: {
padding: {
left: 10,
right: 10
}
},
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
yAxes: [{
ticks: {
display: false
},
gridLines: {
display: false,
}
}],
xAxes: [{
ticks: {
display: false,
max: 3
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="line-chart" height="30"></canvas>

On hover bar is overlapped by label chartjs

I'm trying to generate a bar graph but after generating when i hover on bar first graph the hover works and tooltip is also coming correctly but when i hover on second or third bar the bar color becomes black
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<canvas id="barChart" style="margin-top:10px"></canvas>
var ctxBarChart = document.getElementById('barChart').getContext('2d');
var chart = new Chart(ctxBarChart, {
// The type of chart we want to create
type: 'bar',
// The data for our dataset
data: {
labels: ['bar 1', 'bar 2', 'bar 3'],
datasets: [{
label: 'bar graph label',
backgroundColor: ['#ff7f27', 'DodgerBlue', 'Green'],
borderColor: ['#ff7f27', 'DodgerBlue', 'Green'],
data: [24.6154, 28.4, 28.4]
}]
},
// Configuration options go here
options: {
legend: {
display: false
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
return tooltipItem.yLabel.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,') + '%';
}
}
},
scales: {
xAxes: [{
gridLines: {
display: false
}
}],
yAxes: [{
gridLines: {
display: false
},
ticks: {
// max: 100,
min: 0,
// stepSize:20
}
}]
}
}
});
but the result i'm getting is like this please see following images for bar 1 and bar 2
This seems to be caused by case-sensitivity of colour names.
Change your colours to all lowercase like so:
backgroundColor: ['#ff7f27', 'dodgerblue', 'green'],
borderColor: ['#ff7f27', 'dodgerblue', 'green'],
The CSS3 specification explicitly states the names are case-insensitive so this looks like a bug in Chart.js

Chart.js - Hover labels to display data for all data points on x-axis

I have a graph with multiple data points / lines. Currently, if you hover near a data point, it will display the label/value for that point.
What I'd like is the following: when you hover anywhere on the chart, it will display the labels + values for all data points at that x-value simultaneously in a single label.
For example, let's take the given datasets:
Date (x-labels): ['Jan 01','Jan 02','Jan 03']
Apples Sold: [3,5,1]
Oranges Sold: [0,10,2]
Gallons of Milk Sold: [5,7,4]
When you hover over the middle of the graph, above the 'Jan 02' vertical space, the label should display:
Jan 02
-----------------------
Apples Sold: 5
Oranges Sold: 10
Gallons of Milk Sold: 7
Is there a simple way to accomplish this?
Thanks.
Is there a simple way to accomplish this?
YES !! There is a quite straightforward way to accomplish this. If you would have read the documentation, you could have found that pretty easily.
Anyway, basically you need to set the tooltips mode to index in your chart options, in order to accomplish the behavior you want.
...
options: {
tooltips: {
mode: 'index'
}
}
...
Additionally, you probably want to set the following:
...
options: {
tooltips: {
mode: 'index',
intersect: false
},
hover: {
mode: 'index',
intersect: false
}
}
...
This will make it so all of the expected hover/label interactions will occur when hovering anywhere on the graph at the nearest x-value.
From the Documentation :
# index
Finds item at the same index. If the intersect setting is true, the
first intersecting item is used to determine the index in the data. If
intersect false the nearest item, in the x direction, is used to
determine the index.
Here is a working example :
var ctx = document.getElementById('canvas').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan 01', 'Jan 02', 'Jan 03'],
datasets: [{
label: 'Apples Sold',
data: [3, 5, 1],
borderColor: 'rgba(255, 99, 132, 0.8)',
fill: false
}, {
label: 'Oranges Sold',
data: [0, 10, 2],
borderColor: 'rgba(255, 206, 86, 0.8)',
fill: false
}, {
label: 'Gallons of Milk Sold',
data: [5, 7, 4],
borderColor: 'rgba(54, 162, 235, 0.8)',
fill: false
}]
},
options: {
tooltips: {
mode: 'index',
intersect: false
},
hover: {
mode: 'index',
intersect: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="canvas"></canvas>
For Chart.js 3.3.2, you can use #baburao's approach with a few changes. You can check the documentation. Put tooltip in plugins. Example:
...
options: {
plugins: {
tooltip: {
mode: 'nearest',
intersect: false
}
}
}
...
I know this is an old post, but in a time I needed to divide a bar on multiple datasets, but the labels to be keeped as original values:
eg:
dataset 1: Totals: 10 15 10
dataset 2: Red: 4 5 9
dataset 3: Blue: 4 2 1
In my chart I want to show the "Totals" bar and to collor a part of it in red/blue or "the rest" (which is Totals color). I'll don't write the code to modify the datasets, but I'll complete #busterroni answer for chartjs v3+
plugins: {
tooltip: {
mode: 'index',
intersect: false,
callbacks: {
label: (item) => item.dataset.label + ': ' +
this.originalValues[item.datasetIndex].data[item.dataIndex]
}
}
}
You can achieve this after plotting the data like this:
Html
<div class="container">
<h2>Chart.js — Line Chart Demo</h2>
<div>
<canvas id="myChart"></canvas>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js">
</script>
CSS
.container {
width: 80%;
margin: 15px auto;
}
Javascript
var ctx = document.getElementById('myChart').getContext('2d');
function convert(str) {
var date = new Date(str),
mnth = ("0" + (date.getMonth() + 1)).slice(-2),
day = ("0" + date.getDate()).slice(-2);
return [date.getFullYear(), mnth, day].join("-");
}
var date = ["Tue Jun 25 2019 00:00:00 GMT+0530 (India Standard Time)"];
var y1 = [12];
var y2 = [32];
var y3 = [7];
var dataPoints1 = [], dataPoints2 = [], dataPoints3 = [], datep=[];
console.log(date.length)
if(date.length=="1"){
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["",convert(date[0]),""],
datasets: [{
label:"Tweets",
backgroundColor: "rgba(153,255,51,0.4)",
fill:false,
borderColor:"rgba(153,255,51,0.4)",
data: [null,y1[0],null]
}, {
label:"Retweets",
backgroundColor: "rgba(255,153,0,0.4)",
fill:false,
borderColor:"rgba(255,153,0,0.4)",
data: [null,y2[0],null]
},{
label:"Favourites",
backgroundColor: "rgba(197, 239, 247, 1)",
fill:false,
borderColor:"rgba(197, 239, 247, 1)",
data:[null,y3[0],null]
}
]
},
options: {
scales: {
xAxes: [{
gridLines: {
display: false
}
}],
yAxes: [{
ticks: {
display: true
},
gridLines: {
display: false,
// drawBorder: false //maybe set this as well
}
}]
},
}
});}
else{
for (var i = 0; i < date.length; i++) {
datep.push(convert(date[i]))
dataPoints1.push(y1[i]);
dataPoints2.push(y2[i]);
dataPoints3.push(y3[i]);
}
console.log(datep)
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: datep,
datasets: [{
label:"Tweets",
backgroundColor: "rgba(153,255,51,0.4)",
fill:false,
borderColor:"rgba(153,255,51,0.4)",
data: dataPoints1
}, {
label:"Retweets",
backgroundColor: "rgba(255,153,0,0.4)",
fill:false,
borderColor:"rgba(255,153,0,0.4)",
data: dataPoints2
},{
label:"Favourites",
backgroundColor: "rgba(197, 239, 247, 1)",
fill:false,
borderColor:"rgba(197, 239, 247, 1)",
data:dataPoints3
}
]
},
options: {
scales: {
xAxes: [{
gridLines: {
display: false
}
}],
yAxes: [{
ticks: {
display: true
},
gridLines: {
display: false,
// drawBorder: false //maybe set this as well
}
}]
},
}
});
}
or chk this fiddle https://jsfiddle.net/gqozfb4L/
You could try using JavaScript to track the users mouse and based on the position, return the data at that vertice.
document.querySelector('.button').onmousemove = (e) => {
const x = e.pageX - e.target.offsetLeft
const y = e.pageY - e.target.offsetTop
e.target.style.setProperty('--x', `${ x }px`)
e.target.style.setProperty('--y', `${ y }px`)
}