Highcharts error "cannot read property of undefined" - javascript

I'm creating a chart using Highcharts (and getting the data from a JSON file). However, I'm getting TypeError: Cannot read property 'map' of undefined.
I have the following code:
myData.get(function (data) {
$scope.loadData = data;
});
$('#container').highcharts({
xAxis: {
type: 'datetime'
},
series: [{
name: 'Temperature',
data: $scope.loadData.map(function(d) {
return [d.timestamp, d.actual];
})
}, {
name: 'Range',
data: $scope.loadData.map(function(d) {
return [d.timestamp, d.min, d.max];
}),
type: 'arearange'
}]
});
I've also created a Plunker.
Any tips on what I'm doing wrong here?

So I changed your Plunkr to a working example: http://plnkr.co/edit/Q4z6NdVtp3TRMKgmH5tc?p=preview
First of all, in your data.json you have timestamps added as strings. Highchart does not accept that.
I changed the factory to get JSON data via $http
.factory('myData', function($http) {
return {
getData : function () {
var data = [];
data = $http.get('data.json');
return data;
}
}
})
In the callback of getData I build the chart:
myData.getData().then(function(response) {
$scope.loadData = response.data;
$('#container').highcharts({
xAxis: {
type: 'datetime'
},
series: [{
name: 'Temperature',
data: [$scope.loadData.timestamp, $scope.loadData.actual]
},
{
name: 'Range',
data: [$scope.loadData.timestamp, $scope.loadData.min, $scope.loadData.max],
type: 'arearange'
}]
});
});

this is asynchronous call :
myData.get(function (data) {
console.log("myData.Get");
$scope.loadData = data;
});
So $('#container').highcharts({... will run before the data is set $scope.loadData = data;
you have to move the code inside the callback of myData
myData.get(function (data) {
$scope.loadData = data;
$('#container').highcharts({
xAxis: {
type: 'datetime'
},
series: [{
name: 'Temperature',
data: $scope.loadData.map(function(d) {
return [d.timestamp, d.actual];
})
}, {
name: 'Range',
data: $scope.loadData.map(function(d) {
return [d.timestamp, d.min, d.max];
}),
type: 'arearange'
}]
});
});

Related

highcharts doesn't read data, works with fake data

I'm trying to make visualization of the voltage, Array has 1k elements but I'm testing it on first 10 for now, the thing is that It doesn't display anything, what's more interesting when I use fake date which is commented out now, It shows chart properly. I thought that perhaps there is some problem with array so tried to use Array.from but it also brought no effect, here is my code:
.then(function(res) {
var averageVoltage = []
var inputVoltage = []
var date = []
for (var i = 0; i < 10; i++) {
if (res[i].average_volatage !== undefined) {
averageVoltage.push(res[i].average_volatage)
date.push(res[i].timestamp)
}
}
console.log(averageVoltage)
console.log(date)
Highcharts.chart('battery_chart', {
chart: {
type: 'line'
},
title: {
text: id
},
yAxis: {
title: {
text: 'Measurement'
},
},
xAxis: {
categories: date
},
series: [{
name: 'Average Voltage',
data: averageVoltage
// data: [12283, 12283, 12281, 12280, 12282, 12283, 12281, 12282, 12281, 12280]
},
]
});
and that's how array is shown in console.log:
Your array should show up as [12283, 12281, 12280, etc.] in console as well, instead it shows up as [Number, Number, ...]. Try changing this line:
averageVoltage.push(res[i].average_volatage)
to:
averageVoltage.push(parseInt(res[i].average_volatage))
Additionally, instead of using dates as categories, it could be easier to use the highchart datetime axis. This would let you manipulate how you want the date displayed, have several series with different timestamps in one graph, and many other things. To get this to work, you could do this:
.then(function(res) {
var averageVoltage = []
var inputVoltage = []
for (var i = 0; i < 10; i++) {
if (res[i].average_volatage !== undefined) {
averageVoltage.push({x: new Date(res[i].timestamp).getTime(), y: parseInt(res[i].average_volatage)})
}
}
console.log(averageVoltage)
Highcharts.chart('battery_chart', {
chart: {
type: 'line'
},
title: {
text: id
},
yAxis: {
title: {
text: 'Measurement'
},
},
xAxis: {
type: 'datetime'
},
series: [{
name: 'Average Voltage',
data: averageVoltage
},
]
});

making large csv chartable by querying iso code in highcharts

I'm trying to load a csv and format it so it will display as a chart in highcharts, this is proving difficult because of the structure of the csv data.
Here is the csv: https://pastebin.com/Ynz7GJJh
Sample:
iso,type,year,affected
JAM,Earthquake,1907,90000
JAM,Storm,1912,94820
TON,Volcano,1946,2500
DZA,Earthquake,1954,129250
HTI,Storm,1954,250000
Here is my highcharts.ajax so far
var hsOptions = {
chart: {
type: 'column'
},
title: {
text: 'KEY NATURAL HAZARD STATISTICS'
},
subtitle: {
text: 'Number of People Affected'
},
xAxis: {
categories: []
},
yAxis: {
title: {
text: 'Units'
}
},
series: []
};
Highcharts.ajax({
url: '/pathto.csv',
dataType: 'text',
success: function(csv) {
var rows = csv.split(/\r\n|\n/);
var cell;
var series = [];
var seriesBuilder = {name: countryValue, data: []};
for (var i = 0; i < rows.length; i++) {
cell = rows[i].split(',');
if (cell[0] === countryValue){
seriesBuilder.data.push(cell);
}
}
console.log(seriesBuilder);
series.push(seriesBuilder);
hsOptions.series.push(series);
Highcharts.chart('hazard-stats', hsOptions);
},
error: function (e, t) {
console.error(e, t);
}
});
which does make this
But I need this to build a series per disaster type, then the years have to combine on their own axis... it should be able to render just like this:

Two highchart update issue

I have two line chart that are identical and use same data.
I have written an update code that update both the charts:
c2updateLineGraph(2,[[0, 105993],[25, 659727],[50, 648727],[75, 636627],[100, 636627]]);
function c2updateLineGraph(index,data)
{
c2chart1.series[index].setData(data, true);
c2chart1p.series[index].setData(data, true);
}
My data structure is:
var c2graphdata=[{
name: 'Current year',
data: []
},
{
name: 'Reapair v1',
data: []
},
{
name: 'Repair v2',
data: []
},
{
name: 'Replacement v1',
data: []
},
{
name: 'Replacement v2',
data: []
},
{
name: 'Facelift v1',
data: []
},
{
name: 'Facelift v2',
data: []
},
{
name: 'Reconstruction v1',
data: []
},
{
name: 'Reconstruction v2',
data: []
},
];
Issue is c2chart1 is getting updated, but not c2chart1p. Trick is if I swap the position of c2chart1 and c2chart1p, then c2chart1p get updated only.
I could replicate the issue here jsfiddle.net/hhh2zx3w Check after 8 secs only chart1 gets updated, not chart2
Reset the graph data and setting the data agin will work for you . just change
function c2updateLineGraph(index, data) {
c2chart1.series[index].setData(data, true);
c2chart1p.series[index].setData(c2graphdata, true); //reset the graph data
c2chart1p.series[index].setData(data, true);
}
Updated fiddle:
http://jsfiddle.net/hhh2zx3w/2/
Hope it helps

how to reload dataTable

I want to empty the table before processing. It's showing error.
Cannot read property 'aDataSort' of undefined.
i am calling like this: $('#fulltalktimepdata').dataTable().empty();
$.ajax({
type: "POST",
url: "/recharge_plan/",
data: {
'phone_no': phone_no
},
dataType: "json",
success: function(msg1) {
var fulltalktime_jsonString = msg1.fulltalktime_response_data;
var fulltalktime_temp_data = JSON.parse(fulltalktime_jsonString);
var fulltalktime_array_of_arrays = [];
$.each(fulltalktime_temp_data.data["FTT"], function(i, dataElem) {
fulltalktime_array_of_arrays.push([dataElem.amount, dataElem.detail, dataElem.validity, dataElem.talktime]);
});
console.log(fulltalktime_array_of_arrays);
$('#fulltalktimepdata').dataTable().empty();
$('#fulltalktimepdata').DataTable({
data: fulltalktime_array_of_arrays,
columns: [{
title: "AMOUNT"
},
{
title: "DETAIL"
},
{
title: "VALIDITY"
},
{
title: "TALKTIME"
}
]
});
}
});
Cannot read property 'aDataSort' of undefined

How can I get the value of a var whose value changes inside a function

how can i get the value of a varible whose value changes inside a function for example my var total is changing it's value inside the for which it's inside the load: function but I want to use the result in the Series name
var total = 0;
$scope.chartMedida = {
dataSource: {
load: function () {
var def = $.Deferred();
$http({ method: 'GET', url: ng.api + '/llantas/graficos/'+3}).success(function (data) {
def.resolve(data.data);
for(var i = 0; i<data.data.length; i++){
total = data.data[i].cantidad + total;
}
});
return def.promise();
}
},
palette: 'Soft',
series: {
argumentField: 'medida',
valueField: 'cantidad',
name:total.toString(),
type: 'bar'
},
title: {
text: 'Existencias por medida',
fontSize:4
},
tooltip: {
enabled: true
},
label: {
visible: true
}
};
I'm getting the value of the total var inside the for but I can't display the value out of it , In this example I'm using it on name:total.toString(), pls help for the best answer
try this
$scope.chartMedida = {
total:0,
dataSource: {
load: function () {
var def = $.Deferred();
$http({ method: 'GET', url: ng.api + '/llantas/graficos/'+3}).success(function (data) {
def.resolve(data.data);
for(var i = 0; i<data.data.length; i++){
$scope.chartMedida.total += data.data[i].cantidad;
}
});
return def.promise();
}
},
...
series: {
argumentField: 'medida',
valueField: 'cantidad',
name:$scope.chartMedida.total.toString(),
type: 'bar'
},
Try this instead
series: function() {
return {
argumentField: 'medida',
valueField: 'cantidad',
name:total,
type: 'bar'
}
}
This worked for me on a test page, but I had to use dummy data...
console.log($scope.chartMedida.series());
I think the internal value is being set on init, and then does not change. This way it gets the value when it's asked for it.
Here is a solution. Create a service and have the service set the value when the get data is returned.
I have made a sample Plunker to demonstrate the set up. For the demo purpose, I have stubbed out the processing logic because my get data is just a string.
var app = angular.module('plunker', []);
app.service('myService', function($http) {
this.dataSource = function(inObj) {
$http({
method: 'GET',
//url: ng.api + '/llantas/graficos/' + 3
url: 'myData.html'
})
.success(function(data) {
var total = "";
//for (var i = 0; i < data.data.length; i++) {
// total = data.data[i].cantidad + total;
//}
total = data;
inObj.chartMedida.series.name = total;
})
.error(function(data, status) {
alert("error" + data, status);
});
return "...waiting..."
};
});
app.controller('MainCtrl', function($scope, myService) {
$scope.chartMedida = {
palette: 'Soft',
series: {
argumentField: 'medida',
valueField: 'cantidad',
name: myService.dataSource($scope),
type: 'bar'
},
title: {
text: 'Existencias por medida',
fontSize: 4
},
tooltip: {
enabled: true
},
label: {
visible: true
}
};
});
Here is another answer if you don't want to create a service.
PLUNKER Answer
This one sets up an iife inline function to do the same thing. It just looks messier. In fact, it would be much cleaner to set up a factory for chartMedida and take it out of the controller completely.
app.controller('MainCtrl', function($scope, $http) {
$scope.chartMedida = {
palette: 'Soft',
series: {
argumentField: 'medida',
valueField: 'cantidad',
name: function() {
$http({
method: 'GET',
//url: ng.api + '/llantas/graficos/' + 3
url: 'myData.html'
})
.success(function(data) {
var total = "";
//for (var i = 0; i < data.data.length; i++) {
// total = data.data[i].cantidad + total;
//}
total = data;
$scope.chartMedida.series.name = total;
})
.error(function(data, status) {
alert("error" + data, status);
});
return "...waiting...";
}(),
type: 'bar'
},
title: {
text: 'Existencias por medida',
fontSize: 4
},
tooltip: {
enabled: true
},
label: {
visible: true
}
};
});

Categories