jQuery pushing additional calculated data points to HighChart series - javascript

I am trying to push data points to a data series array for HighCharts. I have started with the standard pie template. I have then added additional $.get statements to calculate the number of lines in the files.
The alert statement on each additional $.get returns the correct number of lines, but the data point is not pushed to the series.
Can anyone help me, I am new to JQuery. Thanks.
$.get('piechart.csv', function(data) {
// Split the lines
var buttons
var lines = data.split('\n');
var series = {
data: []
};
// Iterate over the lines and add categories or series
$.each(lines, function(lineNo,line) {
var items = line.split(',');
series.data.push({
name: items[0],
y:parseFloat(items[1])
});
});
$.get('button0.txt', function(data) {
// Split the lines
var lines = data.split('\n');
series.data.push({
name: 'Power off',
y: (lines.length-1)
});
alert (lines.length-1);
});
$.get('button1.txt', function(data) {
// Split the lines
var lines = data.split('\n');
series.data.push({
name: 'Power on',
y: (lines.length-1)
});
alert (lines.length-1);
});
options.series.push(series);
// Create the chart
var chart = new Highcharts.Chart(options);
});

The data point is, I would assume, being pushed to the series, but the problem lies in the fact that this doesn't happen until after you have already created and rendered your chart instance.
Leaving aside the fact that I don't see a declaration of the options variable in your code, which would suggest that there might be another bug lurking (but I'm assuming that's just a typo?), the problem lies in the fact that HighCharts doesn't do anything to track the initial series that you pass it, so modifying that series isn't going to affect the chart.
You'll need to update the chart yourself - using, for example, the addPoint method of the HighCharts series object. So, in the success callback for your Ajax calls, you'll need to do something along the lines of:
$.get('button0.txt', function(data) {
// Split the lines
var lines = data.split('\n'),
chart = $('#container').highcharts();
chart.series[0].addPoint({
name: 'Power off',
y: lines.length-1
});
});

Related

How to display Dynamic Object Arrays into chart using Anychart.js

What i am trying to do is i want to display a chart based on my dynamic data i used Angular ForEach to loop through all my objects array see my code below:
var parse = JSON.parse(jsondata);
angular.forEach(parse, function (value, key) {
var dataSet = anychart.data.set(value);
var chart = anychart.column();
var series = chart.column(value);
chart.title("Data Sets: Array of Objects");
chart.container("container");
chart.draw();
});
it correctly display the count of my chart but the data of each object array is not showing up see picture below
but if put a static data like this :
var data = [
{x:"January", value: 12000},
{x:"February", value: 15000},
{x:"March", value: 16000},
{x:"April", value: 14000},
{x:"May", value: 10000}
];
the chart displays correctly.
can anyone help me with this ? any help will greatly appreciated.
Everything depends on the value content inside the loop. You are applying the value to the series and dataSet as well.
If you are using dataSet, you should apply the value to the dataSet, map the data, then apply the mapping to the series. Like this:
var dataSet = anychart.data.set(value);
var mapping = dataSet.mapAs({'x': 0, 'value': 1}); // for example
var chart = anychart.column();
var series = chart.column(dataSet);
The mapping depends on your data. If the value includes ready-to-use data that matches the default mapping you can apply it directly to the series.
Can you share the value content?
The chart can work with dynamic data. All you need is to apply new data to the existing dataSet, like this:
dataSet.data(newData);
And that's it! There's no need to recreate chart/series/dataSet.

Highcharts (Highstock): Get data from external CSV, doesn't display date correctly

I'm trying for days now to get Highstock working with an external CSV file. The issue was first that the imported file was sorted in "descending" order whereas Highcharts requires the data to be sorted in "ascending" order. Once I found a JSFiddle/Codepen close to my problem, I managed to display the data correctly.
Now the problem is that on the x-axis the dates are displayed as something like 00:00:00.500 whereas it should be looking like this 2016-03-11.
I have created a codepen since it may be easier for you to respond to it than copy/pasting here a lot of code: http://codepen.io/bauhausweb/pen/aNpbxg
Thanks for looking into my issue!
For your example, there seems to at least be the problem of 2016-03-11 simply being a string and not a timestamp in milliseconds, which causes it to chose the defaults of 0, 1, 2, ... as x-values instead.
Below I've provided an example of how you can use the data modules csv attribute to achieve a similar result, with the help of the complete function:
$(function () {
$.get("https://www.example.com/my.csv", function (csv) {
$('#container').highcharts('StockChart', {
data: {
complete: function(o) {
o.series[0].data.reverse();
},
csv: csv
}
});
});
});
Or look at this JSFiddle demonstration.
Try to do something like this:
$.each(lines, function (lineNo, line) {
if (lineNo > 0 && lineNo < 557) {
var items = line.split(',');
// var seriesname = String(items[0]); // this is the area name
var seriesname = "Gold"; // this is the area name
var price = parseFloat(items[1]);
var f_date = items[0];
var format = String(f_date.replace(/-/g,','));
var date_items = format.split(',');
var d = Date.UTC(date_items[0],date_items[1],date_items[2]);
console.log(d);
var date = d;
// this will be the id of the drilldown
// var shift_one_value = parseFloat(items[3]); // drilldown shift1 value
// var shift_two_value = parseFloat(items[4]); // drilldown shift2 value
series.data.push({
name: seriesname,
y: price,
x: date
});
}
});
The problem is the date it would be formated in UTC
Your code has a lot of oddities. Your xAxis is set to datetime which is good. With a point interval of one day - also good. But, if you look at your series.data you are sending in data formatted like:
{
name: "Gold",
x: "1233.6",
y: 1233.6
}
You are setting the y here:
var date = String(items[1]);
You should be using items[0]. Now, you also have to parse this string into javascript time. Something like this can work:
var arr = String(items[0]).split("-");
var date = Date.UTC(arr[0], arr[1], arr[2]);
However, now your chart throws error that date is not sorted. See updated pen here.

dc.js: extending line and area to end of chart

I'm trying to draw an area chart using dc.js, and the end date (i.e. far right) of the chart is based on the current date, not the last date in the dataset. In cases where there's a date gap between data points, I want the area to extend from one point to the next, not draw at 0.
Given this data:
var data = [
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "6/1/2014", lines_added: 100, lines_deleted: 50},
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "7/1/2014", lines_added: 100, lines_deleted: 50}
];
var ndx = crossfilter(data);
The chart's line/area currently ends at the "7/1/2014" data point, but I want it to stretch the entire length of the chart.
The relevant code for drawing the chart is:
var dateDim = ndx.dimension(function(d) {return d.commit_date;});
var minDate = dateDim.bottom(1)[0].commit_date;
var maxDate = new Date();
var domainGroup = dateDim.group().reduceSum(function(d) {return d.cumulative_lines;});
unshippedlineChart
.width(500).height(200)
.dimension(dateDim)
.group(domainGroup)
.renderArea(true)
.x(d3.time.scale().domain([minDate,maxDate]))
.brushOn(false)
.interpolate('step-after')
.yAxisLabel("Unshipped Value");
Full example is at http://jsfiddle.net/xayhkcvn/1/
You didn't actually ask a question :-), but I think you may be looking for ways to prefilter your data so that it gets extended to today, and to remove any zeros.
This stuff isn't built into dc.js, but there is some example code in the FAQ which may help. Specifically, there is a function remove_empty_bins which adapts a group to remove any zeros.
You could similarly define a function to add a final point (untested):
function duplicate_final_bin(source_group, key) {
return {
all:function () {
var ret = Array.prototype.slice.call(source_group.all()); // copy array
if(!ret.length) return ret;
ret.push({key: key, value: ret[ret.length-1].value});
return ret;
}
};
}
You can compose this with remove_empty_bins:
var super_group = duplicate_final_bin(remove_empty_bins(domainGroup), maxDate);
The idea is to create a wrapper object which dynamically adds or remove stuff from the (always changing) source_group.all() on demand. dc.js will call group.all() whenever it is redrawing, and these wrappers intercept that call and adapt the data the crossfilter group returns.

updating a line graph in d3 is not working

i am trying to update a line graph and it is not throwing any error but it is also not updating the graph.
i am deleting a point and adding a new one with an incremented rate and incremented created_at date by a second(trying to follow http://bl.ocks.org/benjchristensen/1148374)
function redrawWithoutAnimation() {
for (var i in chart_data) {
linedata = chart_data[i];
//delete first element of array
linedata.points.reverse().shift();
//create a new point
rate = linedata.points[0].rate + 1;
created_at = linedata.points[0].created_at + 6000;
new_point = {};
new_point.rate = rate;
new_point.created_at = created_at;
linedata.points.push(new_point);
console.log(linedata);
}
// static update without animation
svg.selectAll("path")
.data([linedata.points]); // set the new data
line(linedata.points); // apply the new data values
}
redrawWithoutAnimation();
setInterval(function () {
redrawWithoutAnimation();
}, 8000);
here is my code
http://jsfiddle.net/yr2Nw/8/
Working fiddle: http://jsfiddle.net/reblace/GsaGb/1
There's a few issues here...
First, you were updating all the chart_data in the for loop, but outside the loop, you were only trying to update the line still stored in the linedata variable after loop execution. You should try to avoid having variables with greater scope than they need. It can lead to bugs like this one:
svg.selectAll("path").data([linedata.points]);
line(linedata.points);
You should instead use D3's data joining to rejoin the new data to all the paths at once declaratively like so:
linesGroup.selectAll("path")
.data(chart_data)
.attr("d", function(d){ return line(d.points); });
What that code's doing is it's selecting the paths and then joining each of them to the chart_data elements and then binding the appropriate line generator to the "d" attribute for the appropriate path.
Then, you need to update your x axis and y axis otherwise the plot will just shoot off the drawn area. This code is updating the domains and then rebinding the axes to the dom elements so they redraw:
xAxis.scale().domain([
d3.min(chart_data, function (c) { return d3.min(c.points, function (v) { return v.created_at; }); }),
d3.max(chart_data, function (c) { return d3.max(c.points, function (v) { return v.created_at; }); })
]);
yAxis.scale().domain([
0,
d3.max(chart_data, function (c) { return d3.max(c.points, function (v) { return v.rate; }); })
]);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
There were a few other bugs I fixed them in the Fiddle. For example, you need to calculate the time for the new point based on the last element in the array, not the first, otherwise the line can't interpolate properly since its no longer a continuous function... and this is a bit more concise way to do your line updates:
for (var i=0; i<chart_data.length; i++) {
linedata = chart_data[i];
//delete first element of array
var removedPoint = linedata.points.shift();
//create a new point
var lastpoint = linedata.points[linedata.points.length-1];
var new_point = {
rate: removedPoint.rate,
created_at: lastpoint.created_at + 6000
};
linedata.points.push(new_point);
}
Also note that you shouldn't use the for(var in) loop for Arrays, that's for iterating over the properties in an object.
There's still some issues, but I think this should help get you over the hurdle you were stuck on. Anyways, it looks cool in action!
Fine fenac.. You facing so many problems since your data is not in good format for your requirements..
as per http://bl.ocks.org/benjchristensen/1148374 The x-axis data must be (data[] (data array))
Your data is something like this
[objects,object,object] where each object holds one element of xaxis value.. so the pushing and shifting is not possible..
try to change the format of the data (linedata.points) to an array (data[]) and try it out sure it works..
You just need to put all the values in linedata.points into an array data[] and use this data[] to animate your line..
Since yours the multiline.. you need to create 2D array and must pass them accordingly...
Cheers..
I updated your jsfiddle
setInterval(function () {
console.log(linedata.points);
var v = linedata.points.shift(); // remove the first element of the array
linedata.points.push(v); // add a new element to the array (we're just taking the number we just shifted off the front and appending to the end)
redrawWithoutAnimation();
}, 3000);
http://jsfiddle.net/yr2Nw/9/
But still it wont works till you do that work...
Personal Suggestion: First Try with single line graph then go with looping for multiline...

highcharts: attempting to create dual-pane chart with data imported from csv

Here's my problem. I can successfully import data from a CSV, parse it, and load it into one chart. What I can't do is create a dual-paned chart using two separate sets of data, both contained in their own variable. Here's a JS Fiddle of the complete code so far.
I parse my data like this:
//parsing the csv into series
function createseries(csv, csv2){
var lines = csv.split('\n'), //separates the lines
series = [];
$.each(lines, function(i, line){
item=line.split(',');
if ( typeof series[item[0]] !== 'object') {
series[item[0]] = series[series.length] = {
type: 'scatter',
name: item[0], //places name, either male or female, as category
data: [],
}
}
series[item[0]].data.push({
y: parseInt(item[1]), //places int in y value
x: parseDate(item[2]), //calls the date function, formats it, places it in x
});
});
var lines2 = csv2.split('\n'), //separates the lines
series2 = [];
$.each(lines2, function(i, line){
item=line.split(',');
if ( typeof series2[item[0]] !== 'object') {
series2[item[0]] = series2[series2.length] = {
name: item[0], //places name, either male or female, as category
data: [],
}
}
series2[item[0]].data.push({
y: parseInt(item[1]), //places int in y value
x: parseDate(item[2]), //calls the date function, formats it, places it in x
});
});
This leaves me with two variables, series, and series 1. If I build the chart using the following code, I get the first series variable plotted.
}],
series: series
});
}
createseries(data, data2);
But I'm not sure how to get series2 to be plotted on a different pane. Any suggestions? I have a feeling it might be something simple, but I just can't figure it out.

Categories