samedi 9 janvier 2016

Choropleth example in D3 is not working properly

Vote count: 0

I have this straight forward example where I wanted to use my data and my topojson instead. I get the data loaded but the visualization is not working properly. Data is loaded properly

Logging the dataRange() gives my -INFINITY,INFINITY, so something with the ranging is noch wokring but I can't see what it is.

<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <title>d3 choropleth map</title>
      #wrapper {
          width: 960px;
          margin: -30px auto 0;
      #map {
          width: 960px;
          height: 580px;
          position: relative;
      .stroke {
        fill: none;
        stroke: #888;
        stroke-width: 2px;

      .fill {
        fill: #fff;

      .graticule {
        fill: none;
        stroke: #777;
        stroke-width: .5px;
        stroke-opacity: .5;

      .land {
        fill: #222;

      .boundary {
        fill: none;
        stroke: #fff;
        stroke-width: .5px;
      .country {
          fill: steelblue;
          stroke: white;
      #play, #clock {
        position: absolute;
        top: 15px;
      #play {
        left: 15px;
      #clock {
        left: 65px;


    <div id="wrapper">
        <div id="map"></div>
      <button id="play">play</button>
      <span id="clock">year</span>

<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
var width, height, projection, path, graticule, svg, attributeArray = [], currentAttribute = 0, playing = false;

function init() {



function setMap() {

  width = 960, height = 580;  // map width and height, matches

  var projection = d3.geo.mercator()
      .translate([width / 2, height])
      //.scale((width - 1) / 2 / Math.PI);

  path = d3.geo.path()  // create path generator function
      .projection(projection);  // add our define projection to it

  graticule = d3.geo.graticule(); // create a graticule

  svg ="#map").append("svg")   // append a svg to our html div to hold our map
      .attr("width", width)
      .attr("height", height);

  svg.append("defs").append("path")   // prepare some svg for outer container of svg elements
      .datum({type: "Sphere"})
      .attr("id", "sphere")
      .attr("d", path);

  svg.append("use")   // use that svg to style with css
      .attr("class", "stroke")
      .attr("xlink:href", "#sphere");

  svg.append("path")    // use path generator to draw a graticule
      .attr("class", "graticule")
      .attr("d", path);

  loadData();  // let's load our data next


function loadData() {

  queue()   // queue function loads all external data files asynchronously
    .defer(d3.json, "mapdata/germany.json")  // our geometries
    .defer(d3.csv, "choroplethmap.csv")  // and associated data in csv file
    .await(processData);   // once all files are loaded, call the processData function passing
                           // the loaded objects as arguments

function processData(error,world,countryData) {
  // function accepts any errors from the queue function as first argument, then
  // each data object in the order of chained defer() methods above

  var countries = world.objects.states_germany.geometries  // store the path in variable for ease
  for (var i in countries) {    // for each geometry object
    for (var j in countryData) {  // for each row in the CSV
      if(countries[i].id == countryData[j].id) {
        //console.log("SUCCESS");   // if they match
        for(var k in countryData[i]) {   // for each column in the a row within the CSV
          if(k != 'name' && k != 'id') {  // let's not add the name or id as props since we already have them
            if(attributeArray.indexOf(k) == -1) {
               attributeArray.push(k);  // add new column headings to our array for later
            countries[i][k] = Number(countryData[j][k])  // add each CSV column key/value to geometry object
        break;  // stop looking through the CSV since we made our match
  }'#clock').html(attributeArray[currentAttribute]);  // populate the clock initially with the current year
  drawMap(world);  // let's mug the map now with our newly populated data object

function drawMap(world) {

    svg.selectAll(".country")   // select country objects (which don't exist yet)
      .data(topojson.feature(world, world.objects.states_germany).features)  // bind data to these non-existent objects
      .enter().append("path") // prepare data to be appended to paths
      .attr("class", "country") // give them a class for styling and access later
      .attr("id", function(d) { return "code_" +; }, true)  // give each a unique id for access later
      .attr("d", path); // create them using the svg path generator defined above

    var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
    d3.selectAll('.country')  // select all the countries
    .attr('fill-opacity', function(d) {
        return getColor(d[attributeArray[currentAttribute]], dataRange);  // give them an opacity value based on their current value

function sequenceMap() {

    var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
    d3.selectAll('.country').transition()  //select all the countries and prepare for a transition to new values
      .duration(750)  // give it a smooth time period for the transition
      .attr('fill-opacity', function(d) {
        return getColor(d[attributeArray[currentAttribute]], dataRange);  // the end color value


function getColor(valueIn, valuesIn) {

  var color = d3.scale.linear() // create a linear scale
    .domain([valuesIn[0],valuesIn[1]])  // input uses min and max values
    .range([.3,1]);   // output for opacity between .3 and 1 %

  return color(valueIn);  // return that number to the caller

function getDataRange() {
  // function loops through all the data values from the current data attribute
  // and returns the min and max values

  var min = Infinity, max = -Infinity;
    .each(function(d,i) {
      var currentValue =[attributeArray[currentAttribute]];
      if(currentValue <= min && currentValue != -99 && currentValue != 'undefined') {
        min = currentValue;
      if(currentValue >= max && currentValue != -99 && currentValue != 'undefined') {
        max = currentValue;
  return [min,max];  //boomsauce

function animateMap() {

  var timer;  // create timer object'#play')
    .on('click', function() {  // when user clicks the play button
      if(playing == false) {  // if the map is currently playing
        timer = setInterval(function(){   // set a JS interval
          if(currentAttribute < attributeArray.length-1) {
              currentAttribute +=1;  // increment the current attribute counter
          } else {
              currentAttribute = 0;  // or reset it to zero
          sequenceMap();  // update the representation of the map
'#clock').html(attributeArray[currentAttribute]);  // update the clock
        }, 2000);'stop');  // change the button label to stop
        playing = true;   // change the status of the animation
      } else {    // else if is currently playing
        clearInterval(timer);   // stop the animation by clearing the interval'play');   // change the button label to play
        playing = false;   // change the status again

window.onload = init();  // magic starts here


So where is the mistake? You can finde the full data (map etc) here

asked 44 secs ago

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at

Choropleth example in D3 is not working properly

Aucun commentaire:

Enregistrer un commentaire