Section Two - Plotting Spatial Data
在本节中,将学习如何使用Python创建和个性化绘制空间数据(包括 矢量 和 栅格 数据)的图形
源代码
学习目标:
- 创建一个包含多个矢量数据集的地图,并根据属性进行着色
- 为矢量数据地图添加自定义图例
- 设置地图的显示范围
- 使用
folium
实现交互式地图 - 实现栅格数据的叠加显示
- 实现栅格地图加载到
folium
中实现交互 - 使用Matplotlib个性化显示栅格数据
1 矢量数据绘制
学习目标:
- 为多个矢量数据集绘制地图,并根据属性进行配色
- 自定义地图图例
创建自定义地图
在本节中,将学习如何自定义地图符号和用于在Python中表示矢量数据的颜色和符号,使用geopandas和matplotlib进行地图绘制
首先导入需要使用到的包:
import os
import matplotlib.pyplot as plt
import numpy as np
from shapely.geometry import box
import geopandas as gpd
import earthpy as et
# 下载数据
# data = et.data.get_data('spatial-vector-lidar')
os.chdir(os.path.join(et.io.HOME, 'learning','python_data_plot'))
# 导入数据
sjer_roads_path="data/california/madera-county-roads/tl_2013_06039_roads.shp"
sjer_roads = gpd.read_file(sjer_roads_path)
print(type(sjer_roads['RTTYP']))
print(sjer_roads['RTTYP'].unique())
['M' None 'S' 'C']
缺失值替换
可以看出道路类型中有一些缺失的值,由于需要绘制所有的道路类型,甚至那些设置为 None
的道路类型,下面将 RTTYP
属性 None
为 Unknown
sjer_roads['RTTYP'].replace(np.nan,"Unknown",inplace=True)
# sjer_roads.loc[sjer_roads['RTTYP'].isnull(), 'RTTYP'] = 'Unknown'
print(sjer_roads['RTTYP'].unique())
['M' 'Unknown' 'S' 'C']
如果使用 geopandas.Plot()
绘制数据,当设置了 column =
参数后,则geopandas将为线条 自动选择颜色 ,可以使用 legend = True
参数添加图例
fig, ax = plt.subplots(figsize=(14,6))
sjer_roads.plot(column='RTTYP',
categorical=True,
legend=True,
ax=ax
)
# 调整图例位置
leg = ax.get_legend()
leg.set_bbox_to_anchor((1.15,0.5))
# 隐藏边框
ax.set_axis_off()
plt.show()
根据属性指定颜色
为了按属性值绘制一个矢量图层,这样每条道路图层就会根据它各自的属性值来着色,所以图例也代表了同样的符号,需要三个步骤:
- 创建一个将特定颜色与特定属性值关联的字典
- 循环遍历并将该颜色应用于每个属性值
- 最后,在绘图中添加一个
label
参数,以便调用ax.legend()
生成最终的图例
下面,先创建一个字典来定义您希望使用哪种颜色绘制每种道路类型:
# Create a dictionary where you assign each attribute value to a particular color
roadPalette = {'M': 'blue',
'S': 'green',
'C': 'purple',
'Unknown': 'grey'}
roadPalette
{'M': 'blue', 'S': 'green', 'C': 'purple', 'Unknown': 'grey'}
接下来,循环遍历每个属性值,并使用字典中指定的颜色用该属性值绘制线条
fig, ax = plt.subplots(figsize=(10,10))
# 根据道路类型分组进行绘制
for ctype,data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
data.plot(color=color,
ax=ax,
label=ctype
)
ax.legend(bbox_to_anchor=(1.0, .5), prop={'size': 12})
ax.set(title='Madera County Roads')
ax.set_axis_off()
plt.show()
调整线条宽度
可以通过 linewidth =
属性对线条宽度进行设置,
fig, ax = plt.subplots(figsize=(10, 10))
# Loop through each group (unique attribute value) in the roads layer and assign it a color
for ctype, data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
data.plot(color=color,
ax=ax,
label=ctype,
linewidth=4) # Make all lines thicker
# Add title and legend to plot
ax.legend()
ax.set(title='Madera County Roads')
ax.set_axis_off()
plt.show()
根据属性调整线条宽度
与着色相同,先创建线条宽度与类型的映射关系,然后分组进行循环绘制
# Create dictionary to map each attribute value to a line width
lineWidths = {'M': 1, 'S': 1, 'C': 4, 'Unknown': .5}
# Plot data adjusting the linewidth attribute
fig, ax = plt.subplots(figsize=(10, 10))
ax.set_axis_off()
for ctype, data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
data.plot(color=color,
ax=ax,
label=ctype,
# Assign each group to a line width using the dictionary created above
linewidth=lineWidths[ctype])
ax.legend()
ax.set(title='Madera County \n Line width varies by TYPE Attribute Value')
plt.show()
自定义绘制图例
在上面的实验中,使用 label=True
显示图例, ax.legend()
的 loc=
参数可以对图例位置进行调整, ax.legend()
的常用参数有:
-
loc=(how-far-right,how-far-above)
-
fontsize=
,设置图例字体大小 -
frameon=
,是否显示图例边框
lineWidths = {'M': 1, 'S': 2, 'C': 1.5, 'Unknown': 3}
fig, ax = plt.subplots(figsize=(10, 10))
# Loop through each attribute value and assign each
# with the correct color & width specified in the dictionary
for ctype, data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
label = ctype
data.plot(color=color,
ax=ax,
linewidth=lineWidths[ctype],
label=label)
ax.set(title='Madera County \n Line width varies by TYPE Attribute Value')
# Place legend in the lower right hand corner of the plot
ax.legend(loc='lower right',
fontsize=15,
frameon=True)
ax.set_axis_off()
plt.show()
观察当将图例 frameon
属性设置为 False
并调整线宽时会发生什么情况,注意 loc = ()
参数被赋予一个元组,它定义了图例相对于绘图区域的 x
和 y
的位置
lineWidths = {'M': 1, 'S': 2, 'C': 1.5, 'Unknown': 3}
fig, ax = plt.subplots(figsize=(10, 10))
for ctype, data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
label = ctype
data.plot(color=color,
ax=ax,
linewidth=lineWidths[ctype],
label=label)
ax.set(title='Madera County \n Line width varies by TYPE Attribute Value')
ax.legend(loc=(1, 0.5),
fontsize=15,
frameon=False,
title="LEGEND")
ax.set_axis_off()
plt.show()
同时对线宽和颜色进行调整
roadPalette = {'M': 'grey', 'S': "blue",
'C': "magenta", 'Unknown': "lightgrey"}
lineWidths = {'M': 1, 'S': 2, 'C': 1.5, 'Unknown': 3}
fig, ax = plt.subplots(figsize=(10, 10))
for ctype, data in sjer_roads.groupby('RTTYP'):
color = roadPalette[ctype]
label = ctype
data.plot(color=color,
ax=ax,
linewidth=lineWidths[ctype],
label=label)
ax.set(title='Madera County Roads \n Pretty Colors')
ax.legend(loc='lower right',
fontsize=20,
frameon=False)
ax.set_axis_off()
plt.show()
向地图中添加点图层
接下来,向地图添加另一个图层,看看如何创建一个更复杂的地图,添加SJER_plot_centroids shapefile,并同时表示两个图层的图例
该点图层包含三种类型:grass,soil,trees
# 导入点图层
sjer_plots_path ="data/california/neon-sjer-site/vector_data/SJER_plot_centroids.shp"
sjer_plots = gpd.read_file(sjer_plots_path)
sjer_plots.head(5)
Plot_ID | Point | northing | easting | plot_type | geometry | |
---|---|---|---|---|---|---|
0 | SJER1068 | center | 4111567.818 | 255852.376 | trees | POINT (255852.376 4111567.818) |
1 | SJER112 | center | 4111298.971 | 257406.967 | trees | POINT (257406.967 4111298.971) |
2 | SJER116 | center | 4110819.876 | 256838.760 | grass | POINT (256838.760 4110819.876) |
3 | SJER117 | center | 4108752.026 | 256176.947 | trees | POINT (256176.947 4108752.026) |
4 | SJER120 | center | 4110476.079 | 255968.372 | grass | POINT (255968.372 4110476.079) |
就像上面所做的一样,创建一个字典来指定与每个图形类型相关联的颜色
pointsPalette = {'trees': 'chartreuse',
'grass': 'darkgreen', 'soil': 'burlywood'}
lineWidths = {'M': .5, 'S': 2, 'C': 2, 'Unknown': .5}
fig, ax = plt.subplots(figsize=(10, 10))
for ctype, data in sjer_plots.groupby('plot_type'):
color = pointsPalette[ctype]
label = ctype
data.plot(color=color,
ax=ax,
label=label,
markersize=100)
ax.set(title='Study area plot locations\n by plot type (grass, soil and trees)')
ax.legend(fontsize=20,
frameon=True,
loc=(1, .1),
title="LEGEND")
ax.set_axis_off()
plt.show()
将点图层叠加到道路图层
接下来,在道路图层上叠加绘制点数据,然后创建一个包含线和点的自定义图例
注意: 在这个例子中,两个图层的投影信息必须匹配
# Reproject the data
# 数据投影
sjer_roads_utm = sjer_roads.to_crs(sjer_plots.crs)
fig, ax = plt.subplots(figsize=(10, 10))
# 点图层绘制
for ctype, data in sjer_plots.groupby('plot_type'):
color = pointsPalette[ctype]
label = ctype # label参数对于图例的生成很重要
data.plot(color=color,
ax=ax,
label=label,
markersize=100)
# 道路图层绘制
for ctype, data in sjer_roads_utm.groupby('RTTYP'):
color = roadPalette[ctype]
label = ctype
data.plot(color=color,
ax=ax,
linewidth=lineWidths[ctype],
label=label)
ax.set(title='Study area plot locations\n by plot type (grass, soil and trees)')
ax.legend(fontsize=15,
frameon=False,
loc=('lower right'),
title="LEGEND")
ax.set_axis_off()
plt.show()