Wrong display of xAxes in Chartjs - chart.js

I have a strange issue. I'm getting the date from the database. All visualization was good. Then I deleted one record and add another one on the same date and time. But that record moved on the right in the chart instead to be ordered on left:
The js code is this:
$(document).ready(function(){
$.ajax({
url: "js/json/otv_fil_iskar/data.php",
method: "POST",
success: function(data) {
console.log(data);
var progress = document.getElementById('animationProgress');
var dateANDtime = [];
var Gblok9osx = [];
var Gblok9osy = [];
var Gblok11osx = [];
var Gblok11osy = [];
var Gfilblok10 = [];
var Gfilblok11 = [];
var Gcvn = [];
var Gndk2 = [];
for(var i in data) {
dateANDtime.push(data[i].to_char);
Gblok9osx.push(data[i].blok9osx);
Gblok9osy.push(data[i].blok9osy);
Gblok11osx.push(data[i].blok11osx);
Gblok11osy.push(data[i].blok11osy);
Gfilblok10.push(data[i].filblok10);
Gfilblok11.push(data[i].filblok11);
Gcvn.push(data[i].cvn);
Gndk2.push(data[i].ndk2);
}
var chartdata = {
labels: dateANDtime,
datasets : [
{fill: false,
label: 'Отвес блок 9 x',
backgroundColor: 'rgba(199, 228, 238, 0.75)',
borderColor: 'rgba(1, 150, 200, 0.75)',
//hoverBackgroundColor: 'rgba(200, 200, 200, 0.75)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Gblok9osx,
hidden: true
},
{fill: false,
label: 'Отвес блок 9 y',
backgroundColor: 'rgba(163, 147, 222, 0.75)',
borderColor: 'rgba(50, 10, 200, 0.75)',
//hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Gblok9osy,
hidden: true
},
{fill: false,
label: 'Отвес блок 11 x',
backgroundColor: 'rgba(221, 221, 241, 0.75)',
borderColor: 'rgba(100, 100, 200, 0.75)',
//hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Gblok11osx,
hidden: true
},
{fill: false,
label: 'Отвес блок 11 y',
backgroundColor: 'rgba(147, 227, 227, 0.75)',
borderColor: 'rgba(1, 200, 200, 0.75)',
//hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Gblok11osy,
hidden: true
},
{fill: false,
label: 'Филтрация блок 10',
backgroundColor: 'rgba(139, 105, 132, 0.75)',
borderColor: 'rgba(255, 1, 200, 0.75)',
//hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(200, 200, 200, 1)',
data: Gfilblok10,
hidden: true
},
{fill: false,
label: 'Филтрация блок 11',
backgroundColor: 'rgba(0, 200, 1, 1)',
borderColor: 'rgba(0, 101,1, 0.75)',
hoverBackgroundColor: 'rgba(200, 200, 200, 1)',
hoverBorderColor: 'rgba(50, 50, 50, 1)',
data: Gfilblok11,
hidden: true
},
{fill: false,
label: 'КВН',
backgroundColor: 'rgba(30, 100, 100, 1)',
borderColor: 'rgba(100, 200,1, 0.75)',
hoverBackgroundColor: 'rgba(101, 200, 200, 1)',
hoverBorderColor: 'rgba(50, 50, 50, 1)',
data: Gcvn,
hidden: false
},
{fill: false,
label: 'Ниво дренажен кладенец',
backgroundColor: 'rgba(30, 100, 100, 1)',
borderColor: 'rgba(100, 200,1, 0.75)',
hoverBackgroundColor: 'rgba(101, 200, 200, 1)',
hoverBorderColor: 'rgba(50, 50, 50, 1)',
data: Gndk2,
hidden: true
}
]
};
$('#reset_zoom').click(function() {
barGraph.resetZoom();
})
$("#save-btn").click(function() {
$("#mycanvas").get(0).toBlob(function(blob) {
saveAs(blob, "chart_1.png");
});
});
var ctx = document.getElementById("mycanvas");
var barGraph = new Chart(ctx, {
type: 'line',
data: chartdata,
options: {
title: {
display: true,
text: 'Диаграма - Отвеси и филтрации'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: '[mm] , [l/s]'
},
ticks: {
beginAtZero:false
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Дата/Час'
},
ticks: {
beginAtZero:true
}
}]
},
// Container for pan options
pan: {
// Boolean to enable panning
enabled: true,
// Panning directions. Remove the appropriate direction to disable
// Eg. 'y' would only allow panning in the y direction
mode: 'y'
},
// Container for zoom options
zoom: {
// Boolean to enable zooming
enabled: true,
// Zooming directions. Remove the appropriate direction to disable
// Eg. 'y' would only allow zooming in the y direction
mode: 'xy'
},
animation: {
duration: 2000,
onProgress: function(animation) {
progress.value = animation.currentStep / animation.numSteps;
},
onComplete: function() {
window.setTimeout(function() {
progress.value = 0;
}, 2000);
}
},
legend: {
display: true,
labels: {
//fontColor: 'rgb(255, 99, 132)'
usePointStyle: true
}
}
},
plugins: [{
beforeDraw: function(c) {
var reset_zoom = document.getElementById("reset_zoom"); //reset button
var ticks = c.scales['x-axis-0', 'y-axis-0'].ticks.length; //x-axis ticks array
var labels = c.data.labels.length; //labels array
if (ticks < labels) reset_zoom.hidden = false;
else reset_zoom.hidden = true;
}
}]
}); //end data
},
error: function(data) {
console.log(data);
}
});
});
The same think is happening when i don't have records in particular time of the day.
I changed xAxes option in the same graph and it's similar output:
xAxes: [{
type: 'time',
time: {
displayFormats: {
'hour': 'DD MMM YYYY г. HH:MM:SS ч.'
}
},
scaleLabel: {
display: true,
labelString: 'Дата/Час'
},
ticks: {
beginAtZero: true
}
}]

The order in the dataset is important because chart.js does not do any sorting of the values. Make sure that you fetch data from the database ordered by date and not id which usually is default.

Related

Chartjs v3 overlap stacked bar chart with groups

I want to create stacked bar chart with groups in use chart.js v3. I
my chart output
I did it and i am getting the following image. But here, instead of the sum of label 1 and label2 appearing as 7000, how can I show the intersection of label 1 and label 2 together as 4000 by starting from the x-axis.
type: 'bar',
data: {
labels: labelsVals,
datasets: [
{
label: 'Label 1',
data: seriesValsPaid,
backgroundColor: 'rgba(21, 169, 225, 0.6)',
borderColor: 'rgba(21, 169, 225, 1)',
borderWidth: 1,
stack: 'first',
},
{
label: 'Label 2',
data: seriesValsWaiting,
backgroundColor: 'rgba(21, 122, 225, 0.6)',
borderColor: 'rgba(21, 122, 225, 1)',
borderWidth: 1,
stack: 'first',
},
{
label: 'Label 3',
data: seriesValsOutgoing,
backgroundColor: 'rgba(255, 0, 0, 0.6)',
borderColor: 'rgba(255, 0, 0, 1)',
borderWidth: 1,
stack: 'second',
}
]
},
});
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
'bar-x-axis1': {
stacked: true,
display:false
},
'bar-x-axis2': {
stacked: true,
display:false
},
y: {
stacked: false,
beginAtZero: true
// display:false
}
}
}
This is how I solved the problem.

How to make the x-axis start from zero in chartjs-plugin-streaming?

I'm working on a project that could display sensing data on local web pages in real time with Django and I made this stream live data chart. But I don't need to this realtime x-axis ticks. I want to make the x-axis starting at zero and increasing 1 step by one second.
I think "xAxes type realtime" is the key, but I'm new to this and it's hard for me to solve alone, so I need your help.
enter image description here
<script>
var chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
function onRefresh(chart) {
var now = Date.now();
chart.data.datasets.forEach(function(dataset) {
dataset.data.push({
x: now,
y: GetData()
});
});
}
var color = Chart.helpers.color;
var config = {
type: 'line',
data: {
datasets: [{
backgroundColor: [
'rgba(100, 200, 200, 0)'
],
borderColor: chartColors.blue,
fill: false,
lineTension: 0,
borderDash: [8, 0],
data: [],
borderWidth:3,
pointRadius:0,
}]
},
options: {
legend:{
display:false
},
title: {
display: true,
text: 'Some Chart',
fontSize:20,
fontFamily:"Tahoma"
},
scales: {
xAxes: [{
ticks:{
beginAtZero: true
},
gridLines:{
display:true
},
type: 'realtime',
display:true,
position:'bottom',
realtime: {
duration: 20000,
refresh: 1000,
delay: 0,
onRefresh: onRefresh
}
}],
yAxes: [{
gridLines:{
display:true
},
scaleLabel: {
display: true,
labelString: 'value'
}
}]
},
}
};
window.onload = function() {
var ctx = document.getElementById('myChart').getContext('2d');
window.myChart = new Chart(ctx, config);
};
</script>
Is there any other way to make streaming live graph with Django, please let me know.
I solved this myself. The key was about 'xAxes ticks callback'. thank you.

ChartJS remove vertical grid lines one on two

I have the below ChartJS code and I would like to hide the grid vertical lines only and not the horizontal ones and keep only one vertical line per two like in the capture below:
image]1
Thanks.
<canvas id="line-chart" width="800" height="450"></canvas>
new Chart(document.getElementById("line-chart"), {
type: 'line',
data: {
labels: [1500,1600,1700,1750,1800,1850,1900,1950,1999,2050],
datasets: [{
data: [86,114,106,106,107,111,133,221,783,2478],
label: "Africa",
borderColor: "#3e95cd",
fill: false
}, {
data: [282,350,411,502,635,809,947,1402,3700,5267],
label: "Asia",
borderColor: "#8e5ea2",
fill: false
}, {
data: [168,170,178,190,203,276,408,547,675,734],
label: "Europe",
borderColor: "#3cba9f",
fill: false
}, {
data: [40,20,10,16,24,38,74,167,508,784],
label: "Latin America",
borderColor: "#e8c3b9",
fill: false
}, {
data: [6,3,2,2,7,26,82,172,312,433],
label: "North America",
borderColor: "#c45850",
fill: false
}
]
},
options: {
title: {
display: true,
text: 'World population per region (in millions)'
}
}
});
Just add grid color as function in options for x axis scale and conditionally change the colors like its done below:
var chartInstance = new Chart(document.getElementById("chartJSContainer"), {
type: 'line',
data: {
labels: [1500, 1600, 1700, 1750, 1800, 1850, 1900, 1950, 1999, 2050],
datasets: [{
data: [86, 114, 106, 106, 107, 111, 133, 221, 783, 2478],
label: "Africa",
borderColor: "#3e95cd",
fill: false
}, {
data: [282, 350, 411, 502, 635, 809, 947, 1402, 3700, 5267],
label: "Asia",
borderColor: "#8e5ea2",
fill: false
}, {
data: [168, 170, 178, 190, 203, 276, 408, 547, 675, 734],
label: "Europe",
borderColor: "#3cba9f",
fill: false
}, {
data: [40, 20, 10, 16, 24, 38, 74, 167, 508, 784],
label: "Latin America",
borderColor: "#e8c3b9",
fill: false
}, {
data: [6, 3, 2, 2, 7, 26, 82, 172, 312, 433],
label: "North America",
borderColor: "#c45850",
fill: false
}]
},
options: {
title: {
display: true,
text: 'World population per region (in millions)'
},
scales: {
x: {
grid: {
display: true, //Make it false to remove all the vertical lines.
color: function(context) {
if (context.tick.value %2 == 0) {
return 'gray';
} else {
return 'white';
}
},
}
}
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.3.1/dist/chart.js"></script>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
I don’t really use chart.js so there may be a better way to do this. I think there may be a built in way to use a callback for this but I couldn’t figure it out. Here’s what does work.
Add this function at the top to create an array of alternating colors.
let colors = [];
function gridColors() {
for (let i=0; i<10; i++) {
colors.push("rgba(0,0,0,0)")
colors.push("rgba(0,0,0,0.1)")
}
}
gridColors()
And in your options add the following
options: {
title: {
display: true,
text: 'World population per region (in millions)'
},
scales: {
x: {
grid: {
beginAtZero: true,
color: colors,
}
}
}
}
});

Can I offset the bars in chart.js stacked bar chart?

Can I offset the bars in the chart.js stacked bar chart like so:
Based on this answer, I created a runnable code snippet that illustrates how it could be done. I'm not using stacked bars because the use case is not clear to me and the image from the question rather looks like a bar with shadows.
const dataset = [40, 80, 50, 60, 70];
const offset = 8;
Chart.pluginService.register({
afterUpdate: function(chart) {
var dataset = chart.config.data.datasets[1];
for (var i = 0; i < dataset._meta[0].data.length; i++) {
var model = dataset._meta[0].data[i]._model;
model.x += offset;
model.controlPointNextX += offset;
model.controlPointPreviousX += offset;
}
}
});
var data = {
labels: ["A", "B", "C", "D", "E"],
datasets: [{
backgroundColor: [
'rgba(255, 99, 132)',
'rgba(255, 206, 86)',
'rgba(54, 162, 235)',
'rgba(75, 192, 192)',
'rgba(153, 102, 255)'
],
borderWidth: 1,
data: dataset,
xAxisID: "bar-x-axis1",
categoryPercentage: 0.5,
barPercentage: 0.5,
},
{
backgroundColor: 'rgba(0, 0, 0, 0.2)',
data: dataset.map(v => v + offset),
xAxisID: "bar-x-axis2",
categoryPercentage: 0.5,
barPercentage: 0.5
}
]
};
var options = {
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
xAxes: [
{
id: "bar-x-axis2"
},
{
id: "bar-x-axis1",
offset: true,
ticks: {
display: false
}
}
],
yAxes: [{
id: "bar-y-axis1",
ticks: {
beginAtZero: true,
stepSize: 50
}
}]
}
};
var ctx = document.getElementById("myChart").getContext("2d");
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="60"></canvas>
For Chart.js v3, you can use a different approach.
In the beforeDatasetsDraw, you save the define the shadow properties on the canvas through CanvasRenderingContext2D. Make sure to first save the state of the rendering context by invoking ctx.save().
In the afterDatasetsDraw hook, you need to restore the state of the rendering context by invoking ctx.restore().
Convert the bars into floating bars through data: data.map(v => [-20, v]) to makes sure, the shadows appear from the base of the bars.
Define a tooltip.callbacks.label function that provides the initial values in the tooltips.
Please take a look at below runnable code and see how it works.
const data = [40, 80, 50, 60, 70];
const offset = 10;
new Chart('myChart', {
type: 'bar',
plugins: [{
beforeDatasetsDraw: chart => {
const ctx = chart.ctx;
ctx.save();
ctx.shadowOffsetX = offset;
ctx.shadowOffsetY = -offset;
ctx.shadowBlur = 5;
ctx.shadowColor = 'rgb(220, 220, 220)';
},
afterDatasetsDraw: chart => chart.ctx.restore()
}],
data: {
labels: ["A", "B", "C", "D", "E"],
datasets: [{
label: 'My Data',
data: data.map(v => [-20, v]),
backgroundColor: [
'rgba(255, 99, 132)',
'rgba(255, 206, 86)',
'rgba(54, 162, 235)',
'rgba(75, 192, 192)',
'rgba(153, 102, 255)'
],
categoryPercentage: 0.8
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: ctx => data[ctx.dataIndex]
}
}
},
scales: {
y: {
min: 0,
max: Math.max(...data) + offset
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<canvas id="myChart" height="100"></canvas>

Chartjs : Remove specific labels

I have the below stacked group chart.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script>
var barChartData = {
labels: ['January', 'March', 'June', 'September', 'December'],
datasets: [{
label: 'Apple',
borderColor: 'rgba(255, 50, 50,1)',
backgroundColor: 'rgba(255, 50, 50,0.5)',
stack: 'Stack 0',
data: [3,6,4,8,2]
}, {
label: 'Orange',
borderColor: 'rgba(255, 160, 242,1)',
backgroundColor: 'rgba(255, 160, 242,0.5)',
stack: 'Stack 0',
data: [2,1,3,0,1]
}, {
label: 'Pear',
borderColor: 'rgba(79, 158, 255,1)',
backgroundColor: 'rgba(79, 158, 255,0.5)',
stack: 'Stack 0',
data: [3,4,1,5,2]
}, {
label: 'Apple',
borderColor: 'rgba(255, 50, 50,1)',
backgroundColor: 'rgba(255, 50, 50,0.5)',
stack: 'Stack 1',
data: [7,16,10,8,5]
},{
label: 'Mango',
borderColor: 'rgba(100, 244, 97,1)',
backgroundColor: 'rgba(100, 244, 97,0.5)',
stack: 'Stack 1',
data: [4,9,12,5,7]
}, {
label: 'Banana',
borderColor: 'rgba(255, 252, 91,1)',
backgroundColor: 'rgba(255, 252, 91,0.5)',
stack: 'Stack 1',
data: [3,6,13,14,5]
}, {
label: 'Orange',
borderColor: 'rgba(255, 160, 242,1)',
backgroundColor: 'rgba(255, 160, 242,0.5)',
stack: 'Stack 1',
data: [7,12,3,0,2]
}, {
label: 'Cherry',
borderColor: 'rgba(255, 132, 38,1)',
backgroundColor: 'rgba(255, 132, 38,0.5)',
stack: 'Stack 1',
data: [8,4,7,11,6]
}, {
label: 'Pear',
borderColor: 'rgba(79, 158, 255,1)',
backgroundColor: 'rgba(79, 158, 255,0.5)',
stack: 'Stack 1',
data: [8,14,9,12,16]
}]
};
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
legend: {
display:true,
},
tooltips: {
mode: 'x',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
</script>
I would like to do two things:
1) Remove the redundant Apple, Orange and Pear labels
2) Highlight/Darken just the border on the individual stacks in the graph with the colors of those individual stacks. Like how the legend is.
Any help would be greatly appreciated.
Image of my graph
You can add custom logic to legend options like:
options: {
legend: {
display: true,
labels: {
generateLabels: function (chart) { ...
You can reach the labels here, customize their color, text, you can group them etc. So in this case you have to group the labels by their text first like
const labelTexts = []
const newLabels = []
labels = Chart.defaults.global.legend.labels.generateLabels(chart);
// group labels
labels.map((label) => {
if (labelTexts.indexOf(label.text) === -1) {
labelTexts.push(label.text)
}
})
labelTexts.map((text) => {
labels.map((label) => {
if (label.text === text) {
newLabels.push(label)
}
})
})
Then you can remove the redundant labels like:
for (var i = 0; i < newLabels.length - 2; i++) {
if (newLabels[i].text !== newLabels[i + 1].text) {
newLabels2.push(newLabels[i])
}
}
Check a working example here