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