Extracting a selection of countries from JSON file - d3.js

I'm using this great example: Countries By Area
However I'm wanting to modify this code for my own use and project only a selection of chosen countries.
I've managed to read the JSON file into an array, and the code is now looking through that array but I don't see any way on rendering a country (or countries) if a criteria is met.
For example, if I want to simply render the country, who has an ID of 533, I don't see any way of attaching a condition.
Can anyone shed any light on how I may be able to do this.
Have edited my original question here as I've managed to do it, but I'm sure there's a more elegant way of achieving it:
Original code was:
var svg = d3.select("#map").selectAll("svg")
.data(topojson.feature(world, world.objects.countries).features)
Which I've changed to:
var svg = chartDetails.plotArea.selectAll("svg")
.data(
function(d){
a = topojson.feature(tempWorld, tempWorld.objects.countries).features
var returnobject =[]
$.each(a, function (i, v) { if (v.id == 826) { returnobject.push(v) } });
return returnobject
})
826 refers to United Kingdom.

If your array looks like this:
var a = [];
a.push({id:1, name:'Argentina'});
a.push({id:2, name:'Bahamas'});
Then you might need to iterate it to find the key(id) you want.
Take a look at these solutions:

Related

D3 How to pass text value from data to variable

I got a great answer yesterday helping me set up a conditional rule that allows me to display the points on my scatter chart as images or dots based on a variable 'displaytype'
Here's the link to the answer: D3 conditionally append image OR circle element based on variable
I'm porting my solution into Power BI and the dataset will contain a field 'display_type' which will be either 'image' or 'dot'
So I'm trying to update my variable and link it to the data but the if statement doesn't seem to recognise the output from the function.
eg
The Current variable is:
var displaytype = "image" // or "dot"
I'm trying to change that to:
var displaytype = function(d) {
return d.display_type
};
or
var displaytype = function(d) {
return data[0].display_type
};
However, the result has no impact to the display whatsoever so I guess I'm missing something (probably simple) ?
Any help much appreciated as always

Unable to filter individual stacks using dc.js with multiple X keys

Stacked Bar chart not able to filter on click of any Stack
I need to filter all the charts when clicking on any stack, which is not happening and struggling for a few days.
I've created a fiddle with link
http://jsfiddle.net/praveenNbd/09t5fd7v/13/
I feel am messing up with keys creation as suggested by gordonwoodhull.
function stack_second(group) {
return {
all: function () {
var all = group.all(),
m = {};
// build matrix from multikey/value pairs
all.forEach(function (kv) {
var ks = kv.key;
m[ks] = kv.value;
});
// then produce multivalue key/value pairs
return Object.keys(m).map(function (k) {
return {
key: k,
value: m[k]
};
});
}
};
}
I tried to follow this example https://dc-js.github.io/dc.js/examples/filter-stacks.html
Not able to figure out how below code works:
barChart.on('pretransition', function (chart) {
chart.selectAll('rect.bar')
.classed('stack-deselected', function (d) {
// display stack faded if the chart has filters AND
// the current stack is not one of them
var key = multikey(d.x, d.layer);
//var key = [d.x, d.layer];
return chart.filter() && chart.filters().indexOf(key) === -1;
})
.on('click', function (d) {
chart.filter(multikey(d.x, d.layer));
dc.redrawAll();
});
});
Can someone please point me out in the right direction.
Thanks for stopping by.
You usually don't want to use multiple keys for the X axis unless you have a really, really good reason. It is just going to make things difficult
Here, the filter-stacks example is already using multiple keys, and your data also has multiple keys. If you want to use your data with this example, I would suggest crunching together the two keys, since it looks like you are really using the two together as an ordinal key. We'll see one way to do that below.
You were also trying to combine two different techniques for stacking the bars, stack_second() and your own custom reducer. I don't think your custom reducer will be compatible with filtering by stacks, so I will drop it in this answer.
You'll have to use the multikey() function, and crunch together your two X keys:
dim = ndx.dimension(function (d) {
return multikey(d[0] + ',' + d[1], d[2]);
});
Messy, as this will create keys that look like 0,0xRejected... not so human-readable, but the filter-stacks hack relies on being able to split the key into two parts and this will let it do that.
I didn't see any good reason to use a custom reduction for the row chart, so I just used reduceCount:
var barGrp = barDim.group();
I found a couple of new problems when working on this.
First, your data doesn't have every stack for every X value. So I added a parameter to stack_second() include all the "needed" stacks:
function stack_second(group, needed) {
return {
all: function() {
var all = group.all(),
m = {};
// build matrix from multikey/value pairs
all.forEach(function(kv) {
var ks = splitkey(kv.key);
m[ks[0]] = m[ks[0]] || Object.fromEntries(needed.map(n => [n,0]));
m[ks[0]][ks[1]] = kv.value;
});
// then produce multivalue key/value pairs
return Object.entries(m).map(([key,value]) => ({key,value}));
}
};
}
Probably the example should incorporate this change, although the data it uses doesn't need it.
Second, I found that the ordinal X scale was interfering, because there is no way to disable the selection greying behavior for bar charts with ordinal scales. (Maybe .brushOn(false) is completely ignored? I'm not sure.)
I fixed it in the pretransition handler by explicitly removing the built-in deselected class, so that our custom click handler and stack-deselected class can do their work:
chart.selectAll('rect.bar')
.classed('deselected', false)
All in all, I think this is way too complicated and I would advise not to use multiple keys for the X axis. But, as always, there is a way to make it work.
Here is a working fork of your fiddle.

D3.js Stacked Bar Chart Selects

I am trying to come to grips with some D3 concepts but feel as though there are some fundamentals gaps in my knowledge. It seems to do with how the D3 stack() function works.
I am trying to understand why the following two code snippets are not equivalent. The first works and populates data, the second does not.
First (Working Code, Simplified):
var mainStack = d3.stack().keys(keys);
var seriesData = mainStack(dataset[0]);
gBars = g.selectAll("g")
.data(seriesData, function (d, i) { return (i); })
.enter().append("g").. more work here
Second (Not Working, Simplifed):
var mainStack = d3.stack().keys(keys);
var seriesData = mainStack(dataset[0]);
gBars = g.selectAll("g")
.data(seriesData, function (d, i) { return (i); });
gBars.enter().append("g").. more work here
Basically, I have just tried to break up the code to make it simpler (for me) to read, and also to allow me to implement an exit() function. However, when i do the above, the graphs fail to display.
I thought that the gBar variables should maintain their previous selects?
Any assistance would be appreciated, I have successfully used this pattern for simple charts, hence my suspicion that this is related to something I am missing when the d3.stacked() function is involved which nests the data?
With some friendly help, I found that the difference is in the way v4 handles selects. The answer was to utilise merges to combine the various selects and then perform any combined updates on the merged nodes.
Eg:
var mainStack = d3.stack().keys(keys);
var seriesData = mainStack(dataset[0]);
var gBarsUpdate = g.selectAll("g")
.data(seriesData, function (d, i) { return (i); });
var gBarsEnter = gBarsUpdate.enter().append("g")
var gBars = gBarsEnter.merge(gBarsUpdate)
//now update combined with common attributes as required
gBars.attr("fill", "#ff0000"); //etc
Hope this helps anyone else a bit confused by this. Took me a bit of time to understand what was going on, but thanks to some smart people, they put me on the right track :-)
ps. My problem ended up having nothing to do with the stack() function.

.append() to different selection depending on condition?

I have a similar issue as in Updating SVG Element Z-Index With D3
My preferred solution would be to have two groups within my svg as described in the answer by notan3xit.
But I have one data set, and a boolean flag on one of the data properties determines to which group the svg element belongs.
svg.selectAll("path")
.data(d)
.enter()
.if(d.property).appendToGroup1()
.else.appendToGroup2()
This obviously doesn't work, but something like this.
I only want to iterate through the data once, and during runtime append the generated svg elements to the according groups.
Any ideas how to go about achieving that with d3.js?
Try
.each(function(d){
var toAppend = $(this);
if (!!d.property){
toAppend.appendtoGroup1();
} else {
toAppend.appendToGroup2();
}
})//...
The general idea would be to pass d into a callback, and apply the right append method inside that callback.
It should be cleaner to first save reference to what you want to append to, in an enclosing scope so you can easily call .append() on it.
Try this:
var selectedPath=svg.selectAll("path").data(d);
svg.selectAll("path").each(function(d,i){
if(d3.select(this).attr("property's name"))
selectedPath.append("some data to group 1")
else
selectedPath.append("some data to group 2")
});
If I had your code better able to help.

How to show "missing" rows in a rowChart using crossfilter and dc.js?

I'm using code similar to that in the dc.js annotated example:
var ndx = crossfilter(data);
...
var dayName=["0.Sun","1.Mon","2.Tue","3.Wed","4.Thu","5.Fri","6.Sat"];
var dayOfWeek = ndx.dimension(function (d) {
var day = d.dd.getDay();
return dayName[day];
});
var dayOfWeekGroup = dayOfWeek.group();
var dayOfWeekChart = dc.rowChart("#day-of-week-chart");
dayOfWeekChart.width(180)
.height(180)
.group(dayOfWeekGroup)
.label(function(d){return d.key.substr(2);})
.dimension(dayOfWeek);
The issue I've got is that only days of the week present in the data are displayed in my rowChart, and there's no guarantee every day will be represented in all of my data sets.
This is desirable behaviour for many types of categories, but it's a bit disconcerting to omit them for short and well-known lists like day and month names and I'd rather an empty row was included instead.
For a barChart, I can use .xUnits(dc.units.ordinal) and something like .x(d3.scale.ordinal.domain(dayName)).
Is there some way to do the same thing for a rowChart so that all days of the week are displayed, whether present in data or not?
From my understanding of the crossfilter library, I need to do this at the chart level, and the dimension is OK as is. I've been digging around in the dc.js 1.6.0 api reference, and the d3 scales documentation but haven't had any luck finding what I'm looking for.
Solution
Based on #Gordon's answer, I've added the following function:
function ordinal_groups(keys, group) {
return {
all: function () {
var values = {};
group.all().forEach(function(d, i) {
values[d.key] = d.value;
});
var g = [];
keys.forEach(function(key) {
g.push({key: key,
value: values[key] || 0});
});
return g;
}
};
}
Calling this as follows will fill in any missing rows with 0s:
.group(ordinal_groups(dayNames, dayOfWeekGroup))
Actually, I think you are better off making sure that the groups exist before passing them off to dc.js.
One way to do this is the "fake group" pattern described here:
https://github.com/dc-js/dc.js/wiki/FAQ#filter-the-data-before-its-charted
This way you can make sure the extra entries are created every time the data changes.
Are you saying that you tried adding the extra entries to the ordinal domain and they still weren't represented in the row chart, whereas this did work for bar charts? That sounds like a bug to me. Specifically, it looks like support for ordinal domains needs to be added to the row chart.

Resources