Matplotlib绘图基本操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hfutdog/article/details/85880928

声明

本文涉及的代码基于python 3.6.5 numpy1.14.3 pandas 0.23.0 matplotlib 2.2.2
matplotlib是python中常用的图表绘制工具;pandas是常用的数据处理工具,关于pandas的使用可以参考我的这篇文章:Pandas基本操作与常用接口;numpy是常用的科学计算工具,关于numpy的使用可以参考我的这篇文章:NumPy基本操作与常用函数
在使用numpy、pandas和matplotlib之前我们首先要导入相关模块:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

绘制简易折线图

现在我们有一个美国从1948年起每个年份每个月份的失业率的数据unrate.csv,数据只有两列,一列是DATE对应相应的月份,一列是VALUE就是相应的失业率。我们先用pandas把它导入进来

unrate = pd.read_csv('unrate.csv')

# 将DATE列数据由字符串转换为datetime类型
unrate['DATE'] = pd.to_datetime(unrate['DATE'])
print(unrate.head(12))
#          DATE  VALUE
# 0  1948-01-01    3.4
# 1  1948-02-01    3.8
# 2  1948-03-01    4.0
# 3  1948-04-01    3.9
# 4  1948-05-01    3.5
# 5  1948-06-01    3.6
# 6  1948-07-01    3.6
# 7  1948-08-01    3.9
# 8  1948-09-01    3.8
# 9  1948-10-01    3.7
# 10 1948-11-01    3.8
# 11 1948-12-01    4.0

然后我们利用这些数据先绘制一个简单的折线图:

first_twelve = unrate[0:12]
plt.plot(first_twelve['DATE'], first_twelve['VALUE'])
plt.show()

figure_1

绘制出来的折线图如上所示,plot()方法的第一个参数为x坐标值,x参数是可选的,若没有设置,默认为[0, ..., N-1]。第二个参数为y坐标值,该参数也可以是多个列数据,分别对应不同的数据集合。下面我们看一下当y为多个数据集合时的用法:

first_twelve = unrate[0:12]
second_twelve = unrate[12:24]
y = np.vstack((first_twelve['VALUE'], second_twelve['VALUE'])).T
plt.plot(first_twelve['DATE'].dt.month, y)  # 横轴取值为每年的12个月份
plt.show()

figure_2
对于y轴上的多个数据集,常用的写法其实是这样的:

first_twelve = unrate[0:12]
second_twelve = unrate[12:24]
plt.plot(first_twelve['DATE'].dt.month, first_twelve['VALUE'], color='red', marker='.', linestyle='dashed',
                linewidth=2, markersize=12)
plt.plot(second_twelve['DATE'].dt.month, second_twelve['VALUE'], 'g-')
plt.show()

figure_3
一般多个图线我们是多次调用plot()方法实现。而plot()方法还可以设置关键字参数来进行一些个性化定制,比如红色折线的color=‘red’设置了折线颜色,marker=’.'设置了折线上标记的样式,linestyle设置了折线的样式,linewidth设置了折线的宽度等等。还有一种方法是像绿线’g-'这样设置格式化字符串。当格式化字符串和关键字参数同时设置且有冲突时,关键字参数优先被使用,也就说:

plt.plot(first_twelve['DATE'].dt.month, first_twelve['VALUE'], 'g-', color='red', marker='.', linestyle='dashed',
                linewidth=2, markersize=12)

plt.plot(first_twelve['DATE'].dt.month, first_twelve['VALUE'], color='red', marker='.', linestyle='dashed',
                linewidth=2, markersize=12)

是等效的。
matplotlib为图形提供了很多自定义样式,具体可以查看文档,这里就不一一列举了。
上面的折线图还并不完整,下面我们进一步将其完善,使用下面这段代码,将得到一个较为完善的图:

first_twelve = unrate[0:12]
plt.plot(first_twelve['DATE'], first_twelve['VALUE'])
plt.xticks(rotation=45)
plt.xlabel('Month')
plt.ylabel('Unemployment Rate')
plt.title('Monthly Unemployment Trends, 1948')
plt.legend(loc='upper left')
plt.show()

figure_4
我们使用xticks()方法设置rotation参数为45度使得x坐标轴上的坐标标记旋转45度(图中"1948-02"等),使用xlabel()方法设置x坐标轴的名称为"Month",使用ylabel()方法设置y坐标轴的名称为"Unemployment Rate",使用title()方法设置图像标题为"Monthly Unemployment Trends, 1948",使用legend()方法为图像设置图例(loc参数表示图例放置的位置,图中为左上角)。
至此,我们就完成了一个简单的折线图了。

子图操作

我们先通过下面这段代码了解子图的概念:

fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 4)
plt.show()

figure_5
在上述代码中我们首先使用figure()方法创建子图,然后使用add_subplot()方法添加子图。子图在整张图中的分布类似于矩阵,add_subplot()的前两个参数表示矩阵的形状,第一个参数表示表示矩阵的行数,第2个参数表示矩阵的列数,在这里就是2行2列的矩阵,第三个参数表示子图在矩阵中的位置序号,位置序号从1开始,从左至右从上到下依次递增。
下面我们在子图上绘制折线图:

fig = plt.figure(figsize=(6, 6))
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 4)
ax1.plot(np.arange(6), np.random.randint(1, 10, 6))
ax2.plot(np.arange(12), np.random.randint(1, 10, 12))
ax3.plot(np.arange(12), np.random.randint(5, 15, 12))
plt.show()

在这里插入图片描述

如上图所示,为了使显示效果看起来好一点,我们设置figure()方法的figsize为(6, 6),也就是宽、高为6英寸,figure()方法还提供了其他一些参数供设置图像的表现形式,详情请参考文档。设置好图像之后,我们添加了3个子图ax1、ax2、ax3,然后调用plot()方法在每个子图上绘制出折线图。注意,这里figure()是设置整个图像的一些性质的方法,而plot()方法才是控制折线图或柱状图等图像的方法。

条形图与散点图

条形图

现在我们手上有一个电影评分数据fandango_scores.csv,格式如下所示:

FILM,RottenTomatoes,RottenTomatoes_User,Metacritic,Metacritic_User,IMDB,Fandango_Stars,Fandango_Ratingvalue,RT_norm,RT_user_norm,Metacritic_norm,Metacritic_user_nom,IMDB_norm,RT_norm_round,RT_user_norm_round,Metacritic_norm_round,Metacritic_user_norm_round,IMDB_norm_round,Metacritic_user_vote_count,IMDB_user_vote_count,Fandango_votes,Fandango_Difference
Avengers: Age of Ultron (2015),74,86,66,7.1,7.8,5,4.5,3.7,4.3,3.3,3.55,3.9,3.5,4.5,3.5,3.5,4,1330,271107,14846,0.5
Cinderella (2015),85,80,67,7.5,7.1,5,4.5,4.25,4,3.35,3.75,3.55,4.5,4,3.5,4,3.5,249,65709,12640,0.5

我们使用pandas从该文件里提取电影名称列和其他5列评分数据:

reviews = pd.read_csv('fandango_scores.csv')
cols = ['FILM', 'RT_user_norm', 'Metacritic_user_nom', 'IMDB_norm', 'Fandango_Ratingvalue', 'Fandango_Stars']
norm_reviews = reviews[cols]

然后我们利用这些数据创建条形图:

num_cols = ['RT_user_norm', 'Metacritic_user_nom', 'IMDB_norm', 'Fandango_Ratingvalue', 'Fandango_Stars']

bar_heights = norm_reviews.ix[0, num_cols].values
bar_positions = np.arange(5) + 0.75
tick_positions = np.arange(5) + 0.5
fig, ax = plt.subplots()

ax.bar(bar_positions, bar_heights, 0.5)
ax.set_xticks(tick_positions)
ax.set_xticklabels(num_cols)

ax.set_xlabel('Rating Source')
ax.set_ylabel('Average Rating')
ax.set_title('Average User Rating For Avengers: Age of Ultron (2015)')

plt.show()

figure_7
那么,上面的代码是什么意思呢?让我们一起来看一下。
首先num_cols定义了我们想要选取数据的列,我们选取这一列数据第一行的值作为bar_heights,也就是条形图里的各个条形的高度。
然后我们定义了bar_positions,也就是条形图中各个条形区域左下角的坐标值。而tick_positions是各个条形区域下方文字标记的坐标。
然后我们利用subplots()方法获取figure和ax。接下来我们的绘图操作都通过ax实现。
我们调用ax的bar()方法来创建条形图,传入bar_postions和bar_heights,而0.5表示的是每个条形区域的宽度。然后调用set_xticks()来设置各条形区域在横轴上的标记位置,set_xticklabels()来设置各条形区域在横轴上的名称。
最后,调用set_xlabel()方法来设置横轴的标签,set_ylabel()方法设置纵轴的标签,set_title()方法设置图表的标题。

散点图

下面我们看一下如何创建散点图:

fig, ax = plt.subplots()
ax.scatter(norm_reviews['Fandango_Ratingvalue'], norm_reviews['RT_user_norm'])
ax.set_xlabel('Fandango')
ax.set_ylabel('Rotten Tomatoes')
plt.show()

figure_8
如上所示,我们只需要调用ax(Axes object or array of Axes objects)的scatter()方法,并传入x坐标值和y坐标值就可以绘制一幅散点图了,其他的一些设置和折线图、条形图类似,这里就不多说了。

直方图和箱线图

直方图

我们可以使用以下的代码绘制直方图:

fig, ax = plt.subplots()
ax.hist(norm_reviews['Fandango_Ratingvalue'], range=(3, 4), bins=10)
plt.show()

figure_9
有的朋友可能会说了,上面的图和条形图不是没差别吗?为什么还要用ax的hist()方法去另外绘制呢?
这里就涉及到直方图和条形图的区别了,下面我简单说一下。

  • 直方图一般用来描述数据的分布情况,而条形图用来描述数据的类别信息;
  • 直方图中的条形面积表示频数、宽度表示组距、高度就是频数/组距,条形图中的条形高度表示频数,宽度是某个类别;
  • 直方图横轴上的数据是一个连续的范围,条形图上横轴是各个孤立的类别;
  • 直方图各个条形之间一般没有空隙,而条形图一般是有的。

接下来我们看一下直方图统计了哪些信息,要了解直方图的作用我们先看下面这幅图
figure_10
假设有一组电影评分的原始数据,每个评分数据只保留到小数点后一位,分值在0至5之间。我们按照分数统计这些评分的频数,然后进行排序,再平均划分分组范围,统计得到每个分组的分数频数,也就是分数范围为Bins,频数为Count。
上面的ax.hist()方法做的也正是这个事。norm_reviews[‘Fandango_Ratingvalue’]是需要统计的数据,range=(3, 4)表示直方图上只展示分数3至4之间的数据分布情况,bins=10表示将区间[3, 4]划分为10组,也就是组距为0.1。这样就得到了一个直方图了。

箱线图

箱线图又称箱式图或盒图,一般用来反映数据的大小、占比、趋势等,主要可以得到均值、分位数、极值等,揭示数据离散程度、异常值、分布差异等。
下面我们直接看一个案例:

num_cols = ['RT_user_norm', 'Metacritic_user_nom', 'IMDB_norm', 'Fandango_Ratingvalue']
fig, ax = plt.subplots()
ax.boxplot(norm_reviews[num_cols].values)
ax.set_xticklabels(num_cols)
ax.set_ylim(0, 5)
plt.show()

figure_11
上面的箱线图反映了四组电影评分的情况。
以第2个箱子为例,我们先介绍箱线图里的几个概念。
首先连接箱子的最下方一条横线称为下边缘,是这组数据的最小值;箱子的下边框表示下四分位数,又称“第一四分位数”,等于该组数据从小到大排列后第25%的数字;箱子中间的红线是中位数,又称“第二四分位数”,等于该组数据从小到大排列后第50%的数字;箱子的上边框表示上四分位数,又称“第三四分位数”,等于该组数据从小到大排列后第75%的数字;连接箱子上方的最上面一条横线称为上边缘,是这组数据的最大值。在上边缘和下边缘之外的值就是异常值,比如第2个箱子下方的圆圈。
从上面四个箱子我们可以看到IMDB的评分分布比较集中,但异常值也比较多,而Fandango的评分相对其他评分都比较高,RT_user的评分就比较分散(箱子较长)。当我们想了解一个电影大致怎么样时,也就可以根据箱线图的效果来选择一个评分作为参考标准。
生成箱线图只需要调用ax.boxplot()方法并传入数据即可,还有很多其他的参数一般并不常用,具体可以参考官方文档。
顺便提一下,set_ylim()方法设置了y轴上数据的上下限,那么同样的也有set_xlim()方法来对x轴进行设置。

其他

有一些图像设置的细节,前文都没有提到,这里再说一下。
我们仍然以前面绘制失业率折线图的代码为例,先看一下原图:
figure_12
现在我们想把坐标轴上值的刻度线给去掉,在原代码的基础上添加一行代码:

unrate = pd.read_csv('unrate.csv')

# 将DATE列数据由字符串转换为datetime类型
unrate['DATE'] = pd.to_datetime(unrate['DATE'])
print(unrate.head(12))

first_twelve = unrate[0:12]
fig, ax = plt.subplots()
ax.plot(first_twelve['DATE'], first_twelve['VALUE'])
# 添加的代码,去除坐标轴上的刻度线
ax.tick_params(bottom='off', top='off', left='off', right='off')
plt.show()

得到下图:
figure_13
很明显,x轴和y轴上的刻度线没了。如果我们连坐标轴和图像边框都不想显示了,可以在plt.show()之前加上如下代码:

for key, spine in ax.spines.items():
    spine.set_visible(False)

得到下图:
figure_14
好了,关于matplotlib的介绍就到这了,限于篇幅,有的东西可能讲的不够细致,但对于基本的操作,这些知识是够用了。最后,感谢各位读者花费时间来阅读这篇文章,如果文章有什么错误之处,欢迎在评论区批评指正,我会及时纠正。

猜你喜欢

转载自blog.csdn.net/hfutdog/article/details/85880928
今日推荐