block by dhoboy c0aff212c1756b0429b4

Force layout #1

Full Screen

Example #1 from learning the Force Layout in d3. The charge is too strong in this example. The big red outlier gets buried inside the mass of bubbles. Not what I wanted. However, I like the tight curve of the entire pack of bubbles.

index.html

<html>
<head>
<script src="//d3js.org/d3.v3.js"></script>
</head>
<body>
<script>
var w = 960, 
    h = 960, 
    padding = 30, // svg boundry padding
    format = d3.format(".2%"),
    maxRadius = 20;

// pull in csv data
d3.csv("/d/283008a26997e97e0490/Student_Weight_Status_Category_Reporting_Results__Beginning_2010.csv", function(error, rows) {
  var dataset = [], counter = 0;
  rows.forEach(function(entry){
	  if ((entry["GRADE LEVEL"] == "DISTRICT TOTAL") && (entry["PCT OVERWEIGHT OR OBESE"] != "")) {
		  var pctOverObese = /[\d]+\.[\d]/.exec(entry["PCT OVERWEIGHT OR OBESE"]);
		  if (pctOverObese != null) {
			pctOverObese = pctOverObese[0] / 100; // form percent mathematically 
			entry["pctOverObese"] = pctOverObese;
			entry["pos"] = counter;
			counter += 1;
			dataset.push(entry);
		  }
	  }
  });
	
  // desired data is loaded. form scales based on it. 
  var xScale = d3.scale.linear()
					   .domain([0, dataset.length])
					   .range([w/4, (3*w)/4]);

  var yScale = d3.scale.linear()
					   .domain([0, d3.max(dataset, function(d){ return d["pctOverObese"]; })])
					   .range([h - padding, padding]);
  	
  var rScale = d3.scale.linear()
					   .domain([0, d3.max(dataset, function(d){ return d["pctOverObese"]; })])
					   .range([2, 20]);
	  						 
  var colorScale = d3.scale.quantize() 
  						 .domain([0, d3.max(dataset, function(d){ return d["pctOverObese"]; })])
 					 	 .range(["#006837", "#1a9850", "#66bd63", "#fdae61", 
						           "#f46d43", "#d73027", "#a50026"]);
  // set node positions
  dataset.forEach(function(node){
    node["x"] = xScale(node["pos"]);
	node["y"] = yScale(node["pctOverObese"]);
  });

  // set up force layout	
  var force = d3.layout.force()
					 .nodes(dataset)
					 .size([w, h])
					 .gravity(.2)
					 .charge(-30)
					 .on("tick", tick) // ticks?
					 .start();
					 
  // append the svg
  var svg = d3.select("body")
		    .append("svg")
		    .attr("width", w)	
		    .attr("height", h);

  // create and draw nodes
  var node = svg.selectAll("circle")
			    .data(dataset)
			    .enter()
			    .append("circle")
  	  		    .attr("r", 0) // so the tween doesn't freak out
  	  		    .style("fill", function(d) { return colorScale(d["pctOverObese"]); })
  	  		    .style("stroke", "rgba(255,255,255,.5)")
  	  		    .call(force.drag); // ?

  node.transition()
  	.duration(750)
  	.delay(function(d, i) { return i * 2; }) // doesn't seem to do anything
  	.attrTween("r", function(d) {
  		var i = d3.interpolate(0, rScale(d["pctOverObese"]));
  		return function(t) { return d["r"] = i(t); };
  	});
  	
  function tick(e) {
  	node
  		.each(collide(.5))
  		.attr("cx", function(d){ return d["x"];	})
  		.attr("cy", function(d){ return d["y"]; })
  		.append("title")
  	  		      .text(function(d) { 
  	  		    	//return d["AREA NAME"] + ": " + format(d["pctOverObese"]);
  	  		    	return d["x"] + "," + d["y"];
  	  			});
  }
  
  function collide(alpha) {
    var quadtree = d3.geom.quadtree(dataset);
    return function(d) {
  	  var r = d["r"] + maxRadius,
  	      nx1 = d["x"] - r,
  	      nx2 = d["x"] + r,
  	      ny1 = d["y"] - r,
  	      ny2 = d["y"] + r;
  	   quadtree.visit(function(quad, x1, y1, x2, y2) {
  	 	  if (quad.point && (quad.point !== d)) {
  	 	    var x = d["x"] - quad.point.x,
  	 	        y = d["y"] - quad.point.y,
  	 	        l = Math.sqrt(x * x + y * y),
  	 	        r = d["r"] + quad.point.radius;
  	 	    if (l < r) {
  	 	  	  l = (l - r) / l * alpha;
  	 	  	  d["x"] -= x *= l;
  	 	  	  d["y"] -= y *= l;
  	 	  	  quad.point.x += x;
  	 	  	  quad.point.y += y;
  	 	    }
  	 	  }
  	 	  return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  	   });
    };
  }

}); // end of d3.csv

d3.select(self.frameElement).style("height", h + "px");

</script>
</body>
</html>