conda install geopandas
然后一路按 yes 即可。
此外,我们还需要安装 descartes 这个包。
conda install descartes
这里我比较推荐使用有交互模式的编辑器来写程序。它的好处是可以及时看到图片的效果。比如:
Jupyter Notebook
安装了 Python 插件的 VSCode
Spyder
我们在程序的最上方引入需要的模块,也就是 GeoPandas 和 Pandas。(为了教学方便,我这里引用的是最主要的必不可少的模块。大家可以根据需求引入其他的模块。)
import geopandas as gpd
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
导入内置世界地图
GeoPandas 这个包的最好的地方在于,它自带一副世界地图。所以我们并不需要依赖其他的地图文件。对于初学者十分友善。
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
world = world[world.continent != 'Antarctica']
这样,我们就读取了除去了南极洲的世界地图,并且存到了 world 这个对象里。这个 world 其实是一个表格,它有一列 name 是国家的名字,一列 geometry 是用来表达这个国家在地图上的形状的一串经纬度的列表。
在地图数据中,任何国家的形状都是由很多很多点围起来的,他们保存在这个叫 geometry 的列中。以后我们遇到了其他的地图数据文件 (Shapefile, .shp),国家的形状也是存在这一列中的。
我们可以让 Python 根据 geometry 这一列的数据来绘制国家的形状。如果想看到及时看到目前的地图,只要输入:
world.plot()
array(['Afghanistan', 'Albania', 'Algeria', 'Angola', 'Argentina',
'Armenia', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas',
'Bangladesh', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bhutan',
'Bolivia', 'Bosnia and Herz.', 'Botswana', 'Brazil', 'Brunei',
'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cameroon',
'Canada', 'Central African Rep.', 'Chad', 'Chile', 'China',
'Colombia', 'Congo', 'Costa Rica', 'Croatia', 'Cuba', 'Cyprus',
'Czechia', "Côte d'Ivoire", 'Dem. Rep. Congo', 'Denmark',
'Djibouti', 'Dominican Rep.', 'Ecuador', 'Egypt', 'El Salvador',
'Eq. Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Falkland Is.',
'Fiji', 'Finland', 'Fr. S. Antarctic Lands', 'France', 'Gabon',
'Gambia', 'Georgia', 'Germany', 'Ghana', 'Greece', 'Greenland',
'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti',
'Honduras', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran',
'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan',
'Kazakhstan', 'Kenya', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Laos',
'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Lithuania',
'Luxembourg', 'Macedonia', 'Madagascar', 'Malawi', 'Malaysia',
'Mali', 'Mauritania', 'Mexico', 'Moldova', 'Mongolia',
'Montenegro', 'Morocco', 'Mozambique', 'Myanmar', 'N. Cyprus',
'Namibia', 'Nepal', 'Netherlands', 'New Caledonia', 'New Zealand',
'Nicaragua', 'Niger', 'Nigeria', 'North Korea', 'Norway', 'Oman',
'Pakistan', 'Palestine', 'Panama', 'Papua New Guinea', 'Paraguay',
'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto Rico',
'Qatar', 'Romania', 'Russia', 'Rwanda', 'S. Sudan', 'Saudi Arabia',
'Senegal', 'Serbia', 'Sierra Leone', 'Slovakia', 'Slovenia',
'Solomon Is.', 'Somalia', 'Somaliland', 'South Africa',
'South Korea', 'Spain', 'Sri Lanka', 'Sudan', 'Suriname', 'Sweden',
'Switzerland', 'Syria', 'Taiwan', 'Tajikistan', 'Tanzania',
'Thailand', 'Timor-Leste', 'Togo', 'Trinidad and Tobago',
'Tunisia', 'Turkey', 'Turkmenistan', 'Uganda', 'Ukraine',
'United Arab Emirates', 'United Kingdom',
'United States of America', 'Uruguay', 'Uzbekistan', 'Vanuatu',
'Venezuela', 'Vietnam', 'W. Sahara', 'Yemen', 'Zambia', 'Zimbabwe',
'eSwatini'], dtype=object)
你会得到地图里面所有国家和地区的列表。(朱老师在这里一般会做一些细节处理,比如调整这幅图里错误的台湾地区和藏南地区。朱老师非常根正苗红政治正确的!)。
我们接下来就要给每个国家一个数字,这样才能把数据最终反馈到地图上不同的颜色。这里便于举例,我使用部分截至2020年3月30日的世界新冠肺炎疫情各国家和地区的确诊病例数。这里选取的国家都是病例数靠前并且在图上面积比较大的国家便于显示。将这些数值存入一个 DataFrame 里。
country_number = {'United States of America': 144060,
'Italy': 97689,
'Spain': 85199,
'China': 81470,
'Taiwan': 81470,
'Germany': 63929,
'Iran': 41495,
'France': 40174,
'United Kingdom': 22141,
'Switzerland': 15668,
'Belgium': 11899,
'Netherlands': 11750,
'South Korea': 9661,
'Canada': 6671,
'Norway': 4436,
'Brazil': 4330,
'Australia': 4247,
'Sweden': 4106,
'Japan': 1866,
'Russia': 1836,
df_country_number = pd.DataFrame(
country_number.items(), columns=['name', 'number'])
这样,我们就得到了一个 DataFrame 表格,里面有两列,一列是国家名 name,另一列是确诊病例数字 number。
合并地图和数值
接下来我们将地图和数值根据国家名合并起来。
world = pd.merge(world, df_country_number, on='name', how='left')
这段代码的意思是:我们将世界地图(国家名——形状数据)这个表格,和国家数据(国家名——病例数字)根据相同的国家名合并在一起。如果一个国家没有数据,那么这个国家依然留在表格中,但是 number 这一栏是空值。我们用0来代替这些空值并把这些数强制定义为整数。
world['number'] = world['number'].fillna(0).astype('int')
好啦,这下,每个在地图数据中的国家,都有一个数值了。如果没有数据,那么数据就是空的。
数据处理完毕,我们可以开始绘制地图了。回到最开始的部分,画一幅数据地图,我们需要画3个要素:
区域的形状。
区域的颜色。
图例和备注。
好在,GeoPandas足够强大,让我们可以一个命令将这些要素全部画进去。
首先,我们新建一个空白的图像和画布用来画图。以下命令定义了这块画布的长宽和清晰度。
fig, ax = plt.subplots(figsize=(15, 10), dpi=200)
区域的形状,国家的边界用0.2粗细的灰色线表示。
区域的颜色:根据 number 这一列的数字来画图,图的颜色是红色。
图例和备注:legend=True 显示一个颜色柱来表示数值和颜色深浅的对应关系。
我们会得到这样一幅图。
world.plot(ax=ax,
linewidth=0.2, edgecolor='gray',
column='number', cmap='Reds',
legend=True)
很好,一副数据地图最基本的特征都有啦。我们接下来做一些修饰。比如去掉坐标轴,加上个标题等等。
fig, ax = plt.subplots(figsize=(15, 10), dpi=200)
world.plot(ax=ax,
linewidth=0.2, edgecolor='gray',
column='number', cmap='Reds',
legend=True)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.get_xaxis().set_ticks([])
ax.get_yaxis().set_ticks([])
ax.set_title(
'Confirmed cases of COVID-19 per selected country (20200330)', size=20)
Text(0.5, 1.0, 'Confirmed cases of COVID-19 per selected country (20200330)')
进阶地图修饰
地图画到这里,我们已经从零开始学会了画一幅基本的数据地图。这已经可以让你应付很多你想要实现的可视化需求。当然,每一个数据地图都是独一无二的,都有一些不一样的特征,需要我们根据需求加以修饰。
比如,刚刚这幅地图中,还有一些值得提升的地方:
地图的区分度不够。因为有些国家的数字太高,导致了线性的“刻度——颜色”的关系无法把一些数字较小的国家区别开来。可能对于疫情地图来说,用对数刻度会更加有表现力。
这里的图例特别长,显得和左边的地图不协调,我们可以对它进行调整。
这里,我们用一些其他的命令就这幅地图进行调整。可以得到一张更加美观的地图。
from mpl_toolkits.axes_grid1 import make_axes_locatable
variable = 'number'
mapcolor = 'Reds'
fig, ax = plt.subplots(figsize=(15, 10), dpi=200)
world.plot(column=variable, cmap=mapcolor,
linewidth=0.2, edgecolor='gray', ax=ax,
scheme='user_defined', classification_kwds={'bins': [0, 10, 100, 1000, 10000, 100000]})
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.get_xaxis().set_ticks([])
ax.get_yaxis().set_ticks([])
ax.set_title(
'Confirmed cases of COVID-19 per selected country (20200330)', size=24)
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.2)
sm = plt.cm.ScalarMappable(cmap=mapcolor)
cbar = fig.colorbar(sm, cax=cax)
bins = [0, 10, 100, 1000, 10000, 100000]
_ = cbar.ax.set_yticklabels(bins)
C:\Users\ZHU\Anaconda3\lib\site-packages\ipykernel_launcher.py:21: UserWarning: FixedFormatter should only be used together with FixedLocator
考虑到这篇文章是朱老师手把手带你入坑门数据地图,就不在一些比较风骚复杂的命令上过多展开了。这些进阶的技巧,大家可以不断在实战和阅读官方文档中学习提升。朱老师接下来也会不定期推出“手把手教你用Python画数据地图之进阶篇”。
怎么样,想不想亲自动手试一试?如果有任何意见、建议、问题,都欢迎来跟我交流哦!我也很欢迎大家跟我分享你们画出的数据地图。
那么谢谢大家的阅读,我们下次再见!