「Matplotlib」全球疫情数据可视化

本文写于2020.3

目标

使用Python中的Matplotlib库对全球各国的日新增确诊病例进行数据可视化。

正文

读取数据

进行数据可视化,首先,我们需要获取全球各国的日新增确诊病例的数据。

我在Our World In Data上下载了从ECDC获取的CSV数据。

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()

Figure_1.png

这样,我们就能知道我们需要改进的问题:

  • 标题及对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()

来看看效果。

Figure_1.png

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()

Figure_1.png

控制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,程序会自动为你选择最合适的放置图例的位置。

Figure_1.png

绘制多个国家的数据

至此,我们的图标已经完成的差不多了,我们还需要让程序能够同时显示多个国家的数据。

我们可以将多个国家的名称储存在列表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)

复选框

Figure_1.png

源代码

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()

资料库

posted @ 2020-10-03 19:57  Liuxizai  阅读(366)  评论(0编辑  收藏  举报