javascriptd3.js

Set axis range based on data set minimum and maximum in d3.js


I'm trying to set the x and y axes ranges based on the maximum and minimum values for each (i.e., max and min for x and max and min for y). I know that domain controls this range, but I can't figure out how to set it dynamically based on the data. I know a bunch of this code isn't applicable to the issue, but figured I'd post it all. Here goes:

var margin = {t:30, r:20, b:20, l:40 },
    w = 600 - margin.l - margin.r,
    h = 500 - margin.t - margin.b,
    x = d3.scale.linear().range([0, w]),
    y = d3.scale.linear().range([h - 60, 0]),
    //colors that will reflect geographical regions
    color = d3.scale.category10();

var svg = d3.select("#chart").append("svg")
    .attr("width", w + margin.l + margin.r)
    .attr("height", h + margin.t + margin.b);
    fig = svg.append("g").attr("transform", "translate(40, 20)");

// set axes, as well as details on their ticks
var xAxis = d3.svg.axis()
    .scale(x)
    .ticks(20)
    .tickSubdivide(true)
    .tickSize(6, 3, 0)

    .orient("bottom");


var yAxis = d3.svg.axis()
    .scale(y)
    .ticks(20)
    .tickSubdivide(true)
    .tickSize(6, 3, 0)
    .orient("left");

var startX = d3.min(x.domain()),
endX = d3.max(x.domain()),
startY = d3.min(y.domain()),
endY = d3.max(y.domain());
var lines = [{x1: startX, x2: endX, y1: (startY + endY)/2, y2: (startY + endY)/2},
         {x1: (startX + endX)/2, x2: (startX + endX)/2, y1: startY, y2: endY}]

fig.selectAll(".grid-line")
.data(lines).enter()
.append("line")
.attr("x1", function(d){ return x(d.x1); })
.attr("x2", function(d){ return x(d.x2); })
.attr("y1", function(d){ return y(d.y1); })
.attr("y2", function(d){ return y(d.y2); })
.style("stroke", "#000")



// group that will contain all of the plots
var groups = svg.append("g").attr("transform", "translate(" + margin.l + "," + margin.t + ")");

// array of the regions, used for the legend
var regions = ["Demographic", "Financial", "Content Interests", "Social Media", "Behaviors & Attributes", "Location Distribution","CPG Buying"]



d3.csv("trust-business.csv", function(data) {

// sort data alphabetically by region, so that the colors match with legend
data.sort(function(a, b) { return d3.ascending(a.region, b.region); })
console.log(data)

var x0 = Math.max(-d3.min(data, function(d) { return d.trust; }), d3.max(data, function(d) { return d.trust; }));


x.domain([0,100]);
y.domain([0,100])

// style the circles, set their locations based on data
var circles =
groups.selectAll("circle")
    .data(data)
  .enter().append("circle")
  .attr("class", "circles")
  .attr({
    cx: function(d) { return x(+d.trust); },
    cy: function(d) { return y(+d.business); },
    r: 8,
    id: function(d) { return d.country; }
  })
    .style("fill", function(d) { return color(d.region); });

// what to do when we mouse over a bubble
var mouseOn = function() { 
    var circle = d3.select(this);

// transition to increase size/opacity of bubble
    circle.transition()
    .duration(800).style("opacity", 1)
    .attr("r", 16).ease("elastic");

    // append lines to bubbles that will be used to show the precise data points.
    // translate their location based on margins
    svg.append("g")
        .attr("class", "guide")
    .append("line")
        .attr("x1", circle.attr("cx"))
        .attr("x2", circle.attr("cx"))
        .attr("y1", +circle.attr("cy") + 26)
        .attr("y2", h - margin.t - margin.b)
        .attr("transform", "translate(40,20)")
        .style("stroke", circle.style("fill"))
        .transition().delay(200).duration(400).styleTween("opacity", 
                    function() { return d3.interpolate(0, .5); })

    svg.append("g")
        .attr("class", "guide")
    .append("line")
        .attr("x1", +circle.attr("cx") - 16)
        .attr("x2", 0)
        .attr("y1", circle.attr("cy"))
        .attr("y2", circle.attr("cy"))
        .attr("transform", "translate(40,30)")
        .style("stroke", circle.style("fill"))
        .transition().delay(200).duration(400).styleTween("opacity", 
                    function() { return d3.interpolate(0, .5); });

// function to move mouseover item to front of SVG stage, in case
// another bubble overlaps it
    d3.selection.prototype.moveToFront = function() { 
      return this.each(function() { 
        this.parentNode.appendChild(this); 
      }); 
    };

// skip this functionality for IE9, which doesn't like it
    if (!$.browser.msie) {
        circle.moveToFront();   
        }
};
// what happens when we leave a bubble?
var mouseOff = function() {
    var circle = d3.select(this);

    // go back to original size and opacity
    circle.transition()
    .duration(800).style("opacity", .5)
    .attr("r", 8).ease("elastic");

    // fade out guide lines, then remove them
    d3.selectAll(".guide").transition().duration(100).styleTween("opacity", 
                    function() { return d3.interpolate(.5, 0); })
        .remove()
};

// run the mouseon/out functions
circles.on("mouseover", mouseOn);
circles.on("mouseout", mouseOff);

// tooltips (using jQuery plugin tipsy)
circles.append("title")
        .text(function(d) { return d.country; })

$(".circles").tipsy({ gravity: 's', });

// the legend color guide
var legend = svg.selectAll("rect")
        .data(regions)
    .enter().append("rect")
    .attr({
      x: function(d, i) { return (40 + i*80); },
      y: h,
      width: 25,
      height: 12
    })
    .style("fill", function(d) { return color(d); });


// legend labels    
    svg.selectAll("text")
        .data(regions)
    .enter().append("text")
    .attr({
    x: function(d, i) { return (40 + i*80); },
    y: h + 24,
    })
    .text(function(d) { return d; });

// draw axes and axis labels
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(" + margin.l + "," + (h - 60 + margin.t) + ")")
    .call(xAxis);

svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + margin.l + "," + margin.t + ")")
    .call(yAxis);

svg.append("text")
    .attr("class", "x label")
    .attr("text-anchor", "end")
    .attr("x", w + 50)
    .attr("y", h - margin.t - 5)
    .text("Total Incidence");

svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("x", -20)
    .attr("y", 45)
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text("Relative Variance");
});

Solution

  • You can use d3.extent() to get the extent of an array and use it in a domain:

    x.domain(d3.extent(data, function(d) { return +d.trust; }));
    y.domain(d3.extent(data, function(d) { return +d.business; }));