根据一组坐标

时间:2018-01-14 20:20:55

标签: python macos svg geometry geospatial

我有一套1000个坐标,每个坐标代表一个特定州的城市中心。这些城镇属于20个县之一,我知道哪个城镇属于哪个县。我希望根据每个县的数据为地图着色。例如,如果一个县的值为100%,那么我希望将该县的颜色设置为深红色,如果一个县与0%相关联,那么我将将该地图的这部分颜色设置为白色。

我没有每个县的边界,因为这些是旧县,并且涉及大量的工作来追踪旧地图的边界。我有国家的边界​​,包括岛屿和湖泊等。

所以这是我的数据:

Town1 50.1,4.89 County1    
Town2 49.9,4.78 County1    
Town3 50.3,4.59 County1    
Town4 50.2,4.99 County1    
Town5 50.0,4.99 County1    
...
Town1000 57.0,8.33 County20 

County1 100%   
County2 100%   
County3 68%   
...
County20 0% 

以及州界限。

解决方案1:因此,创建我想要的地图的一种方法可能是围绕每个坐标(城镇)创建多边形,此多边形表示地图上距离该城镇最近的所有区域,并且更接近其他城镇。然后我根据其县的数据为这个多边形着色。

解决方案2:也许更好的方法是在城镇之间混合颜色。因此,如果我在不同的县有两个相邻的城镇,一个有100%,一个有0%,那么它们之间的中间点将是粉红色(深红色和白色之间)。

所以我希望以图像文件的形式编程生成这个地图,这个文件很容易扩展,我可以将它导入Photoshop之类,以便添加其他元素。在这种情况下你会推荐SVG吗?

我可以使用哪种库或算法来生成解决方案1中所需的多边形?

是否有一个库可用于生成一个SVG文档,其中包含解决方案2所需的渐变网格?

我希望尽可能使用Python3,但我对其他语言持开放态度。我也对SVG的其他解决方案和替代方案持开放态度。

我正在使用MacOS。

3 个答案:

答案 0 :(得分:1)

您的第一种方法称为Voronoi diagramm

请参阅wikipedia

中的说明

对于使用D3库的javascipt

,这种图表有一个解决方案

D3 approach

为了完成这个解决方案,我在这里粘贴M.Bostock示例中的代码

var w = 1280,
    h = 800;

var projection = d3.geo.azimuthal()
    .mode("equidistant")
    .origin([-98, 38])
    .scale(1400)
    .translate([640, 360]);

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

var svg = d3.select("body").insert("svg:svg", "h2")
    .attr("width", w)
    .attr("height", h);

var states = svg.append("svg:g")
    .attr("id", "states");

var cells = svg.append("svg:g")
    .attr("id", "cells");

d3.json("us-states.json", function(collection) {
  states.selectAll("path")
      .data(collection.features)
    .enter().append("svg:path")
      .attr("d", path);
});

d3.csv("airports.csv", function(airports) {
  var positions = [];

  airports.forEach(function(airport) {
    positions.push(projection([+airport.longitude, +airport.latitude]));
  });

  // Compute the Voronoi diagram of airports' projected positions.
  var polygons = d3.geom.voronoi(positions);

  var g = cells.selectAll("g")
      .data(airports)
    .enter().append("svg:g");

  g.append("svg:path")
      .attr("class", "cell")
      .attr("d", function(d, i) { return "M" + polygons[i].join("L") + "Z"; })
      .on("mouseover", function(d, i) {
        d3.select("#footer span").text(d.name);
        d3.select("#footer .hint").text(d.city + ", " + d.state);
      });

  g.append("svg:circle")
      .attr("cx", function(d, i) { return positions[i][0]; })
      .attr("cy", function(d, i) { return positions[i][1]; })
      .attr("r", 1.5);
});

使用OpenGL和Gouraud着色可以轻松实现第二个解决方案,但是将其导出到SVG(或者除了位图之外的任何其他内容)并不容易。我会考虑任何替代方案。

答案 1 :(得分:1)

对于python中的Solution1,您可以在scipy中使用Voronoi Diagrams。以下代码(此SO post的修改版本)创建了一个voronoi图表,根据每个国家/地区的值使用不同的alpha绘制它并将其保存到图像Map.png

import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial import Voronoi, voronoi_plot_2d
import random

# make up data points
points = np.random.rand(15,2)
values = np.random.uniform(low=0.0, high=1.0, size=(len(points),))

# compute Voronoi tesselation
vor = Voronoi(points)

# plot
voronoi_plot_2d(vor)

# colorize
for region, value in zip(vor.regions, values):
    if not -1 in region:
        polygon = [vor.vertices[i] for i in region]
        plt.fill(*zip(*polygon), color='r',  alpha=value)

plt.savefig('Map.png')

您的积分应加载到第7行的points变量和第8行的values变量中的国家/地区百分比中。

答案 2 :(得分:0)

虽然有强大的通用数据表示框架,但这个特定任务的适当工具是GIS。我将尝试解释如何在QGIS中执行此操作。

  1. 准备数据以导入QGIS。
  2. 使用以下格式创建包含数据的CSV文件:

    Town,X,Y,County,Value
    Town1,50.1,4.89,County1,100
    Town2,49.9,4.78,County1,100
    Town3,50.3,4.59,County1,100
    Town4,50.2,4.99,County1,100
    Town5,50.0,4.99,County1,100
    ...
    Town1000,57.0,8.33,County20,0
    
    1. 将其添加为CSV(分隔文本)图层

      • 图层 - >添加图层 - >添加分隔文本图层
    2. 自定义已创建图层的样式,以获得您在第二个版本中描述的热图。

      • 右键单击图层面板上的图层标题(左下角) - >属性 - >符号
      • 更改"单个符号"下载到"热图"
      • 点击"应用"
      • 选择"价值"字段(请记住它以CSV格式?)在"权重点中按"
      • "应用"
      • 根据需要调整其他参数(颜色渐变,半径)
    3. 从此图层

      创建Voronoi多边形
      • 矢量 - >几何工具 - > Voronoi多边形
      • 点击" ..."在目标图层路径输入框附近,选择"保存到文件",将其保存到GeoJSON图层(QGIS不支持CSV格式的多边形图层,如果您了解,可以选择其他格式)。
      • 点击"在后台运行"。
    4. 自定义新创建的图层的样式,以使每个县的区域以不同的颜色着色。

      • 右键单击图层面板上的图层标题(左下角) - >属性 - >符号
      • 选择"分类"而不是"单个符号"
      • 选择"县"在"列"下拉
      • 点击"分类"为所有县分配颜色
      • "应用"
    5. 从当前地图创建SVG:

      • 项目 - >新的打印布局

      • 点击"在布局中添加新地图"工具面板上的按钮,绘制大矩形的地图,将其放置在布局上。

      • 点击"导出为SVG"

    6. 这就是全部。

      Voronoi多边形上的黑到透明热图 - https://svgshare.com/s/5MZ

      仅限热图 - https://svgshare.com/s/5ND

      我用来生成数据的脚本 - https://gist.github.com/ei-grad/1355223cd8a3c6ba16deb454ddef50b4