Merge D3 Scatterplot with D3 Google Map

I have a D3, Google map and put the points of latitude and longitude from the CSV file to the Google map. Below is the D3 code that creates a map and displays data points from a CSV file.

// Create the Google Map…
var map = new google.maps.Map(d3.select("#map").node(), {
  zoom: 7,
  center: new google.maps.LatLng(51.5000, 0.1167),
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

var data = [
      { oa: "E00000001", lng: -0.095154937, lat: 51.520236 },
      { oa: "E00000003", lng: -0.096352226, lat: 51.519869 },  
      { oa: "E00000005", lng: -0.096674785, lat: 51.519047 },
      { oa: "E00000007", lng: -0.096970467, lat: 51.516795 },
      { oa: "E00000010", lng: -0.097464624, lat: 51.522576 },
      { oa: "E00000012", lng: -0.09591956 , lat: 51.521948 },
      { oa: "E00000013", lng: -0.096452804, lat: 51.520914 },
      { oa: "E00000014", lng: -0.096907519, lat: 51.522108 },
      { oa: "E00000016", lng: -0.093145103, lat: 51.521076 },
      { oa:"E00000017", lng: -0.091830999, lat: 51.520443 },
    ];


// Load the station data. When the data comes back, create an overlay.
var overlay = new google.maps.OverlayView();

// Add the container when the overlay is added to the map.
overlay.onAdd = function() {
  var layer = d3.select(this.getPanes().overlayLayer).append("div")
        .attr("height", "100%")
        .attr("width", "100%")
        .attr("class", "stations")
        .attr("id", "layer");

  layer[0][0].style.width = "1366px";
  layer[0][0].parentNode.style.width = "100%";
  layer[0][0].parentNode.style.height = "100%";
  layer[0][0].parentNode.parentNode.style.width = "100%";
  layer[0][0].parentNode.parentNode.style.height = "100%";
  layer[0][0].parentNode.parentNode.parentNode.style.width = "100%";
  layer[0][0].parentNode.parentNode.parentNode.style.height = "100%";
  layer[0][0].parentNode.parentNode.parentNode.parentNode.style.width = "100%";
  layer[0][0].parentNode.parentNode.parentNode.parentNode.style.height = "100%";

  // Draw each marker as a separate SVG element.
  // We could use a single SVG, but what size would it have?
  overlay.draw = function() {
    var projection = this.getProjection(),
        padding = 10;

    var marker = layer.selectAll("svg")
        .data( data )
        .each(transform) // update existing markers
      .enter().append("svg:svg")
        .each(transform)
        .attr("class", "marker aaa")

    marker.append("svg:circle")
        .attr("r", 7)
        .attr("cx", padding )
        .attr("cy", padding );

    // add a label.
    marker.append("svg:text")
        .attr("x", padding + 7)
        .attr("y", padding)
        .attr("dy", ".31em")
        .text( function(d) { 
          return d.oa; }
        );

    var v = d3.geom.voronoi( translate(data) );
    console.log( "v is :" );
    console.log( v );

    var edges = layer.selectAll("path")
        .data( v )
      .enter().append("svg:svg").attr("width", "100%").attr("width","100%").style("position", "absolute")
        .append("svg:path")
        .attr( "d", function(d){
          var e = transform_path(d)
          var p = 'M' + e.join('L') + 'Z'
          console.log( 'PATH: ' + p)
          return p
        }).attr("fill", "none").attr("stroke", "black")
        ;

    function translate(data) {
      var d = []
      for( var i=0; i<data.length; i++){
        var c = [ data[i].lat, data[i].lng ]
        d.push( c )
      }
      return d
    }

    function _projection( lat, lng ) {
      e = new google.maps.LatLng( lat, lng );
      e = projection.fromLatLngToDivPixel(e);
      return [ e.x - padding, e.y - padding]
      // return [ e.x, e.y ]
    }

    function transform(d) {
      e = _projection( d.lat, d.lng )
      console.log("marker " + d.lat +', ' + d.lng + " -> left: " + e[0] +", top: " + e[1] )
      return d3.select(this)
          .style("left", e[0] + "px")
          .style("top", e[1] + "px");
    }

    function transform_path(data) {
      var d = []
      console.log(data)
      for( var i=0; i<data.length; i++) {
        var c = _projection( data[i][0], data[i][1] )
        console.log( ' path point: ' + JSON.stringify(data[i]) + ' -> left: ' + c[0] + ", top: " + c[1])
        d.push( c )
      }
      // console.log(d)
      return d
    }

  };
};

// Bind our overlay to the map…
overlay.setMap(map);

Now, using the same D3 card code, I want to change it to allow D3 Scatterplot Matrix Brushing Scatterplot to be used on the card.

More precisely, I am trying to get the same brush selection (from the Scatterplot example) using the map and my plotted data points.

I tried to play with Scatterplot and the Google D3 map code to combine them somehow, but did not see to get a brush selection from the Scatterplot example to work on my map.

here is the Scatterplot code:

<b>
<!DOCTYPE html>
<meta charset="utf-8">
<style>

svg {
   font: 10px sans-serif;
   padding: 10px;
}

.axis,
.frame {
   shape-rendering: crispEdges;
}

.axis line {
   stroke: #ddd;
}

.axis path {
   display: none;
}

.frame {
   fill: none;
   stroke: #aaa;
}

circle {
   fill-opacity: .7;
}

circle.hidden {
   fill: #ccc !important;
}

.extent {
   fill: #000;
   fill-opacity: .125;
   stroke: #fff;
 }

</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var width = 960,
  size = 150,
  padding = 19.5;

var x = d3.scale.linear()
  .range([padding / 2, size - padding / 2]);

var y = d3.scale.linear()
  .range([size - padding / 2, padding / 2]);

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .ticks(5);

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left")
  .ticks(5);

var color = d3.scale.category10();

d3.csv("flowers.csv", function(error, data) {
  var domainByTrait = {},
    traits = d3.keys(data[0]).filter(function(d) { return d !== "species"; }),
  n = traits.length;

  traits.forEach(function(trait) {
    domainByTrait[trait] = d3.extent(data, function(d) { return d[trait]; });

});

  xAxis.tickSize(size * n);
  yAxis.tickSize(-size * n);

  var brush = d3.svg.brush()
   .x(x)
   .y(y)
   .on("brushstart", brushstart)
   .on("brush", brushmove)
   .on("brushend", brushend);

  var svg = d3.select("body").append("svg")
   .attr("width", size * n + padding)
   .attr("height", size * n + padding)
  .append("g")
   .attr("transform", "translate(" + padding + "," + padding / 2 + ")");

  svg.selectAll(".x.axis")
   .data(traits)
  .enter().append("g")
    .attr("class", "x axis")
    .attr("transform", function(d, i) { return "translate(" + (n - i - 1) *  size + ",0)"; })
   .each(function(d) { x.domain(domainByTrait[d]);    d3.select(this).call(xAxis); });

  svg.selectAll(".y.axis")
   .data(traits)
  .enter().append("g")
    .attr("class", "y axis")
    .attr("transform", function(d, i) { return "translate(0," + i * size + ")"; })
   .each(function(d) { y.domain(domainByTrait[d]);  d3.select(this).call(yAxis); });

  var cell = svg.selectAll(".cell")
   .data(cross(traits, traits))
  .enter().append("g")
   .attr("class", "cell")
   .attr("transform", function(d) { return "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")"; })
   .each(plot);

 // Titles for the diagonal.
 cell.filter(function(d) { return d.i === d.j; }).append("text")
   .attr("x", padding)
   .attr("y", padding)
   .attr("dy", ".71em")
   .text(function(d) { return d.x; });

 cell.call(brush);

function plot(p) {
  var cell = d3.select(this);

  x.domain(domainByTrait[p.x]);
  y.domain(domainByTrait[p.y]);

  cell.append("rect")
    .attr("class", "frame")
    .attr("x", padding / 2)
    .attr("y", padding / 2)
    .attr("width", size - padding)
    .attr("height", size - padding);

  cell.selectAll("circle")
    .data(data)
   .enter().append("circle")
    .attr("cx", function(d) { return x(d[p.x]); })
    .attr("cy", function(d) { return y(d[p.y]); })
    .attr("r", 3)
    .style("fill", function(d) { return color(d.species); });
 }

 var brushCell;

// Clear the previously-active brush, if any.
function brushstart(p) {
if (brushCell !== this) {
  d3.select(brushCell).call(brush.clear());
  x.domain(domainByTrait[p.x]);
  y.domain(domainByTrait[p.y]);
  brushCell = this;
}
}

// Highlight the selected circles.
function brushmove(p) {
var e = brush.extent();
svg.selectAll("circle").classed("hidden", function(d) {
  return e[0][0] > d[p.x] || d[p.x] > e[1][0]
      || e[0][1] > d[p.y] || d[p.y] > e[1][1];
});
}

// If the brush is empty, select all circles.
function brushend() {
if (brush.empty()) svg.selectAll(".hidden").classed("hidden", false);
}

function cross(a, b) {
var c = [], n = a.length, m = b.length, i, j;
for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j});
return c;

}

d3.select(self.frameElement).style( "height", * n + padding + 20 + "px" ); });

</script>
</b>

- ?

+4

All Articles