I not sure why d3.min() and d3.max() return the same result in the end. Here is the code:
var groupByAgeAndtime = d3.nest()
.key(function(d) { return d.age; })
//.key(function(d) { return d.time_in_hospital; })
.rollup(function(v) {
return{
mean_time_in_hospital : d3.mean(v, function(d){ return d.time_in_hospital;})
} })
.object(datapoints);
console.log(groupByAgeAndtime);
var radiusScale = d3.scaleSqrt().domain([d3.min(Object.keys(groupByAgeAndtime), function(d){
return groupByAgeAndtime[d];//minimum average time spent
}),d3.max(Object.keys(groupByAgeAndtime), function(d){
return groupByAgeAndtime[d];//maximum average time spent
})]).range([50,150])
console.log('Min: ',d3.min(Object.keys(groupByAgeAndtime), function(d){
return groupByAgeAndtime[d];//manimum average time spent
}));
console.log('Max: ',d3.max(Object.keys(groupByAgeAndtime), function(d){
return groupByAgeAndtime[d];//maximum average time spent
}));
Here is the screenshot of the console in Mozilla Firefox:
Screenshot
Hhere is the link for my jsfiddle: Link
Can anyone explain to me why it behave like that? Where did I do wrong in the code?
Object.keys returns an array of a given object's own property names.
Object.keys(groupByAgeAndtime) // return Array(3) [ "0-10", "10-20", "20-30" ]
When you accessor function returns groupByAgeAndtime[d] you get the value of each key:
{ mean_time_in_hospital: 1 }
{ mean_time_in_hospital: 2 }
{ mean_time_in_hospital: 6 }
...
As #jrook has pointed out, your function get the min/max base on the keys in that objects, that is always the same: mean_time_in_hospital.
Instead of the keys from your object you want the values and then to return the value of the mean_time_in_hospital key.
var groupByAgeAndtime = {
"0-10": {
mean_time_in_hospital: 1
},
"10-20": {
mean_time_in_hospital: 2
},
"20-30": {
mean_time_in_hospital: 6
},
};
console.log('Min: ', d3.min(Object.values(groupByAgeAndtime), function(d) {
return d.mean_time_in_hospital; //manimum average time spent
}));
console.log('Max: ', d3.max(Object.values(groupByAgeAndtime), function(d) {
return d.mean_time_in_hospital; //maximum average time spent
}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Related
Here is the fiddle for a stacked bar chart. This chart filters another line chart.
To remove empty bins, I tried dc.js FAQ, this example and this.
I saw this and this for a stacked bar chart scenario, but my grouping is different.
I've tried different things but I'm not able to get it to work.
Pretty sure I'm missing something simple.
Kindly review my code. Am I doing something wrong? How do i get the remove_empty_bins() working?
var stack = dc.barChart('#stack');
var XDimension = ndx.dimension(function (d) {return d.no;});
var YDimension_before = XDimension.group().reduce(
function(p, d) {
p[d.sub_no] = (p[d.sub_no]|| 0) + +d.avg;
return p;
},
function(p, d) {
p[d.sub_no] = (p[d.sub_no]|| 0) - +d.avg;
return p;
},
function() {
return {};});
var YDimension = remove_empty_bins(YDimension_before);
stack.width(550)
.height(400)
.dimension(XDimension)
.group(YDimension, '1', sel_stack(1))
.transitionDuration(500)
.xUnits(dc.units.ordinal)
.x(d3.scaleBand())
.margins({left: 80, top: 20, right: 80, bottom: 80})
.brushOn(false)
.clipPadding(20)
.elasticX(true)
.elasticY(true)
.title(function(d) {
return [ d.key + '[' + this.layer + '] ',
d.value[this.layer]].join('\n')
});
stack.stack(YDimension, '2', sel_stack(2))
.stack(YDimension, '3', sel_stack(3))
function remove_empty_bins(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
return d.value != 0;
});
}
};
}
I think the problem is that you are reducing to an object, so d.value never equals zero.
You could use Object.values and Array.some to check if any stack is non zero for each bin:
function remove_competely_empty_bins(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
return Object.values(d.value).some(v => v!=0);
});
}
};
}
Warning: dc.js isn't happy if the different stacks don't have the same x values. So that's why you wouldn't want to remove just the empty stacks. Only remove the bin if all the stacks are zero.
So I have a data.table object that is being outputed like this:
gender hair-color pets group1.totals group2.totals group3.totals
F black Y 10 0 0
F black Y 0 7 0
F black Y 0 0 8
How do I collapse it so that it will be like this?
gender hair-color pets group1.totals group2.totals group3.totals
F black Y 10 7 8
I have tried reducing the dimensions but it doesn't seem to work. My code is below:
ndx = crossfilter(data);
dataTable = dc.dataTable('#data-table');
var tableDim = ndx.dimension(function(d) {
return d.gender + "/" + d.hair-color + "/" + d.pets;
});
dataTable
.width(400)
.height(800)
.dimension(tableDim)
.group(function(d){
return "Data Counts";
}),
.columns([
function(d) {
return d.gender;
},
function(d) {
return d.hair-color;
},
function(d) {
return d.pets;
}
function(d) {
if (d.group == 1) return d.totals;
else return 0;
},
function(d) {
if (d.group == 2) return d.totals;
else return 0;
},
function(d) {
if (d.group == 3) return d.totals;
else return 0;
Essentially I know that I have to reduce and group my data but I can't find specifically what I have to do in order to achieve. Any help would be great, thanks!
Use the following code;
var ndx=crossfilter(data);
var dimension=ndx.dimension(function(d){return d.hair-color});
var dataByHairColor=dimension.group().reduceCount();
I hope it'll solve the problem. If you want other filtering option use that. I used hair color. Let me know if you are still facing issues
I'm trying to create a dashboard using dc.js and I want to customize how a data table is visualized. So my data looks something like this
agegroup gender group scores total
18-24 M 1 0.04 1
45-54 F 2 2.23 13
25-34 M 1 0.74 6
25-34 M 2 1.47 8
18-24 F 1 2.88 7
35-44 F 2 3.98 14
When I initialize a data table, it'll look the same as my original csv. However what if I want
agegroup gender group1.scores group1.total group2.scores group2.total
18-24 M 0.04 1 0.0 0
18-24 F 2.88 1 0.0 0
25-34 M 0.74 8 1.47 8
25-34 F 0.0 0 0.0 0
Here is how I initalize and set up my data table
dataTable = dc.dataTable('#data-table');
var tableDim = ndx.dimension(function(d) {
return d.gender;
});
dataTable
.width(400)
.height(800)
.dimension(tableDim)
.group(function(d){
return "Counts"
})
.size(20)
.columns([
function(d){
return d.gender;},
function(d){
return d.agegroup;
},
function(d){
return d.group;
},
function(d){
return d.scores;
},
function(d){
return d.total;
},
])
.order(d3.ascending)
.sortBy(function(d){
return d.gender;
});
I know that crossfilter allows you to filter and subset data quickly but I'm not sure how it'll function transforming datasets. Thanks!
So far, I was able to do this for now.
var tableDim = ndx.dimension(function (d) {
return d.agegroup;
});
var dataTable = dc.dataTable("#someTable");
dataTable.width(300).height(800)
.dimension(tableDim)
.group(function (d) {
return "Counts";
})
.columns([
function (d) {
return d.agegroup;
},
function (d) {
return d.gender;
},
function (d) {
if (d.group == 1) return d.scores;
else return 0;
},
function (d) {
if (d.group == 1) return d.total;
else return 0;
},
function (d) {
if (d.group == 2) return d.scores;
else return 0;
},
function (d) {
if (d.group == 2) return d.total;
else return 0;
}]);
dc.renderAll();
Here is the JSFiddle working with the above code. Use this or make a new one next time when you are asking for such solutions on SO.
Remember, using dc.dataTable you may not be able to reduce the number of rows in the data set. If you really want to reduce the number of rows you may try group().reduce() methods and create new fields for group1.total, group1.scores etc..
I ran into the exact same issue #SamSelikoff ran into here Update the y-axis of a brushed area chart. The example he was working off of was a single data series area chart here http://bl.ocks.org/mbostock/1667367 while i'm working on a multi-line chart like the one here http://bl.ocks.org/mbostock/3884955.
How do i adapt a data filter for the more complex data mapping in the multi line chart? i.e. with data mapped like so
var cities = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
And the y.domain set up like so
y.domain([
d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.temperature; }); }),
d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); })
]);
How do i create a filter similar to this (Sam's univariate data solution)
// Use x.domain to filter the data, then find the max and min duration of this new set, then set y.domain to that
x.domain(brush.empty() ? x2.domain() : brush.extent());
var dataFiltered = data.filter(function(d, i) {
if ( (d.date >= x.domain()[0]) && (d.date <= x.domain()[1]) ) {
return d.duration;
}
})
y.domain([0, d3.max(dataFiltered.map(function(d) { return d.duration; }))]);
I've tried putting a filter within the same syntax used for the min and max of the full data set's y-axis like so
x.domain(brush.empty() ? x2.domain() : brush.extent());
var testMin = d3.min(cities.filter(function(c) { return c.values, function(v) {if ( (v.dates >= x.domain()[0]) && (v.dates <= x.domain()[1]) ){ return v.temperature; } }}))
No luck so far. Any ideas?
Hope somebody can help me out because I can't find any reference about this error.
I was working on this piece of code:
var xMin = d3.min(data, function(d) { return d.value; });
var xMax = d3.max(data, function(d) { return d.value; });
if (0 > xMin & 0 > xMax) {
xMax = 0;
}
if (0 < xMin & 0 < xMax) {
xMin = 0;
}
x.domain(xMin, xMax).nice();
y.domain(data.map(function(d) { return d.label; }));
but I must have made some mistake cause now the loading blocks with the error message below in the web console:
"TypeError: t.map is not a function # http://d3js.org/d3.v3.min.js:2
.domain() takes an array as argument, i.e.
x.domain(xMin, xMax).nice();
should be
x.domain([xMin, xMax]).nice();
I had this error when I switched the mock data from an example.
var dataset = d3.layout.stack()(["CountPending", "CountDenied"].map(function (type) {
return data.map(function (d) {
return { x: d.Name, y: +d[type] };
});
}));
In my dataset the example data was using ["pending","denied"] while my real data used the following keys ["CountPending", "CountDenied"]
Use the right keys!
While this might not help the OP, I hope it helps someone.