D3地图-在哪个阶段将数据引入地理区域?


12

我想映射一个世界choropleth以便与D3 la一起显示:

我有一个要显示为ISO-alpha-3键的数据集。所以...

danger.csv
iso,level
AFG,100
ALB,0
DZA,12

等等

按照关于topojson的说明,我知道我可以做...

wget "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/50m/cultural/ne_50m_admin_0_countries.zip"
unzip ne_50m_admin_0_countries.zip
ogr2ogr -f "GeoJSON" output_features.json ne_50m_admin_0_countries.shp -select iso_a3
topojson -o topo.json output_features.json --id-property iso_a3

生成由ISO3标识的worldmap json。

我的问题是:我应该在工作流中的哪一点将anger.csv中的数据合并到地理数据中?我以前曾将qGIS作为GUI使用,但合并应该在哪里发生?在.shp中?在ogr2ogr之后?在topojson缩小之后在浏览器中动态地动态显示(例如此处http://bl.ocks.org/mbostock/4060606 http://bl.ocks.org/mbostock/3306362)?

我对python很好,但是对javascript来说还很陌生,发现自己复制和粘贴Bostock示例比实际成为那里的生成编码器更多。

(我也有一个与Stackoverflow相关但涉及更多的后续活动,也许我应该在这里进行迁移:https : //stackoverflow.com/questions/18604877/how-to-do-time-data-in-d3-maps


我只是在查看@mbostock的示例,然后看到有一个专门针对GeoJoins的示例,即“一个用于将带有外部属性的GeoJSON文件连接到CSV或TSV文件中的简单脚本;是从TopoJSON中提取的”
RyanKDalton

Answers:


11

问自己两个问题:

  1. 您要在多个数据集上重用地理信息吗?

    如果您要对多个数据集使用相同的地理位置,则必须将地理位置和数据分开,然后将其加入客户端。因此,我的许多示例都有单独的CSV(或TSV)文件。这样,可以重用美国各州和县世界其他国家的 TopoJSON,而不必为每个示例创建单独的TopoJSON。

    另一方面,如果只使用一次此地理位置,则可能只是为了简化代码,应该将数据作为属性“烘焙”到该地理位置中。这种方法比较简单,因为您只需要加载一个文件(因此不需要queue.js),并且由于数据是作为每个功能的属性存储的,因此不需要在客户端中联接数据(因此无需d3)。地图)。

    旁注:TSV和CSV在存储属性方面通常比GeoJSON和TopoJSON更有效,这仅仅是因为后者必须在每个对象上重复属性名称。文件大小可能是将数据存储在单独文件中并将其加入客户端的另一个原因。

  2. 您的数据是否已经绑定到地理位置(例如,shapefile的属性)?

    假设您对第一个问题回答“否”,并希望将数据烘焙到地理区域中(而不是在客户端中进行),则如何执行取决于数据的格式。

    如果数据已经是shapefile的属性,则使用topojson -p来控制将哪些属性保存到生成的TopoJSON文件中。您还可以使用它来重命名属性并将其强制为数字。有关示例,参见“制作地图 ”。

    如果您的数据位于单独的CSV或TSV文件中,请使用topojson -e(除之外-p)指定可与您的地理要素连接的外部属性文件。如果您有这样的TSV文件,请从Wiki抓取示例:

    FIPS    rate
    1001    .097
    1003    .091
    1005    .134
    1007    .121
    1009    .099
    1011    .164
    1013    .167
    1015    .108
    1017    .186
    1019    .118
    1021    .099
    

    使用-e,您可以将它们映射到名为“失业”的数字输出属性:

    topojson \
      -o output.json \
      -e unemployment.tsv \
      --id-property=+FIPS \
      -p unemployment=+rate \
      -- input.shp
    

    这种方法的一个例子是肯塔基州的居民区,bl.ocks.org / 5144735


2
在这里,我问的是关于stackoverflow而不是gis.stackexchange的D3映射问题,因为我认为那里有更多的专业知识,然后管理员自己在这里回答了我的问题。=)好吧,这让我今天学到了两件事。谢谢!
Mittenchops

3

好问题。您提供的示例之一似乎可以解决问题,尽管很难遵循。

您会注意到该示例有两个外部数据文件us.json失业.tsv您可以将失业.tsv视为您的danger.csv;us.json是您要与anger.csv中的参数关联的地理特征。后者(employees.tsv)具有idrate字段,其中的字段ididus.json中的相同。

至少在此示例中,应该在具有D3的客户端中合并数据和功能。在此示例中,使用d3.map()函数将失业率添加到县要素中,这是在客户端中。这是初始化的地方:

var rateById = d3.map();

这是rate映射到的位置id

queue()
    .defer(d3.json, "/mbostock/raw/4090846/us.json")
    .defer(d3.tsv, "unemployment.tsv", function(d) { rateById.set(d.id, +d.rate); })
    .await(ready);

我必须承认我不知道这queue()是什么意思,但这对这次讨论并不重要。重要的是要注意的是,每个县id田野都被失业所取代raterate是现在由共享标识符访问id编辑:由于@ blord卡斯蒂略指出,这实际上是一个新的关联数组,或密钥哈希,其中所述的产生rate被映射到id)。在rate这里出于符号系统的目的而调用了(此处,每个分位数都可以使用预定义的CSS类):

...
.enter().append("path")
  .attr("class", function(d) { return quantize(rateById.get(d.id)); })
  .attr("d", path);

quantize()函数在其中返回CSS类的名称,该CSS类应用于根据其失业率来为该要素(县)设置样式,该失业率现在在要素id字段中定义。



队列允许异步并行加载数据源,而不是串行加载。
blord-castillo 2013年

1
在该示例中发生的是rateById是键哈希。不会更改国家/地区功能,并且us.json数据保持不变。取而代之的是,employees.tsv会转换为称为“ rateById”的键哈希。将rateById.set()遍历失业.tsv,以便为失业.tsv中的每个id插入一个密钥(不在us.json中),并且该密钥的值设置为失业.tsv中该id的rate字段。稍后,调用rateById.get()来使用哈希值通过id查找失业率;该值用于在us.json功能上设置样式,然后丢弃。
blord-castillo 2013年

为什么将此ID / ID / ID替换为速率,而不是将其作为属性附加到其他位置?这似乎使以后的选择变得更加困难。
Mittenchops

1
它不会将ID替换为费率。它会创建一个从ID到速率的查找哈希。
blord-castillo 2013年

2

首先,csv的第一行必须是用逗号分隔的列名列表,才能使用此方法。如果无法做到这一点,请添加对此的评论,我将看看是否可以d3.csv.parseRows代替来确定使用方法d3.csv.parsed3.csv.parse由的评估功能调用.defer(function, url, assessor)

我假设您的文件现在看起来像这样:

danger.csv
iso,level
AFG,100
ALB,0
DZA,12
...

使用此功能,您可以创建从ISO3到危险级别的查找哈希。

var dangerByISO3 = d3.map();
queue()
    .defer(d3.json, "url to topo.json")
    .defer(d3.csv, "url to danger.csv", function(d) {dangerByISO3.set(d.iso, +d.level);})
    .await(ready);
function ready(error, world) {
    //You now have world as your available topojson
    //And you have dangerByISO3 as your danger level hash
    //You can lookup a danger level by dangerByISO3.get(ISO3 code)
}

代码演练

var dangerByISO3 = d3.map();

首先,您将创建一个d3.map()对象,该对象将用作键哈希,并将其存储在变量angerByISO3中。

queue()

使用队列进行并行加载。

.defer(d3.json, "url to topo.json")

加载您的topojson作为要传递给await函数的第一个参数(错误后)。请注意此处的样式,其中这是上的链接函数queue(),但在单独的行上列出(在上没有终止分号queue())。

.defer(d3.csv, "url to danger.csv", function(d) {dangerByISO3.set(d.iso, +d.level);})

这里发生了两件事。首先,您要加载hazard.csv作为第二个参数传递给await函数。正如您将在下面看到的,此参数实际上并未使用。而是将评估函数参数提供给加载函数d3.csv。该评估员将处理csv的每一行。在这种情况下,我们在angerByISO3上调用set函数,以便对于iso键的每个组合,将set设置level为与该键对应的值。该+d.level符号使用一元+将d.level的值强制为数字。

.await(ready);

加载两个数据源后,它们将作为两个单独的参数传递给函数ready()。回调的第一个参数始终是发生的第一个错误。如果未发生错误,则将null传递为第一个参数。第二个参数是第一个数据源(第一个任务的结果),第三个参数是第二个数据源(第二个任务的结果)。

function ready(error, world) {...}

这是回调函数ready()。首先error,如果两个加载任务成功完成(我们应该添加语言以捕获和处理错误),则我们采用的参数应为null。接下来,我们将topojson数据作为对象countries。该数据应在函数主体中使用进行处理.data(topojson.feature(world,world.objects.countries).features)。由于ready()不接受第三个参数,因此仅丢弃第二个任务的结果,即csv。我们仅使用它来构建密钥哈希,此后不需要它。


是的,是的,我的csv实际上看起来像是格式良好的csv,而不是我发布的粗心演示。=)抱歉,我将进行更新。
Mittenchops
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.