I am trying to make a django website which will display a chart that is updated every 1sec. I dont know why but except for the lines everything else is getting update a snapshot of the graph with the console log. the code below is my jquery in the html page
{% block jquery %}
<script>
var updateInterval = 20 //in ms
var numberElements = 5
var values = []
//Globals
var updateCount = 0
var endpoint = '/api/chart/data'
var ctx = document.getElementById('myChart');
var gchart = new Chart(ctx, {
type: 'line',
data: {
label: [],
datasets: [{
label: 'Wholesale 24 K',
data: [],
fill: true,
borderColor: 'rgb(245, 0, 0)',
tension: 0.1,
parsing: {
yAxisKey: 'b1'
}
}, {
label: 'Retail 24 K',
data: [],
fill: true,
borderColor: 'rgb(245, 225, 0)',
tension: 0.1,
parsing: {
yAxisKey: 's24K'
}
}]
}, options: {
interaction: {
mode: 'index',
}
},
})
function addData(chart, label, data) {
console.log(data)
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
if (updateCount > numberElements) {
gchart.data.labels.shift();
gchart.data.datasets[0].data.shift();
gchart.data.datasets[1].data.shift();
}
else updateCount++;
chart.update();
}
setInterval(ajaxcal, 1000)
function ajaxcal() {
$.ajax({
method: "GET",
url: endpoint,
success: function (data) {
var lal = data.time
addData(gchart, lal, data)
},
error: function (error_data) {
console.log(error_data)
console.log("Failed to fetch chart data from " + endpoint + "!")
},
})
}
</script>
and this is my apiview
class ChartData(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
g_dic = GetGoldRates()
now = datetime.datetime.now()
current_time = now.strftime("%H:%M:%S")
tg = {
'time': current_time,
'b1': float(g_dic['karat24']),
's24K': float(g_dic['fixkarat24']),
}
return Response(tg)
g_dic will usually get a dic like this {'api_rate': '1796.03', 'karat24': '17.501', 'karat22': '16.031', 'karat21': '15.313', 'karat18': '13.126', 'fixkarat24': '17.950', 'fixkarat22': '17.050', 'fixkarat21': '16.300', 'fixkarat18': '14.000'}
Could someone please help and point out my mistake
You are telling chart.js which custom key it needs to look for for the y axis but not for the x axis. So chart.js is looking for the x key in the object.
Changing your parsing config to include the xAxisKey: 'time' will fix your issue.
<script>
var updateInterval = 20 //in ms
var numberElements = 5
var values = []
//Globals
var updateCount = 0
var endpoint = '/api/chart/data'
var ctx = document.getElementById('myChart');
var gchart = new Chart(ctx, {
type: 'line',
data: {
label: [],
datasets: [{
label: 'Wholesale 24 K',
data: [],
fill: true,
borderColor: 'rgb(245, 0, 0)',
tension: 0.1,
parsing: {
yAxisKey: 'b1',
xAxisKey: 'time'
}
}, {
label: 'Retail 24 K',
data: [],
fill: true,
borderColor: 'rgb(245, 225, 0)',
tension: 0.1,
parsing: {
yAxisKey: 's24K',
xAxisKey: 'time'
}
}]
}, options: {
interaction: {
mode: 'index',
}
},
})
function addData(chart, label, data) {
console.log(data)
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
if (updateCount > numberElements) {
gchart.data.labels.shift();
gchart.data.datasets[0].data.shift();
gchart.data.datasets[1].data.shift();
}
else updateCount++;
chart.update();
}
setInterval(ajaxcal, 1000)
function ajaxcal() {
$.ajax({
method: "GET",
url: endpoint,
success: function (data) {
var lal = data.time
addData(gchart, lal, data)
},
error: function (error_data) {
console.log(error_data)
console.log("Failed to fetch chart data from " + endpoint + "!")
},
})
}
</script>
Related
hello I have the following problem I use the plugin Chart.js to display statistics now I have the following problem sometimes the chart is displayed and sometimes not see screenshot
I have asked in a Discord Chat but that did not help, i hope i can get help here
Chart.js Version:2.1.4
The Code:
function LoadProviderChart() {
$(document).ready(function() {
var providercount = JSON.parse(window.localStorage.getItem('providercount_' + window.location.pathname.split('/')[4]));
console.log(providercount);
providercount = Object.keys(providercount).map(function (key) {
return [key, providercount[key]];
})
providercount.sort(function (a, b) {
return b[1].count - a[1].count;
})
var cutProviderCount = providercount.slice(0, 6);
if(window.ProviderChart != null) {
window.ProviderChart.destroy();
console.log("ProviderChart destroyed");
}
Chart.defaults.global.defaultFontFamily = 'Rubik';
Chart.defaults.global.defaultFontColor = '#fff';
var ctxB = document.getElementById("barChart").getContext('2d');
var config = {
type: 'bar',
data: {
labels: cutProviderCount.map(function(x) { return x[0] }),
datasets: [{
label: 'Games of Providers',
data: cutProviderCount.map(function(x) { return x[1].count }),
backgroundColor: "" + getComputedStyle(document.body).getPropertyValue('--highlight_color').toString().replace(' ', '') + "",
}],
},
options: {
scales: {
yAxes: [{
gridLines:{
display: false,
},
ticks: {
beginAtZero: true
}
}],
xAxes: [{
gridLines:{
display:false,
},
}]
}
}
}
window.ProviderChart = new Chart(ctxB, config);
});
}
I'm trying to calculate the sum of the dataset values at the end of a tooltip in ChartJS.
When I execute this code in "label" callback, works correctly. However, when I execute this code in a different callback in "afterBody" or "footer" callback, it results in NaN.
new Chart(document.getElementById("line-chart"), {
type: 'line',
data: {
labels: [2018, 2019, 2020],
datasets: [{
data: [1.09, 1.48, 2.48],
label: "ABC",
borderColor: "#3e95cd",
fill: false
}, {
data: [0.63, 0.81, 0.95],
label: "DEF",
borderColor: "#8e5ea2",
fill: false
}, {
data: [0.17, 0.17, 0.18],
label: "GHI",
borderColor: "#3cba9f",
fill: false
}]
},
options: {
title: {
display: true,
text: 'Past 2FY + Current FY Estimate, US$ millions'
},
tooltips: {
mode: 'index',
callbacks: {
label: function(tooltipItem, data) {
if (tooltipItem.index > 0) {
var previousdata = tooltipItem.index - 1;
var growth = ", YoY: " + ((data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] / data.datasets[tooltipItem.datasetIndex].data[previousdata] * 100) - 100).toFixed(1) + "%";
} else {
var growth = '';
};
return data.datasets[tooltipItem.datasetIndex].label + ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + growth;
},
afterBody: function(tooltipItem, data){
var total = 0;
for(var i=0; i < data.datasets.length; i++)
total += data.datasets[i].data[tooltipItem.index];
return 'Sum:'+total;
}
}
}
}
});
<canvas id="line-chart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
Any help will be great!
I expect tooltip "Sum:" returns the sum of dataset values (in this case 'ABC' + 'CDE' + 'GHI' values).
Your use case is the given example for tooltip callbacks on the Chart.js samples page with the following code:
// Use the footer callback to display the sum of the items showing in the tooltip
footer: function(tooltipItems, data) {
var sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
});
return 'Sum: ' + sum;
}
Editing your snippet as per the above example seems to yield the result you want, although you probably want it formatted to match the rest of your tooltip:
new Chart(document.getElementById("line-chart"), {
type: 'line',
data: {
labels: [2018, 2019, 2020],
datasets: [{
data: [1.09, 1.48, 2.48],
label: "ABC",
borderColor: "#3e95cd",
fill: false
}, {
data: [0.63, 0.81, 0.95],
label: "DEF",
borderColor: "#8e5ea2",
fill: false
}, {
data: [0.17, 0.17, 0.18],
label: "GHI",
borderColor: "#3cba9f",
fill: false
}]
},
options: {
title: {
display: true,
text: 'Past 2FY + Current FY Estimate, US$ millions'
},
tooltips: {
mode: 'index',
callbacks: {
label: function(tooltipItem, data) {
if (tooltipItem.index > 0) {
var previousdata = tooltipItem.index - 1;
var growth = ", YoY: " + ((data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] / data.datasets[tooltipItem.datasetIndex].data[previousdata] * 100) - 100).toFixed(1) + "%";
} else {
var growth = '';
};
return data.datasets[tooltipItem.datasetIndex].label + ': $' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + growth;
},
footer: function(tooltipItems, data) {
var sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
});
return 'Sum: ' + sum;
}
}
}
}
});
<canvas id="line-chart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
I am trying to hide data labels generated by the data labels plugin for small screens.
I thought that I could use the onResize property of chartjs and set display to false when the width got small. This is much like the hide labels solution found here.
Unfortunately, I've not been able to get this to work. I have the following CodePen that doesn't work.
var moneyFormat = wNumb({
decimals: 0,
thousand: ',',
prefix: '$',
negativeBefore: '-'
});
var percentFormat = wNumb({
decimals: 0,
suffix: '%',
negativeBefore: '-'
});
/*
* Unregister chartjs-plugins-datalabels - not really necessary for this use case
*/
Chart.plugins.unregister(ChartDataLabels);
var doughnutdata = {
labels: ['Housing',
'Food',
'Transportation',
'Clothing',
'Healthcare',
'Childcare',
'Misc'],
datasets: [
{
backgroundColor: [
'#9B2A00',
'#5B5C90',
'#6B8294',
'#1A6300',
'#BE0000',
'#B8A853',
'#64A856'
],
borderColor: [
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF'
],
data: [88480, 57680, 40050, 18430, 23860, 25840, 17490]
}
]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {
labels: {
boxWidth: 20
}
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var index = tooltipItem.index;
return data.labels[index] + ': ' + moneyFormat.to(data.datasets[0].data[index]) + '';
}
}
},
plugins: {
datalabels: {
anchor: 'end',
backgroundColor: function (context) {
return context.dataset.backgroundColor;
},
borderColor: 'white',
borderRadius: 25,
borderWidth: 1,
color: 'white',
font: {
size: 10
},
formatter: function (value, pieID) {
var sum = 0;
var dataArr = pieID.chart.data.datasets[0].data;
dataArr.map(function (data) {
sum += data;
});
var percentage = percentFormat.to((value * 100 / sum));
return percentage;
}
}
}
};
var doughnutID = document.getElementById('doughnutchart').getContext('2d');
var pieChart = new Chart(doughnutID, {
plugins: [ChartDataLabels],
type: 'doughnut',
data: doughnutdata,
options: chartOptions,
onResize: function(chart, size) {
var showLabels = (size.width < 500) ? false : true;
chart.options = {
plugins: {
datalabels: {
display: showLabels
}
}
};
}
});
Any ideas concerning what I'm doing wrong (and fixes) would be greatly appreciated.
Responsiveness can be implemented using scriptable options and in your case, you would use a function for the display option that returns false if the chart is smaller than a specific size. (Example):
options: {
plugins: {
datalabels: {
display: function(context) {
return context.chart.width > 500;
}
}
}
}
As usual, as soon as I post a question I come up with an answer. One solution using inline plugin definitions is given at the following CodePen. If you put a browser into developer mode and shrink the window to less than 540 px, the data labels will vanish.
The code is shown below:
"use strict";
/* global Chart */
/* global wNumb */
/* global ChartDataLabels */
/*
* Unregister chartjs-plugins-datalabels - not really necessary for this use case
*/
Chart.plugins.unregister(ChartDataLabels);
var moneyFormat = wNumb({
decimals: 0,
thousand: ",",
prefix: "$",
negativeBefore: "-"
});
var percentFormat = wNumb({
decimals: 0,
suffix: "%",
negativeBefore: "-"
});
var doughnutdata = {
labels: [
"Housing",
"Food",
"Transportation",
"Clothing",
"Healthcare",
"Childcare",
"Misc"
],
datasets: [
{
backgroundColor: [
"#9B2A00",
"#5B5C90",
"#6B8294",
"#1A6300",
"#BE0000",
"#B8A853",
"#64A856"
],
borderColor: [
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF"
],
data: [88480, 57680, 40050, 18430, 23860, 25840, 17490]
}
]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {
labels: {
boxWidth: 20
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var index = tooltipItem.index;
return (
data.labels[index] +
": " +
moneyFormat.to(data.datasets[0].data[index]) +
""
);
}
}
},
plugins: {
datalabels: {
anchor: "end",
backgroundColor: function(context) {
return context.dataset.backgroundColor;
},
borderColor: "white",
borderRadius: 25,
borderWidth: 1,
color: "white",
font: {
size: 10
},
formatter: function(value, pieID) {
var sum = 0;
var dataArr = pieID.chart.data.datasets[0].data;
dataArr.map(function(data) {
sum += data;
});
var percentage = percentFormat.to(value * 100 / sum);
return percentage;
}
}
}
};
var doughnutID = document.getElementById("doughnutchart").getContext("2d");
var pieChart = new Chart(doughnutID, {
plugins: [
ChartDataLabels,
{
beforeLayout: function(chart) {
var showLabels = (chart.width) > 500 ? true : false;
chart.options.plugins.datalabels.display = showLabels;
}
},
{
onresize: function(chart) {
var showLabels = (chart.width) > 500 ? true : false;
chart.options.plugins.datalabels.display = showLabels;
}
}
],
type: "doughnut",
data: doughnutdata,
options: chartOptions
});
I hope that this is useful.
How can I remove this square from tooltip?
I would prefer if I could manage to just have it one line like this: February - 2
var data = {
labels: ['January', 'February', 'March'],
datasets: [
{
data: [1,2,3]
}
]
};
var myLineChart = new Chart(document.getElementById('chart'), {
type: 'line',
data: data,
options: {
legend: {
display: false
}
}
});
Add this in your options object
tooltips: {
displayColors: false
}
Update for version 3 or greater (from #hanumanDev below):
Remove 's' from tooltips
tooltip: {
displayColors: false
}
here you go:
jsfiddle: http://jsfiddle.net/1v9fy5mz/
code:
html
<canvas id="canvas"></canvas>
js:
var ctx = document.getElementById("canvas").getContext("2d");
var data = {
labels: ['January', 'February', 'March'],
datasets: [{
data: [1, 2, 3]
}]
};
var myLineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
showAllTooltips: true,
tooltips: {
custom: function(tooltip) {
if (!tooltip) return;
// disable displaying the color box;
tooltip.displayColors = false;
},
callbacks: {
// use label callback to return the desired label
label: function(tooltipItem, data) {
return tooltipItem.xLabel + " :" + tooltipItem.yLabel;
},
// remove title
title: function(tooltipItem, data) {
return;
}
}
}
}
});
tooltips: {
displayColors: false,
callbacks: {
// use label callback to return the desired label
label: function(tooltipItem, data) {
return tooltipItem.xLabel + " :" + tooltipItem.yLabel;
},
// remove title
title: function(tooltipItem, data) {
return;
}
}
}
In version 3.8.0 of the chart.js plugin the tooltip config needs to go in the plugins config object, like this:
options: {
plugins: {
tooltip: {
displayColors: false
}
}
}
I have a bit of a strange config of my chart.js because of the data that is being fed into it and also the line colours. However I was wondering if somebody could point me in the direction of how to customise the legend:
$(document).ready(function(){
$.ajax({
url : "../acredash/teamData.php",
timeout: 4000,
type : "GET",
success :function(data){
console.log(data);
var chartata = {
labels: [
"Strategic Development and Ownership",
"Driving change through others",
"Exec Disposition",
"Commercial Acumen",
"Develops High Performance Teams",
"Innovation and risk taking",
"Global Leadership",
"Industry Leader"
]};
var ctx = $("#mycanvas");
var config = {
type: 'radar',
data: chartata,
animationEasing: 'linear',
options: {
legend: {
display: true,
position: 'bottom'
},
tooltips: {
enabled: true
},
scale: {
ticks: {
fontSize: 15,
beginAtZero: true,
stepSize: 1
}
}
},
},
LineGraph = new Chart(ctx, config);
var colorArray = [
["#7149a5", false],
["#57B6DD", false],
["#36bfbf", false],
["#69bd45", false],
['#9adfdf', false],
['#c6b6db' ,false],
["#5481B1", false],
['#8d6db7', false],
['#d2ebc7', false],
["#6168AC", false]
];
for (var i in data) {
tmpscore=[];
tmpscore.push(data[i].score_1);
tmpscore.push(data[i].score_2);
tmpscore.push(data[i].score_3);
tmpscore.push(data[i].score_4);
tmpscore.push(data[i].score_5);
tmpscore.push(data[i].score_6);
tmpscore.push(data[i].score_7);
tmpscore.push(data[i].score_8);
var color, done = false;
while (!done) {
var test = colorArray[parseInt(Math.random() * 10)];
if (!test[1]) {
color = test[0];
colorArray[colorArray.indexOf(test)][1] = true;
done = !done;
}
}
newDataset = {
label: data[i].firstName+' '+data[i].lastName,
borderColor: color,
backgroundColor: "rgba(0,0,0,0)",
data: tmpscore,
};
config.data.datasets.push(newDataset);
}
LineGraph.update();
},
});
});
I have looked around without much luck because of how my chart is being generated. It just used the default legend and its a it messy. I would like to just have control over it.
Step 1:
set callback for legend on options
legendCallback: function(chart) {
var legendHtml = [];
legendHtml.push('<ul>');
var item = chart.data.datasets[0];
for (var i=0; i < item.data.length; i++) {
legendHtml.push('<li>');
legendHtml.push('<span></span>');//add what ever you want :-p
legendHtml.push('<span class="chart-legend-label-text">' + chart.data.labels[i]+'</span>');
legendHtml.push('</li>');
}
legendHtml.push('</ul>');
return legendHtml.join("");
},legend:false,
Step 2:
Place your legend where ever you want :-p
<div id="my-legend-con" class="legend-con"></div>
Step 3:
Initialise the legend.
$('#my-legend-con').html(myChartName.generateLegend());
Step 3:
Do what ever you want...