d3.js t.map is not a function - javascript

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.

Related

D3: Passing extra arguments to attr functions inside a selection.join()

I've some code inside a selection.join() pattern:
const nodeWidth = (node) => node.getBBox().width;
const toolTip = selection
.selectAll('g')
.data(data)
.join(
(enter) => {
const g = enter
.append('g')
g.append('text')
.attr('x', 17.5)
.attr('y', 10)
.text((d) => d.text);
let offset = 0;
g.attr('transform', function (d) {
let x = offset;
offset += nodeWidth(this) + 10;
return `translate(${x}, 0)`;
});
selection.attr('transform', function (d) {
return `translate(${
(0 - nodeWidth(this)) / 2
},${129.6484} )`;
});
},
(update) => {
update
.select('text')
.text((d) => d.text);
let offset = 0;
update.attr('transform', function (d) {
let x = offset;
offset += nodeWidth(this) + 10;
return `translate(${x}, 0)`;
});
selection.attr('transform', function (d) {
return `translate(${
(0 - nodeWidth(this)) / 2
},${129.6484} )`;
});
}
);
as you can see, in the enter and update section I need to call a couple of functions to calculate several nodes transformations. In particular, the code stores in the accumulation var offset the length of the previous text element. This properly spaces text elements (ie, text0 <- 10 px -> text1 <- 10 px -> ...).
As you can see, the "transform functions" in the enter and update section are identical. I'm trying to define them just in one place and call them where I need. E.g.,
(update) => {
update.attr('transform', foo);
selection.attr('transform', bar);
}
However, I cannot refactor the code this way because it looks like I cannot pass in neither the offset value nor this to the function passed to attr().
Is there a way to do it?
EDIT:
As per Gerardo Furtado's hint (if I got it right), you can define foo as follows:
const foo = function(d, i, n, offset) {
let x = offset;
offset += nodeWidth(n[i]) + 10;
return `translate(${x}, 0)`;
}
then in the selection.join¡ you have to call foo this way:
(update) => {
let offset = 0;
update.attr('transform', (d, i, n) => foo(d, i, n, offset));
}
However, refactoring this way, offset is ever equal to 0. A possibile solution here: https://stackoverflow.com/a/21978425/4820341
Have a look at Function.prototype.bind().
const doSomething = (d) => {
return `translate(${
(0 - nodeWidth(this)) / 2
},${129.6484} )`;
}
Calling the function inside (enter) and (update)
selection.attr('transform', doSomething.bind(d));
This way the function gets executed in the current scope.
I guess this is what you are looking for. Please be aware that I could not test my code!

dc.js: Reducing rows in data table

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

Transforming a dataset with crossfilter

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..

d3 chart - get x axis time of max value

I have a array of values [date, value].
I can find the max value with:
max_value = d3.max(data_array, function(d) { return d[1]; } );
How do I get the d[0] value of d[1] maximum so I can mark the position of maximum value on chart?
Use javascript array filter function.
var max_value = d3.max(data_array, function(d) { return d[1]; } );
var requiredArr = data_array.filter(function(d){
return d[1]==max_value;
});
var dateWithMaxValue = requiredArr[0];
If you don't care about performance too much, here's a one-liner:
// d is [x, y] where x is what you're looking for
var d = data_array.sort(function (a, b) { return b[1] - a[1]; })[0];
Here's a simple demo.

Update the y-axis of a brushed multi line chart.

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?

Categories