使用 GeoPandas 比较国家大小

用GeoPandas比较国家地区大小

原文:towardsdatascience.com/comparing-country-sizes-with-geopandas-2ce027282ba0

快速成功数据科学

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2b97659cc49c3fc97e60a74661fae8c9.png

我住在德克萨斯州(耶-哈!),我们喜欢将德克萨斯州与其他州、国家、岛屿、小行星等进行比较。我们甚至会将德克萨斯州与德克萨斯州进行比较:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3c58e90e1801e3bf25a83f56023bb133.png

没错,伙计们,德克萨斯州比德克萨斯州还要大!(作者)

我喜欢比较一个地理区域与另一个地理区域大小的梗图。尽管我对地理有很好的了解,但我经常感到惊讶。例如,澳大利亚是否比巴西大?新西兰是否比意大利小?德克萨斯州与德国、印度和智利相比如何?以下是答案:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/05039e296b3cb52c46d1d33c24f1f656.png

巴西略大于澳大利亚(作者)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f08028565195b8f036e3fddae1d76cf8.png

意大利略大于新西兰(作者)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/44f7a78494815c961f65f2c1683946a4.png

德克萨斯州比德国大(作者)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d8f200afdfb8d4bc2b03b3c6d1ac0d2c.png

他们不是没有理由称印度为次大陆的!(作者)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/201bdbac650cd2c1a214f8256070baa0.png

智利比德克萨斯州更大(更长)(作者)

除了娱乐性,这些比较也是学生们的优秀学习工具。

在这个快速成功数据科学项目中,我们将编写 Python 代码,以便轻松叠加和比较各国或美国各州的地图。这是一种了解地理空间数据集及其如何使用*GeoPandas*库进行操作的好方法。


流程

这里是我们将使用的一般流程:

  1. 加载每个国家或州的shapefiles(边界多边形)。

  2. 使用坐标参考系统投影边界。

  3. 将一个边界的质心平移以匹配另一个。

  4. 将一个边界平移和旋转,直到它很好地适应另一个。

  5. 绘制边界。


GeoPandas 库

*GeoPandas*是一个开源的第三方库,旨在支持 Python 中的地理空间映射。它建立在 pandas 数据分析库之上,使得处理地理空间矢量数据与处理表格数据类似。它还使 Python 能够执行通常需要专用地理空间数据库的操作,例如 PostGIS。

GeoPandas 的GeoDataFrame是一个具有特殊“geometry”列的 pandas DataFrame,用于存储位置数据。这个列将几何对象的类型(如点、线字符串、多边形等)和绘制它所需的坐标(经度和纬度)捆绑在一起。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e59451327823ad658b66760497accc90.png

GeoDataFrame 中的几何列(由作者Python Tools for Scientists提供)

您可以在这里找到 GeoPandas 的安装说明。像往常一样,conda 用户操作简单(conda install geopandas)。如果您使用 pip,您还需要安装 shapely、pyproj、fiona、pyogrio 和 rtree 的主要依赖项,具体请参阅说明。

我们还需要 Matplotlib 进行绘图。作为 GeoPandas 的可选依赖项,当采用 conda 路径时,它应该会自动安装。


Shapefiles

对于国家和州边界,我们将依赖shapefiles。shapefile 是一种地理空间矢量数据格式,用于地理信息系统(GIS)软件。它用于在空间上描述矢量特征,如线、点和多边形。文件中的项目包括描述性属性,如名称。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4a412b6e479b4a484f2337a6ef6aa113.png

向量数据类型的示例(来自Python Tools for Scientists

“shapefile”不是一个单独的文件,而是一个集合,位于文件夹中的文件。下面的图示显示了用于主要湖泊轮廓的示例 shapefile。注意这个文件夹中的文件名如何使用文件夹名作为前缀。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fedddd611d9a8095657dc805e9ab2df2.png

示例 shapefile 目录(图片由作者提供)

三个文件是强制性的,文件扩展名为.shp.shx.dbf。虽然实际的 shapefile 专门关联到.shp文件,但其他支持文件是捕获形状几何所必需的。有关这些文件的更多详细信息,请查看维基百科页面上的 shapefiles 和这篇文章:

用 Shapefiles 提升您的地图

我们需要向 GeoPandas 提供 shapefiles文件夹的目录路径(压缩或解压缩)。GeoPandas 将使用此文件夹中的文件自动在 GeoDataFrame 中生成geometry列。还有什么比这更简单吗?


国家比较代码

以下代码通过在大约相同的比例上叠加地图来比较两个国家的地图。在文章的后面部分,我们将探讨比较美国

导入库

GeoPandas,与 pandas 类似,是基于 Matplotlib 构建的,因此我们将导入 Matplotlib 进行绘图。

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import geopandas as gpd

分配常量

为了方便起见,我们将在程序的顶部分配常数,这样它们将很容易找到和更改。这些包括国家名称、旋转角度(以便更好地“适应”一个国家到另一个国家),以及从 3D 地球到 2D 地图的投影坐标系(CRS)。

# Assign constants:
COUNTRY1 = 'China'      # Plots in the background (back).
COUNTRY2 = 'Australia'  # Plots in the foreground (front).
ROTATE =   -17          # Direction and amount to rotate COUNTRY2
CRS_1 =    'EPSG:3415'  # Coordinate Reference System for COUNTRY1             
CRS_2 =    'EPSG:3112'  # Coordinate Reference System for COUNTRY2 

坐标系(CRS)对于准确比较一个国家的面积与另一个国家非常重要。你可能熟悉标准 _墨卡托*地图投影以及它们如何扭曲极地附近国家的面积:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0b7908f68d7403526aa379adc0314a46.png

世界墨卡托投影(作者提供)

格陵兰与南美洲在大小上不相上下,而南极洲则纯粹是夸张。这是由于经线在极地附近汇聚的结果。因为这些线是非平行的,将它们展平到 2D 地图上会在赤道以外造成越来越大的扭曲:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/48a941a7714d183153d25c389a55edf6.png

经线在极地附近汇聚(来自作者提供的Real-world Python

这种扭曲可能会严重破坏大小比较。当你将澳大利亚与加拿大的墨卡托投影和更好地保留面积的兰伯特投影进行比较时,会发生以下情况:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f4492a2af4103db7fd8d5d6e7fc81d4b.png

澳大利亚与加拿大的墨卡托投影(左)与兰伯特投影(右)(作者提供)

幸运的是,有很多方法可以将球体投影到平面上,其中一些方法可以保留面积。不幸的是,这需要付出代价。

地图投影就像挤压气球。如果你掌握了一个参数,比如面积,另一个参数,比如角度形状,就会在你的手指之间凸起。

虽然有“等面积”投影,如 _兰伯特方位等面积投影阿尔伯斯等面积圆锥投影,它们可以保留地图上区域的相对大小*,但它们会扭曲国家轮廓。如果人们注意到国家的形状不熟悉,他们会怀疑显示的真实性,我们可不能有这种情况!

我找到的最好解决方案是使用每个国家的推荐本地投影系统进行投影,然后将一个移动并绘制在另一个之上。本地投影最适合在本地保留面积和形状。缺点是必须处理许多本地投影。尽管如此,这比使用单一投影对两国来说更令人满意,尤其是如果它们位于不同的纬度范围内。

我们将使用 EPSG 代码选择投影。根据 维基百科,“EPSG 地理参数数据集(也称为 EPSG 注册表)是一个公共注册表,包含 地理基准空间参考系统地球椭球体、坐标转换和相关的 测量单位,由欧洲石油调查组(EPSG)的成员于 1985 年创建。”

要找到国家的 EPSG 代码,请使用诸如 “澳大利亚推荐的 EPGS 代码是什么?” 等查询在线搜索。以下是我在这个项目中使用的代码列表:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/886a2abfbfac9a1082986511469009da.png

本文使用的 ESPG 代码(作者提供)

如果您想使用长列表的代码,考虑将它们作为字典输入,国家名称作为键,代码作为值。

选择和投影形状文件

Geopandas 以前附带 Natural Earth 公有领域 数据集,其中包含国家和州边界形状文件。这已在 2024 年初被弃用,因此我们必须手动下载文件。

幸运的是,这很简单。只需导航到这个 网站 并点击下面高亮显示的黄色下载链接:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/126ea7604511a1dea2f61cbdf5d34a09.png

点击高亮链接下载 “countries” 形状文件(作者提供)

将压缩文件移动到包含您的 Python 脚本或笔记本的文件夹中,然后运行以下代码:

# Download the shapefile used below from:
# https://www.naturalearthdata.com/downloads/110m-cultural-vectors/

world = gpd.read_file('ne_110m_admin_0_countries.zip')

# Select countries from GeoDataFrames:
front = world[world['SOVEREIGNT'] == COUNTRY2]
back = world[world['SOVEREIGNT'] == COUNTRY1]

# Project to a CRS before calculating the centroid:
front = front.to_crs(CRS_2)
back = back.to_crs(CRS_1)

形状文件被分配给 world 变量,并使用 GeoPandas 的 read_file() 方法加载。这里显示不出来,但如果你想查看内容,输入 world.head(),就像查看 pandas DataFrame 一样。

front 国家将在显示的前景中以红色显示。back 国家将在背景中以黑白显示。

最后两行将形状文件转换为由 EPSG 代码指定的正确坐标参考系统。

旋转和移动边界多边形

以下代码找到每个国家多边形的 质心,如果需要,旋转 front(前景)多边形,并将其移动,使两个多边形具有相同的中心点。

# Calculate the geographical center of each country:
front_center = front.geometry.centroid.iloc[0]
back_center = back.geometry.centroid.iloc[0]

# Rotate COUNTRY2 around center by ROTATE value (0 = no rotation):
front_rotated = front.set_geometry(front.rotate(ROTATE, origin='centroid'))

# Shift foreground country to overlap background country:
front_shifted = front_rotated.set_geometry(front_rotated.translate(
                                           xoff=back_center.x-front_center.x, 
                                           yoff=back_center.y-front_center.y))

ROTATE 常量允许您旋转前景国家的多边形,以改善其在背景多边形内的放置。值应在 0 到 180 之间。负值将使多边形 顺时针旋转

还可以将前景多边形在垂直和水平方向上移动。我们将在关于美国各州的章节中稍后介绍这个选项。

绘制地图并检查面积

下一个单元格绘制地图,然后打印每个国家多边形的面积,作为质量控制步骤。后者有助于确保我们使用的是有效的 EPSG 代码。

# Plot the background country (COUNTRY1):
base = back.plot(color='white', edgecolor='black')

# Plot the foreground country (COUNTRY2):
front_shifted.plot(ax=base, color='red', alpha=0.5)

# Add a legend:
red_patch = mpatches.Patch(color='red', alpha=0.5, label=COUNTRY2)
plt.legend(handles=[red_patch], loc='best')

# Turn off axis labels and ticks:
plt.xticks([])
plt.yticks([])

# Add a title:
plt.title(f"{COUNTRY2} vs. {COUNTRY1} Size Comparison")

# Save plot (optional):
plt.savefig(f'{COUNTRY2} vs {COUNTRY1}.png', dpi=600)

plt.show();

# Print the country area beneath the map:
front['area_km2'] = front.area / 10**6
back['area_km2'] = back.area / 10**6
print(f"{COUNTRY2} area = {front.area_km2.to_string(index=False)} sq km")
print(f"{COUNTRY1} area = {back.area_km2.to_string(index=False)} sq km n")

前两个步骤绘制背景和前景边界。然后我们添加图例。这里的一个关键步骤是使用 Matplotlib 的mpatches.Patch()类制作一个红色矩形来指定前景国家。

然后我们关闭 x 轴和 y 轴的刻度,添加标题,并保存绘图。

最后,我们计算每个多边形的面积并打印结果。然后我们可以在网上搜索每个国家的面积,看看结果是否匹配。由于我们使用的边界多边形是简化的,所以它们不会完全精确,但它们足够接近,以确保我们的 EPSG 代码没有出错。

下面是澳大利亚与中国比较的结果:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5d859c1bad29ede42702bc09bc11e833.png

澳大利亚与中国(作者)

Australia area = 7.593688e+06 sq km
China area = 1.028958e+07 sq km

关于绘制联合王国的说明

我们的 shapefile 包括与联合王国的福克兰群岛,这可能会弄乱您的质心计算。为了解决这个问题,请在“ADMIN”列下删除“福克兰群岛”,如下所示:

# Remove the Falkland Islands:
world = gpd.read_file('ne_110m_admin_0_countries.zip')
world = world[(world.ADMIN != 'Falkland Islands')]

接下来,我们将比较美国各州与其他州和国家。


美国各州比较代码

我们必须从 Natural Earth 网站下载一个新的 shapefile 来比较美国各州。点击下面突出显示的黄色链接,并将文件移动到包含您的 Python 脚本或笔记本的文件夹中:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5f704c84147248b07dd3f09f90d36b6d.png

点击突出显示的链接下载“州和省”shapefile(作者)

记住,您不需要解压缩文件即可使用它。

各州之间比较

下面是用于比较一个州与另一个州(在这种情况下,加利福尼亚州与德克萨斯州)的完整代码。它与之前基本相同,但使用了新的 shapefile 和一些变量名称的调整:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import geopandas as gpd

# Assign constants:
STATE1 = 'Texas'       # Plots in the background (back).
STATE2 = 'California'  # Plots in the foreground (front).
ROTATE =   13          # Direction and amount to rotate STATE2
CRS1 =    'EPSG:5070'  # Coordinate Reference System for STATE1
CRS2 =    'EPSG:5070'  # Coordinate Reference System for STATE2

# Load the shapefile:
usa = gpd.read_file('ne_110m_admin_1_states_provinces.zip')

# Select states from GeoDataFrame:
front = usa[(usa.name == STATE2)]
back = usa[(usa.name == STATE1)]

# Project to a CRS before calculating the centroid:
front = front.to_crs(CRS2)
back = back.to_crs(CRS1)

# Calculate the geographical center of each state:
front_center = front.geometry.centroid.iloc[0]
back_center = back.geometry.centroid.iloc[0]

# Rotate STATE2 around center by ROTATE value (0 = no rotation):
front_rotated = front.set_geometry(front.rotate(ROTATE, origin='centroid'))

# Shift foreground state to overlap background state:
front_shifted = front_rotated.set_geometry(front_rotated.translate(
                                           xoff=back_center.x-front_center.x, 
                                           yoff=back_center.y-front_center.y))

# Plot the background state (STATE1):
base = back.plot(color='white', edgecolor='k', lw=3)

# Plot the foreground state (STATE2):
front_shifted.plot(ax=base, color='red', alpha=0.5)

# Add a legend:
red_patch = mpatches.Patch(color='red', alpha=0.5, label=STATE2)
plt.legend(handles=[red_patch], loc='best')

# Turn off axis labels and ticks:
plt.xticks([])
plt.yticks([])

# Add a title:
plt.title(f"{STATE2} vs. {STATE1} Size Comparison")
plt.savefig(f'{STATE2}_vs_{STATE1}.png', dpi=600)
plt.show();

# Print the area of each beneath the map:
front['area_km2'] = front.area / 10**6
back['area_km2'] = back.area / 10**6
print(f"{STATE2} area = {front.area_km2.to_string(index=False)} sq km")
print(f"{STATE1} area = {back.area_km2.to_string(index=False)} sq km n")

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/47d1b39aa0aed925b506111518b86b50.png

加利福尼亚州与德克萨斯州(作者)

各州与国家比较

要将一个州(或多个州)与另一个国家进行比较,我们必须加载国家和州的 shapefile。以下是一个比较澳大利亚与下 48 个州的示例:

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import geopandas as gpd

# Assign constants:
COUNTRY1 = 'USA'        # Plots in the background (back).
COUNTRY2 = 'Australia'  # Plots in the foreground (front).
ROTATE =   0            # Direction and amount to rotate COUNTRY2
CRS_1 =    'EPSG:5070'  # Coordinate Reference System for COUNTRY1             
CRS_2 =    'EPSG:3112'  # Coordinate Reference System for COUNTRY2   

# Load the shapefiles:
world = gpd.read_file('ne_110m_admin_0_countries.zip')
usa = gpd.read_file('ne_110m_admin_1_states_provinces.zip')

# Exclude Alaska and Hawaii from USA:
usa = usa[(usa.name != 'Alaska') & (usa.name != 'Hawaii')]

# Select regions from GeoDataFrames:
front = world[world['SOVEREIGNT'] == COUNTRY2]
back = usa

# Project to a CRS before calculating the centroid:
front = front.to_crs(CRS_2)
back = back.to_crs(CRS_1)

# Calculate the geographical center of each region:
front_center = front.geometry.centroid.iloc[0]
back_center = back.geometry.centroid.iloc[0]

# Rotate front around center by ROTATE value (0 = no rotation):
front_rotated = front.set_geometry(front.rotate(ROTATE, origin='centroid'))

# Shift front to overlap back:
front_shifted = front_rotated.set_geometry(front_rotated.translate(
                                           xoff=back_center.x-front_center.x, 
                                           yoff=back_center.y-front_center.y))

# Plot the background region:
base = back.plot(color='white', edgecolor='black')

# Plot the foreground region:
front_shifted.plot(ax=base, color='red', alpha=0.5)

# Add a legend:
red_patch = mpatches.Patch(color='red', alpha=0.5, label=COUNTRY2)
plt.legend(handles=[red_patch], loc='best')

# Turn off axis labels and ticks:
plt.xticks([])
plt.yticks([])

# Add a title:
plt.title(f"{COUNTRY2} vs. {COUNTRY1} Size Comparison")

plt.show();

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d0cae10be66aa1171ce6f5598407c579.png

澳大利亚与下 48 个州(作者)

这里有一个问题。澳大利亚太北了,不适合进行比较。为了解决这个问题,我们需要将澳大利亚向下移动。

垂直和水平移动边界多边形

我们已经通过将前景多边形的质心设置为背景多边形的质心来移动前景多边形。为了进一步在南北和东西方向上调整它,我们可以分配额外的常数:

SHIFT_SOUTH = 550_000  # in meters 
SHIFT_WEST = 350_000  # in meters

ROTATE常数一样,显示的值是通过试错得到的。

我们接着编辑将前多边形移动以包含新常数的代码行:

front_shifted = front_rotated.set_geometry(front_rotated.translate(
                                xoff=back_center.x-front_center.x-SHIFT_WEST, 
                                yoff=back_center.y-front_center.y-SHIFT_SOUTH))

这将澳大利亚向下移动 550 公里,向左移动 350 公里:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2b97659cc49c3fc97e60a74661fae8c9.png

澳大利亚与下 48 个州对比,澳大利亚向西和向南移动(作者绘制)

这样可以做出更好的比较。

有趣的是,我在 20 世纪 90 年代初住在墨尔本时,并没有意识到澳大利亚的面积有美国大陆那么大。然后我从墨尔本东南部飞往西海岸的珀斯。这次飞行略超过 4 小时,与从亚特兰大到圣地亚哥的旅行相似。一些简单的数学计算(4 小时 x 500 英里/小时)显示我飞行了 2000 多英里。难怪澳大利亚被归类为大陆!


摘要

Python 的GeoPandas库使得操作地理空间数据以创建有趣的地图变得容易。GeoPandas 的表格GeoDataFrame在流行的 pandas DataFrame的基础上构建,通过包含一个“Geometry”列来存储如多边形和线这样的矢量数据的坐标。这使得 GeoDataFrames“空间感知”。

“Geometry”列通常使用一种名为shapefile的地理空间矢量数据格式来填充。使用 GeoDataFrame,你可以使用坐标参考系统将地理空间数据投影到平面上,旋转和移动数据,计算面积,绘制数据等等。


谢谢!

感谢阅读,并请关注我,未来将有更多快速成功数据科学项目。

关于 阿里云盘CLI。仿 Linux shell 文件处理命令的阿里云盘命令行客户端,支持JavaScript插件,支持同步备份功能,支持相册批量下载。 特色 多平台支持, 支持 Windows, macOS, linux(x86/x64/arm), android, iOS 等 阿里云盘多用户支持 支持备份盘,资源库无缝切换 下载网盘内文件, 支持多个文件或目录下载, 支持断点续传和单文件并行下载。支持软链接(符号链接)文件。 上传本地文件, 支持多个文件或目录上传,支持排除指定文件夹/文件(正则表达式)功能。支持软链接(符号链接)文件。 同步备份功能支持备份本地文件到云盘,备份云盘文件到本地,双向同步备份保持本地文件和网盘文件同步。常用于嵌入式或者NAS等设备,支持docker镜像部署。 命令和文件路径输入支持Tab键自动补全,路径支持通配符匹配模式 支持JavaScript插件,你可以按照自己的需要定制上传/下载中关键步骤的行为,最大程度满足自己的个性化需求 支持共享相册的相关操作,支持批量下载相册所有普通照片、实况照片文件到本地 支持多用户联合下载功能,对下载速度有极致追求的用户可以尝试使用该选项。详情请查看文档多用户联合下载 如果大家有打算开通阿里云盘VIP会员,可以使用阿里云盘APP扫描下面的优惠推荐码进行开通。 注意:您需要开通【三方应用权益包】,这样使用本程序下载才能加速,否则下载无法提速。 Windows不第二步打开aliyunpan命令行程序,任何云盘命令都有类似如下日志输出 如何登出和下线客户端 阿里云盘单账户最多只允许同时登录 10 台设备 当出现这个提示:你账号已超出最大登录设备数量,请先下线一台设备,然后重启本应用,才可以继续使用 说明你的账号登录客户端已经超过数量,你需要先登出其他客户端才能继续使用,如下所示
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值