I have this json Format
var personArray =
[
{name:"person1",code:"101011",mainDept:"mainD 1",dept:"dept1",SubDept:"Sub01"},
{name:"person2",code:"201012",mainDept:"mainD 1",dept:"dept1",SubDept:"Sub11"},
{name:"person3",code:"301013",mainDept:"mainD 1",dept:"dept2",SubDept:"Sub12"},
{name:"person4",code:"401014",mainDept:"mainD 1",dept:"dept2",SubDept:"Sub12"},
{name:"person5",code:"501015",mainDept:"mainD 1",dept:"dept2",SubDept:"Sub13"},
{name:"person6",code:"601116",mainDept:"mainD 1",dept:"dept3",SubDept:"Sub21"},
{name:"person7",code:"701117",mainDept:"mainD 1",dept:"dept3",SubDept:"Sub21"},
{name:"person8",code:"801118",mainDept:"mainD 1",dept:"dept4",SubDept:"Sub22"},
{name:"person9",code:"901119",mainDept:"mainD 2",dept:"dept12",SubDept:"Sub23"},
{name:"person10",code:"101111",mainDept:"mainD 2",dept:"dept12",SubDept:"Sub24"},
{name:"person12",code:"121012",mainDept:"mainD 2",dept:"dept13",SubDept:"Sub25"},
{name:"person13",code:"131013",mainDept:"mainD 2",dept:"dept131",SubDept:"Sub26"},
{name:"person14",code:"141014",mainDept:"mainD 3",dept:"dept132",SubDept:"Sub27"},
{name:"person15",code:"151015",mainDept:"mainD 3",dept:"dept132",SubDept:"Sub27"},
{name:"person16",code:"161116",mainDept:"mainD 4",dept:"dept141",SubDept:"Sub1"},
{name:"person17",code:"171117",mainDept:"mainD 4",dept:"dept141",SubDept:"Sub1"},
{name:"person18",code:"181118",mainDept:"mainD 4",dept:"dept141",SubDept:"Sub1"},
{name:"person21",code:"211012",mainDept:"mainD 4",dept:"dept141",SubDept:"Sub1"},
{name:"person22",code:"221013",mainDept:"mainD 4",dept:"dept141",SubDept:"Sub001"},
{name:"person23",code:"231014",mainDept:"mainD 4",dept:"dept151",SubDept:"Sub002"},
{name:"person24",code:"241015",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"},
{name:"person25",code:"251116",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"},
{name:"person26",code:"261117",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"},
{name:"person27",code:"271118",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"},
{name:"person28",code:"281119",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"},
{name:"person29",code:"291119",mainDept:"mainD 5",dept:"dept161",SubDept:"Sub003"}];
and i want to build data for jsTree (https://www.jstree.com/docs/json/)
multi level grouping will be like this i.e mainDept -> dept - > SubDept - > person
i tried this to get one level grouping but cant figure out how to get multi level grouping.
var linq = Enumerable.From(personArray);
var grp = linq.GroupBy("$.mainDept","{text:$.dept}","{name:$,children:$$.ToArray()}").ToArray()
There really isn't a nice way to an arbitrarily deeply nested grouping, particularly if you need to do something different at each level. Doing some sort of recursion makes this simple. Fortunately Linq.js has a Let() function to allow for this. With some specially crafted functions, this could be done rather nicely.
function grouper(propertyName, selector) {
return function (e) {
return e.GroupBy("$." + propertyName, null, function (k, g) {
return {
text: k,
children: g.Let(selector).ToArray()
};
});
};
}
var items = Enumerable.From(personArray)
.Let(grouper('mainDept', function (g1) {
return g1.Let(grouper('dept', function (g2) {
return g2.Let(grouper('SubDept', function (g3) {
return g3.Select("$.name").ToArray();
}));
}));
}))
.ToArray();
fiddle
For a different approach, you utilize jstree's alternate form of coming up with the parent/child relationships. You don't need to nest anything anymore, just come up with a flat list of the config nodes.
var items = Enumerable.From(personArray)
.Let(function (e) {
var roots = { '#': {}, mainDept: {}, dept: {}, SubDept: {} };
e.ForEach(function (p) {
roots['#'][p.mainDept] = '#';
roots['mainDept'][p.dept] = p.mainDept;
roots['dept'][p.SubDept] = p.dept;
roots['SubDept'][p.name] = p.SubDept;
});
function makeNode(root) {
return Enumerable.From(roots[root]).Select("{ parent: $.Value, id: $.Key, text: $.Key }");
}
return makeNode('#').Concat(makeNode('mainDept')).Concat(makeNode('dept')).Concat(makeNode('SubDept'));
})
.ToArray();
fiddle
First you have to parse your personArray into json acceptable by jsTree and then feed it to jsTree initialisation. I can't help you with linq, but with plain javascript it could work like in this demo - Fiddle.
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'; });
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.)
I am working on a d3.js visualization for a time reporting application.
I have row data in an array actuals containing project time reports (simplified):
[{ resource: "John Smith",
reporting_period: "2012/04/1",
project: "Java implementation",
hours: 8}
... }]
I am trying to use the d3.nest operator to group the project actuals hierarchically by project, resource and period. Everything works great but I cannot find a way to get the subtotals of hours at the intermediate levels of the grouping using the nest.rollup() operator.
I have something like:
actuals_by_prj_rsrc_period = d3.nest()
.key(function(d) { return d["project"]; })
.key(function(d) { return d["resource"]; })
.key(function(d) { return d["reporting_period"]; })
.rollup(function(rows) {return {
tot_hours:d3.sum(rows, function(d) {return d["hours"];}),
actuals: rows
};})
.entries(actuals);
but it returns tot_hours only at the leaf level.
Any advice on how to approach this using only d3.nest?
from docs:
nest.rollup(function)
Specifies a rollup function to be applied on each group of leaf
elements. The return value of the rollup function will replace the
array of leaf values in either the associative array returned by the
map operator, or the values attribute of each entry returned by the
entries operator.
As you can see rollup works with leaf elements. You could bypass this by having data nested at multiple levels:
function nest(keys, data, rollupFunc) {
var nst = d3.nest();
keys.forEach(function(key) {
nst.key(function(d) { return d[key]; });
});
if (rollupFunc) {
nst.rollup(rollupFunc);
}
return nst.entries(data);
}
var rollupFunction = function(d) {
return {
"total_hours": d3.sum(d, function(dd) { return dd["hours"]})
}
}
var rez1 = nest(["project", "resource"], actuals);
var rez2 = nest(["project"], actuals, rollupFunction);
var rez3 = nest(["project", "resource"], actuals, rollupFunction);
But this very inefficient for larger data sets. Otherwise I would suggest using nest() function to create all intermediate levels. Then you could aggregate total hours using your own recursive function. Pseudocode:
function aggregate(node) {
if (node has property total_hours) {
return total_hours
}
sum = 0
foreach child in data.values {
sum += aggregate(child)
}
node.total_hours = sum
return node.total_hours
}
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) {
// ...
});