Question

I'm trying to load a D3 map with topjson and join with it a separate CSV file with data I'd like to use to color the map. I'm able to switch between the multiple layers but not without redrawing the map each time. I've scoured the boards for some clue on how to do this but I can't seem to figure it out. Can anyone provide any help?

I'd like to keep the CSV and JSON data separate in case we want to dynamically edit the CSV as we go. I'd like to either add the relevant classes to each country in one go or to add and remove the classes as the user toggles between the three buttons. Either works for me, I just can't seem to figure out how to do it.

var width = 945

var height = 550

var svg = d3.select('#content').append('svg').attr('width', width).attr('height', height);

var projection = d3.geo.mercator().scale(175);

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

var all_data = {};

var tierById = d3.map();

var quantize = d3.scale.quantize()
    .domain([0, 1])
    .range(d3.range(2).map(function(i) { return "tier" + i; }));

queue()
  .defer(d3.json, "data/world.json")
  .defer(d3.csv, "data/wod.csv")
  .await(setUpChoropleth);

function setUpChoropleth(error, json) {

  svg.append("g")
     .attr("class", "countries")
  .selectAll("path")
    .data(topojson.feature(json, json.objects.countries).features)
  .enter().append("svg:path")
    .attr("d", path);

} 

function drawTierI() {
  queue()
      .defer(d3.json, "data/world.json")
      .defer(d3.csv, "data/wod.csv", function(d) { tierById.set(d.id, +d.tier_i); })
      .await(ready);

  function ready(error, json) {
    svg.append("g")
        .attr("class", "countries")
      .selectAll("path")
        .data(topojson.feature(json, json.objects.countries).features)
      .enter().append("path")
        .attr("class", function(d) { return quantize(tierById.get(d.id)); })
        .attr("d", path);

  }
}

function drawTierII() {
  queue()
      .defer(d3.json, "data/world.json")
      .defer(d3.csv, "data/wod.csv", function(d) { tierById.set(d.id, +d.tier_ii); })
      .await(ready);

  function ready(error, json) {
    svg.append("g")
        .attr("class", "countries")
      .selectAll("path")
        .data(topojson.feature(json, json.objects.countries).features)
      .enter().append("path")
        .attr("class", function(d) { return quantize(tierById.get(d.id)); })
        .attr("d", path);

  }
}

function drawTierIIPlus() {
  queue()
      .defer(d3.json, "data/world.json")
      .defer(d3.csv, "data/wod.csv", function(d) { tierById.set(d.id, +d.tier_ii_plus); })
      .await(ready);

  function ready(error, json) {
    svg.append("g")
        .attr("class", "countries")
      .selectAll("path")
        .data(topojson.feature(json, json.objects.countries).features)
      .enter().append("path")
        .attr("class", function(d) { return quantize(tierById.get(d.id)); })
        .attr("d", path);

  }
}

$('button#tier_i').click(function (e) {
  $( "svg" ).empty();
  drawTierI();
});

$('button#tier_ii').click(function (e) {
  $( "svg" ).empty();
  drawTierII();
});

$('button#tier_ii_plus').click(function (e) {
  $( "svg" ).empty();
  drawTierIIPlus();
});

Here's a jfiddle of my code: http://jsfiddle.net/2H7Pm/ I seem to be having some syntax issues with the JSON there, however.

The example map DOES work on my github however: http://newamericafoundation.github.io/worldofdrones/

Thanks for the help!

Was it helpful?

Solution

You just need to select the existing paths instead of appending new ones after the initial setup of the choropleth, e.g.

function drawTierI() {
  csv.forEach(function(d) { tierById.set(d.id, +d.tier_i); });

  function ready(error, json) {
    svg.selectAll("path")
        .attr("class", function(d) { return quantize(tierById.get(d.id)); })
        .attr("d", path);

  }
}

and similarly for the other functions. You don't need to reload the JSON and CSV at each step either -- the above code is assuming that your CSV data is stored in the variable csv, which you would populate thusly:

var csv;
function setUpChoropleth(error, json, _csv) {
  csv = _csv;
  // rest of setup
}

Then you can simply do

$('button#tier_i').click(function (e) {
  drawTierI();
});

to change the displayed variable without needing to empty the SVG first.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top