Using d3 in Leaflet - javascript

This is a follow up question to my other one.
http://fiddle.jshell.net/zw8TR/16/
I have managed to utilise d3 to visualise the route between my map markers. I used this example by Mike Bostock as guidance.
The reason I'm using d3 for this instead of Leaflets built in Polyline, is because I'd like to experiment with d3's interpolation to smooth out some routes, and also create arc's for others (for flight routes). At this stage though, I'm just trying to find a way to get these to work for all routes.
The examples I've seen only use the interpolate() method with d3.svg.line(), whereas the Leaflet integration requires me to use d3.geo.path(). Is there a place in my code where it's possible to use this method with d3.geo.path()?
Another possibly helpful link.
And another.
Thanks for any help.

Doing this is a bit messier than using d3.geo.path because that already implements all the boilerplate functionality you need for maps, but it's certainly possible. The idea is to extract the list of user coordinates from the geo path and translate them to screen coordinates in the line function. This translation can be done in the .x() and .y() functions of the line.
var path1 = d3.svg.line()
.interpolate("cardinal")
.x(function(d) { return map.latLngToLayerPoint(new L.LatLng(d[1], d[0])).x; })
.y(function(d) { return map.latLngToLayerPoint(new L.LatLng(d[1], d[0])).y; });
Now we just need to extract the coordinates from the feature.
feature.attr("d", function(d) { return path1(d.geometry.coordinates); });
Complete example here.

Related

D3 V6 and JavaScript - GeoJSON fill is "spilling" outside of path [duplicate]

This question already has answers here:
D3.js Drawing geojson incorrectly
(2 answers)
Closed 2 years ago.
Creating a map using D3 V6, showing educational attainment by county. I have a counties.topojson and csvData.csv which are loaded:
var promises = [];
promises.push(d3.csv("data/csvData.csv")); //load attributes from csv
promises.push(d3.json("data/counties.topojson")); //load background spatial data
Promise.all(promises).then(callback);
and in a callback function assigned to variables csvData and counties. The counties are then translated using:
miCounties = topojson.feature(counties, counties.objects.collection).features;
The csvData is joined to the county data, and the join is confirmed in console.log(joinedCounties), within the callback function setEnumerationUnits() is called (where colorScale is quantile scale based on an array created from the csvData and map is the SVG element:
function setEnumerationUnits(joinedCounties,map,path,colorScale){
var counties = map.selectAll(".counties")
.data(joinedCounties)
.enter()
.append("path")
.attr("class", function(d){
return "counties " + d.properties.NAME;
})
.attr("d", path)
.style("fill", function(d) {
return choropleth(d.properties, colorScale);
})
I should also mention adding "fill" to the .counties class in CSS also creates the "spilling". I have checked the topojson in QGIS and Pro, which both appear normal. I have also tried a second source of data with the same results.
Here is the result:
Here is what is looks like without styling, no fill, just stroke defined in CSS:
I receive no errors in the console. I appreciate any help anyone can give! Thanks!
Thank you! The turf.rewind worked!!
here's what I added to make it work (after installing turf library):
miCounties.forEach(function(feature){
feature.geometry = turf.rewind(feature.geometry, {reverse:true});
One or more of your GeoJSON entries are the wrong way around. The values are correct, but they are in the wrong order. d3-geo generally expects GeoJSON features to be clockwise:
Spherical polygons also require a winding order convention to determine which side of the polygon is the inside: the exterior ring for polygons smaller than a hemisphere must be clockwise, while the exterior ring for polygons larger than a hemisphere must be anticlockwise.
You can fix the winding of your data using a plugin or tool like turf, which you can use to "rewind" your shapes - though you should use the reverse: true option.

d3 pie chart all black fill, d3.schemeCategory20c not being called

Since this is getting marked as a duplicate let me clarify my problem is not that I am getting a Uncaught TypeError: d3.schemeCategory20 error like the post that is suggested in fact if you look at my code and that one I am making the call the same way as the accepted answer.
If read my issue my chart is fill colors are all black, MY ISSUE is that d3.schemeCategory20c array doesn't seems to be called at all. I have no errors I have unexpected output by the method.
I'm going through Barrett Clark's Data Visualization Toolkit book, first chapter. I have updated the code to reflect the changes in d3 v4 but my pie chart renders with one color here is my scaleOrdinal assignment
var color = d3.scaleOrdinal(d3.schemeCategory20c);
Here's the json call:
$.getJSON('/residential/data', function(data) {
totals = data.totals;
var g = svg.selectAll('.arc').data(pie(d3.keys(totals))).enter()
.append('g').attr('class', 'arc');
g.append('path').attr('d', arc).style('fill', function(d) { return color(d.data); });
g.append('text').attr('transform',
function(d) { return 'translate('+ arc.centroid(d) +')'; }).attr('dy', '.35em')
.style('text-anchor', 'middle').text(function(d) { return d.data; });
});
This renders a great pie chart with every slice filled in black, I've tried reading the docs but can't seem to find this implementation. I've culled from other tuts that this should work but it doesn't.
My answer was found in the Changes in D3 5.0 doc.
D3 no longer provides the d3.schemeCategory20* categorical color schemes. These twenty-color schemes were flawed because their grouped design could falsely imply relationships in the data: a shared hue can imply that the encoded data are part of a group (a super-category), while relative lightness can imply order. Instead, D3 now includes d3-scale-chromatic, which implements excellent schemes from ColorBrewer, including categorical, diverging, sequential single-hue and sequential multi-hue schemes. These schemes are available in both discrete and continuous variants.
I was searching for issues with d3.schemeCategory20c so I kept getting old posts, this morning when I console'd d3.schemeCategory20c (something I should've did a while ago) and found it to be undefined. I figured it out.

D3 geo node plotting on map?

I've recently created this D3 map which I had intended to put nodes on the map with links between each node. However I don't know how to do this without using force layout. So far I have created a map of the world using d3 geo map. I have seen a couple of examples of the lines e.g. http://datamaps.github.io/old.html but these don't have nodes on the end of them. I've put my version on JSFiddle which can be found here: http://jsfiddle.net/GarrettUK/n396w4vq/2/.
I'm sure the way to do the lines would be like this:
var election = new Datamap({
scope: 'world',
element: document.getElementById('arcs'),
projection: 'mercator'
});
I would refer you back to the Data Maps arc tutorial.
http://datamaps.github.io/
As far a creating nodes, you could always just append an image to your map using the d3.append and then decide what attributes if any to assign those images. If your looking for the classic node, just append a circle by doing something like this.
var img = g.append("svg:image")
.attr("xlink:href", "circle")

Not able to get the Zoom/Pan and States name appear in India Map - D3?

I am new to D3.js. However after being practiced the examples of this site, I tried to play ahead with Mr.John Coogan's map given here. The output that I found in his site is as under
But when I am trying to do the same thing by placing his .js,css,.json and index.html in plunker it is coming as
Problems
a) No States are getting displayed
b) Zoom and Pan is not working
In another word, at this point of time I am looking only for the Indian map to work exactly as the example shown by Mr. Coogan.
What needs to be done for this?
Here's the working plunk: http://plnkr.co/1EqpIFecwJmkbvypTyQD?p=preview
You needed to uncomment this line:
.call(d3.behavior.zoom().on("zoom", redraw))
on line 40 of the index.html in your plunk, and then zoom and pan will work.
The state colors (based on wealth) are not showing because of various, more complex errors. The error shown in the console (svg is not defined referencing line 78) is just the start (you need to replace svg with india, which is defined).
In fact the whole original gist your example is based on is really just a work in progress, but most of the answers for how to fix it can be found in this thread from the google group, from Mike Bostock himself.
Essentially, the json data loads asynchronously, so need to be loaded in series.
// load the two JSON files in series
d3.json("states.json", function(states) {
d3.json("wealth.json", function(wealthdata) {
...
});
});
Then you can just apend the relevant colorbrewer CSS class when you first create each path:
india.selectAll("path")
.data(states.features)
.enter().append("path")
.attr("d", path)
.attr("class", function(d) {
return "q" + quantize(wealthdata[d.id]) + "-9";
})
.attr("d", path);
But you also need to define the quantize scale, range...:
var quantize = d3.scale.quantize()
.range(d3.range(9));
... and domain (which you can only do once the data has been loaded:
quantize.domain([0, d3.max(d3.values(wealthdata))]);

Chained animations/transitions over each graph node - D3.js

I want to be able to change the radius of each node in my graph that i am creating using d3.js. However, i want to change the radius of each node, one at a time, and i want to able to control the delay between each change along with the sequence of the nodes.
For now this is what i have in terms of code:
var nodes = svg.selectAll(".node");
nodes.each(function() {
d3.select(this).
transition().
delay(100).
attr("r", "5")
});
You can replicate this simply by using the code at this link: http://bl.ocks.org/mbostock/4062045. The code that i have pasted above is simply an addition to the code at the aforementioned link.
When i run this, all the nodes in my graph transition simultaneously, i.e. grow in size (radius) simultaneously. I however want them to transition i.e. grow in size (radius), one at a time. I repeat that i want to be able to control:
the delay between the transition of each node and
the order of nodes that undergo the transitions.
Any pointers, tutorials, or even other stackoverflow answers would be great. I would ideally want some code examples.
The closest i have come to in terms of online references is this subsection of a tutorial on d3.js transitions: http://bost.ocks.org/mike/transition/#per-element. However, it lacks a concrete code example. I, being new to d3.js and javascript in general, am not able to pick it up without concrete code examples.
You can do this quite easily by calculating a delay based on each node's index. Mike Bostock has an example of such an implementation here. This is the relevant code:
var transition = svg.transition().duration(750),
delay = function(d, i) { return i * 50; };
transition.selectAll(".bar")
.delay(delay)
.attr("x", function(d) { return x0(d.letter); }); // this would be .attr('r', ... ) in your case
To control the order of the transition, all you would then have to do is sort the array so that the elements' indices reflect the animation flow you want. To see how to sort an array, refer to the documentation on JavaScript's array.sort method and also see the Arrays > Ordering section of the D3 API reference.

Categories

Resources