地图中的圆圈在 D3 V4 中显示的位置不正确
Circles in Map Displayed Incorrect Location in D3 V4
我正在使用教程学习如何在 D3.v3 中生成地图,但我使用的是 D3.v4。我只是想让一些圆圈出现在地图上(见下文)。该代码有效,除了圆圈在内华达州上空并且应该在湾区。我想这是地图投影和投影坐标之间的不匹配。我不确定地图在哪个投影中,但我试图将其强制为 albersUsa(请参阅我生成路径的注释掉的命令)但这会导致整个地图消失。如有任何帮助,我们将不胜感激!
<!DOCTYPE html>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
var w = 960,
h = 600;
var projection = d3.geoAlbersUsa();
var path = d3.geoPath()
//.projection(projection)
d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
if (error) throw error;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("class", "states")
.attr("d", path);
svg.append("path")
.attr("class", "state-borders")
.attr("d", path(topojson.mesh(us, us.objects.states)))
svg.append("path")
.attr("class", "county-borders")
.attr("d", path(topojson.mesh(us, us.objects.counties)));
aa = [-122.490402, 37.786453];
bb = [-122.389809, 37.72728];
svg.selectAll("circle")
.data([aa,bb]).enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
.attr("r", "8px")
.attr("fill", "red")
});
</script>
您的美国 json 已经投影,为了显示它您使用了空投影:
var path = d3.geoPath()
//.projection(projection)
如果不定义投影,您的 topojson/geojson 坐标将转换为直线像素坐标。碰巧这个特定的 topojson 文件的像素坐标在 [0,0] 和 [960,600] 之间,几乎与默认 bl.ock 视图的大小相同。在不知道所使用的投影的情况下创建该文件,您无法复制该投影以将地理特征与您的数据对齐。 除非您直接将特征与像素值放在一起并完全跳过投影(对于不靠近可识别地标或精度很重要的点没有用)。
你的 US topojson 特征在使用 geoUsaAlbers()
投影时消失,因为你在平面上获取像素坐标并将它们转换为 svg 坐标,就好像它们是三维地球上的点一样( d3 投影期望纬度经度对)。
而是使用未投影的地形json 或地理json。也就是说它包含 latitude/longitude 对并将该数据与您的点一起投影。请参阅此 bl.ock 示例,其中未投影(lat/long 对)json 用于美国使用您的代码(但将投影分配给 path
)。
要检查您是否有 latitude/longitude 对,您可以在 geojson 文件中轻松查看这些要素的几何形状,并查看这些值是否为有效的经纬度点。对于 topojson,topojson 库将要素转换为 geojson,因此您可以在转换后查看几何图形。
这是美国的未投影地形json:https://bl.ocks.org/mbostock/raw/4090846/us.json
假设您真的想使用相同的 topojson 文件,那么我们或许可以推断出它使用的投影。首先,我将显示您的投影点(通过使用未投影的美国轮廓)和已经投影的 topojson(未投影的 topojson 是用 d3.geoAlbersUsa()
投影的,用空投影投影):
投影 d3.geoAlbersUsa 可能针对 bl.ocks.org 默认视口 960x500 进行了优化。未投影的数据集有一个大约 960x600 的边界框,所以也许如果我们将比例增加 600/500 倍并调整平移,我们可以在 960x600 的 svg 中对齐我们的特征:
var projection = d3.geoAlbersUsa();
var scale = projection.scale() * 600 / 500;
projection.scale(scale).translate([960/2,600/2])
var projectedPath = d3.geoPath().projection(projection);
而且,这看起来对齐得很好,我看不出两者之间的区别:
这里是 block 显示对齐的特征。
但正如我在评论中提到的,即使您可以对齐特征:
任何缩放或居中都会有问题,因为您需要对已经投影的数据使用 geoTransform,但对原始地理数据使用 geoProjection。使用所有(统一)投影数据或所有未投影数据使生活更简单。
我正在使用教程学习如何在 D3.v3 中生成地图,但我使用的是 D3.v4。我只是想让一些圆圈出现在地图上(见下文)。该代码有效,除了圆圈在内华达州上空并且应该在湾区。我想这是地图投影和投影坐标之间的不匹配。我不确定地图在哪个投影中,但我试图将其强制为 albersUsa(请参阅我生成路径的注释掉的命令)但这会导致整个地图消失。如有任何帮助,我们将不胜感激!
<!DOCTYPE html>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
var w = 960,
h = 600;
var projection = d3.geoAlbersUsa();
var path = d3.geoPath()
//.projection(projection)
d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
if (error) throw error;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("class", "states")
.attr("d", path);
svg.append("path")
.attr("class", "state-borders")
.attr("d", path(topojson.mesh(us, us.objects.states)))
svg.append("path")
.attr("class", "county-borders")
.attr("d", path(topojson.mesh(us, us.objects.counties)));
aa = [-122.490402, 37.786453];
bb = [-122.389809, 37.72728];
svg.selectAll("circle")
.data([aa,bb]).enter()
.append("circle")
.attr("cx", function (d) { return projection(d)[0]; })
.attr("cy", function (d) { return projection(d)[1]; })
.attr("r", "8px")
.attr("fill", "red")
});
</script>
您的美国 json 已经投影,为了显示它您使用了空投影:
var path = d3.geoPath()
//.projection(projection)
如果不定义投影,您的 topojson/geojson 坐标将转换为直线像素坐标。碰巧这个特定的 topojson 文件的像素坐标在 [0,0] 和 [960,600] 之间,几乎与默认 bl.ock 视图的大小相同。在不知道所使用的投影的情况下创建该文件,您无法复制该投影以将地理特征与您的数据对齐。 除非您直接将特征与像素值放在一起并完全跳过投影(对于不靠近可识别地标或精度很重要的点没有用)。
你的 US topojson 特征在使用 geoUsaAlbers()
投影时消失,因为你在平面上获取像素坐标并将它们转换为 svg 坐标,就好像它们是三维地球上的点一样( d3 投影期望纬度经度对)。
而是使用未投影的地形json 或地理json。也就是说它包含 latitude/longitude 对并将该数据与您的点一起投影。请参阅此 bl.ock 示例,其中未投影(lat/long 对)json 用于美国使用您的代码(但将投影分配给 path
)。
要检查您是否有 latitude/longitude 对,您可以在 geojson 文件中轻松查看这些要素的几何形状,并查看这些值是否为有效的经纬度点。对于 topojson,topojson 库将要素转换为 geojson,因此您可以在转换后查看几何图形。
这是美国的未投影地形json:https://bl.ocks.org/mbostock/raw/4090846/us.json
假设您真的想使用相同的 topojson 文件,那么我们或许可以推断出它使用的投影。首先,我将显示您的投影点(通过使用未投影的美国轮廓)和已经投影的 topojson(未投影的 topojson 是用 d3.geoAlbersUsa()
投影的,用空投影投影):
投影 d3.geoAlbersUsa 可能针对 bl.ocks.org 默认视口 960x500 进行了优化。未投影的数据集有一个大约 960x600 的边界框,所以也许如果我们将比例增加 600/500 倍并调整平移,我们可以在 960x600 的 svg 中对齐我们的特征:
var projection = d3.geoAlbersUsa();
var scale = projection.scale() * 600 / 500;
projection.scale(scale).translate([960/2,600/2])
var projectedPath = d3.geoPath().projection(projection);
而且,这看起来对齐得很好,我看不出两者之间的区别:
这里是 block 显示对齐的特征。
但正如我在评论中提到的,即使您可以对齐特征: 任何缩放或居中都会有问题,因为您需要对已经投影的数据使用 geoTransform,但对原始地理数据使用 geoProjection。使用所有(统一)投影数据或所有未投影数据使生活更简单。