使用D3.js绘制自定义json映射 [英] Plotting custom json maps with D3.js

查看:98
本文介绍了使用D3.js绘制自定义json映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用D3.js创建地图. 我首先从此处下载国家(加拿大)shapefile: https://www.arcgis.com/home/item.html?id= dcbcdf86939548af81efbd2d732336db

I am creating a map with D3.js. I began by downloading the country (Canada) shapefile here: https://www.arcgis.com/home/item.html?id=dcbcdf86939548af81efbd2d732336db

..,然后将其转换为geojson(链接到下面的文件): http://mapshaper.org/

..and converted it into a geojson here (link to file below): http://mapshaper.org/

到目前为止,我所看到的只是一个彩色块,控制台上没有任何错误.我的问题是,我怎么知道我的json文件或代码不正确? 这是我的代码,底部是指向json文件的链接.

So far all I see is a coloured block, without any errors on the console. My question is, how can I tell if my json file or my code is incorrect? Here is my code and on bottom is a link to json file.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>D3: Setting path fills</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
        <!-- <script src="https://d3js.org/topojson.v1.min.js"></script> -->
        <style type="text/css">
        /* styles */       
        </style>
    </head>
    <body>
        <script type="text/javascript">
        var canvas = d3.select("body").append("svg")
        .attr("width", 760)
        .attr("height", 700)
        d3.json("canada.geo.json", function(data) {
        var group = canvas.selectAll("g")
        .data(data.features)
        .enter()
        .append("g")

        var projection = d3.geo.mercator();
        var path = d3.geo.path().projection(projection);
        var areas = group.append("path")
        .attr("d",path)
        .attr("class","area")
        })
        </script>
    </body>
</html>

链接到json文件: https://github.com/returnOfTheYeti/CanadaJSON/blob/master/canada.geo.json

Link to json file: https://github.com/returnOfTheYeti/CanadaJSON/blob/master/canada.geo.json

推荐答案

d3 geoProjection使用未投影的坐标-三维地球上的坐标. geoProjection获取这些坐标并将其投影到二维平面上.未投影坐标的单位通常是经度和纬度,并且d3 geoProjection会期望这样做.问题在于您的数据已经被投影.

A d3 geoProjection uses unprojected coordinates - coordinates on a three dimensional globe. The geoProjection takes those coordinates and projects them onto a two dimensional plane. The units of unprojected coordinates are generally degrees longitude and latitude, and a d3 geoProjection expects this. The problem is that your data is already projected.

有两种快速的方法来确定是否投影您的数据:

There are two quick methods to determine if your data is projected:

  • 查看数据的元数据

  • look at the meta data of the data

自己查看地理坐标

查看地理元数据

数据使用的投影是在.prj文件中定义的,该文件是构成shapefile的文件集合的一部分:

The projection your data uses is defined in the .prj file that forms part of the collection of files that makes up a shapefile:

PROJCS["Canada_Albers_Equal_Area_Conic",
   GEOGCS["GCS_North_American_1983",
      DATUM["D_North_American_1983",
        SPHEROID["GRS_1980",6378137.0,298.257222101]],
      PRIMEM["Greenwich",0.0],
      UNIT["Degree",0.0174532925199433]],
  PROJECTION["Albers"],
  PARAMETER["False_Easting",0.0],
  PARAMETER["False_Northing",0.0],
  PARAMETER["Central_Meridian",-96.0],
  PARAMETER["Standard_Parallel_1",50.0],
  PARAMETER["Standard_Parallel_2",70.0],
  PARAMETER["Latitude_Of_Origin",40.0],
  UNIT["Meter",1.0]]

您的数据已经使用Albers投影进行了投影,测量单位是米.像将其包含经纬度对一样来投影该数据将无法正常工作.

Your data is already projected with an Albers projection, and the unit of measurement is the meter. Projecting this data as though it consists of lat/long pairs will not work.

如果只有geojson文件而没有参考shapefile,则某些geojson文件会在投影属性中指定EPSG编号,如果该编号不是4326,则可能是您已投影了数据.

If you only have a geojson file and no reference shapefile, some geojson files will specify an EPSG number in a projection propery, if this number is something other than 4326 you probably have projected data.

查看坐标

您可以说您的数据没有非投影数据,因为每个坐标的值都在经度和纬度(东/西+/- 180度,南北+/- 90度)的范围之外:

You can tell your data doesn't have unprojected data because the values of each coordinate are outside the bounds of longitude and latitude (+/-180 degrees east/west, +/- 90 degrees north south):

"coordinates":[[[[899144.944639163,2633537.

您的坐标在全球范围内多次转换:这就是为什么您的投影结果生成svg时会完全填充要素的原因.

Your coordinates translate around the globe several times: this is why your projection results in an svg is filled entirely with features.

有两种主要的解决方案供您选择:

There are two primary solutions available for you:

  • 转换投影,以便geojson由纬度和经度点组成

  • Convert the projection so that the geojson consists of latitude and longitude points

使用d3.geoTransform或d3.geoIdentity转换您的投影数据.

Use d3.geoTransform or d3.geoIdentity to transform your projected data.

转换投影

要执行此操作,您想取消投影"数据,或者投影数据,使其包含经度,纬度点.

To do this you want to "unproject" your data, or alternatively, project it so that it consists of longitude, latitude points.

大多数GIS软件都可以重新投影数据.使用shapefile比使用geojson容易得多,因为shapefile在GIS软件中更为常见. GDAL,QGIS,ArcMap提供了相对容易的转换.

Most GIS software offers the ability to reproject data. It's much easier with a shapefile than a geojson, as shapefiles are much more common in GIS software. GDAL, QGIS, ArcMap offer relatively easy conversion.

也有在线转换器,mapshaper.org可能是最简单的转换器,并且在处理d3时还增加了好处-简化(许多shapefile包含太多用于Web映射目的的细节).将shapefile的所有文件拖到mapshaper窗口中,打开控制台并键入:proj wgs84.导出为geojson(简化后),您已经为d3准备好了geojson.

There are also online converters, mapshaper.org is probably the easiest for this, and has added benefits when dealing with d3 - simplification (many shapefiles contain way too much detail for the purposes of web mapping). Drag all the files of the shapefile into the mapshaper window, open the console and type: proj wgs84. Export as geojson (after simplification), and you've got a geojson ready for d3.

重新投影后,您可能会发现您的数据看起来很尴尬.不用担心,它是未投影的(好吧,是某种未投影的,它显示为2d,但是具有非常简单的投影,假定笛卡尔输入数据).

After reprojecting, you may notice that your data is awkward looking. Don't worry, it's unprojected (well, kind of unprojected, it's shown as 2d, but with a very simple projection that assumes Cartesian input data).

使用未投影的数据,现在可以在d3中投影数据了.

With your unprojected data, you are now ready to project your data in d3.

以下是您的数据的示例(d3-v4.在mapshaper上重新投影(对我没有隶属关系))

Here's an example with your data (d3-v4. data is simplified and reprojected on mapshaper (no affiliation to me))

使用d3.geoIdentity或d3.geoTransform

为此,我建议您使用d3v4(我看到您的代码是v3).虽然geo.transform在v3中可用,但是如果没有v4中可用的新方法(即d3.geoIdentity和projection.fitSize),则麻烦得多.我将在这里介绍使用投影数据的v4方法

使用数据,您可以定义另一种类型的投影:

With your data you can define a different sort of projection:

var projection = d3.geoIdentity();

但是,如果您不小心,这种类型的投影"会给您带来麻烦.它基本上吐出给出的x,y值.但是,地理投影坐标空间通常在左下角的某个位置具有[0,0],而svg坐标空间在左上角的[0,0].在svg坐标空间中,y值随着您沿着坐标平面的下降而增加,在数据的投影坐标空间中,y值随着您的上升而增加.因此,使用身份将使您的数据倒置.

However, this type of "projection" will give you trouble if you aren't careful. It basically spits out the x,y values it is given. However, geographic projected coordinate spaces typically have [0,0] somewhere in the bottom left, and svg coordinates space has [0,0] in the top left. In svg coordinate space, y values increase as you go down the coordinate plane, in the projected coordinate space of your data, y values increase as you go up. Using an identity will therefore project your data upside down.

幸运的是我们可以使用:

Luckily we can use:

var projection = d3.geoIdentity()
   .reflectY(true);

最后一个问题仍然存在:geojson中的坐标未缩放或转换,因此要素未正确居中.为此,有fitSize方法:

One last problem remains: the coordinates in the geojson are not scaled or translated so that the features are properly centered. For this there is the fitSize method:

   var projection = d3.geoIdentity()
       .reflectY(true)
       .fitSize([width,height],geojsonObject)

这里的width和height是SVG(或我们要在其中显示特征的父容器)的宽度和高度,而geojsonObject是geojson特征.请注意,它不会采用一系列功能,如果您具有一系列功能,请将它们放置在功能集中.

Here width and height are the width and height of the SVG (or parent container we want to display the feature in), and the geojsonObject is a geojson feature. Note it won't take an array of features, if you have an array of features, place them in a feature collection.

此处显示的数据是采用这种方法的(我仍然简化了geojson).

Here's your data shown taking this approach (I still simplified the geojson).

您还可以使用geoTransform,这有点复杂,但是允许您指定自己的变换方程式.在大多数情况下,可能要矫kill过正,坚持使用geoIdentity.

You can also use a geoTransform, this is a bit more complex, but allows you to specify your own transform equation. For most situations it is probably overkill, stick with geoIdentity.

取消投影数据:

除了最初的工作之外,要取消投影数据,还需要取消投影数据,使其包含经度纬度对,因此每次显示数据时都必须进行一些额外的处理.

Beyond the initial leg work to unproject the data, by unprojecting the data so that it consists of longitude latitude pairs you have to do some extra processing each time you show the data.

但是,通过访问任何d3 geoProjection,您在显示数据方面也具有高度的灵活性.使用未投影的数据还可以使您更轻松地对齐不同的图层:您不必担心分别缩放和转换多个图层.

But, you also have a high degree of flexibility in how you show that data by accessing any d3 geoProjection. Using unprojected data also allows you to more easily align different layers: you don't have to worry about rescaling and transforming multiple layers individually.

保留预计的数据

通过保持数据的投影,您无需进行球形数学运算,从而节省了计算时间.缺点是上面列出的优点,很难匹配不共享此投影的数据(如果使用此投影导出所有内容,这很好),并且您难以使用表示法-d3.geoTransform在将您的投影从墨卡托转换为阿尔伯斯的方法.

By keeping the projection the data comes in, you save on computing time by not having to do spherical math. The downsides are the upsides listed above, it's difficult to match data that doesn't share this projection (which is fine if you export everything using this projection), and your stuck with the representation - a d3.geoTransform doesn't offer much in the way of converting your projection from say a Mercator to an Albers.

请注意,我在上面的选项2中使用的fit.size()方法可用于所有geoProjections(v4).

Note that that the fit.size() method I used for option two above is available for all geoProjections (v4).

在两个示例中,我尽可能使用了您的代码.尽管有一些警告,但我更改为d3v4(例如,d3.geo.path-> d3.geoPath,d3.geo.mercator-> d3.geoMercator).我还将变量canvas的名称更改为svg,因为它是svg的选择,而不是画布.最后,在第一个示例中,我没有修改您的投影,墨卡托的中心默认为[0,0](长/拉),这说明了奇怪的位置

In the two examples, I used your code where possible. A couple caveats though, I changed to d3v4 (d3.geo.path -> d3.geoPath, d3.geo.mercator -> d3.geoMercator, for example). I also changed the name of your variable canvas to svg, since it is a selection of an svg and not a canvas. Lastly, in the first example I didn't modify your projection, and a mercator's center defaults to [0,0] (in long/lat), which explains the odd positioning

这篇关于使用D3.js绘制自定义json映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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