0

I am trying to create two heatmaps showing different data updated by a common date drop down. I am using heatmap with data update and creating two separate svgs to update when a new date field is selected in the dropdown. I was able to follow some of the SO answers to create two plots in the same page, but I am totally clueless as to have just one drop down of the locations update both charts simultaneously. Any pointers on how to achieve this would be greatly appreciated. I have included the code I have been working with and the json data. I have the data in two different files for now. Would be even better if it can be just from one file to make it easier to read the location dropdown value.

var dataset;
  var dataset2;
  var days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
 times = d3.range(24);
  
  var margin = {top:40, right:50, bottom:70, left:50};
  
  // calculate width and height based on window size
  var w = Math.max(Math.min(window.innerWidth, 1000), 500) - margin.left - margin.right - 20,
  gridSize = Math.floor(w / times.length),
 h = gridSize * (days.length+2);

  //reset the overall font size
 var newFontSize = w * 62.5 / 900;
 d3.select("html").style("font-size", newFontSize + "%");
  
  // svg container
  var svg = d3.select("#heatmap")
   .append("svg")
   .attr("width", w + margin.top + margin.bottom)
   .attr("height", h + margin.left + margin.right)
   .append("g")
   .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
 
  // svg container
  var svg2 = d3.select("#heatmap2")
   .append("svg")
   .attr("width", w + margin.top + margin.bottom)
   .attr("height", h + margin.left + margin.right)
   .append("g")
   .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  
  // linear colour scale
  var colours = d3.scaleLinear()
   .domain(d3.range(1, 11, 1))
   .range(["#87cefa", "#86c6ef", "#85bde4", "#83b7d9", "#82afce", "#80a6c2", "#7e9fb8", "#7995aa", "#758b9e", "#708090"]);
  
  var dayLabels = svg.selectAll(".dayLabel")
   .data(days)
   .enter()
   .append("text")
   .text(function(d) { return d; })
   .attr("x", 0)
   .attr("y", function(d, i) { return i * gridSize; })
   .style("text-anchor", "end")
  .attr("transform", "translate(-6," + gridSize / 1.5 + ")")
  
  var dayLabels = svg2.selectAll(".dayLabel")
   .data(days)
   .enter()
   .append("text")
   .text(function(d) { return d; })
   .attr("x", 0)
   .attr("y", function(d, i) { return i * gridSize; })
   .style("text-anchor", "end")
  .attr("transform", "translate(-6," + gridSize / 1.5 + ")")

  var timeLabels = svg.selectAll(".timeLabel")
    .data(times)
    .enter()
    .append("text")
    .text(function(d) { return d; })
    .attr("x", function(d, i) { return i * gridSize; })
    .attr("y", 0)
    .style("text-anchor", "middle")
    .attr("transform", "translate(" + gridSize / 2 + ", -6)");
 
  var timeLabels = svg2.selectAll(".timeLabel")
    .data(times)
    .enter()
    .append("text")
    .text(function(d) { return d; })
    .attr("x", function(d, i) { return i * gridSize; })
    .attr("y", 0)
    .style("text-anchor", "middle")
    .attr("transform", "translate(" + gridSize / 2 + ", -6)");

  // load data heatmap 1
  d3.json("test.json", function(error, data) {
    data.forEach(function(d) {
        d.day = +d.day;
        d.hour = +d.hour;
        d.value = +d.value;
    });
    dataset = data;

    // group data by location
    var nest = d3.nest()
      .key(function(d) { return d.location; })
      .entries(dataset);

    // array of locations in the data
    var locations = nest.map(function(d) { return d.key; });
    var currentLocationIndex = 0;

    // create location dropdown menu
    var locationMenu = d3.select("#locationDropdown1");
    locationMenu
      .append("select")
      .attr("id", "locationMenu")
      .selectAll("option")
        .data(locations)
        .enter()
        .append("option")
        .attr("value", function(d, i) { return i; })
        .text(function(d) { return d; });

    // function to create the initial heatmap
    var drawHeatmap = function(location) {

      // filter the data to return object of location of interest
      var selectLocation = nest.find(function(d) {
        return d.key == location;
      });

      var heatmap = svg.selectAll(".hour")
        .data(selectLocation.values)
        .enter()
        .append("rect")
        .attr("x", function(d) { return (d.hour-1) * gridSize; })
        .attr("y", function(d) { return (d.day-1) * gridSize; })
        .attr("class", "hour bordered")
        .attr("width", gridSize)
        .attr("height", gridSize)
        .style("stroke", "white")
        .style("stroke-opacity", 0.6)
        .style("fill", function(d) { return colours(d.value); })
      }
    drawHeatmap(locations[currentLocationIndex]);

    var updateHeatmap = function(location) {
      // filter data to return object of location of interest
      var selectLocation = nest.find(function(d) {
        return d.key == location;
      });

      // update the data and redraw heatmap
      var heatmap = svg.selectAll(".hour")
        .data(selectLocation.values)
        .transition()
          .duration(500)
          .style("fill", function(d) { return colours(d.value); })
    }

    // run update function when dropdown selection changes
    locationMenu.on("change", function() {
      // find which location was selected from the dropdown
      var selectedLocation = d3.select(this)
        .select("select")
        .property("value");
      currentLocationIndex = +selectedLocation;
      // run update function with selected location
      updateHeatmap(locations[currentLocationIndex]);
    });    

  })
  
    // load data heatmap 2
  d3.json("test2.json", function(error, data2) {
    data2.forEach(function(d2) {
        d2.day = +d2.day;
        d2.hour = +d2.hour;
        d2.value = +d2.value;
    });
    dataset2 = data2;

    // group data by location
    var nest2 = d3.nest()
      .key(function(d2) { return d2.location; })
      .entries(dataset2);

    // array of locations in the data
    var locations2 = nest2.map(function(d2) { return d2.key; });
    var currentLocationIndex2 = 0;

    // create location dropdown menu
    var locationMenu2 = d3.select("#locationDropdown2");
    locationMenu2
      .append("select")
      .attr("id", "locationMenu")
      .selectAll("option")
        .data(locations2)
        .enter()
        .append("option")
        .attr("value", function(d2, i2) { return i2; })
        .text(function(d2) { return d2; });

    // function to create the initial heatmap
    var drawHeatmap2 = function(location2) {

      // filter the data to return object of location of interest
      var selectLocation2 = nest2.find(function(d2) {
        return d2.key == location2;
      });

      var heatmap2 = svg2.selectAll(".hour")
        .data(selectLocation2.values)
        .enter()
        .append("rect")
        .attr("x", function(d2) { return (d2.hour-1) * gridSize; })
        .attr("y", function(d2) { return (d2.day-1) * gridSize; })
        .attr("class", "hour bordered")
        .attr("width", gridSize)
        .attr("height", gridSize)
        .style("stroke", "white")
        .style("stroke-opacity", 0.6)
        .style("fill", function(d2) { return colours(d2.value); })
      }
    drawHeatmap2(locations2[currentLocationIndex2]);

    var updateHeatmap2 = function(location2) {
      console.log("currentLocationIndex: " + currentLocationIndex2)
      // filter data to return object of location of interest
      var selectLocation2 = nest2.find(function(d2) {
        return d2.key == location2;
      });

      // update the data and redraw heatmap
      var heatmap2 = svg2.selectAll(".hour")
        .data(selectLocation2.values)
        .transition()
          .duration(500)
          .style("fill", function(d2) { return colours(d2.value); })
    }

    // run update function when dropdown selection changes
    locationMenu2.on("change", function() {
      // find which location was selected from the dropdown
      var selectedLocation2 = d3.select(this)
        .select("select")
        .property("value");
      currentLocationIndex2 = +selectedLocation2;
      // run update function with selected location
      updateHeatmap2(locations2[currentLocationIndex2]);
    });    

  })
<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
  html { 
      font-size: 62.5%; 
    } 
    
    body {
      margin-top: 30px;
      font-size: 1.4rem;
      font-family: 'Source Sans Pro', sans-serif;
      font-weight: 400;
      fill: #696969;
      text-align: center;
    }
    
    .timeLabel, .dayLabel {
      font-size: 1.6rem;
      fill: #AAAAAA;
      font-weight: 300;
  }

    #nav-container {
      display: flex;
      justify-content: center;
      cursor: pointer;
    }
  </style>
</head>

<body>
<div id="nav-container">
    <div id="locationDropdown1"></div>
 
</div>
<div id="heatmap"></div>
<div id="nav-container">
    <div id="locationDropdown2"></div>
 
</div>

<div id="heatmap2"></div>

JSON sample is the same as the link above .. just with some values modified to show differentiation. (Not sure how to include a big json file on here). Thanks again.

user6529266
  • 27
  • 1
  • 4
  • why do you have "identical" code to draw the heatmaps and process the JSON files? You have 2 tags with `id="nav-container"` Use scales for x and y coordinates. – rioV8 Sep 04 '18 at 17:21
  • Used the methodology similiar to here (http://bl.ocks.org/d3noob/5987480) and here (https://stackoverflow.com/questions/41940439/display-multiple-d3-js-charts-in-a-single-html-page). Unsure as to how to create a function that would take the data files as input and render it the way i want with a single drop down for location updating both charts. – user6529266 Sep 04 '18 at 18:06

0 Answers0