javascriptjsoncsvd3.jsworld-map

D3 Functions Not Working When Multiple Data Sources Are Used


I've adapted this "Making a world map with d3, topojson, and a csv" tutorial into a usable v5 version: https://www.youtube.com/watch?v=aNbgrqRuoiE&t=216s

However, the issue comes in at the point where I am to bring in a separate datasource, being the CSV file. When I bring it in and check the data, I get an array of objects, which is fine. But in order to turn the locations in the CSV into dots on the map using the long and lat coordinate values, I obviously need to access those column values within the CSV. In the tutorial, the author does that easily, using the following:

svg.selectAll("state-circle")
.data(data)
.enter().append("circle")
.attr("class", "state-circle")
.attr("r",2)
.attr("cx", function(d) {
    var coords = projection([d.long, d.lat])
    return coords[0];})
.attr("cy", function(d) {
    var coords = projection([d.long, d.lat])
    return coords[1];});

But given the version of D3 he's using, the way he's written the code makes that simple. I don't know how to do it using the v5 syntax adaptation.

So in order to do what he's done, I need to find a way to access the latitude and longitude attributes inside the objects. Now I'm pretty new to D3 but I managed to achieve this using the following calculation (but I'm open to a better method as I'm not sure this is technically the best way or that it will work with what he's done above):

var long = d3.entries({longitude: true});
var lat = d3.entries({latitude: true});

The problem is that this code only works when I test it in a separate .js file, where the CSV is the only data source. When I try to run the code inside the .js file that also contains the .json datasource, it doesn't work. It continues to return the original array of objects, with all its attributes.

This is all the code I'm using so far:

var margin = {top: 50, left: 50, right: 50, bottom: 50},
        height = 400 - margin.top - margin.bottom,
        width = 1600 - margin.left - margin.right;

var svg = d3.selectAll("body")
        .append("svg")
        .attr("height", height + margin.top + margin.bottom)
        .attr("width", width + margin.left + margin.right)
        .append("g");

d3.json("https://d3js.org/world-50m.v1.json").then(function (data)
    {console.log(data);

var countries = topojson.feature(data,data.objects.countries).features;

// console.log(countries);

var projection = d3.geoMercator()
    .translate([width/2, height/2])
    .scale(100);

var path = d3.geoPath()
    .projection(projection);

svg.selectAll(".country")
    .data(countries)
    .enter().append("path")
    .attr("class", "country")
    .attr("d", path)
    .on("mouseover", function(d)
        {d3.select(this).classed("hover", true)})
    .on("mouseout", function(d)
        {d3.select(this).classed("hover", false)});
    });

    d3.csv("TData.csv", function(d) {
              return {
                city: d.City,
                continent: d.Continent,
                country: d.Country,
                dimension: d.Dimension,
                identity: d.Identity,
                score: +d.Score,
                state: d.Subdivision,
                trait: d.Trait,
                index: d.Index,
                longitude: d.Latitude,
                latitude: d.Longitude
              }
            }).then(function(data) {
                // console.log(data);

                    var long = d3.entries({longitude: true});
                    var lat = d3.entries({latitude: true});

    console.log(long);
    console.log(lat);

            });

Sample of the CSV file, is:

City,Continent,Country,Dimension,Identity,Score,Subdivision,Trait,Index,Latitude,Longitude
Wilmington,North America,United States,Pride,1270858,45,Delaware,Ego,1,"39,7932","-75,6181"
Wilmington,North America,United States,Humility,1270858,23,Delaware,Selflessness,2,"39,7932","-75,6181"
Wilmington,North America,United States,Humility,1270858,23,Delaware,Generosity,3,"39,7932","-75,6181"
Wilmington,North America,United States,Anger,1270858,48,Delaware,Impatience,4,"39,7932","-75,6181"

Solution

  • With the given csv file, you had to parse the string coordinates to a float variable -- and for that you need to replace the commas there as well -- the following code works

    var margin = {top: 50, left: 50, right: 50, bottom: 50},
    	height = 400 - margin.top - margin.bottom,
    	width = 1600 - margin.left - margin.right;
    
    var svg = d3.selectAll("body")
    	.append("svg")
    	.attr("height", height + margin.top + margin.bottom)
    	.attr("width", width + margin.left + margin.right)
    	.append("g");
    
    var gBackground = svg.append("g"); // appended first
    var gDataPoints = svg.append("g"); // appended second
    			
    d3.json("https://d3js.org/world-50m.v1.json").then(function (data) {
    	console.log(data);
    
    	var countries = topojson.feature(data,data.objects.countries).features;
    	var long = d3.entries({longitude: true});
    	var lat = d3.entries({latitude: true});
    
    	console.log(long);
    	console.log(lat);
    
    	gBackground.selectAll(".country")
    		.data(countries)
    		.enter().append("path")
    		.attr("class", "country")
    		.attr("d", path)
    		.on("mouseover", function(d)
    			{d3.select(this).classed("hover", true)})
    		.on("mouseout", function(d)
    			{d3.select(this).classed("hover", false)});
    });	
    
    var projection = d3.geoMercator();
    // .translate([width/2, height/2])
    // .scale(100);
    // need fixing - not sure why they're not working
    
    var path = d3.geoPath()
    	.projection(projection);
    
    		
    d3.csv("TruityData.csv", function(d) {
    	return {
    		city: d.City,
    		continent: d.Continent,
    		country: d.Country,
    		dimension: d.Dimension,
    		identity: d.Identity,
    		score: +d.Score,
    		state: d.Subdivision,
    		trait: d.Trait,
    		index: d.Index,
    		latitude: d.Latitude,
    		longitude: d.Longitude
    	}
    }).then(function(data) {
    	// console.log(data[0]);
    	
    	gDataPoints.selectAll("state-circle")
    		.data(data)
    		.enter().append("circle")
    		.attr("class", "state-circle")
    		.attr("r",3)
    		.attr("cx", function(d) {
    			var dln = parseFloat(d.longitude.replace(",", "."));
    			var dlt = parseFloat(d.latitude.replace(",", "."));
    			var coords = projection([dln, dlt]);
    			return coords[0];})
    		.attr("cy", function(d) {
    			var dln = parseFloat(d.longitude.replace(",", "."));
    			var dlt = parseFloat(d.latitude.replace(",", "."));
    			var coords = projection([dln, dlt]);
    			return coords[1];});
    		
    });