我在D3 JS中制作热图,其中沿X轴为Year,沿Y轴为Month.每个单元格都是温度,并基于此获得不同的"填充"颜色.我的问题是如何制作一个使用一系列颜色代码映射minTemp/maxTemp域的色标.到目前为止我有下面的代码,但这不起作用:
var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/global-temperature.json" d3.json(url, function(json){ //load data from API and save in variable data var data = json.monthlyVariance; var baseTemp = json.baseTemperature; //Add temperature to each object in data set for(var i = 0; i < data.length; i++){ var temperature = baseTemp + data[i].variance data[i].temperature = temperature; var monthString = ""; switch(data[i].month){ case 1: data[i].monthString = "January"; break; case 2: data[i].monthString = "February"; break; case 3: data[i].monthString = "March"; break; case 4: data[i].monthString = "April"; break; case 5: data[i].monthString = "May"; break; case 6: data[i].monthString = "June"; break; case 7: data[i].monthString = "July"; break; case 8: data[i].monthString = "August"; break; case 9: data[i].monthString = "September"; break; case 10: data[i].monthString = "October"; break; case 11: data[i].monthString = "November"; break; case 12: data[i].monthString = "December"; break; } } //Set dimensions of div container, svg, and chart area(g element) var margin = {top: 20, right: 40, bottom: 40, left: 80}; //Width of the chart, within SVG element var w = 1000 - margin.left - margin.right; //Height of the chart, within SVG element var h = 500 - margin.top - margin.bottom; //Create SVG element and append to #chart div container var svg = d3.select("#chart") .append("svg") .attr("width", w + margin.left + margin.right) .attr("height", h + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //Get Min Max values var maxYear = d3.max(data, function(d){ return d.year; }); var minYear = d3.min(data, function(d){ return d.year; }); var maxTemp = d3.max(data, function(d){ return d.temperature; }); var minTemp = d3.min(data, function(d){ return d.temperature; }) //Create X scale, axis and label var xScale = d3.scaleLinear() .domain([minYear, maxYear]) .range([0,w]); var xAxis = d3.axisBottom() .scale(xScale) .ticks(20) .tickFormat(d3.format("d")); svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + h + ")") .call(xAxis); //Create Y scale, axis and label var cellHeight = (h / 12); var yRange = []; for(var i = 0; i < 12 ; i++){ yRange.push(i * cellHeight); } var yScale = d3.scaleOrdinal() .domain(["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]) .range(yRange); var yAxis = d3.axisLeft() .scale(yScale) .ticks(12); svg.append("g") //append a g element .attr("class", "axis") .call(yAxis) //call yAxis function on this g element .selectAll(".tick text") //select all elements with class tick and nested text element .attr("transform", "translate(0," + (cellHeight/2) + ")"); //move all text elements half a cell height down //Create color scale var colors = d3.scaleOrdinal() .domain([minTemp,maxTemp]) .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]); //Select all rect elements in G container element, bind data and append var cells = svg.selectAll("cells") .data(data) .enter() .append("rect"); var cellAttributes = cells .attr("x", function(d){ return xScale(d.year); }) .attr("y", function(d){ return yScale(d.monthString); }) .attr("width", w/(maxYear-minYear)) .attr("height", h/12) .attr("fill", function(d){ return colors(d); }) .attr("class", "cell"); });
我可以在fill属性函数中编写一个long if/else语句,将温度映射到颜色代码,但这不是我认为的"D3方式".我怎么能用比例做?:
var colors = d3.scaleOrdinal() .domain([minTemp,maxTemp]) .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
Gerardo Furt.. 14
你不需要这里的顺序尺度.您需要量化比例:
量化标度类似于线性标度,除了它们使用离散而非连续范围.基于输出范围中的值的数量(即,基数),将连续输入域划分为均匀段.
因此,这应该是你的规模:
var colors = d3.scaleQuantize() .domain([minTemp,maxTemp]) .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
这是一个演示:
var data = d3.range(50);
var colors = d3.scaleQuantize()
.domain([0,50])
.range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598",
"#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
var svg = d3.select("svg");
var rects = svg.selectAll(".rects")
.data(data)
.enter()
.append("rect")
.attr("y", 10)
.attr("height", 100)
.attr("x", (d,i)=>10 + i*9)
.attr("width", 6)
.attr("fill", d=>colors(d))
.attr("stroke", "gray");
您也可以使用scaleLinear
,它具有在颜色之间进行插值的优点(因此,您的颜色数组中将包含多于11种颜色).但是,请注意在域中设置相同数量的元素,使用d3.ticks
:
d3.ticks(minTemp, maxTemp, 11);
这是一个演示scaleLinear
:
var data = d3.range(50);
var colors = d3.scaleLinear()
.domain(d3.ticks(0, 50, 11))
.range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598",
"#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
var svg = d3.select("svg");
var rects = svg.selectAll(".rects")
.data(data)
.enter()
.append("rect")
.attr("y", 10)
.attr("height", 100)
.attr("x", (d,i)=>10 + i*9)
.attr("width", 6)
.attr("fill", d=>colors(d))
.attr("stroke", "gray");
你不需要这里的顺序尺度.您需要量化比例:
量化标度类似于线性标度,除了它们使用离散而非连续范围.基于输出范围中的值的数量(即,基数),将连续输入域划分为均匀段.
因此,这应该是你的规模:
var colors = d3.scaleQuantize() .domain([minTemp,maxTemp]) .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
这是一个演示:
var data = d3.range(50);
var colors = d3.scaleQuantize()
.domain([0,50])
.range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598",
"#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F", "#9E0142"]);
var svg = d3.select("svg");
var rects = svg.selectAll(".rects")
.data(data)
.enter()
.append("rect")
.attr("y", 10)
.attr("height", 100)
.attr("x", (d,i)=>10 + i*9)
.attr("width", 6)
.attr("fill", d=>colors(d))
.attr("stroke", "gray");