简体   繁体   English

如何使用 d3、javascript 和 json 文件将地图划分为邮政编码?

[英]How to divide a map into zipcodes using d3, javascript, and a json file?

I'm trying to create a nyc map with zipcode areas I can color in based on census data (like color an area red if majority white or blue if majority nonwhite).我正在尝试创建一个纽约地图,其中包含我可以根据人口普查数据着色的邮政编码区域(例如,如果多数为白色,则将区域着色为红色,如果多数为非白色,则为蓝色)。 I am simply using one of the shape files I found online from here ( https://data.cityofnewyork.us/Business/Zip-Code-Boundaries/i8iw-xf4u/data ).我只是使用我从这里在线找到的形状文件之一( https://data.cityofnewyork.us/Business/Zip-Code-Boundaries/i8iw-xf4u/data )。

I converted the shp file to a geojson and then a topojson file.我将 shp 文件转换为 geojson,然后转换为 topojson 文件。

I'd appreciate it if someone could look at my code below, and let me know how I can go about doing this.如果有人可以查看我下面的代码,并让我知道如何进行此操作,我将不胜感激。

Code:代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>

<script>

var width = 500,
    height = 500;

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

  var projection = d3.geo.albers()
   .center([0,40.7])
   .rotate([74,0])
   .translate([width/2,height/2])
   .scale(65000);

   var path = d3.geo.path()
    .projection(projection);

d3.json("zipcode.json", function(error, uk) {
    console.log(uk)
    console.log(uk.objects)
    console.log(uk.objects.zipcode)
  if (error) return console.error(error);
  var subunits = topojson.feature(uk, uk.objects.zipcode);

    svg.append("path")
        .datum(subunits)
        .attr("d", path);
});

Output:输出:

在此处输入图片说明

The last part of my code (and the first part) is modeled after https://bost.ocks.org/mike/map/ .我的代码的最后一部分(和第一部分)是在https://bost.ocks.org/mike/map/之后建模的。 I understand I am trying to "Select All" of the some sort of feature array from the json file I am using in order to create paths.我知道我正在尝试从我正在使用的 json 文件中“全选”某种特征数组以创建路径。 In my data, there's a coordinates array, which I am trying to access and use.在我的数据中,有一个坐标数组,我正在尝试访问和使用它。 My code doesn't throw any errors so I'm not sure where to look to debug.我的代码没有抛出任何错误,所以我不确定在哪里调试。

Also, I'm I supposed to color the areas the paths create in this step or after I create the paths?另外,我应该在此步骤中还是在创建路径之后为路径创建的区域着色?

This answer uses d3 v3 and considers census tracts rather than zip codes (reflecting the original edit, but the principles remain the same)这个答案使用 d3 v3 并考虑人口普查区而不是邮政编码(反映原始编辑,但原则保持不变)

The selection's role in adding features:选择在添加功能中的作用:

I understand I am trying to "Select All" of the some sort of feature array from the json file I am using in order to create paths.我知道我正在尝试从我正在使用的 json 文件中“全选”某种特征数组以创建路径。

Rather than selecting something from the json file, you are selecting elements in the DOM.您不是从 json 文件中选择内容,而是选择 DOM 中的元素。 D3 will bind the data in the json to the features where they exist, produce an enter() selection where they don't, and produce an exit() selection where there are excess DOM elements selected in relation to the json data. D3 将 json 中的数据绑定到它们存在的特征,在它们不存在的地方产生一个 enter() 选择,并产生一个 exit() 选择,其中选择了与 json 数据相关的多余 DOM 元素。

This is why the initial appending of data with a selectAll(type).data(data) statement is followed with an .enter() statement generally.这就是为什么使用selectAll(type).data(data)语句初始附加数据后通常会使用.enter()语句的原因。 The enter returns the elements that must be added to the DOM: enter 返回必须添加到 DOM 的元素:

svg.selectAll(".tract")
    // bind data to the selection
    .data(topojson.feature(uk, uk.objects.nyct2010).features)
  .enter()
    // set properties for the new elements:
    .append("path") 
    .attr("class", "tract")
    .attr("d", path);

If you were updating the data - say showing some year by year property in your maps, you wouldn't need the .enter() if the number of geographic features was constant (likely the case), you would just set the data and then modify the properties.如果您正在更新数据 - 比如说在地图中显示一些逐年的属性,如果地理特征的数量是恒定的(可能是这种情况),则不需要.enter() ),您只需设置数据,然后修改属性。 If the number of elements in your new data array is the same as the old one, then the enter() selection will actually be empty.如果新数据数组中的元素数量与旧数据相同,则enter()选择实际上将为空。

The intial append with this method generally assumes the selectAll statement is empty, so that all items in the data are appended with the enter selection, this causes many people a lot of grief ( a ) ( b ) ( c ) ( d ) ( e ) ( f ) .这种方法的初始追加一般假设selectAll语句为空,这样数据中的所有项都追加了回车选择,这让很多人很伤心( a ) ( b ) ( c ) ( d ) ( e ) ( f )

When using the alternate approach:使用替代方法时:

svg.append('path')
  .datum(subunits)
  .attr('d',path')

You just append one path element encompassing all features, which makes styling individual areas impossible.您只需添加一个包含所有功能的路径元素,这使得无法对单个区域进行样式设置。 In contrast, the top approach appends one path for each element in your json.相比之下,top 方法为 json 中的每个元素附加一个路径。

Setting map attributes:设置地图属性:

You may have difficulty in setting the the class of each path to d.coordinates .您可能难以将每个路径的类设置为d.coordinates Using topojson.feature(data, data.objects.features).features returns geojson from your topojson.使用topojson.feature(data, data.objects.features).features .features 从您的 topojson 返回 geojson。 The coordinates property of each feature is an array - which might not won't work with a class declaration.每个特征的坐标属性是一个数组——它可能不适用于类声明。

But, you have the right approach.但是,您有正确的方法。 An inline function can set attributes easily:内联函数可以轻松设置属性:

var color = d3.scale.category20();

svg.selectAll("path")
  .data(subunits) // from the question code.
  .enter()
  .append('path')
  .attr('fill',function(d,i) { return color(i); })
  .attr("d", path);

Using this I get:使用这个我得到:

在此处输入图片说明

( block )

But, let's look at d in that inline function above ( .attr('fill',function(d,i) { console.log(d); return color(i); }) ).但是,让我们看看上面的内联函数中的 d( .attr('fill',function(d,i) { console.log(d); return color(i); }) )。 It is a geojson object:它是一个 geojson 对象:

Object { type: "Feature", properties: Object, geometry: Object }

If you don't see any properties (it'll always have a properties property, but it might be empty or contain only methods), you have some bad news, the properties are empty.如果你没有看到任何属性(它总是有一个 properties 属性,但它可能是空的或只包含方法),你有一些坏消息,这些属性是空的。 Consequently, there are no properties containing data that can be displayed - eg coloring the map.因此,没有包含可以显示的数据的属性 - 例如为地图着色。 There are also no identifiers in the data.数据中也没有标识符。 This makes joining outside data to each feature impossible and there is no data in the feature to show.这使得将外部数据连接到每个特征变得不可能,并且特征中没有数据可显示。 Topojson doesn't compress properties so you should be able to see them if they are present in the text of the file: Topojson 不压缩属性,因此如果它们存在于文件的文本中,您应该能够看到它们:

..."Polygon","properties":{"CTLabel":"1223","BoroCode":"4","BoroName":"Queens","CT2010":"...

Showing properties of geographical features显示地理要素的属性

You'll need to find a geographical dataset that has properties.您需要找到具有属性的地理数据集。 Property-less features might be great for backgrounds, but less useful for everything else.无属性的功能可能对背景很有用,但对其他一切用处不大。

I found a source of the 2010 census tracts here .我在这里找到了 2010 年人口普查区的来源。 I downloaded the shapefile and converted it to topojson at mapshaper.org (be sure to copy all the files into the window - drag and drop - so that the data and the projection data is transfered).我在mapshaper.org下载了 shapefile 并将其转换为topojson (确保将所有文件复制到窗口中 - 拖放 - 以便传输数据和投影数据)。 The data is already projected (to the New York State Plane), so you should unproject/'project' it to WGS84 by typing proj wgs84 in the console.数据已经投影(到纽约州平面),因此您应该通过在控制台中键入proj wgs84来取消投影/“投影”到 WGS84。 This answer might help in terms of understanding projected/unprojected data and d3这个答案可能有助于理解投影/未投影数据和 d3

The file I'm working with has the property BoroCode which I'll use to display in a choropleth type display:我正在使用的文件具有属性BoroCode ,我将使用它在 choropleth 类型显示中显示:

svg.selectAll("path")
   .data(topojson.feature(data, data.objects.nyct2010).features)
   .enter()
   .append('path')
   .attr('fill',function(d) {return color(d.properties.BoroCode); })
   .attr("d", path);

This gives me:这给了我:

在此处输入图片说明

( block )

Joining data to features将数据连接到特征

Many shapefiles, topojsons, geosjons, feature classes etc don't include many properties/attributes.许多 shapefile、topojson、geosjons、要素类等不包含许多属性/属性。 These files containing geographic coordinates are often joined to files that contain properties/attributes (but no coordinates) in a data join based on an identifier shared in each data source.这些包含地理坐标的文件通常基于每个数据源中共享的标识符连接到数据连接中包含属性/属性(但没有坐标)的文件。

There is an excellent example here on that in practice, though a better explanation might be here .在实践中,这里有一个很好的例子,尽管这里可能有更好的解释。 I'll use the one of the few files I could find (relatively quickly and free) with census tract identifiers.我将使用我能找到的少数文件之一(相对快速且免费),其中包含人口普查区标识符。 Census information is generally great as it contains standardized identifiers.人口普查信息通常很好,因为它包含标准化的标识符。 This file is a csv containing disposable income data.该文件是一个包含可支配收入数据的 csv。

Now with the shared identifier, we can show the geographic shapes and assign colors to them based on the income values in the csv.现在使用共享标识符,我们可以显示地理形状并根据 csv 中的收入值为其分配颜色。

Once both files are loaded, I'll make a dictionary:加载两个文件后,我将制作一个字典:

var lookup = {};
income.forEach(function(d) { lookup[d.tractID] = +d.disposable_income; });

and then I'll show the features, almost the same as above:然后我将展示功能,几乎与上面相同:

svg.selectAll("path")
   .data(topojson.feature(data, data.objects.nyct2010).features)
   .enter()
   .append('path')
   .attr('fill',function(d) { return color(lookup[parseInt(d.properties.CT2010)] ); })
   .attr("d", path);

I used parseInt as I modified the csv's in Excel and lost the leading zeros in the csv, parseInt drops the leading zeros from my geojson identifiers.我使用了parseInt因为我在 Excel 中修改了 csv 并丢失了 csv 中的前导零, parseInt从我的 geojson 标识符中删除了前导零。

The end result looks something like:最终结果类似于:

在此处输入图片说明

( block )

If you took a look at the block, you'll see I nested d3.csv inside the d3.json callback function.如果您查看该块,您会看到我将 d3.csv 嵌套在 d3.json 回调函数中。 Each of these is asynchronous, so unless we use a library like queue.js we'll need to wait until the json is loaded before loading the csv.每一个都是异步的,所以除非我们使用像 queue.js 这样的库,否则我们需要等到 json 加载后才能加载 csv。 This nested approach solves the problem of potentially styling the features before the csv is loaded这种嵌套方法解决了在加载 csv 之前可能对特征进行样式设置的问题

This should cover how to color a map either based on increment, property within the geo/topo json and/or by joining the data from a non-spatial source to the spatial shapes.这应该涵盖如何基于增量、geo/topo json 中的属性和/或通过将来自非空间源的数据连接到空间形状来为地图着色。 See the blocks for the implementation of a color scale, without a proper scale color(i) won't return anything.请参阅色标的实现块,如果没有适当的color(i)color(i)将不会返回任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM