Choropleth图是一种统计图表,用于在地理区域内显示数据分布。这种图表通过不同的颜色、阴影或图案来表示不同区域内的数据值。Choropleth图常用于展示人口密度、经济指标、政治投票结果等数据,其中每个区域(如州、县、国家)的填色或图案代表该区域的数据值。
欢迎关注本人公众号--交通数据探索师
1、颜色设置
绘制choropleth图时,可以自定义颜色,也可以引用python已经定义好的颜色。
1.1、引用定义好的颜色
将定义好的颜色名称传给cmap参数,如下
data.plot(column='status', categorical=True, legend=True, cmap='Spectral')
怎么查找这些定义好的颜色名称呢?
可以在下面的网址中找到
Choosing Colormaps in Matplotlib — Matplotlib 3.9.0 documentation
部分内容如下,
完整代码如下,
import geopandas as gpd import matplotlib.pyplot as plt # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] # 读取shp文件 data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # column='status': 指定status列进行分类,status列值相同的赋予相同的颜色 # categorical=False:这个参数指定了'status'列的数据是否是分类的 # 如果设置为False,表示'status'列包含的是数值数据,而不是分类数据 # 当不传入cmap参数时,将使用默认颜色进行绘图 data.plot(column='status', categorical=True, legend=True, cmap='jet') # 关闭坐标轴 plt.axis('off') plt.show()
输出结果如下,
1.2、自定义颜色
有时候已经定义好的颜色无法满足项目需求,需要我们自己定义颜色,比如把区定义成橘黄色(orange),把县定义成绿色(green),自定义cmap的代码如下,
import matplotlib.colors as mcolors colors = ['orange', 'green'] cmap = mcolors.ListedColormap(colors)
输出结果如下,
完整代码如下,
import geopandas as gpd import matplotlib.pyplot as plt import matplotlib.colors as mcolors # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # 设置画布 fig, ax = plt.subplots(figsize=(10, 8), dpi=300) # 这里选取一些特定的颜色来自定义一个颜色映射 colors = ['orange', 'green'] cmap = mcolors.ListedColormap(colors) # 通过设置cmap参数来使用颜色映射 data.plot(ax=ax, column='status', cmap=cmap, edgecolor='grey', linewidth=0.1, legend=True) # 关闭坐标轴 plt.axis('off') plt.show()
输出结果如下,
2、图例设置
通过plot函数绘制Choropleth图时,可以通过其自带的legend=True参数显示图例,通过legend_kwds参数设置图例的样式;
或者不用legend参数,而是额外添加一个colorbar充当图例。
1、使用legend参数设置图例
import geopandas as gpd import matplotlib.pyplot as plt # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] # 读取shp文件 data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # legend_kwds参数可用来设置图例的位置和显示形式(如分几列显示) # column='status': 指定status列进行分类,status列值相同的赋予相同的颜色 # categorical: 指定了'status'列的数据是否是分类的。 # 如果设置为False,表示'status'列包含的是数值数据,将使用数值到颜色的映射来绘制Choropleth图 # legend=True: 显示图例 data.plot(column='status', categorical=True, legend=True) # 不显示坐标轴 plt.axis('off') plt.show()
输出结果如下,
可使用legend_kwds参数再对图例样式进行调整
data.plot(column='status', categorical=True, legend=True, legend_kwds={'loc': 'upper left', # 图例的位置, upper left为左上角 'ncols': 2, # 图例分成几列显示 'bbox_to_anchor': (0, 1), # 图例具体显示位置 'title': '行政区划', # 图例的标题 'fontsize': 10, # 图例的字体大小 'framealpha': 0, # 图例边框透明度 'title_fontsize': 10, # 图例标题的字体大小 'labelspacing': 1}) # 标签与图例之间的间隔
输出结果如下,
2、额外设置一个colorbar充当图例
import geopandas as gpd import matplotlib.pyplot as plt import matplotlib.colors as mcolors # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # 设置画布 fig, ax = plt.subplots(figsize=(10, 8), dpi=300) # 这里选取一些特定的颜色来创建一个颜色映射 colors = ['orange', 'green'] cmap = mcolors.ListedColormap(colors) # 通过设置cmap参数来使用颜色映射 data.plot(ax=ax, column='status', cmap=cmap) # 添加离散的colorbar scatter1 = ax.collections[0] # label: 设置colorbar的标签 # orientation: 设置colorbar的方向 默认是vertical, 可设置为horizontal(水平) # location: 设置colorbar的位置 默认是bottom, 可设置为top, left, right # location要与orientation配合使用,如果orientation为vertical,则location只能设置为bottom, top; # 如果orientation为horizontal,则location只能设置为left, right cbar = plt.colorbar(scatter1,ax = ax,label='colorbar', orientation='horizontal', location='bottom') # set_ticks: 设置colorbar的刻度 cbar.set_ticks([0, 0.25, 0.5, 0.75, 1]) # set_ticklabels: 设置colorbar的标签 # 这里通过设置一个空字符串来去除colorbar在0、0.5、1的位置的标签, # 来实现colorbar的标签与图例的标签居中对齐 cbar.set_ticklabels(['', '区', '', '县', '']) # 通过设置length=0来去除colorbar的刻度线 cbar.ax.tick_params(length=0) plt.axis('off') plt.show()
输出结果如下,
3、显示文字
通过plt.text参数显示每个区域的文字
# 通过data.geometry.centroid获取每个区域的中心点坐标 # 通过data.geometry.centroid.x获取区域的中心点坐标的x坐标,即经度 # 通过data.geometry.centroid.y获取区域的中心点坐标的y坐标,即纬度 for x, y, label in zip(data.geometry.centroid.x, data.geometry.centroid.y, data['地名']): plt.text(x, y, label, ha='center', va='center', fontsize=6)
完整代码如下,
import geopandas as gpd import matplotlib.pyplot as plt import matplotlib.colors as mcolors # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # 设置画布 fig, ax = plt.subplots(figsize=(10, 8), dpi=300) # 这里选取一些特定的颜色来创建一个颜色映射 colors = ['orange', 'green'] cmap = mcolors.ListedColormap(colors) # 通过设置cmap参数来使用颜色映射 data.plot(ax=ax, column='status', cmap=cmap, edgecolor='grey', linewidth=0.1) # 添加离散的colorbar scatter1 = ax.collections[0] # label: 设置colorbar的标签 # orientation: 设置colorbar的方向 默认是vertical, 可设置为horizontal(水平) # location: 设置colorbar的位置 默认是bottom, 可设置为top, left, right # location要与orientation配合使用,如果orientation为vertical,则location只能设置为bottom, top; # 如果orientation为horizontal,则location只能设置为left, right cbar = plt.colorbar(scatter1,ax = ax,label='colorbar', orientation='horizontal', location='bottom') # set_ticks: 设置colorbar的刻度 cbar.set_ticks([0, 0.25, 0.5, 0.75, 1]) # set_ticklabels: 设置colorbar的标签 # 这里通过设置一个空字符串来去除colorbar在0、0.5、1的位置的标签, # 来实现colorbar的标签与图例的标签居中对齐 cbar.set_ticklabels(['', '区', '', '县', '']) # 通过设置length=0来去除colorbar的刻度线 cbar.ax.tick_params(length=0) # 显示每个区域的文字 for x, y, label in zip(data.geometry.centroid.x, data.geometry.centroid.y, data['地名']): plt.text(x, y, label, ha='center', va='center', fontsize=6) # 关闭坐标轴 plt.axis('off') plt.show()
输出结果如下,
4、添加底图
通过contextily库进行底图的添加
比如高德底图:http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}
谷歌底图:http://mt2.google.cn/vt/lyrs=m&scale=2&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}
但需要注意的是高德底图使用的是gcj02坐标系,谷歌使用的是wgs84坐标系。
而我们上面所使用的shp文件,其地理坐标系则使用的是wgs84,所以如果使用高德底图,则会出现一定程度的偏差。
但谷歌底图需要翻墙获取,这里先使用高德底图近似代替一下。
添加底图代码如下,
import contextily as ctx ctx.add_basemap(ax, source=r"http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}", reset_extent=False, crs='epsg:4326', alpha=1)
完整代码如下,
import geopandas as gpd import matplotlib.pyplot as plt import matplotlib.colors as mcolors import contextily as ctx # 解决中文乱码问题,并设置字体 plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.family'] = ['SimHei'] plt.rcParams['font.sans-serif'] = ['SimHei'] data = gpd.read_file('./train_data/kaifeng.shp') data['status'] = data['地名'].apply(lambda x: '区' if x.endswith('区') else '县') # 设置画布 fig, ax = plt.subplots(figsize=(10, 8), dpi=300) # 这里选取一些特定的颜色来创建一个颜色映射 colors = ['orange', 'green'] cmap = mcolors.ListedColormap(colors) # 通过设置cmap参数来使用颜色映射 data.plot(ax=ax, column='status', cmap=cmap, edgecolor='grey', linewidth=0.1) # 添加离散的colorbar scatter1 = ax.collections[0] # label: 设置colorbar的标签 # orientation: 设置colorbar的方向 默认是vertical, 可设置为horizontal(水平) # location: 设置colorbar的位置 默认是bottom, 可设置为top, left, right # location要与orientation配合使用,如果orientation为vertical,则location只能设置为bottom, top; # 如果orientation为horizontal,则location只能设置为left, right # fraction参数:fraction设置colorbar的大小 # pad参数:pad参数用于指定colorbar与图像之间的间距 cbar = plt.colorbar(scatter1,ax = ax,label='colorbar', orientation='vertical', location='right', fraction=0.0315, pad=0.02) # set_ticks: 设置colorbar的刻度 cbar.set_ticks([0, 0.25, 0.5, 0.75, 1]) # set_ticklabels: 设置colorbar的标签 # 这里通过设置一个空字符串来去除colorbar在0、0.5、1的位置的标签, # 来实现colorbar的标签与图例的标签居中对齐 cbar.set_ticklabels(['', '区', '', '县', '']) # 通过设置length=0来去除colorbar的刻度线 cbar.ax.tick_params(length=0) # 显示每个区域的文字 for x, y, label in zip(data.geometry.centroid.x, data.geometry.centroid.y, data['地名']): plt.text(x, y, label, ha='center', va='center', fontsize=6) ctx.add_basemap(ax, source=r"http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}", reset_extent=False, crs='epsg:4326', alpha=1) # 设置显示范围 ax.set_xlim(113.79001023, 115.36218228) ax.set_ylim(34.09641126, 35.12607713) plt.axis('off') plt.tight_layout() plt.show()
输出结果如下,