使用geopandas重新排列多边形以便在matplotlib中进行绘图。

4
我正在开发一个项目,使用形状文件制作美国的分级地图。为此,我从美国人口普查局这里下载了标准形状文件。经过一些整理(一些多余的岛屿领土通过更改绘图轴限制进行去除),我能够让连续的州地图与matplotlib图形的边界完美契合。请参见下面的编辑4作为参考。 编辑1:我使用的是cb_2018_us_state_500k.zip [3.2 MB]形状文件。
现在唯一的问题是,通过设置轴限制,我不能再看到阿拉斯加和夏威夷(因为这些显然被限制的轴限制切掉)。我现在想把这两个多边形添加回我的地图中,但现在放到图形的下部(这是大多数此类地图给予的处理方式),尽管这样做在地理上不准确。
更具体地说,我希望选择代表阿拉斯加和夏威夷的多边形形状,并将它们移动到我的图形的左下角。这是可能的吗?
我可以使用布尔蒙版创建:
mask = df['STUSPS'] == 'AK'

我想单独获取该州的多边形;然而,我现在有点困惑如何在选择后移动/重新定位它。

编辑2:因为每个州都由geometry数据类型表示,所以我可以对多边形中的每个点应用变换吗?对于阿拉斯加,几何列显示为:

27    MULTIPOLYGON (((179.48246 51.98283, 179.48656 ...
Name: geometry, dtype: geometry

将列表中的每个数字乘以相同的常数可以实现这一点吗?

我想把阿拉斯加放在左下角,大约在(-125, 27)的位置,夏威夷放在其旁边,大约在(-112, 27)的位置。

编辑3:

我的代码:

import geopandas as gpd
import matplotlib.pyplot as plt

# import the United States shape file 
df = gpd.read_file('Desktop/cb_2018_us_state_500k/cb_2018_us_state_500k.shp')

# exclude the values that we would not like to display
exclude = df[~df['STUSPS'].isin(['PR', 'AS', 'VI', 'MP', 'GU','AK'])]

# create a plot figure
fig, ax = plt.subplots(1, figsize=(20, 10))

exclude.plot(column="NAME", ax=ax)
_ = ax.set_xlim([-130, -64])
_ = ax.set_ylim([22, 53])

我现在有一个示例图:

enter image description here

非常感谢提供任何见解或资源链接,解释或示例。

注意: 从技术上讲,我可以通过使用已经在此位置包括阿拉斯加和夏威夷的形状文件(例如由内政部提供的形状文件)来避免这个问题; 然而,如果我想添加关岛或波多黎各,则无法使用此方法。

期望的结果:

编辑4: 我想要做类似于这个问题的事情,但是用Python而不是R。

enter image description here

图片来源: Murphy


可能的解决方案在这里 https://dev59.com/F8Dqa4cB1Zd3GeqPjri4 - swatchai
该链接还使用更适合绘图的“地图投影”。 - swatchai
2个回答

1
你可以这样做。你需要找到正确的偏移量来精确定位阿拉斯加在你想要的位置。

现在,你有以下数据框:
 STATEFP   STATENS     AFFGEOID GEOID STUSPS            NAME LSAD  \
0      28  01779790  0400000US28    28     MS     Mississippi   00   
1      37  01027616  0400000US37    37     NC  North Carolina   00   
2      40  01102857  0400000US40    40     OK        Oklahoma   00   

          ALAND       AWATER  \
0  121533519481   3926919758   
1  125923656064  13466071395   
2  177662925723   3374587997   

                                            geometry  
0  MULTIPOLYGON (((-88.50297 30.21523, -88.49176 ...  
1  MULTIPOLYGON (((-75.72681 35.93584, -75.71827 ...  
2  POLYGON ((-103.00257 36.52659, -103.00219 36.6...  

你可以按照之前的方式提取阿拉斯加,或者类似的方式:
USA_ALS = USA[USA.STUSPS=='AK']

从那里开始,您需要执行以下操作:
USA_ALS['geometry'] = USA_ALS.geometry.apply(lambda x: shapely.affinity.translate(x, xoff=0, yoff=-100))

该程序将几何图形沿x和y轴进行翻译。

从原始df中删除旧的Alska,并与新的连接起来:

USA = USA[USA.STUSPS!='AK']
New_USA = pd.concat([USA,USA_ALS])
New_USA.geometry.plot()

这个给出:

enter image description here

``


谢谢您的回复。我想我明白您在这里做什么。我们如何缩小多边形呢? - Ethan
使用GeoSeries.scale(xfact=1.0, yfact=1.0, zfact=1.0, origin='center')进行缩放。例如geo_df.geometry = df.geometry.scale(xfact=1/10000, yfact=1/10000, zfact=1.0, origin=(0, 0))。在移动多边形之前执行此操作。 - Serge de Gosson de Varennes
谢谢,这个有效。不过我有一个问题——似乎大多数像这样的地图都让阿拉斯加看起来更“扁平”。这里的较长的阿拉斯加是由于这个特定的形状文件造成的吗? - Ethan
是的,没错。但是使用缩放可以恢复形状。 - Serge de Gosson de Varennes
你会建议只在x轴上进行缩放吗? - Ethan

1
您可以使用ax.inset_axes() 轻松实现最终目标,然后在插图上指定不同的经度/纬度边界。
以下是一种简单的方法:
# import the United States shape file
df = gpd.read_file('cb_2018_us_state_500k/cb_2018_us_state_500k.shp')

# set state code as index, exclude states that we will never display
df = df.set_index('STUSPS').drop(index=['PR', 'VI', 'MP', 'GU', 'AS'])

# create an axis with 2 insets − this defines the inset sizes
fig, continental_ax = plt.subplots(figsize=(20, 10))
alaska_ax = continental_ax.inset_axes([.08, .01, .20, .28])
hawaii_ax = continental_ax.inset_axes([.28, .01, .15, .19])

# Set bounds to fit desired areas in each plot
continental_ax.set_xlim(-130, -64)
continental_ax.set_ylim(22, 53)

alaska_ax.set_ylim(51, 72)
alaska_ax.set_xlim(-180, -127)

hawaii_ax.set_ylim(18.8, 22.5)
hawaii_ax.set_xlim(-160, -154.6)

# Plot the data per area - requires passing the same choropleth parameters to each call
# because different data is used in each call, so automatically setting bounds won’t work
vmin, vmax = df['ALAND'].agg(['min', 'max'])
df.drop(index=['HI', 'AK']).plot(column="ALAND", ax=continental_ax, vmin=vmin, vmax=vmax)
df.loc[['AK']].plot(column="ALAND", ax=alaska_ax, vmin=vmin, vmax=vmax)
df.loc[['HI']].plot(column="ALAND", ax=hawaii_ax, vmin=vmin, vmax=vmax)

# remove ticks
for ax in [continental_ax, alaska_ax, hawaii_ax]:
    ax.set_yticks([])
    ax.set_xticks([])

这是结果,您可以看到颜色与每个州的土地面积成比例:

enter image description here


惊人的解决方案,特别是使用inset_axes()的想法非常完美。感谢您花时间提供这个详细的解决方案。只有一个快速澄清,插图是否与原始地理数据框有关,还是它们是分开的?例如,如果我们向地理数据框附加表示人口的列,那么绘制此数据将把阿拉斯加和夏威夷的值映射到它们各自的插图中吗? - Ethan
1
你正在将相同的地理数据框绘制在插入图和主图上@Ethan。这是3个单独的.plot()调用,因此如果您添加了一个人口列,请确保在所有3个绘图命令(以及最小/最大计算中)中使用name ='population',那么就没问题了。 - Cimbali

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