Problem creating scatter graph using chart.js - javascript

I have been trying to create a scatter graph using chart.js, and using data from a JSON object I am fetching from a public api, however my graph is not being created but I am not getting any errors on my console therefore I am unsure as to where the problem is.
This is the structure of my JSON object
0:{
first_name: "Shkodran"
form: "2.3"
points_per_game: "3.2"
now_cost: 51
second_name: "Mustafi"
web_name: "Mustafi"
minutes: 620
goals_scored: 0
assists: 2
clean_sheets: 2
goals_conceded: 9
}
Each entry is a different player and there are 628 entries.
Below is the code I am using
Fetching the public api and parsing the response
var request = new XMLHttpRequest()
var json;
request.open('GET','https://cors- anywhere.herokuapp.com/https://fantasy.premierleague.com/api/bootstrap-static/' , true)
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
json = JSON.parse(this.response);
}
console.log(json);
}
request.send();
Generating the datasets for the scatter graph as I want my graph to be x:now_cost and y:points_per_game.
Creating the chart using chart.js
if (document.readyState === 'complete') {
function generateData() {
var data=[];
json.elements.forEach(elements => {
data.push({
x: elements.now_cost,
y: points_per_game
});
});
return data;
}
var ctx = document.getElementById('chart1').getContext('2d');
var scatterChart = new Chart(ctx, {
type: 'scatter',
data: {
dataset: [{
data: generateData()
}]
},
options: {
title: {
display: true,
text: 'Cost vs Points Per Game Chart'
},
scales: {
xAxes: [{
title:{
display:true,
text: 'Cost'
},
type: 'linear',
position: 'bottom'
}],
yAxes: [{
title:{
display:true,
text: 'Points Per Game'
},
type: 'linear',
position: 'bottom'
}]
}
}
});
}

Your data is not of valid JSON format, individual properties need to be separated by a comma each. There's also an error inside the generateData function with the assignment to the y property. It should be rewritten as follows:
function generateData() {
var data = [];
json.elements.forEach(element => {
data.push({
x: element.now_cost,
y: element.points_per_game
});
});
return data;
}
Or you could even get rid of this function generateData and assign data directly as follows:
dataset: [{
data: json.elements.map(e => ({ x: e.now_cost, y: e.points_per_game }))
}]

Related

Render chart only once with multiple events : Highcharts

So what I have is a chart in which I have events function which loads data for multiple sets.
suppose I have data of 3000 points. The first data set renders the first 1000 points and after that second data set renders 2000 points.
for which I am calling my 'events' function .
but the problem arises that after showing the first 1000 set of data. The chart starts from the begining.
I don't want that.
That's why I need a solution so that my Highchart's chart render only once and the event function loads continuously.
Here's a snip of my Highchart's js
Highcharts.chart("chartcontainer", { // make thsi chart load only once.
chart: {
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
//Load this event function as the data updates
events: {
load: function() {
var series = this.series[0],
chart = this;
setInterval(function() {
//some logic regarding the chart
//..
v = {
y: y,
x: x
};
console.log("V value", v);
series.addSeries(v, false, true);
counter++;
localcounter++;
} else
{
oldcounter=counter;
flagToreload=1;
}
}, 1000/130);
setInterval(function() {
chart.redraw(false);
}, 100);
}
}
},
time: {
useUTC: false
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'Value',
gridLineWidth: 1
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
gridLineWidth: 1
},
tooltip: {
headerFormat: '<b>{series.name}</b><br/>',
pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
},
exporting: {
enabled: false
},
series: [{
animation: false,
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = counter,
i;
for (i = -1000; i <= 0; i += 1) {
data.push([
counter,
null
]);
}
return data;
}())
}]
});
You can use:
addPoint method:
chart: {
events: {
load: function() {
var newData,
chart = this,
series = chart.series[0];
setInterval(function() {
newData = getRandomData();
newData.forEach(function(el) {
series.addPoint(el, false);
});
chart.redraw();
}, 2000);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/2a8qswhf/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint
setData method:
chart: {
events: {
load: function() {
var newData,
chart = this,
combinedData,
series = chart.series[0];
setInterval(function() {
newData = getRandomData();
combinedData = series.userOptions.data.concat(newData);
series.setData(combinedData);
}, 2000);
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/Lmsk8yw9/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Series#setData

Highcharts Not displaying function's data values

i Have created a Highchart using the Following Highchart's Demo:
https://www.highcharts.com/demo/dynamic-update
Now What I did I created my Own function to add dynamic values to the Chart.
I created a function to get the dynamic data from a particular php file whose data changes on every page load event.
I am getting the data values in the getData function console.log
Here is the Script That I am using.
<script type="text/javascript">
$(document).ready(function(){
function getData(){
$.ajax({
type: 'GET',
url: 'data.php',
success: function(data){
// var number = document.write(data) ;
console.log(data);
return data ;
}
}) ;
}
Highcharts.chart('chart', {
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = getData();
console.log(y);
series.addPoint([x, y], true, true);
}, 1000);
}
}
},
time: {
useUTC: false
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
headerFormat: '<b>{series.name}</b><br/>',
pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: getData()
});
}
return data;
}())
}]
});
});
</script>
Now as you can see that I have created a getData function and getting the data value in return.
On console log under the getData function, I am getting integer Value in return every one second.
the problem is that under the Highchart's function, I am not able to get the data values using getData function, it's returning undefined in the console .
Highchart's is running but it does not show any data points. it is moving but without showing any data points.
Please correct me in the area , where I am doing wrong.
Any help is appreciated. Thanks
ajax calls are run asynchronously so you cant really return data from it.
instead you should render chart inside the ajax success function.
A good example is here already.
https://www.highcharts.com/docs/working-with-data/live-data
Basically
1. point on load to call a function getData
2. in Getdata call ajax function.
3. in success of ajax render chart with new data.
document.addEventListener('DOMContentLoaded', function() {
chart = Highcharts.chart('container', {
chart: {
type: 'spline',
events: {
load: requestData
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
maxZoom: 20 * 1000
},
yAxis: {
minPadding: 0.2,
maxPadding: 0.2,
title: {
text: 'Value',
margin: 80
}
},
series: [{
name: 'Random data',
data: []
}]
});
});
/**
* Request data from the server, add it to the graph and set a timeout
* to request again
*/
function requestData() {
$.ajax({
url: 'live-server-data.php',
success: function(point) {
var series = chart.series[0],
shift = series.data.length > 20; // shift if the series is
// longer than 20
// add the point
chart.series[0].addPoint(point, true, shift);
// call it again after one second - add this if you want to auto refresh
// setTimeout(requestData, 1000);
},
cache: false
});
}

Firebase web keeps duplicating apexchart everytime data is updated

Hey all i am using javascript with ApexCharts to draw a chart and this chart gets its data from firebase but each time the data is changed in firebase instead of replacing the chart or updating it it appends new chart under it
this is the code
function dailyTracking(){
var query = firebase.database().ref('Facilities').on('value', function(snapshot) {
var options = {
chart: {
height: 380,
width: "100%",
type: "bar",
stacked: false
},
series: [
{
name: "Library",
data: snapshotToArray(snapshot.child('Library'))
},
{
name: "Canteen",
data: [5]
},
{
name: "Free Lab",
data: [42]
}
],
xaxis: {
labels: {
formatter: function (value, timestamp) {
return new Date() // The formatter function overrides format property
},
}
}
};
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
query.off();
return snapshotToArray(snapshot);});}
I managed to solve it by adding this line
document.getElementById('chart').innerHTML = '';
before rendering the chart
Try not to wrap the chart.render() call in the event. Render the chart once and call the update event when you get new data by calling chart.updateSeries()

How to show the transition in highchart series graph without refreshing the html webpage?

I am getting JSON data using an api which is being stored in an data.json file.
Later a javascript is using that data.json file and using it to draw highcharts. The JSON File is changing every instant and the data.json file is getting update with the data.I am linking this javascript file to an html file and later running it on chrome browser. As data.json file is changing every instant then the graph corresponding to it is also changing every instant. In order to see the graphs I have to manually refresh to see that graph . How do I show the transitions in the data in the graphs without refreshing the browser.
I DONOT WANT TO REFRESH THE DIV OR EITHER THE ENTIRE HTML PAGE something dynamically.
Reference: https://onedesigncompany.com/
Similar to the transitions in this website.
This is how my graph looks like
This is my html + javascript code
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
enter code here<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore.js" type="text/javascript"></script>
<div id="container" style="min-width: 310px; height: 400px; max-width: 800px; margin: 0 auto"></div>
<script type="text/javascript">
$(document).ready(function() {
$("#container").load("index.html");
var options = {
chart: {
renderTo: 'container',
type: 'scatter',
zoomType: 'xy'
},
title: {
text: 'Number of people Versus floor'
},
xAxis: {
title: {
enabled: true,
text: 'Uids'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
title: {
text: 'Floor'
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 70,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF',
borderWidth: 1
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: 'uid: {point.x} , floor: {point.y} '
}
}
},
// series: [{}]
};
$.getJSON('/static/data/data.json', function(data) {
//floor0 data
var floor0=[];
var i,j;
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="0")
floor0.push(data.occupancy_information[i].uids);
}
var merged0 = [].concat.apply([], floor0);
var result0=[];
result0=merged0.map(Number);
var len0=result0.length;
var iMax0 = len0;
var jMax0 = 2;
var f0 = new Array();
for (i=0;i<iMax0;i++) {
f0[i]=new Array();
for (j=0;j<jMax0;j++) {
f0[i][0]=parseInt(merged0[i]);
f0[i][1]=0;
}
}
//floor1 data
var floor1=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="1")
floor1.push(data.occupancy_information[i].uids);
}
var merged1 = [].concat.apply([], floor1);
var result1=[];
result1=merged1.map(Number);
var len1=result1.length;
var iMax1 = len1;
var jMax1 = 2;
var f1 = new Array();
for (i=0;i<iMax1;i++) {
f1[i]=new Array();
for (j=0;j<jMax1;j++) {
f1[i][0]=parseInt(merged1[i]);
f1[i][1]=1;
}
}
//floor2 data
var floor2=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="2")
floor2.push(data.occupancy_information[i].uids);
}
var merged2 = [].concat.apply([], floor2);
var result2=[];
result2=merged2.map(Number);
var len2=result2.length;
var iMax2 = len2;
var jMax2 = 2;
var f2 = new Array();
for (i=0;i<iMax2;i++) {
f2[i]=new Array();
for (j=0;j<jMax2;j++) {
f2[i][0]=parseInt(merged2[i]);
f2[i][1]=2;
}
}
//floor3 data
var floor3=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="3")
floor3.push(data.occupancy_information[i].uids);
}
var merged3 = [].concat.apply([], floor3);
var result3=[];
result3=merged3.map(Number);
var len3=result3.length;
var iMax3 = len3;
var jMax3 = 2;
var f3 = new Array();
for (i=0;i<iMax3;i++) {
f3[i]=new Array();
for (j=0;j<jMax3;j++) {
f3[i][0]=parseInt(merged3[i]);
f3[i][1]=3;
}
}
//floor4 data
var floor4=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="4")
floor4.push(data.occupancy_information[i].uids);
}
var merged4 = [].concat.apply([], floor4);
var result4=[];
result4=merged4.map(Number);
var len4=result4.length;
var iMax4 = len4;
var jMax4 = 2;
var f4 = new Array();
for (i=0;i<iMax4;i++) {
f4[i]=new Array();
for (j=0;j<jMax4;j++) {
f4[i][0]=parseInt(merged4[i]);
f4[i][1]=4;
}
}
//floor5 data
var floor5=[];
for(i=0;i<data.size;i++)
{
if(data.occupancy_information[i].building=="Academic" && data.occupancy_information[i].floor=="5")
floor5.push(data.occupancy_information[i].uids);
}
var merged5 = [].concat.apply([], floor5);
var result5=[];
result5=merged5.map(Number);
var len5=result5.length;
var iMax5 = len5;
var jMax5 = 2;
var f5 = new Array();
for (i=0;i<iMax5;i++) {
f5[i]=new Array();
for (j=0;j<jMax5;j++) {
f5[i][0]=parseInt(merged5[i]);
f5[i][1]=5;
}
}
var chart = new Highcharts.Chart(options);
chart.addSeries({
name: 'Ground floor',
data: f0
}, false);
chart.addSeries({
name: 'First Floor',
data: f1
}, false);
chart.addSeries({
name: 'Second Floor',
data: f2
}, false);
chart.addSeries({
name: 'Third Floor',
data: f3
}, false);
chart.addSeries({
name: 'Fourth Floor',
data: f4
}, false);
chart.addSeries({
name: 'Fifth Floor',
data: f5
}, false);
chart.redraw();
});
});
</script>
Keep your ajax /getJson in the set interval and pass the data to your massager function when it returns data every five seconds, this way the page doesn't get refreshed.
Look at this example
var time_interval = 5000;
setInterval(function () {
$.ajax({
url: 'your_path_to_the_api',
data: '',
cache: false,
type: 'POST',
success: function (data) {
$('#container').text(data);
}
});
}, time_interval);
You want to update chart, when your data in the backend is updated. To achieve that you have two ways:
as the other answer states, use AJAX with setInterval, where you will request new data from the backend. The problem is that, your data may be not updated yet, or updated before, so you may miss/late with the graph update.
use websockets (or long polling) with database which will have publish possibility (like Redis). Then create websocket connection between backend and frontend. When connection is set, your database should emit signal that "new data is available" and in the backend gather all new data and send via websocket to the front end, and in front end update data using chart.series[index].setData(new_data).
The second solution of course requires backend: database and server. If this is too much, then you need to use the first one.
You can also consider using some platform which implements natively second solution. For example Meteor.
Why not set a time interval so that it refreshes every 5 seconds?
http://devzone.co.in/automatically-refresh-html-page-div-specific-time-interval/

Highchart xAxis label steps wrong

I am loading Highcharts like this.
var options = {
credits: {
enabled: false
},
chart: {
renderTo: 'chart_box',
type: 'areaspline'
},
title: {
text: ''
},
xAxis: {
crosshairs: true,
labels: {
step: 5,
rotation: -45
}
},
series: []
};
Then I have a function which is called when graph needs to be loaded. Upon calling the function, data is fetched through AJAX and assigned to series and date lie this:
$.ajax({
url: 'url/charts',
type: 'post',
data: data
}).done(function(data) {
var dateCount = data.dates.length;
var stepCount = 1;
if (dateCount > 10) {
stepCount = 5;
}
options.xAxis.categories = data.dates;
$.each(data.series, function(name, elem) {
options.series.push({
name: name.replace('_', ' ').toUpperCase().trim(),
data: elem
})
});
chart = new Highcharts.Chart(options);
});
The issue here is that even though I have given step as 5 , it is showing dates with 15 dates interval. I mean in xAxis labels. It seems like it will be multiplied by three always. If I give 2, it will show 6 days interval in labels. Everything working fine in a chart which is not using AJAX to load data.

Categories