D3 v6 Choropleth Map仅显示单一颜色问题求助
D3 v6 等值区域地图单一颜色问题解决
问题说明
使用D3 v6制作等值区域地图时,地图仅显示单一颜色,期望基于total_cases_per_million字段为不同国家着色,控制台无报错。
原代码
// The svg const margin ={ top: 500, bottom: 500, left: 100, right: 0}, width = 600, height = 500; //Choropleth Map const svg1 = d3.select('body') .append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) // Map and projection const path = d3.geoPath(); const projection = d3.geoMercator() .scale(70) .center([0,20]) .translate([width / 2, height / 2]); // Data and color scale const data = new Map(); const colorScale = d3.scaleThreshold() .domain([0, 300000000]) .range(d3.schemeBlues[9]); // Load external data and boot Promise.all([ d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"), d3.csv("mapdata.csv", function(d) { data.set(d.country, +d.total_cases_per_million); }) ]).then(function(loadData){ let topo = loadData[0] console.log(data); let mouseOver = function(d) { d3.selectAll(".Country") .transition() .duration(200) .style("opacity", .5) d3.select(this) .transition() .duration(200) .style("opacity", 1) .style("stroke", "black") } let mouseLeave = function(d) { d3.selectAll(".Country") .transition() .duration(200) .style("opacity", .8) d3.select(this) .transition() .duration(200) .style("stroke", "transparent") } // Draw the map svg1.append("g") .selectAll("path") .data(topo.features) .enter() .append("path") // draw each country .attr("d", d3.geoPath() .projection(projection) ) // set the color of each country .attr("fill", function (d) { d.total = data.get(data.total_cases_per_million) || 0; return colorScale(d.total); }) .style("stroke", "transparent") .attr("class", function(d){ return "Country" } ) .style("opacity", .8) .on("mouseover", mouseOver ) .on("mouseleave", mouseLeave ) })
CSV数据示例
iso_code,country,total_cases_per_million AFG,Afghanistan,2917418.02 ALB,Albania,58135447.4 DZA,Algeria,3715179.438 AND,Andorra,270897098
当前效果

问题根源与修复方案
1. 数据匹配错误(核心问题)
设置填充色的回调中,data.get(data.total_cases_per_million)写法错误:data是Map对象,不存在total_cases_per_million属性,导致始终取不到对应国家的数值,最终d.total默认值为0,所有国家都使用同一颜色。
需改为通过GeoJSON中每个国家的名称(d.properties.name)匹配Map中的total_cases_per_million值:
.attr("fill", function (d) { d.total = data.get(d.properties.name) || 0; return colorScale(d.total); })
2. 颜色比例尺Domain设置不合理
d3.scaleThreshold的Domain需要设置与Range长度匹配的阈值数量:Range用了d3.schemeBlues[9](9种颜色),因此Domain需要8个阈值划分9个区间。原代码仅设置[0, 300000000],仅能划分2个区间,无法充分利用颜色梯度。
建议根据数据实际分布生成合理阈值,比如使用分位数:
// 提取Map中所有数值 const values = Array.from(data.values()); // 生成8个分位数作为阈值 const thresholds = d3.scaleQuantize() .domain(d3.extent(values)) .range(d3.range(8)) .thresholds(); const colorScale = d3.scaleThreshold() .domain(thresholds) .range(d3.schemeBlues[9]);
修正后的关键代码片段
// Data and color scale const data = new Map(); // Load external data and boot Promise.all([ d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"), d3.csv("mapdata.csv", function(d) { data.set(d.country, +d.total_cases_per_million); }) ]).then(function(loadData){ let topo = loadData[0]; const values = Array.from(data.values()); const thresholds = d3.scaleQuantize() .domain(d3.extent(values)) .range(d3.range(8)) .thresholds(); const colorScale = d3.scaleThreshold() .domain(thresholds) .range(d3.schemeBlues[9]); // ... 其他代码保持不变 // Draw the map svg1.append("g") .selectAll("path") .data(topo.features) .enter() .append("path") .attr("d", d3.geoPath().projection(projection)) .attr("fill", function (d) { d.total = data.get(d.properties.name) || 0; return colorScale(d.total); }) // ... 其他属性和事件监听保持不变 })
内容的提问来源于stack exchange,提问作者Mr.Muu
相关产品推荐
相关产品推荐

