如何解决如何为 geoAlbersUsa() 投影绘制经度纬度坐标?
我正在尝试创建一个简单的气泡图,该图使用美国国土安全部数据按一个县的许多招生人数绘制经纬度对。我的 CSV 文件包含县名、经度、纬度、录取类型、录取类别、录取人数和原籍国。我创建了一些复选框,让用户可以看到被美国录取的不同招生类别的气泡图。
我了解到 d3geoAlbersUsa 投影将美国地图投影在 [0,0] 处,位于非洲海岸附近。从下面的照片(请参阅 Imgur 链接),您可以看到我的点似乎绘制在正确的坐标处。但是,背景地图不可见。当我使用 d3.geoMercator() 并将投影居中于 [0,0] 时,我会看到地图。在这两种情况下,我都不知道如何让气泡出现在地图上。
我是 d3 的新手,所以我不知道该怎么做。如何使用长纬度坐标和 d3geoAlbersUsa 投影创建气泡图?感谢您的帮助。
这是我的 index.html:
var width = 750
var height = 750
// The svg
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width",width)
.attr("height",height)
// Map and projection
// Map and projection
// var projection = d3.geoMercator()
// //.center([-100,30]) // GPS of location to zoom on
// .center([0,0])
// .scale(200) // This is like the zoom
// .translate([ width/2,height/2 ])
var projection = d3.geoAlbersUsa()
//.center([0,0])
.scale([1000]) // This is like the zoom
.translate([width / 2,height / 2])
var data = d3.csv("sheet.csv",function(data) {
var markers = data.filter(function(d) {
if (
(d["MajorClassAdmission"] == "EmploymentPreference1st" ||
d["MajorClassAdmission"] == "EmploymentPreference2nd" ||
d["MajorClassAdmission"] == "EmploymentPreference3rd") &&
d["CountryofBirth"] == "Bangladesh" && d["Admissions"] != "D" && d["lon"] != "NA" && d["lat"] != "NA") {
return d;
}
})
//console.log(markers)
// Load external data and boot
//d3.json("projectedgeography.json",function(data){
d3.json("projectedgeography.geojson",function(data) {
//d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson",function(data){
// Filter data
//data.features = data.features.filter( function(d){return d.properties.name=="USA"} )
//data.features = data.features.filter( function(d){return d.properties.name=="USA"} )
// Create a color scale
var color = d3.scaleOrdinal()
.domain(["EmploymentPreference1st","EmploymentPreference2nd","EmploymentPreference3rd"])
.range(["#402D54","#D18975","#8FD175"])
// Add a scale for bubble size
var size = d3.scaleLinear()
.domain([1,100]) // What's in the data
.range([4,50]) // Size in pixel
//var path = d3.geo.path().projection(projection)
//Draw the map
svg.append("g")
.selectAll("path")
.data(data.features)
.enter()
.append("path")
.style("stroke","#black")
.style("opacity",.3)
//create a tooltip (hover information)
var Tooltip = d3.select("#my_dataviz")
.append("div")
.attr("class","tooltip")
.style("opacity",1)
.style("background-color","white")
.style("border","solid")
.style("border-width","2px")
.style("border-radius","5px")
.style("padding","5px")
// Three function that change the tooltip when user hover / move / leave a cell
var mouseover = function(d) {
Tooltip.style("opacity",1)
}
var mousemove = function(d) {
Tooltip
.html(d.CountyState + "<br>" + "long: " + d.lon + "<br>" + "lat: " + d.lat + "<br>" + "Admissions: " + d.Admissions)
.style("left",(d3.mouse(this)[0] + 10) + "px")
.style("top",(d3.mouse(this)[1]) + "px")
}
var mouseleave = function(d) {
Tooltip.style("opacity",0)
}
// Add circles:
svg
.selectAll("myCircles")
.data(markers)
.enter()
.append("circle")
.attr("class",function(d) {
return (d.MajorClassAdmission)
})
.attr("cx",function(d) {
return projection([d.lon,d.lat])[0]
})
.attr("cy",d.lat])[1]
})
.attr("r",function(d) {
return d.Admissions
})
.style("fill",function(d) {
return color(d.MajorClassAdmission)
})
.attr("stroke",function(d) {
return color(d.MajorClassAdmission)
})
.attr("stroke-width",3)
.attr("fill-opacity",.4)
.on("mouseover",mouseover)
.on("mousemove",mousemove)
.on("mouseleave",mouseleave)
// This function is gonna change the opacity and size of selected and unselected circles
function update() {
// For each check box:
d3.selectAll(".checkbox").each(function(d) {
cb = d3.select(this);
group = cb.property("value")
//console.log(group)
// If the box is check,I show the group
if (cb.property("checked")) {
//console.log("checked")
svg.selectAll("." + group).transition().duration(1000).style("opacity",1).attr("r",function(d) {
return d.Admissions
})
// Otherwise I hide it
} else {
//console.log("unchecked")
svg.selectAll("." + group).transition().duration(1000).style("opacity",0).attr("r",0)
}
})
}
// When a button change,I run the update function
d3.selectAll(".checkbox").on("change",update)
// And I initialize it at the beginning
update()
})
})
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
.circle:hover {
stroke: black;
stroke-width: 4px;
}
.legend circle {
fill: none;
stroke: #ccc;
}
.legend text {
fill: #777;
font: 10px sans-serif;
text-anchor: middle;
}
</style>
<!-- Load d3.js and the geo projection plugin -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
<!-- <script src="http://d3js.org/d3.geo.projection.v0.min.js"></script> optional,depending on projection -->
<h1>LPR Top 200 Bangladesh</h1>
<!-- Button -->
<div>
<input type="checkbox" class="checkbox" value="EmploymentPreference1st" checked><label>Employment Preference 1</label>
<input type="checkbox" class="checkbox" value="EmploymentPreference2nd" checked><label>Employment Preference 2</label>
<input type="checkbox" class="checkbox" value="EmploymentPreference3rd" checked><label>Employment Preference 3</label>
</div>
<!-- Create an element where the map will take place -->
<!-- <svg id="my_dataviz" width="500" height="500"></svg> -->
<div id="my_dataviz"></div>
附上我的数据截图以及我的气泡图如何使用 d3.geoMercator() 和 d3.geoAlbersUsa()
以下是屏幕截图:https://imgur.com/gallery/dRghqAf
编辑:看起来我使用了一个糟糕的 geojson。我最初从美国人口普查局下载了 shapefile 并使用 Mapshaper 转换为 geojson 文件。使用那个 geojson,我使用了一个投影应用程序来创建一个带有 geoalbersUsa 投影的 geojson。实际上,我在已经转换为该投影的 geojson 上使用了 d3.geoAlbersUsa()。我误解了 geoAlbersUsa() 的工作原理。使用 Mapshaper 的原始 geojson,我得到了我正在寻找的地图:https://imgur.com/gallery/9sj68SM
解决方法
D3 投影都非常相似。如果一个投影正确地投影了一个给定的点,那么其他每个投影都有可能。他们以十进制度数为单位获取坐标,并以像素为单位输出坐标,其他的不多。因此,您的陈述是:“d3geoAlbersUsa
投影将美国地图投影在非洲海岸附近的 [0,0]
。”是不正确的。以度为单位的 [0,0]
在非洲海岸附近,以像素为单位的 [0,0]
可以是任何地方。 D3 为您提供像素,而不是度数。
如果您的要素/图块/栅格显示了美国所在的非洲,反之亦然,则说明您的投影或坐标系存在冲突,而不是 d3.geoAlbersUsa 的失败。
此外,如果您将预投影几何体和未投影几何体混合在一起,这将变得太困难:您需要确保用于预投影一个几何体的投影与用于投影的投影相匹配第二个,除非你使用 d3 在某处离线预投影几何体,否则会让你头疼。
如果您有一个带有十进制度数坐标的 csv 和一个具有相同坐标的 geojson,您可以假设投影(以及因此,任何路径)将一致且正确地呈现(其中正确不一定等同于所需...).
现在 d3.geoAlbersUsa 是一个特殊的投影,因为它是一个复合投影,结合了几个不同的投影(都是阿尔伯斯,同时也将阿拉斯加缩小了几次)。假设屏幕尺寸为 960x600 像素,它被校准为以美国为中心。您不需要更改中心点,它已经为您设置好了。但是,必须在您的情况下修改平移,因为这会平移投影坐标。默认翻译需要 960x600 像素的容器。您希望翻译等于 width/2,height/2,正如您所拥有的。更棘手的是比例,默认比例是 1070,将美国扩展到 960 像素。这个比例因子是线性的,所以我们可以使用:1070/960*width 创建一个新的比例因子(假设宽度是限制因子)。
d3.geoMercator 更简单,但我们需要正确地将投影居中,因为默认情况下它不是以美国为中心。我们可以使用:
d3.geoMercator()
.center([-100,30]) // as you had
.scale(1000) // or whatever
.translate([width/2,height/2])
我们仍然需要应用翻译,因为默认值不期望正方形 750x750 svg。
请注意,还有 projection.fitSize()
会自动调整比例并转换为以 geojson 功能为中心,如下所示:
d3.geoMercator()
.fitSize([width,height],geojson) // geojson must be a valid geojson object,not an array of geojson features.
我们将投影传递给路径生成器,然后相对简单地绘制点和geojson:
以下使用注释掉的行访问 geojson,如果您共享 projectedgeography.geojson
,我可以为您提供一些有关为什么您的代码无法按预期工作的信息。但考虑到它的名字,它看起来肯定不是未投影的数据
AlbersUsa
var width = 750
var height = 400
// The svg
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width",width)
.attr("height",height);
// Create a color scale
var color = d3.scaleOrdinal()
.domain(["A","B","C" ])
.range([ "#402D54","#D18975","#8FD175"])
var projection = d3.geoAlbersUsa()
.translate([width/2,height/2])
.scale(1070/960*width); // scale the scale factor,otherwise map will overflow SVG bounds.
var path = d3.geoPath(projection);
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson",function(geojson){
geojson.features = geojson.features.filter( function(d){return d.properties.name=="USA"} )
// d3.csv("file.csv",function(csv) {
// As I cannot access your csv,I'm reproducing a few lines here:
var csv = [
{lon: -116.2,lat: 43.5,Admissions: 24,MajorClassAdmission: "A"},{lon: -81.7,lat: 41.4,Admissions: 13,MajorClassAdmission: "B"},{lon: -74.1,lat: 40.9,Admissions: 35,MajorClassAdmission: "C"},{lon: -121.6,lat: 37.3,Admissions: 14,{lon: -73.9,lat: 40.68,]
svg.selectAll("path")
.data(geojson.features)
.enter()
.append("path")
.attr("d",path);
svg.selectAll("circle")
.data(csv)
.enter()
.append("circle")
.attr("cx",function(d) {
return projection([d.lon,d.lat])[0];
})
.attr("cy",function(d) {
return projection([d.lon,d.lat])[1];
})
.attr("r",function(d) {
return d.Admissions
})
.attr("fill",function(d) {
return color(d.MajorClassAdmission);
})
// ...
// })
})
.circle:hover{
stroke: black;
stroke-width: 1px;
}
path {
fill: none;
stroke: #ccc;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<div id="my_dataviz"></div>
墨卡托
var width = 750
var height = 400
// The svg
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width","#8FD175"])
var projection = d3.geoMercator()
var path = d3.geoPath(projection);
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson",function(geojson){
geojson.features = geojson.features.filter( function(d){return d.properties.name=="USA"} )
projection.fitSize([width,geojson)
// d3.csv("file.csv",function(d) {
return color(d.MajorClassAdmission);
})
// ...
// })
})
.circle:hover{
stroke: black;
stroke-width: 1px;
}
path {
fill: none;
stroke: #ccc;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<div id="my_dataviz"></div>
虽然您的代码中的注释混淆了您用来生成有问题的地图的代码,但您的代码中有一些潜在的简化:鉴于使用 d3.geo,您似乎同时使用了 d3v4 和 d3v3。 path (v3) 而不是 d3.geoPath (v4+)。基础 d3 包包含您需要的所有地理功能,因此您无需导入 https://d3js.org/d3-geo-projection.v2.min.js 或任何其他模块。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。