使用topomerge合并topojson会打乱缠绕顺序

Posted

技术标签:

【中文标题】使用topomerge合并topojson会打乱缠绕顺序【英文标题】:Merging topojson using topomerge messes up winding order 【发布时间】:2021-01-24 08:09:52 【问题描述】:

我正在尝试创建一个自定义世界地图,其中国家被合并到区域中,而不是单独的国家。不幸的是,由于某种原因,整个过程中的缠绕顺序似乎有些混乱。

作为基础数据,我使用的是自然地球10m_admin_0_countries 可用的形状文件here。作为合并国家/地区的标准,我有一个如下所示的查找地图:

const countryGroups = 
  "EUR": ["ALA", "AUT", "BEL"...],
  "AFR": ["AGO", "BDI", "BEN"...],
  ...

合并我正在使用的形状topojson-client。由于我希望获得比 CLI 命令提供的更高级别的控制,因此我编写了一个脚本。它遍历查找图并挑选出属于一个组的所有 topojson 特征并将它们合并为一个形状,并将生成的合并特征放入一个 geojson 框架中:

const topojsonClient = require("topojson-client");
const topojsonServer = require("topojson-server");

const worldTopo = topojsonServer.topology(
  countries: JSON.parse(fs.readFileSync("./world.geojson", "utf-8")),
);

const geoJson = 
  type: "FeatureCollection",
  features: Object.entries(countryGroups).map(([region, ids]) => 
    const relevantCountries = worldTopo.objects.countries.geometries.filter(
      (country, i) =>
        ids.indexOf(country.properties.ISO_A3) >= 0
    );

    return 
      type: "Feature",
      properties:  region, countries: ids ,
      geometry: topojsonClient.merge(worldTopo, relevantCountries),
    ;
  ),
;

到目前为止,一切都运行良好(据称)。当我尝试使用github gist(或任何其他可视化工具,如 vega lite)来可视化地图时,形状似乎都一团糟。我怀疑我在合并功能期间做错了什么,但我无法弄清楚它是什么。

当我尝试使用 CLI 执行相同操作时,它似乎工作正常。但由于我需要对合并进行更多控制,因此仅使用 CLI 并不是一个真正的选择。

【问题讨论】:

【参考方案1】:

最后一个特征,称为“世界”,应该包含所有剩余个国家,但相反,它包含所有国家,句号。您可以在以下展示中看到这一点。

var w = 900,
  h = 300;

var projection = d3.geoMercator().translate([w / 2, h / 2]).scale(100);
var path = d3.geoPath().projection(projection);
var color = d3.scaleOrdinal(d3.schemeCategory10);

var svg = d3.select('svg')
  .attr('width', w)
  .attr('height', h);

var url = "https://gist.githubusercontent.com/Flave/832ebba5726aeca3518b1356d9d726cb/raw/5957dca433cbf50fe4dea0c3fa94bb4f91c754b7/world-regions-wrong.topojson";
d3.json(url)
  .then(data => 
    var geojson = topojson.feature(data, data.objects.regions);
    geojson.features.forEach(f => 
      console.log(f.properties.region, f.properties.countries);
    );

    svg.selectAll('path')
      // Reverse because it's the last feature that is the problem
      .data(geojson.features.reverse())
      .enter()
      .append('path')
      .attr('d', path)
      .attr('fill', d => color(d.properties.region))
      .attr('stroke', d => color(d.properties.region))
      .on('mouseenter', function() 
        d3.select(this).style('fill-opacity', 1);
      )
      .on('mouseleave', function() 
        d3.select(this).style('fill-opacity', null);
      );
  );
path 
  fill-opacity: 0.3;
  stroke-width: 2px;
  stroke-opacity: 0.4;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
<script src="https://d3js.org/topojson.v3.js"></script>
<svg></svg>

要解决此问题,我会确保始终从列表中删除所有指定的国家/地区。从您的数据中,我看不出“世界”的定义位置,以及它是否包含地球上的所有国家,或者它是否是通配符分配。

无论如何,您应该能够通过从worldTopo 中删除所有匹配项来修复它:

const topojsonClient = require("topojson-client");
const topojsonServer = require("topojson-server");

const worldTopo = topojsonServer.topology(
  countries: JSON.parse(fs.readFileSync("./world.geojson", "utf-8")),
);

const geoJson = 
  type: "FeatureCollection",
  features: Object.entries(countryGroups).map(([region, ids]) => 
    const relevantCountries = worldTopo.objects.countries.geometries.filter(
      (country, i) =>
        ids.indexOf(country.properties.ISO_A3) >= 0
    );

    relevantCountries.forEach(c => 
      const index = worldTopo.indexOf(c);
      if (index === -1) throw Error(`Expected to find country $c.properties.ISO_A3 in worldTopo`);
      worldTopo.splice(index, 1);
    );

    return 
      type: "Feature",
      properties:  region, countries: ids ,
      geometry: topojsonClient.merge(worldTopo, relevantCountries),
    ;
  ),
;

【讨论】:

感谢您的回答!我明白了,那么这里实际上可能有两个问题。我通过简单地删除“世界”功能解决了重叠的形状。但是,缠绕顺序问题(我假设)仍然存在。至少当我尝试使用 vega lite 可视化地图时,形状似乎是错误的,如您所见here。但是,当我使用您的 d3 脚本时,它是 correct。那么这可能是一个 vega lite 问题吗? 我没有Vega的经验,所以不能说 我尝试了一些解决方法,但即使只有一个功能,这个问题总是存在。肯定和vega有关,不管是设置还是别的,我都说不准

以上是关于使用topomerge合并topojson会打乱缠绕顺序的主要内容,如果未能解决你的问题,请参考以下文章

D3为geojson添加路径但不添加topojson

初涉CentOS 7,关闭缠人的selinux

GeoJSON 和 TopoJSON 的区别

如何按坐标过滤 GeoJSON/TopoJSON 数据?

d3.js onclick 和 touch 在 topojson 地图上工作不稳定

如何让我的topojson文件与数据图一起使用?