地图中的圆圈在 D3 V4 中显示的位置不正确 [英] Circles in Map Displayed Incorrect Location in D3 V4

查看:13
本文介绍了地图中的圆圈在 D3 V4 中显示的位置不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用教程来学习如何在 D3.v3 中生成地图,但我使用的是 D3.v4.我只是想让一些圆圈出现在地图上(见下文).该代码有效,只是圆圈在内华达州上空并且应该在湾区.我想这是地图投影和投影坐标之间的不匹配.我不确定地图所在的投影,但我试图将其强制为 albersUsa(请参阅我生成路径的注释命令),但这会导致整个地图消失.任何帮助将不胜感激!

<script src="https://d3js.org/d3.v4.min.js"></script><script src="https://d3js.org/topojson.v2.min.js"></script><脚本>无功 w = 960,h = 600;var 投影 = d3.geoAlbersUsa();var 路径 = d3.geoPath()//.投影(投影)d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {如果(错误)抛出错误;var svg = d3.select("body").append("svg").attr("宽度", w).attr("高度", h);svg.selectAll("路径").data(topojson.feature(us, us.objects.states).features).enter().append("路径").attr("class", "states").attr("d", 路径);svg.append("路径").attr("class", "state-borders").attr("d", path(topojson.mesh(us, us.objects.states)))svg.append("路径").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("圆").data([aa,bb]).enter().append("圆圈").attr(cx",函数(d){返回投影(d)[0];}).attr(cy",函数(d){返回投影(d)[1];}).attr("r", "8px").attr(填充",红色")});</script>

解决方案

您的 US json 已经被投影,为了显示它,您可以使用空投影:

var path = d3.geoPath()//.投影(投影)

不定义投影,您的 topojson/geojson 坐标将被转换为直线像素坐标.碰巧这个特定的 topojson 文件的像素坐标在 [0,0] 和 [960,600] 之间,几乎与默认的 bl.ock 视图大小相同.在不知道所使用的投影也创建该文件的情况下,您无法复制该投影以将地理要素与您的数据对齐.除非您直接使用像素值放置特征并完全跳过投影(对于不在可识别地标附近或精度很重要的点没有用).

使用 geoUsaAlbers() 进行投影时,您的美国 topojson 特征会消失,因为您在平面上获取像素坐标并将它们转换为 svg 坐标,就好像它们是三维地球上的点一样(d3 投影期望纬度经度对).

相反,请使用未投影的 topojson 或 geojson.也就是说,它包含纬度/经度对,并将该数据与您的点一起投影.请参阅此

d3.geoAlbersUsa 的投影可能针对 bl.ocks.org 默认视口 960x500 进行了优化.未投影的数据集有一个大约 960x600 的边界框,所以也许如果我们将比例增加 600/500 并调整平移,我们可以在 960x600 的 svg 中对齐我们的特征:

var 投影 = d3.geoAlbersUsa();var 比例=projection.scale() * 600/500;投影.比例(比例).翻译([960/2,600/2])var 投影路径 = d3.geoPath().projection(projection);

而且,这似乎很好地对齐,我看不出两者之间的区别:

这是一个显示对齐特征的.

但正如我在评论中提到的,即使您可以对齐功能:任何缩放或居中都会有问题,因为您需要对已经投影的数据使用 geoTransform 而对原始地理数据使用 geoProjection.使用所有(均匀)投影数据或所有未投影数据使生活更简单.

I am using a tutorial to learn how to generate maps in D3.v3, but I am using D3.v4. I am just trying to get some circles to appear on the map (see below). The code works except that the circles are over Nevada and should be in the Bay Area. I imagine this is a mismatch between projections of the map and the projected coordinates. I am not sure what projection the map is in, but I have tried to force it to be albersUsa (see commented out commands where I generate path) but this causes the entire map to disappear. Any help would be appreciated!

<!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>

解决方案

Your US json is already projected, and to show it you use a null projection:

var path = d3.geoPath()
             //.projection(projection)

Without defining a projection, your topojson/geojson coordinates will be translated to straight pixel coordinates. It just so happens that this particular topojson file has pixel coordinates that are within [0,0] and [960,600], almost the same size as a default bl.ock view. Without knowing the projection used too create that file you cannot replicated that projection to align geographic features to your data. Unless you place your features with pixel values directly and skip the projection altogether (not useful for points not near identifiable landmarks or where precision matters).

Your US topojson features disappear when projecting with a geoUsaAlbers() because you are taking pixel coordinates on a plane and transforming them to svg coordinates as though they were points on a three dimensional globe (d3 projections expect latitude longitude pairs).

Instead, use a topojson or geojson that is unprojected. That is to say it contains latitude/longitude pairs and project that data along with your points. See this bl.ock for an example with unprojected (lat/long pairs) json for the US using your code (but assigning a projection to path).

To check if you have latitude/longitude pairs you can view the geometry of these features in a geojson file easily and see if the values are valid long, lat points. For topojson, the topojson library converts features to geojson, so you can view the geometries after this conversion.

Here's an unprojected topojson of the US: https://bl.ocks.org/mbostock/raw/4090846/us.json


Let's say you really wanted to use the same topojson file though, well we can probably deduce the projection it uses. First, I'll show the difference between your projected points (by using an unprojected outline of the US) and the already projected topojson (the unprojected topojson is projected with d3.geoAlbersUsa() and the projected with a null projection):

Chances are the projection d3.geoAlbersUsa is optimized for a bl.ocks.org default viewport, 960x500. The unprojected dataset has a bounding box of roughly 960x600, so perhaps if we increase the scale by a factor of 600/500 and adjust the translate we can align our features in an svg that is 960x600:

var projection = d3.geoAlbersUsa();
var scale = projection.scale() * 600 / 500;
projection.scale(scale).translate([960/2,600/2])
var projectedPath = d3.geoPath().projection(projection);

And, this appears to align fairly well, I can't see the difference between the two:

Here's a block showing the aligned features.

But as I mention in the comments, even if you can align the features: any zoom or centering would be problematic as you need to use a geoTransform on already projected data but a geoProjection on the raw geographic data. Using all (uniformly) projected data or all unprojected data makes life simpler.

这篇关于地图中的圆圈在 D3 V4 中显示的位置不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆