「Matplotlib」全球疫情数据可视化
本文写于2020.3
目标
使用Python中的Matplotlib库对全球各国的日新增确诊病例进行数据可视化。
正文
读取数据
进行数据可视化,首先,我们需要获取全球各国的日新增确诊病例的数据。
我在Our World In Data上下载了从ECDC获取的CSV数据。
CSV:逗号分隔值,其文件以纯文本形式存储表格数据,便于程序对其进行分析。
要在Python程序中使用csv文件内储存的数据,可以使用自带的csv库,也可以使用pandas,在这里,我选择的是pandas。
import pandas as pd
data = pd.read_csv("daily-cases-covid-19.csv")
print(data)
print(type(data))
这样就完成了读取文件的工作,简单粗暴。我们使用print
来查看data现在储存的数据。
Entity Code Date Daily confirmed cases (cases)
0 Afghanistan AFG Dec 31, 2019 0
1 Afghanistan AFG Jan 1, 2020 0
2 Afghanistan AFG Jan 2, 2020 0
3 Afghanistan AFG Jan 3, 2020 0
4 Afghanistan AFG Jan 4, 2020 0
... ... ... ... ...
7600 Zimbabwe ZWE Mar 25, 2020 0
7601 Zimbabwe ZWE Mar 26, 2020 1
7602 Zimbabwe ZWE Mar 27, 2020 0
7603 Zimbabwe ZWE Mar 28, 2020 2
7604 Zimbabwe ZWE Mar 29, 2020 2
[7605 rows x 3 columns]
<class 'pandas.core.frame.DataFrame'>
DataFrame是pandas的表格型数据结构,包含一组有序的列,每列可以是不同的值类型。DataFrame有行索引和列索引,可以看成由Series组成的字典(Series只含有列索引)。
我们会发现,现在我们读取的数据是以0开始的序号来作为索引的,但是,为了我们后面能更好的处理数据,使用国家作为索引会更好。
Entity这一列储存了数据所对应的国家,index_col='Entity'
使国家这一列成为了数据的索引。
data = pd.read_csv("daily-cases-covid-19.csv", index_col='Entity')
再来查看我们的输出。
Code Date Daily confirmed cases (cases)
Entity
Afghanistan AFG Dec 31, 2019 0
Afghanistan AFG Jan 1, 2020 0
Afghanistan AFG Jan 2, 2020 0
Afghanistan AFG Jan 3, 2020 0
Afghanistan AFG Jan 4, 2020 0
... ... ... ...
Zimbabwe ZWE Mar 25, 2020 0
Zimbabwe ZWE Mar 26, 2020 1
Zimbabwe ZWE Mar 27, 2020 0
Zimbabwe ZWE Mar 28, 2020 2
Zimbabwe ZWE Mar 29, 2020 2
[7605 rows x 3 columns]
注意两者的差异,现在,国家成为了索引。
使用plt绘制表格,我们需要的是纵坐标数据是新增病例数组成的列表,即Daily confirmed cases (cases)列,横坐标则为日期,即为Date列,另外,还需要对国家进行筛选。
要想从DataFrame中获取这些数据并将其组成列表,我们可以使用loc
对行、列进行筛选,并使用values
将这些数据组成列表。这里,国家以中国为例。
va = data.loc["China", ["Date", "Daily confirmed cases (cases)"]].values
此时的va
是一个二维列表,为了将x坐标和y坐标分离出来,我使用了map
函数。
va_x = list(map(lambda x: x[0], va))
va_y = list(map(lambda x: x[1], va))
绘制
我们首先用最简单的绘制函数来看看效果。
plt.plot(va_x, va_y)
plt.show()
这样,我们就能知道我们需要改进的问题:
- 标题及对y轴所表示数据的说明
- x坐标上的日期需要倾斜显示,并且需要一定间隔
- 增加图例
标题及对y轴所表示数据的说明
这个比较简单,直接上代码。
import matplotlib.pyplot as plt
import pandas as pd
data = pd.read_csv("daily-cases-covid-19.csv", index_col='Entity')
va = data.loc["China", ["Date", "Daily confirmed cases (cases)"]].values
va_x = list(map(lambda x: x[0], va))
va_y = list(map(lambda x: x[1], va))
plt.title("Global outbreak data - covid-19")
plt.ylabel("Daily confirmed cases (cases)")
plt.plot(va_x, va_y)
plt.show()
来看看效果。
x坐标上的日期需要倾斜显示,并且需要一定间隔
为了实现这个目的,我们在对画布进行初始化时,使用fig, ax = plt.subplots()
,这一行代码的作用是方便我们在一张画布上呈现多个图表,在这里,我只需要一张图标,使用它是为了能够调用ax.set_xticks(xticks)
。
修改后的代码如下。
import matplotlib.pyplot as plt
import pandas as pd
data = pd.read_csv("daily-cases-covid-19.csv", index_col='Entity')
va = data.loc["China", ["Date", "Daily confirmed cases (cases)"]].values
va_x = list(map(lambda x: x[0], va))
va_y = list(map(lambda x: x[1], va))
fig, ax = plt.subplots()
fig.autofmt_xdate()
xticks = list(range(0, 90, 10))
ax.set_xticks(xticks)
plt.title("Global outbreak data - covid-19")
plt.ylabel("Daily confirmed cases (cases)")
plt.plot(va_x, va_y)
plt.show()
控制x轴间隔的值为xticks = list(range(0, 90, 10))
中的10,另外,这里的90指x坐标上的日期共有90个,这里要依照你下载下来的疫情数据而定。
增加图例
增加图例需要用到的函数是plt.legend()
。
在我们的程序中,实现增加图例的功能,只需要在plt.show()
这一行之前加上plt.legend(labels=["China"], loc=0)
。
labels
就是图例上的文字,这里需要传递的是一个列表,legend
函数会按照绘制线条的先后顺序自动匹配文字。
loc
为图例的显示位置,0
指代的是best
,程序会自动为你选择最合适的放置图例的位置。
绘制多个国家的数据
至此,我们的图标已经完成的差不多了,我们还需要让程序能够同时显示多个国家的数据。
我们可以将多个国家的名称储存在列表countrys
,并利用for循环,分别匹配对应的数据。
import matplotlib.pyplot as plt
import pandas as pd
data = pd.read_csv("daily-cases-covid-19.csv", index_col='Entity')
countrys = ["China", "United States"]
fig, ax = plt.subplots()
fig.autofmt_xdate()
xticks = list(range(0, 90, 10))
ax.set_xticks(xticks)
plt.title("Global outbreak data - covid-19")
plt.ylabel("Daily confirmed cases (cases)")
for country in countrys:
va = data.loc[country, ["Date", "Daily confirmed cases (cases)"]].values
va_x = list(map(lambda x: x[0], va))
va_y = list(map(lambda x: x[1], va))
plt.plot(va_x, va_y)
plt.legend(labels=countrys, loc=0)
plt.show()
用户输入
以上的代码,需要对源代码进行改动才能修改显示的国家,而我更希望让用户能够输入他们想要查看的国家数据。
使用input()
我认为并不好,单词输错可能会让他们很头疼,所以,我更加倾向于用「Tkinter」完成一个图形化界面,不过,用「EasyGUI」可能会更方便一些。
我们首先要做的事是将所有国家汇总于一个列表中。
# 这里将所有的索引放到了total列表里
total = list(data.index)
index = 0
# 这里对total列表进行了删去重复项的操作
while True:
if index >= len(total):
break
elif total.count(total[index]) > 1:
del total[index]
else:
index += 1
制作一个复选框就很容易了。
import easygui
# --snip--
countrys = easygui.multchoicebox(msg="Please select the country outbreak data to view:", title="", choices=total)
源代码
import matplotlib.pyplot as plt
import pandas as pd
import easygui
data = pd.read_csv("daily-cases-covid-19.csv", index_col='Entity')
total = list(data.index)
index = 0
while True:
if index >= len(total):
break
elif total.count(total[index]) > 1:
del total[index]
else:
index += 1
countrys = easygui.multchoicebox(msg="Please select the country outbreak data to view:", title="", choices=total)
fig, ax = plt.subplots()
fig.autofmt_xdate()
xticks = list(range(0, 90, 10))
ax.set_xticks(xticks)
plt.title("Global outbreak data - covid-19")
plt.ylabel("Daily confirmed cases (cases)")
for country in countrys:
va = data.loc[country, ["Date", "Daily confirmed cases (cases)"]].values
va_x = list(map(lambda x: x[0], va))
va_y = list(map(lambda x: x[1], va))
plt.plot(va_x, va_y)
plt.legend(labels=countrys, loc=0)
plt.show()
资料库
- 9 popular ways to perform Data Visualization in Python - Analytics Vidhya
- 菜鸟笔记Python3——数据可视化(三)世界GDP分析 - 简书
- 绘制折线图和面积图 - 简书
- 2019 冠状病毒病疫情状况 - WHO
- B-spline interpolation with Python - Stack Overflow
- Coronavirus Disease (COVID-19) – the data - Our World In Data
- Python之Pandas使用技巧 - 知乎
- Reading and Writing CSV Files in Python - Real Python
- Python学习笔记--图例 legend - Cnblogs