function scatterPlot() {
  // Private variables
  var margin = { top: 20, right: 20, bottom: 50, left: 100 };
  var width = 960 - margin.left - margin.right;
  var height = 500 - margin.top - margin.bottom;
  var color = d3.scale.category20();
  var dispatch = d3.dispatch("mouseover", "mouseout");
 
  var x = function (d) { return d.x; };
  var y = function (d) { return d.y; };
  var radius = function (d) { return d.radius; };
  var fill = function (d) { return d.color; };
  var stroke = function (d) { return color(d.color); };
  var strokeWidth = 0;
  var opacity = 1;
  var circleClass = "circle";
 
  var xScale = d3.scale.linear();
  var yScale = d3.scale.log();
  var xAxis = d3.svg.axis().orient("bottom");
  var yAxis = d3.svg.axis().orient("left");
 
  var axisX = { 
    axisClass: "x axis", 
    titleClass: "x-label",
    x: function () { return width / 2; },
    y: 30,
    dy: ".71em",
    textAnchor: "middle",
    title: ""
  };
 
  var axisY = {
    axisClass: "y axis", 
    titleClass: "y-label",
    x: function () { return -height / 2; },
    y: -60,
    dy: ".71em",
    textAnchor: "middle",
    title: ""
  };
 
  function chart(selection) {
    selection.each(function (data, index) {
 
      // Re-define data. Do not alter original dataset
      data.forEach(function (d, i) {
        d.x = x.call(data, d, i);
        d.y = y.call(data, d, i);
        d.radius = radius.call(data, d, i);
        d.color = fill.call(data, d, i);
      });
 
      var svg = d3.select("#chart").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
 
      xScale
        .domain(d3.extent(data, function (d) { return d.x; }))
        .range([0, width])
        .nice();
 
      yScale
        .domain(d3.extent(data, function (d) { return d.y; }))
        .range([height, 0])
        .nice();
 
      // Creating the x axis.
      svg.append("g")
        .attr("class", axisX.axisClass)
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis.scale(xScale))
        .append("text")
        .attr("class", axisX.titleClass)
        .attr("x", axisX.x)
        .attr("y", axisX.y)
        .attr("dy", axisX.dy)
        .style("text-anchor", axisX.textAnchor)
        .text(axisX.title);
 
      // Creating the y axis.
      svg.append("g")
        .attr("class", axisY.axisClass)
        .call(yAxis.scale(yScale).tickFormat(yScale.tickFormat(10, ",.1s")))
        .append("text")
        .attr("class", axisY.titleClass)
        .attr("transform", "rotate(-90)")
        .attr("x", axisY.x)
        .attr("y", axisY.y)
        .attr("dy", axisY.dy)
        .style("text-anchor", axisY.textAnchor)
        .text(axisY.title);
 
      // Creating clipPath - prevents circles from
      // being drawn outside the chart
      svg.append("clipPath")
        .attr("id", "chart-area")
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", width)
        .attr("height", height);
 
      // Creating the bubble chart.
      var g = svg.append("g")
        .attr("class", "group")
        .attr("clip-path", "url(#chart-area)");
        
      var circles = g.selectAll("circle")
        .data(data.sort(function (a, b) {
          return b.radius - a.radius;
        }));
      
      // Exit  
      circles.exit().remove();
      
      // Enter
      circles.enter().append("circle")
        .attr("class", circleClass)
        .attr("r", function (d) { return d.radius; });
        
      // Update
      circles
        .attr("cx", function (d) { return xScale(d.x); })
        .attr("cy", function (d) { return yScale(d.y); })
        .attr("stroke", stroke)
        .attr("stroke-width", strokeWidth)
        .style("fill", function (d) { return color(d.color); })
        .style("opacity", opacity)
        .on("mouseover", function (d, i) {
          return dispatch.mouseover.call(this, d, i);
        })
        .on("mouseout", function (d, i) {
          return dispatch.mouseout.call(this, d, i);
        });
    });
  }
 
  // Public API
  chart.margin = function (_) {
    if (!arguments.length) { return margin; }
    margin.top = typeof _.top !== "undefined" ? _.top : margin.top;
    margin.right = typeof _.right !== "undefined" ? _.right : margin.right;
    margin.bottom = typeof _.bottom !== "undefined" ? _.bottom : margin.bottom;
    margin.left = typeof _.left !== "undefined" ? _.left : margin.left;
    return chart;
  };
 
  chart.width = function (_) {
    if (!arguments.length) return width;
    width = _;
    return chart;
  };
 
  chart.height = function (_) {
    if (!arguments.length) return height;
    height = _;
    return chart;
  };
 
  chart.color = function (_) {
    if (!arguments.length) return color;
    color = _;
    return chart;
  };
 
  chart.x = function (_) {
    if (!arguments.length) return x;
    x = _;
    return chart;
  };
 
  chart.y = function (_) {
    if (!arguments.length) return y;
    y = _;
    return chart;
  };
 
  chart.xScale = function (_) {
    if (!arguments.length) return xScale;
    xScale = _;
    return chart;
  };
 
  chart.yScale = function (_) {
    if (!arguments.length) return yScale;
    yScale = _;
    return chart;
  };

  chart.radius = function (_) {
    if (!arguments.length) return radius;
    radius = _;
    return chart;
  };
 
  chart.stroke = function (_) {
    if (!arguments.length) return stroke;
    stroke = _;
    return chart;
  };
 
  chart.strokeWidth = function (_) {
    if (!arguments.length) return strokeWidth;
    strokeWidth = _;
    return chart;
  };
 
  chart.opacity = function (_) {
    if (!arguments.length) return opacity;
    opacity = _;
    return chart;
  };
 
  chart.fill = function (_) {
    if (!arguments.length) return fill;
    fill = _;
    return chart;
  };

  chart.dispatch = function (_) {
    if (!arguments.length) return dispatch;
    dispatch = _;
    return chart;
  };

  chart.circleClass = function (_) {
    if (!arguments.length) return circleClass;
    circleClass = _;
    return chart;
  };
 
  chart.axisX = function (_) {
    if (!arguments.length) { return axisX; }
    axisX.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisX.axisClass;
    axisX.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisX.titleClass;
    axisX.x = typeof _.x !== "undefined" ? _.x : axisX.x;
    axisX.y = typeof _.y !== "undefined" ? _.y : axisX.y;
    axisX.dy = typeof _.dy !== "undefined" ? _.dy : axisX.dy;
    axisX.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisX.textAnchor;
    axisX.title = typeof _.title !== "undefined" ? _.title : axisX.title;
    return chart;
  };
 
  chart.axisY = function (_) {
    if (!arguments.length) { return axisY; }
    axisY.axisClass = typeof _.axisClass !== "undefined" ? _.axisClass : axisY.axisClass;
    axisY.titleClass = typeof _.titleClass !== "undefined" ? _.titleClass : axisY.titleClass;
    axisY.x = typeof _.x !== "undefined" ? _.x : axisY.x;
    axisY.y = typeof _.y !== "undefined" ? _.y : axisY.y;
    axisY.dy = typeof _.dy !== "undefined" ? _.dy : axisY.dy;
    axisY.textAnchor = typeof _.textAnchor !== "undefined" ? _.textAnchor : axisY.textAnchor;
    axisY.title = typeof _.title !== "undefined" ? _.title : axisY.title;
    return chart;
  };
 
  d3.rebind(chart, dispatch, "on");
  return chart;
}