错误:属性d的<path>:期望数字

3

我正在尝试使用cartogram.js和d3.js创建一个卡托图。我已经使用在cartogram.js repo中找到的示例和这里组合了一个脚本,使用d3.geo.mercator()投影在SVG内生成了一个世界地图,现在我正在尝试使用cartogram.js库扭曲地图,但是出现以下错误:

d3.js:8756 Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL…".
   (anonymous function) @ d3.js:8756
   tick @ d3.js:8956
   (anonymous function) @ d3.js:8936
   d3_timer_mark @ d3.js:2166
   d3_timer_step @ d3.js:2147

这是我用来扭曲地图的代码:

var dataLoaded = new Event("dataLoaded"),
svg = d3.select("svg"),
proj = d3.geo.mercator(),
path = d3.geo.path()
    .projection(proj),
countries = svg.append("g")
    .attr("id", "countries")
    .selectAll("path"),
carto = d3.cartogram()
    .projection(proj)
    .properties(function(d) {
        return d.properties
    }),
mapData = d3.map(),
geometries,
topology

function init() {
    d3.csv("data/data.csv", function(data) {
        data.forEach(function (d) {
            mapData.set(d.COUNTRY, d.VALUE)
        })
    })

    d3.json("data/world.json", function(data) {
        topology = data
        geometries = topology.objects.countries

        var features = carto.features(topology, geometries)

        countries = countries
            .data(features)
            .enter()
            .append("path")
            .attr("fill", function (e) {
                return "#000000"
            })
            .attr("d", path)

        document.dispatchEvent(dataLoaded)
    })
}

document.addEventListener("dataLoaded", function() {
    $("#container").css("visibility", "visible").hide().fadeIn("fast")
    $("header").css("visibility", "visible").hide().fadeIn("slow")

     carto.value(function(d) {
        return +mapData.get(d.properties.name)
     })

     countries.data(carto(topology, geometries).features)

     countries.transition()
        .duration(750)
        .attr("d", carto.path);
})

init()

还有包含我想要用来扭曲地图的数据的CSV文件:

COUNTRY,VALUE
Afghanistan,90
Albania,390
Algeria,90
Andora,110
Angola,10
Antigua,2400
Argentina,320
Armenia,40
Australia,6600
Austria,1300
Axerbaijan,0
Bahamas,1900
Bahrain,90
Bangladesh,50
Barbados,8100
Belarus,20
Belgium,260
Belize,480
Benin,0
Bhutan,170
Bolivia,90
Bosnia,70
Botswana,110
Brazil,1300
Brunei,40
Bulgaria,3600
Burkina Faso,0
Burundi,0
Cabo Verde,0
Cambodia,720
Cameroon,10
Canada,4400
Central African Republic,0
Chad,10
Chile,320
China,1600
Combodia,0
Comoros,10
Congo,20
Costa Rica,2900
Cote d'Ivoire,0
Croatia,9900
Cuba,14800
Cyprus,8100
Czech Republic,70
Denmark,320
Dijbouti,0
Dominica,0
Dominican Republic,4400
Ecuador,90
Egypt,6600
El Salvador,10
Equatorial Guinea,0
Eritrea,10
Estonia,110
Ethiopia,70
Fiji,1900
Finland,720
France,2900
Gabon,10
Gambia,2400
Georgia,70
Germany,880
Ghana,210
Greece,14800
Grenada,720
Guatemala,40
Guinea,0
Guinea - Bissau,0
Guyana,50
Haiti,90
Honduras,110
Hungary,170
Iceland,8100
India,2900
Indonesia,390
Iran,390
Iraq,140
Ireland,1900
Israel,590
Italy,9900
Jamaica,6600
Japan,3600
Jordan,480
Kazakhstan,40
Kenya,1000
Kiribati,10
Kosovo,10
Kuwait,40
Kyrgyzstan,10
Laos,70
Latvia,110
Lebanon,70
Lesotho,0
Liberia,10
Libya,30
Liechtenstein,10
Lithuania,70
Luxembourg,50
Macedonia,70
Madagascar,0
Malawi,40
Malaysia,1300
Maldives,12100
Mali,40
Malta,12100
Marshall Islands,10
Mauritania,10
Mauritius,6600
Mexico,18100
Micronesia,20
Moldova,20
Monaco,590
Mongolia,110
Montenegro,880
Morocco,4400
Mozambique,90
Myanmar,90
Namibia,210
Nauru,10
Nepal,0
Netherlands,50
New Zealand,1900
Nicaragua,50
Niger,10
Nigeria,90
North Korea,390
Norway,1600
Oman,590
Pakistan,110
Palau,50
Palestine,10
Panama,210
Papua New Guinea,40
Paraguay,10
Peru,1000
Philippines,590
Poland,880
Portugal,12100
Qatar,210
Romania,320
Russia,480
Rwanda,20
Saint Kitts and Nevis,0
Saint Lucia,90
Saint Vincent and the Grenadines,0
Samoa,90
San Marino,70
Sao Tome and Principe,10
Saudi Arabia,110
Senegal,70
Serbia,50
Seychelles,1600
Sierra Leone,20
Singapore,880
Slovakia,70
Slovenia,390
Solomon Islands,10
Somalia,70
South Africa,1900
South Korea,140
South Sudan ,0
Spain,14800
Sri Lanka,3600
Sudan,20
Suriname,10
Sweden,720
Switzerland,1300
Syria,590
Taiwan,50
Tajikistan,10
Tanzania,260
Thailand,14800
Timor-Leste,0
Togo,10
Tonga,50
Trinidad and Tobago,140
Tunisia,4400
Turkey,9900
Turkmenistan,10
Tuvalu,30
Uganda,50
Ukraine,70
United Arab Emirates,20
United Kingdom,50
United States of America,3600
Uruguay,50
Uzbekistan,30
Vanuatu,30
Vatican City,30
Venezuela,170
Vietnam,2400
Yemen,20
Zambia,90
Zimbabwe,70

在这个项目之前,我没有使用过d3.js,所以我希望你能给我一些反馈/指导。

我正在使用d3的3.5.17版本,供您参考。

谢谢。


更新 - 2016年9月8日15:22 BST

根据@Mark的建议,我已经实现了d3-queue,但问题仍然存在。如果我在这个实现中做错了什么,我会非常感激任何人能够给我提供帮助! :)

var svg = d3.select("svg"),
proj = d3.geo.mercator(),
path = d3.geo.path()
    .projection(proj),
countries = svg.append("g")
    .attr("id", "countries")
    .selectAll("path"),
carto = d3.cartogram()
    .projection(proj)
    .properties(function(d) {
        return d.properties
    }),
queue = d3.queue()
    .defer(csv)
    .defer(json)
    .awaitAll(ready),
mapData = d3.map(),
geometries,
topology

function json(callback) {
    d3.json("data/world.json", function(data) {
        topology = data
        geometries = topology.objects.countries

        var features = carto.features(topology, geometries)

        countries = countries
            .data(features)
            .enter()
            .append("path")
            .attr("fill", function (e) {
                return "#000000"
            })
            .attr("d", path)

        callback()
    })
}

function csv(callback) {
    d3.csv("data/data.csv", function(data) {
        data.forEach(function (d) {
            mapData.set(d.COUNTRY, +d.VALUE)
        })

        callback()
    })
}

function ready() {
    $("#container").css("visibility", "visible").hide().fadeIn("fast")
    $("header").css("visibility", "visible").hide().fadeIn("slow")

    carto.value(function(d) {
        if (mapData.has(d.properties.name)) {
            return +mapData.get(d.properties.name)
        }
    })

    countries.data(carto(topology, geometries).features)

    countries.transition()
        .duration(750)
        .attr("d", carto.path);
}

更新2 - 2016年9月8日18:05英国夏令时

这是最新的脚本版本,可以通过@Mark提供的Plunker进行测试:http://plnkr.co/edit/iK9EZSIfwIXjIEBHhlep?p=preview

看起来我的初始错误已经被修复了,尽管生成的卡托图显示不正确。


更新3 - 2016年10月8日20:45 BST

@Mark的回答帮助我澄清了很多问题,我因此有了一个部分功能的卡托克图,但为了解决详细信息在这里中提到的问题,我使用--stitch-poles false参数重新生成了我的地图文件,然后再次收到以下错误消息:

d3.js:8756 Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL…".

@Mark最初的修复仍然有效,因此我很困惑为什么这个错误又出现了。您可以在这里看到我的最新代码和这里的新地图topojson文件。再次感谢。

1
在 cartogram.js 中:carto.path = d3.geo.path().projection(null); - James Brooks
1
d3.csv()d3.json()都是异步的。像在init()中所做的那样依次调用它们仍然会并行执行,使您无法控制这些函数返回的顺序。我猜测,在d3.csv()返回之前,dataLoaded事件已经被触发,因此在尝试访问事件处理程序时,mapData只有很少的数据。 - altocumulus
数据正在按时加载,这已经通过多个console.log()语句证明,这是一个经典的竞态条件,只有有时才会成立。此外,如果console.log指向对象引用,它有时会“撒谎”,它将在您检查时显示对象本身,而不是您console.log时的对象。我建议您使用d3.queue重构代码,或者至少在触发事件之前检查两个异步函数是否完成。 - Mark
@Mark,我已经更新了我的代码。 - James Brooks
尝试复制你的代码,你从哪里获取world.json的?我正在尝试使用这些文件,但是它们不相匹配。国家没有name属性。 - Mark
显示剩余9条评论
1个回答

1

好的,我正在取得进展。修复了您的 .value 函数后,您无法获得猫图的原因是您的值差异太大。为什么这会使 cartogram.js 出错,我不确定,但问题可以通过引入比例尺轻松解决。

使用您的数据:

s = d3.scale.linear().range([1,100]).domain(d3.extent(data, function(d){ return  +d.VALUE}));

然后在你的 .value 访问器中:
carto.value(function(d,i) {
  if (mapData.has(d.properties.name)) {
    return s(mapData.get(d.properties.name));
  } else {
    return 1;
  }
});

不幸的是,你的问题还没有全部解决。似乎使用cartogram.js生成的路径会使“包裹”投影(例如俄罗斯和斐济)的国家发生扭曲。但是,在这里详细讨论了一种修复方法。

尽管如此,我们已经取得了一些进展


谢谢!我已经创建了一个新的topojson文件(在此处找到:https://gist.github.com/brks/e04f62bd9e96d65ca4a1b91913c6a889),基于那个线程,尽管我似乎回到了最初的“NaN”错误出现的地方,而且我不知道为什么,因为我改变的唯一事情是地图的json文件。 - James Brooks
我应该补充说明,在我切换地图文件之前,等值线图是可以工作的。 - James Brooks
这是一个最新的 Plunker 示例:http://plnkr.co/edit/1kFV484rtIdSGLaMsdFb?p=preview - James Brooks
@JamesBrooks,你的问题出在南极洲。调试cartogram.js时,你会发现在第80行计算南极洲的“面积”时,它返回了NaN,然后对这些NaN进行了各种数学运算,导致了各种问题。为了证明这一点,我删除了南极洲,一切都好了 - Mark
哇,我根本想不到。谢谢! - James Brooks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接