ignoring a group with the D3 nest function - javascript

I have some data where, in a given column of a csv, there are six possible values:
1,2,3,4,5,NaN.
I am currently trying to group the data using the d3.nest and rollup functions. My goal is to group the data but exclude "NaN" values in the final output.
This is my current code:
var nested = d3.nest()
.key(function(d){return d[question];
})
.rollup(function(leaves){
var total = data.length
var responses = leaves.length;
return {
'responses' : responses,
'percent' : responses/total
};
})
.entries(data)
As you can see, I would like to return both a count of each of the categories as well as the percentage of the total that they represent. After removing NaN, I would also like the removal of NaN represented in percentage values of all of the other categories so that they sum to 100%.

The easiest way to do this is to remove the rows the contain NaN before passing the data to d3.nest():
var filtered = data.filter(function(d) { return d.question !== 'NaN'; });

Related

Get array of interested values from d3.nest() - D3JS

I used d3.nest() to group my data into category.
d3.nest()
.key(function(d) { return d[indexCateCol]; })
.entries(irisData);`
However, I'd like to know how can I make an array of value from the attribute that I am interested in.
(3) [Object, Object, Object]
0:Object
key:"setosa"
values:Array(50)
0:Array(5)
0:5.1
1:3.5
2:1.4
3:0.2
4:"setosa"
length:5
1:Array(5)
2:Array(5)`
In other words, what I want to produce is arrays of column that I'm interested for each Species like [5.1, 4.9, 4.7, 4.6, ...] for "Sepal.Length" or from '0: 5.1' from each array in value.
I believe that I can write a loop to get those arrays but there are any more JavaScript-ish ways to do this.
If you want to get the array of values for each species (from what I understand based on the data you're showing), you can do :
var myNest = d3.nest()
.key(function(d) { return d[indexCateCol]; })
.entries(irisData);`
/* Get the values of setosa as an array of arrays*/
var arrSetosa = myNest.setosa.values;
/* Get the 1st value of the 3rd "column" */
var val = arrSetosa[2][0];

Reshape data for D3 stacked bar chart

I have some csv data of the following format, that I have loaded with d3.csv():
Name, Group, Amount
Bill, A, 25
Bill, B, 35
Bill, C, 45
Joe, A, 5
Joe, B, 8
But as I understand from various examples, I need the data like this to use it in a stacked bar chart:
Name, AmountA, AmountB, AmountC
Bill, 25, 35, 45
Joe, 5, 8, NA
How can I transform my data appropriately in the js script? There is also the issue of missing data, as you can see in my example.
Thanks for any help.
Yes, you are correct that in order to use d3.stack your data needs re-shaping. You could use d3.nest to group the data by name, then construct an object for each group - but your missing data will cause issues.
Instead, I'd do the following. Parse the data:
var data = `Name,Group,Amount
Bill,A,25
Bill,B,35
Bill,C,45
Joe,A,5
Joe,B,8`;
var parsed = d3.csvParse(data);
Obtain an array of names and an array of groups:
// obtain unique names
var names = d3.nest()
.key(function(d) { return d.Name; })
.entries(parsed)
.map(function(d) { return d.key; });
// obtain unique groups
var groups = d3.nest()
.key(function(d) { return d.Group; })
.entries(parsed)
.map(function(d) { return d.key; });
(Note, this is using d3.nest to create an array of unique values. Other utility libraries such as underscore have a simpler mechanism for achieving this).
Next, iterate over each unique name and add the group value, using zero for the missing data:
var grouped = names.map(function(d) {
var item = {
name: d
};
groups.forEach(function(e) {
var itemForGroup = parsed.filter(function(f) {
return f.Group === e && f.Name === d;
});
if (itemForGroup.length) {
item[e] = Number(itemForGroup[0].Amount);
} else {
item[e] = 0;
}
})
return item;
})
This gives the data in the correct form for use with d3.stack.
Here's a codepen with the complete example:
https://codepen.io/ColinEberhardt/pen/BQbBoX
It also makes use of d3fc in order to make it easier to render the stacked series.

Creating stacked charts in dc js with panel dataset

I'm having trouble creating a stacked barchart, I cannot figure out how to properly apply the dimensions to a panel dataset
My data looks like this:
Date name value
12/1/15 name1 5
12/1/15 name2 6
12/1/15 name3 2
13/1/15 name1 2
13/1/15 name2 7
13/1/15 name3 8
14/1/15 name1 2
14/1/15 name2 5
14/1/15 name3 10
Stored in JSON format
I would like to create stacked charts that plot the values associated with the different names over time.
As I understand dc-js I need to provide a chart with the date dimension, and then another dimension by the different names which then groups the values, however I am unsure how to proceed.
Does anyone know how I can do this with?
Here's how to produce the group, from the FAQ:
var group = dimension.group().reduce(
function(p, v) { // add
p[v.type] = (p[v.type] || 0) + v.value;
return p;
},
function(p, v) { // remove
p[v.type] -= v.value;
return p;
},
function() { // initial
return {};
});
(In your case, v.name instead of v.type.)
Basically you create a group which reduces to objects containing the values for each stack.
Then use the name and accessor parameters of .group() and .stack(). Unfortunately you have to spell it out, as the first has to be .group and the rest .stack.
As so:
chart.group(group, 'name1', function(d) { return d.name1; })
.stack(group, 'name2', function(d) { return d.name2; })
.stack(group, 'name3', function(d) { return d.name3; })
...
(Somewhere on SO or the web is a loop form of this, but I can't find it ATM.)

Merge two object arrays for Chart

I've two arrays which I'm going to merge and then load in chart.
range = date array generated from moment.js, there is date of every day in example one month or specific date range with one another attribute count: "0"
data = fetched data from database through backbone
Now I want set atrribute count from data count, where date is same in both arrays.
I'm using lodash...
_.forEach(range, function(n) {
console.log(n.date.substring(0, date.length-6));
// IF n.date = date from data replace count to value from data array
});
Thanks for any help
You can use _.find to match your items in the range to the ones in the data.
_.forEach(range, function(r) {
var d = _.find(data, {date: r.date}); //Find an item in "data" with date matching r.date
if(d) {
r.count = d.count;
}
});

Applying a date range filter to a crossfilter dimension

I'm attempting to use the crossfilter javascript library (in conjunction with D3.js) to group and filter json data.
My json data has the following fields: week_date, category, team_name, title, subtitle
I've been able to successfully group on all records to produce YTD totals, using something like this:
var dimension = data.dimension(function(d) { return d[target]; });
var dimensionGrouped = dimension.group().all();
Where target is either category or team_name.
In addition to keeping the YTD totals, I also want to display totals for a given range. For example, a user-selected week (i.e. Oct 1st - 5th).
How do I create a filtered group which returns the totals for a given date range? Using my week_date field.
Well, after some superficial research, including skimming over crossfilter's issues list, I've concluded that crossfilter does not currently support grouping on multiple fields.
I was able to work around this by using a filtered copy of the data instead, as such:
// YTD rows
var crossfilterData = crossfilter(data);
var ytdDimension = crossfilterData.dimension(function(d) { return d[target]; });
var ytdDimensionGrouped = ytdDimension.group().all();
ytdDimensionGrouped.forEach(function (item) {
// ...
});
// Ranged rows
var filteredData = data.filter(function (d) {
return d.week_date >= filter[0] && d.week_date <= filter[1];
});
crossfilterData = crossfilter(filteredData);
var rangeDimension = crossfilterData.dimension(function(d) { return d[target]; });
var rangeDimensionGrouped = rangeDimension.group().all();
rangeDimensionGrouped.forEach(function (item) {
// ...
});

Categories

Resources