我有一套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。
答案 0 :(得分:1)
您的第一种方法称为Voronoi diagramm
请参阅wikipedia
中的说明对于使用D3库的javascipt
,这种图表有一个解决方案为了完成这个解决方案,我在这里粘贴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中执行此操作。
使用以下格式创建包含数据的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
将其添加为CSV(分隔文本)图层
自定义已创建图层的样式,以获得您在第二个版本中描述的热图。
从此图层
创建Voronoi多边形自定义新创建的图层的样式,以使每个县的区域以不同的颜色着色。
从当前地图创建SVG:
项目 - >新的打印布局
点击"在布局中添加新地图"工具面板上的按钮,绘制大矩形的地图,将其放置在布局上。
点击"导出为SVG"
这就是全部。
Voronoi多边形上的黑到透明热图 - https://svgshare.com/s/5MZ。
仅限热图 - https://svgshare.com/s/5ND。
我用来生成数据的脚本 - https://gist.github.com/ei-grad/1355223cd8a3c6ba16deb454ddef50b4。