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>
I am working on this pie-chart in D3.js.
This is the data:
DATA.JSON
[
{
"key":"amministrazione",
"categoria":"funzioni",
"val2015":404571081,
"val2013":374545999
},
{
"key":"sociale",
"categoria":"funzioni",
"val2015":235251679,
"val2013":258973653
},
{
"key":"territorio e ambiente",
"categoria":"funzioni",
"val2015":286164667,
"val2013":274949400
},
{
"key":"viabilità e trasporti",
"categoria":"funzioni",
"val2015":144185664,
"val2013":140619534
},
{
"key":"istruzione",
"categoria":"funzioni",
"val2015":168774925,
"val2013":170016208
},
{
"key":"cultura",
"categoria":"funzioni",
"val2015":55868045,
"val2013":55735535
},
{
"key":"sport",
"categoria":"funzioni",
"val2015":27219432,
"val2013":31244800
},
{
"key":"turismo",
"categoria":"funzioni",
"val2015":9544845,
"val2013":7674419
},
{
"key":"sviluppo economico",
"categoria":"funzioni",
"val2015":14790363,
"val2013":16635868
},
{
"key":"servizi produttivi",
"categoria":"funzioni",
"val2015":4334,
"val2013":4440
},
{
"key":"polizia locale",
"categoria":"funzioni",
"val2015":99007202,
"val2013":102065987
},
{
"key":"giustizia",
"categoria":"funzioni",
"val2015":12147068,
"val2013":12880138
},
{
"key":"anticipazioni di cassa",
"categoria":"rimborso prestiti",
"val2015":304323808,
"val2013":304323808
},
{
"key":"finanziamenti a breve termine",
"categoria":"rimborso prestiti",
"val2015":0,
"val2013":0
},
{
"key":"prestiti obbligazionari",
"categoria":"rimborso prestiti",
"val2015":38842996,
"val2013":36652213
},
{
"key":"quota capitale di debiti pluriennali",
"categoria":"rimborso prestiti",
"val2015":0,
"val2013":47152
},
{
"key":"quota capitale di mutui e prestiti",
"categoria":"rimborso prestiti",
"val2015":128508755,
"val2013":329885961
},
{
"key":"spese per conto terzi",
"categoria":"altro",
"val2015":232661261,
"val2013":236921438
},
{
"key":"disavanzo di amministrazione",
"categoria":"altro",
"val2015":0,
"val2013":0
}
]
It shows how the governmental budget is allocated to different functions (i.e. "key"). A value is given for each year (e.g. "val2015", "val2013") and each function is part of a macro-category (i.e. "funzioni", "rimborso prestiti", or "altro").
I am trying to create a color() function that dynamically changes its domain and range depending on:
the colorRange arbitrarily assigned as domain: greenRange for "funzioni", redRange for "rimborso prestiti" and blueRange for "altro"
the number of functions ("key") in each category that have a positive value, thus ignoring functions for which no resources were allocate during a given year. Done through the count() function (which works)
Then creates X number of shades for each ranging depending on the count() function of point 2
And assigns the appropriate color to each of the pie's wedges
This is my starting point:
var greenRange = ["rgb(199,233,192)", "rgb(0,68,27)"]; //range for the first 12 wedges of the pie (assuming they are all >0)
var redRange = ["rgb(252,187,161)", "rgb(103,0,13)"]; //range for the following 5 wedges of the pie (same assumption)
var blueRange = ["rgb(198,219,239)", "rgb(8,48,107)"]; //range for the last 3 wedges of the pie (same assumption)
I tried two options but neither works.
OPTION 1
function draw () {
//(1) count the number of data points with value > 0 in each category - This works well!
var countFunzioni=0;
dataset.forEach (function (d) {if (d.categoria=="funzioni" && d.val2015>0) { countFunzioni += 1;}})
var countRimborso=0;
dataset.forEach (function (d) {if (d.categoria=="rimborso prestiti" && d.val2015>0) { countRimborso += 1;}})
var countAltro=0;
dataset.forEach (function (d) {if (d.categoria=="altro" && d.val2015>0) { countAltro += 1;}})
//(2) create a color method for each category based on a the count calculated above and the range I determined
var colorFunzioni = d3.scale.linear()
.domain([0, countFunzioni])
.range(redRange);
var colorRimborso = d3.scale.linear()
.domain([0, countRimborso])
.range(redRange);
var colorAltro = d3.scale.linear()
.domain([0, countAltro])
.range(blueRange);
//draw the chart
chart = d3.select("#visualizationInner")
.append("svg")
.attr("id", "visualization")
.attr("width", w)
.attr("height", h)
.append("g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
//draw and color the paths
var path = chart.datum(dataset).selectAll("path")
.data(pie)
.enter()
.append("path")
//(3) return the appropriate color method depending on the datum's category
.attr("fill", function(d, i) {
if (d.data.categoria=="funzioni") {return colorFunzioni(i);}
else if (d.data.categoria=="rimborso prestiti") {return colorRimborso(i);}
else if (d.data.categoria=="altro") {return colorAltro(i);}
})
.style("fill-opacity", 0.75)
.attr("d", arc);
}
Which returns this result:
This goes close, however it assigns a range of red colors to the first 12 wedges (which should get the greenRange instead) and no color to the wedges pertaining to the other categoreis
OPTION 2
function draw () {
//(1) same as above
//(2) create a color method that adapts to each category's count and range
var color = d3.scale.linear()
.domain([0, function (d) {
if (d.data.categoria=="funzioni") {return countFunzioni;}
else if (d.data.categoria=="rimborso prestiti") {return countRimborso;}
else if (d.data.categoria=="altro") {return countAltro;}
}])
.range(function (d) {
if (d.cdata.ategoria=="funzioni") {return greenRange;}
else if (d.data.categoria=="rimborso prestiti") {return redRange;}
else if (d.data.categoria=="altro") {return blueRange;}
});
////(3) return the appropriate color method depending on the datum's category
.attr("fill", function(d, i) {return color(i);}
}
This does not get any coloring done.
Any idea how to solve this?
Option1 Remarks:
.attr("fill", function(d, i) {
if (d.data.categoria=="funzioni") {return colorFunzioni(i);}
else if (d.data.categoria=="rimborso prestiti") {return colorRimborso(i);}
else if (d.data.categoria=="altro") {return colorAltro(i);}
})
The trouble is the above is written as if 'i' will maintain separate tallies for the three categories. It doesn't though, it keeps an index for all elements in your selection, and as soon as the first 12 items in the selections are done, the next items are going to be out of range of any of the scales you described and return "#000000" - this is why the first 12 are coloured (and the first 12 may be red because you assign the red range to two scales, and the green range isn't used) and the rest aren't.
As a quick fix, keep a tally in the data itself of where it occurs in each category like this:
dataset.forEach (function (d) {if (d.categoria=="altro" && d.val2015>0) { countAltro += 1; d.catIndex = countAltro; }})
do this for each category
and then in the fill attr function do:
else if (d.data.categoria=="altro") {return colorAltro(d.data.catIndex);}
and again that needs done for each category.
As a separate thing, you can get rid of those else-if's by assigning the colors like this:
var colorMap = {
funzioni: colorFunzioni,
altro: colorAltro,
"rimborso prestiti": colorRimborso
}
and then later doing
.attr("fill", function(d, i) {
var scale = colorMap[d.data.categoria];
if (scale) return scale(d.data.catIndex)
})
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 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.