d3.js convert data using nest - javascript

I'm trying out d3.js for the first time and trying the stacked to grouped bars example.
My data is in the following format:
var data = [
{"year":2015, values:[1,2,3]},
{"year":2016, values:[10,20,30]},
{"year":2017, values:[100,200,300]}
];
I would like the x-axis to be year and the y-axis to be the values.
I am having trouble determining which parts of the api to use. Do I use nest, map, or both?
I need the data to be graphed as value1 (1,10,100), value2 (2,20,200), and value3 (3,30,300)
Thanks

Your data is like this
var data = [
{"year":2015, values:[1,2,3]},
{"year":2016, values:[10,20,30]},
{"year":2017, values:[100,200,300]}
];
Need a paser to parse your date
parse = d3.time.format("%Y").parse;
next group the data
//[0,1,2] index of the array so that the y can be calculated as d.values[grp]..here grp will be group which will have value 0 1 2
var newData = d3.layout.stack()([0,1,2].map(function(grp) {
return data.map(function(d) {
return {x: parse("" +d.year), y: +d.values[grp]};
});
}));
This will make the newData in the format you wish:
[[{"x":"2014-12-31T18:30:00.000Z","y":1,"y0":0},
{"x":"2015-12-31T18:30:00.000Z","y":10,"y0":0},
{"x":"2016-12-31T18:30:00.000Z","y":100,"y0":0}],
[{"x":"2014-12-31T18:30:00.000Z","y":2,"y0":1},
{"x":"2015-12-31T18:30:00.000Z","y":20,"y0":10},
{"x":"2016-12-31T18:30:00.000Z","y":200,"y0":100}],
[{"x":"2014-12-31T18:30:00.000Z","y":3,"y0":3},
{"x":"2015-12-31T18:30:00.000Z","y":30,"y0":30},
{"x":"2016-12-31T18:30:00.000Z","y":300,"y0":300}]]
Hope this helps!
Working sample here

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.

D3 sorting with an ordinal scale and selecting top 5

I am trying to sort then select the top 5 in a D3 chart.
I have two series: "OL" and "NOL". The first thing I want to be able to do is to sort and have the labels match on the y axis. The second thing I want to do is to only show the top 5 with the two series still together udner one name in the y axis.
jsfiddle
Data is like so:
var values = feature.properties;
var data = [
{key: "N11", name:"N11OL",value:values["N11OL"]},
{key: "N11", name:"N11NOL",value:values["N11NOL"]},
{key: "N21", name:"N21OL",value:values["N21OL"]},
{key: "N21", name:"N21NOL",value:values["N21NOL"]},
{key: "N22", name:"N22OL",value:values["N22OL"]},
{key: "N22", name:"N22NOL",value:values["N22NOL"]},
{key: "N23", name:"N23OL",value:values["N23OL"]},
{key: "N23", name:"N23NOL",value:values["N23NOL"]},
{key: "N31-33", name:"N31_33OL",value:values["N31_33OL"]},
{key: "N31-33", name:"N31_33NOL",value:values["N31_33NOL"]},
{key: "N41", name:"N41OL",value:values["N41OL"]},
{key: "N41", name:"N41NOL",value:values["N41NOL"]}
];
Right now, the chart works before I sort the bars. When I sort the data with the code below, the ordinal domain doesn't match the bars anymore.
data.sort(function (a, b) {
return d3.ascending(a.value, b.value);
});
I could use
domain(data.map(function(d) { return d.name; }))`
});
to get the names from the data to show on the axis but I want "OL" and "NOL" series to be under one name: N11, etc. not show with all bars. That is why I have set a domain with :
.domain(["NAICS11", "NAICS21", "NAICS22", "NAICS23", "NAICS31-33", "NAICS41"])
That is half of the problem. Once I have sorted and the names are matching with the axis, I would like to have only the top 5 for both series.
I would be very grateful for any suggestions on how to do this.
EDIT I added a key to the data for the pairs and modified the D3 code. I feel this will make it easier going forward to get this chart where I want it.
How about:
// create temporary array with data grouped by
// the first part of our name (cut off the OL/NOL)
var tmp = d3.nest().key(function(d){
return d.name.substring(0, 3);
}).entries(data);
// sort this array descending with the max of our
// now "paired" entries
tmp.sort(function(a,b){
return (d3.max([a.values[0].value,
a.values[1].value]) >
d3.max([b.values[0].value,
b.values[1].value])) ? -1 : 1;
});
// loop our tmp array and
// flatten the data back out
// also use our substring names to for the domain
data = [];
domain = [];
tmp.forEach(function(d){
domain.push(d.key);
data.push(d.values[0]);
data.push(d.values[1]);
});
Updated fiddle.

Create table from data with multiple values for each property using d3.js

I have data being read in from a .csv file. I think find the min and max values and save them into a variable with the format like this:
min_max = {"a":[1,10],"b":[11,20],"c":[21,30]}
Where the first value for each property is the min and the second value is the max. I want to create a table of the min and max values for the data. Since the .csv is dynamic and will not always have the same headers, I cannot use something like min_max.a ect. I need to have the table be dynamic.
Edit
I should add in that the min and max values are obtained using the following code. If there is a better way to do this, please enlighten me. I am new to object oriented coding and haven't found another way to find all min and max values for each property within the data file.
var data_v2 = [
{"a":5,"b":480,"c":250,"d":100,"e":220},
{"a":1,"b":90,"c":50,"d":33,"e":88}
];
var x = d3.scale.ordinal().rangePoints([0, w], 1),
y = {};
y.max={};
x.domain(dimensions = d3.keys(data[0]).filter(function(d) {
return (min_max[d] = d3.extent(data, function(p) { return +p[d]; }));
}));

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.

Categories