Data Vis, Heat map, D3 Legend Struggles

I’m working on the 3rd project for the Data Vis certification. Believe it or not I started this project 5 years ago, and could never refine it, so I started it fresh.

I’m pretty pleased I have the main temperature data and axes correctly displayed.

Now I am working on the Legend, and this is my pseudocode:

//create new svg for legend width 400 - margins
//determine the domain of temp data  using d3.extent()
//create linearScale based on size of SVG for legend as range (margin + width - margin)
//create the array containing the stepped intervals for the full scale of temp data using d3.range
//add a new "rect" element based on this array using data / enter / append flow
//determine x value using legendXSCale(temperature )

The problem is when I plug the lowest and highest temps from my temp range into the scale function, it correctly returns an X value within the SVG size I established for the legend.

But when I try to then get X values for my “rect” elements with a data callback function using the exact same scale, and all the temp values in the array between the low & high I tested above, the X values are mostly beyond the range of the SVG, and don’t appear on my output.

Here is my legend code:

//       //Make the legend
//       //https://gist.github.com/mbostock/4573883
        let legendH = 50
        let legendW = 400
      const legend = d3
        .select("body")
        .append("svg")
        .attr("id", "legend")
        .attr("width", legendW)
        .attr("height", legendH);

      //create a set of evenly spaced discrete values to be used for the domain
     
      //get min & max of temp variance
      var tempRange = d3.extent(monthlyVariance, (d) => d.variance);
      
      //calculate step size based on number of categories/ length of color array
      var step = (tempRange[1] - tempRange[0]) / colors.length;
      
     //create array of evenly spaced temps from low to high in dataset
      var temperatureDomain = d3.range(
        tempRange[0] + baseTemperature,
        tempRange[1] + baseTemperature,
        step
      )
      .map((elem) => parseFloat(elem.toFixed(2)));
      console.log (temperatureDomain)

      //create the threshold limits for each color category
      var thresholdScale = d3
        .scaleThreshold()
        .domain(temperatureDomain)
        .range([
          "5E4FA2",
          "#3288BD",
          "#66C2A5",
          "#ABDDA4",
          "#E6F598",
          "#FFFFBF",
          "#FEE08B",
          "#FDAE61",
          "#F46D43",
          "#D53E4F",
          "#9E0142"
        ]);

      //create the linear scale for the legend's individual categories
      
      var legendLinearXScale = d3
      .scaleLinear()
      .domain(tempRange)
      .range([margin.left, legendW - margin.right]);

 //draw the legend boxes "rect" (based on code above)
      legend
        .selectAll("rect")
        .data(temperatureDomain)
        .enter()
        .append("rect")
        .attr("class", "legend")
        .attr("x", (d) => legendLinearXScale(d))
        .attr("y", 20)
        .attr("width", 20)
        .attr("height", 20)

//         //colr them
        .style("fill", (d) => zScale(d))

Here is my logging code to compare the values

      console.log("Range for lowest temp: ", parseInt(legendLinearXScale(tempRange[0].toFixed(2))))
      console.log("Range for highest temp: ", parseInt(legendLinearXScale(tempRange[1].toFixed(2))))
      
      console.log("Range for the full temp scale")
      temperatureDomain.forEach((elem) => {
      console.log(elem,parseInt(legendLinearXScale(elem).toFixed(2)) )
      })

Here is the output on the console

Range for lowest temp:  59
Range for highest temp:  380
Range for the full temp scale
Temp Range
1.68 286
2.79 316
3.9 345
5.01 374
6.12 403
7.23 432
8.34 461
9.45 490
10.56 519
11.67 548
12.78 578

Why isn’t the same number being returned each time for the same input ?

Here is a link to the full pen:
https://codepen.io/AdventureBear/pen/KKBGGvB

Alright I solved this myself! Typing out the full question for someone else (you folks) helps clarify the issue.

In this case I was not accounting for base temperature when creating my temperature range, then was adding the base temperature back in when creating my array of temp values.

So the top end of my initial domain was about 5 degrees, but my highest temp was 12+ degrees, so naturally it would be scaled beyond the top of my intended domain.

INstead i added in the base temperature when calculating the high & low range and scaled on that value. Seems to be working. Just a few more tweaks to pass the rest of the tests.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.