【宝藏级】全网最全的Matplotlib详细教程(4.5万字总结)
1. 数据分析中常用图
折线图:
折线图用于显示数据在一个连续的时间间隔或者时间跨度上的变化,它的特点是反映事物随时间或有序类别而变化的趋势。示例图如下:
折线图应用场景:
- 折线图适合
X 轴是一个连续递增或递减的,对于没有规律的,则不适合使用折线图,建议使用柱状图。 - 如果折线图条数过多,则不应该都绘制在一个图上。
柱状图:
典型的柱状图(又名条形图),使用垂直或水平的柱子显示类别之间的数值比较。其中一个轴表示需要对比的分类,另一个轴代表相应的数值。
柱状图有别于直方图,柱状图无法显示数据在一个区间内的连续变化趋势。柱状图描述的是分类数据,回答的是每一个分类中“有多少?”这个问题。 示例图如下:
柱状图应用场景:
- 适用于分类数据对比。
- 垂直条形图最多不超过12个分类(也就是12个柱形),横向条形图最多不超过30个分类。如果垂直条形图的分类名太长,那么建议换成横向条形图。
- 柱状图不适合表示趋势,如果想要表示趋势,应该使用折线图。
直方图:
直方图(Histogram),又称质量分布图,是一种统计报告图,由一系列高度不等的条纹表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。
直方图是数值数据分布的精确图形表示。为了构建直方图,第一步是将值的范围分段,即将整个值的范围分成一系列间隔,然后计算每个间隔中有多少值。这些值通常被指定为连续的,不重叠的变量间隔。间隔必须相邻,并且通常是(但不是必须的)相等的大小。
直方图的应用场景:
- 显示各组数据数量分布的情况。
- 用于观察异常或孤立数据。
- 抽取的样本数量过小,将会产生较大误差,可信度低,也就失去了统计的意义。因此,样本数不应少于50个。
散点图:
散点图也叫 X-Y 图,它将所有的数据以点的形式展现在直角坐标系上,以显示变量之间的相互影响程度,点的位置由变量的数值决定。
通过观察散点图上数据点的分布情况,我们可以推断出变量间的相关性。如果变量之间不存在相互关系,那么在散点图上就会表现为随机分布的离散的点,如果存在某种相关性,那么大部分的数据点就会相对密集并以某种趋势呈现。数据的相关关系主要分为:正相关(两个变量值同时增长)、负相关(一个变量值增加另一个变量值下降)、不相关、线性相关、指数相关等,表现在散点图上的大致分布如下图所示。那些离点集群较远的点我们称为离群点或者异常点。
示例图如下:
散点图的应用场景:
- 观察数据集的分布情况。
- 通过分析规律,根据样本数据特征计算出回归方程。
饼状图:
饼状图通常用来描述量、频率和百分比之间的关系。在饼图中,每个扇区的弧长大小为其所表示的数量的比例。
饼状图的应用场景:
- 展示多个分类的占比情况,分类数量建议不超过9个。
- 对于一些占比值非常接近的,不建议使用饼状图,可以使用柱状图。
箱线图:
箱线图(Box-plot)又称为盒须图、盒式图或箱型图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。在各种领域也经常被使用,它主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比较。箱线图的绘制方法是:先找出一组数据的上限值、下限值、中位数(Q2)和下四分位数(Q1)以及上四分位数(Q3);然后,连接两个四分位数画出箱子;再将最大值和最小值与箱子相连接,中位数在箱子中间。
四分位数(Quartile)也称四分位点,是指在统计学中把所有数值由小到大排列并分成四等份,处于三个分割点位置的数值。多应用于统计学中的箱线图绘制。它是一组数据排序后处于25%和75%位置上的值。四分位数是通过3个点将全部数据等分为4部分,其中每部分包含25%的数据。很显然,中间的四分位数就是中位数,因此通常所说的四分位数是指处在25%位置上的数值(称为下四分位数)和处在75%位置上的数值(称为上四分位数)。与中位数的计算方法类似,根据未分组数据计算四分位数时,首先对数据进行排序,然后确定四分位数所在的位置,该位置上的数值就是四分位数。与中位数不同的是,四分位数位置的确定方法有几种,每种方法得到的结果会有一定差异,但差异不会很大。
上限的计算规则是: IQR=Q3-Q1 上限=Q3+1.5IQR 下限=Q1-1.5IQR
箱线图的应用场景:
- 直观明了地识别数据中的异常值。
- 利用箱线图判断数据的偏态。
- 利用箱线图比较几批数据的形状。
- 箱线图适合比较多组数据,如果知识要看一组数据的分布情况,建议使用直方图。
更多参考:
https://antvis.github.io/vis/doc/chart/classify/compare.html
2. Matplotlib库
Matplotlib 是一个Python 的2D 绘图库,通过Matplotlib ,开发者可以仅需要几行代码,便可以生成折线图,直方图,条形图,饼状图,散点图等。
安装:
如果是用Anaconda ,可以通过conda install matplotlib 或者通过pip install matplotlib 进行安装。
基本使用:
首先先看以下例子:
import matplotlib.pyplot as plt
import numpy as np
plt.plot(range(10),[np.random.randint(0,10) for x in range(10)])
那么就会出现以下图:
其中plot 是一个画图的函数,他的参数为plot([x],y,[fmt],data=None,**kwargs) 。其中fmt 可以传一个字符串,用来给这个图做一些样式修改的。默认的绘制样式是b- ,也就是蓝色实体线条。比如我想将原来的图的线条改成点状,那么可以通过以下代码实现:
import matplotlib.pyplot as plt
plt.plot(range(10),[np.random.randint(0,10) for x in range(10)],":")
其中使用: 代表点线,是matplotlib 的一个缩写。这些缩写还有以下的:
字符 | 类型 | 字符 | 类型 |
---|
‘-’ | 实线 | ‘–’ | 虚线 | ‘-.’ | 虚点线 | ‘:’ | 点线 | ‘.’ | 点 | ‘,’ | 像素点 | ‘o’ | 圆点 | ‘v’ | 下三角点 | ‘^’ | 上三角点 | ‘<’ | 左三角点 | ‘>’ | 右三角点 | ‘1’ | 下三叉点 | ‘2’ | 上三叉点 | ‘3’ | 左三叉点 | ‘4’ | 右三叉点 | ‘s’ | 正方点 | ‘p’ | 五角点 | ‘*’ | 星形点 | ‘h’ | 六边形点1 | ‘H’ | 六边形点2 | ‘+’ | 加号点 | ‘x’ | 乘号点 | ‘D’ | 实心菱形点 | ‘d’ | 瘦菱形点 | ‘_’ | 横线点 | | |
除了设置线条的形状外,我们还可以设置点的颜色。示例代码如下:
plt.plot([1,2,3,4,5],[1,2,3,4,5],'r')
plt.plot([1,2,3,4,5],[1,2,3,4,5],color='red')
plt.plot([1,2,3,4,5],[1,2,3,4,5],color='#000000')
plt.plot([1,2,3,4,5],[1,2,3,4,5],color=(0,0,0,0))
给线条设置颜色总体来说有三种方式,第一种是使用颜色名称(r 是red 的缩写)的形式,第二种是使用十六进制的方式,第三种是使用RGB 或RGBA 的方式。如果使用的是颜色名称,那么可以和线的形状写在同一个字符串中。比如使用红色的五角点,那么可以使用如下的方式实现:
plt.plot([1,2,3,4,5],[1,2,3,4,5],'rp')
其中可以表示颜色的缩写字符有如下:
字符 | 颜色 |
---|
‘b’ | 蓝色,blue | ‘g’ | 绿色,green | ‘r’ | 红色,red | ‘c’ | 青色,cyan | ‘m’ | 品红,magenta | ‘y’ | 黄色,yellow | ‘k’ | 黑色,black | ‘w’ | 白色,white |
设置图的信息:
现在我们添加图后,没有指定x轴代表什么,y轴代表什么,以及这个图的标题是什么。因此以下我们通过一些属性来设置一下。
设置线条样式:
-
使用plot 方法:plot 方法就是用来绘制线条的,因此可以在绘制的时候就把线条相关的样式通过参数传进去。示例代码如下: plt.plot(x,y,linewidth=2)
-
通过Line2D 对象来设置:plot 方法会返回一个装有Line2D 对象的列表,比如lines=plt.plot(x1,y1,x2,y2) 因为绘制了两根线条,因此lines 中会有两个2D 对象。而如果plot 只绘制一根线条,那么lines 中就只有一个Line2D 对象。拿到这个Line2D 对象后就可以通过set_属性名 设置线条的样式了: lines = plt.plot(x,y)
line = lines[0]
line.set_aa(False)
line.set_alpha(0.5)
-
使用plt.setp 来设置:setp 的好处是一次性可以设置多根线条的样式。示例代码如下: lines = plt.plot(x,y)
plt.setp(lines,linewidth=10,alpha=0.5)
-
更多Line2D 属性:
设置轴和标题:
-
设置轴名称:可以通过plt.xlabel 和plt.ylabel 来设置x 轴和y 轴的的名称。示例代码如下: plt.plot(x,y,linewidth=10,color='red')
plt.xlabel("x轴")
plt.ylabel("y轴")
默认情况下是显示不了中文的。需要设置字体。可以通过以下代码来实现:
font = font_manager.FontProperties(fname="C:\Windows\Fonts\msyh.ttc")
plt.plot(x,y,linewidth=10,color='red')
plt.xlabel("x轴",fontproperties=font)
plt.ylabel("y轴",fontproperties=font)
加载字体的时候,可以到C:\Windows\Fonts 中找你喜欢的并且可以显示中文的字体。找到字体后,还需要找到字体的真实名称。方法是右键->属性->安全->对象名称:
- 设置标题:可以通过
plt.title 方法来实现。示例代码如下:
font = font_manager.FontProperties(fname="C:\Windows\Fonts\msyh.ttc")
plt.title("sin函数",fontproperties=font)
-
设置x 轴和y 轴的刻度:之前我们画的图,x 轴和y 轴的刻度都是matplotlib 自动生成的。如果想要在生成图的时候手动的指定,那么可以通过plt.xticks 和plt.yticks 来实现: plt.xticks(range(0,20,2))
以上会把那个刻度显示在x 轴上。如果想要显示字符串类型,那么可以再构造一个数组,这个数组的长度必须和x 轴刻度的长度保持一致。然后传给xticks 的第二个参数。示例代码如下:
_x = range(0,20,2)
_xticks = ["%d坐标"%i for i in _x]
plt.xticks(_x,_xticks,fontproperties=font)
同样y 轴的刻度设置也是一样的。示例代码如下:
_y = np.arange(-1,1,0.25)
_yticks = ["%.2f点"%i for i in _y]
plt.yticks(_y,_yticks,fontproperties=font)
效果图如下:
复仇者联盟电影票房案例:
avenger = [17974.4,50918.4,30033.0,40329.1,52330.2,19833.3,11902.0,24322.6,47521.8,32262.0,22841.9,12938.7,4835.1,3118.1,2570.9,2267.9,1902.8,2548.9,5046.6,3600.8]
plt.figure(figsize=(15,5))
plt.plot(avenger,marker="o")
font.set_size(10)
plt.xticks(range(20),["第%d天"%x for x in range(1,21)],fontproperties=font)
plt.xlabel("天数",fontproperties=font)
plt.ylabel("票房数(万)",fontproperties=font)
plt.grid()
设置marker:
有时候,我们想要在一些关键点上重点标记出来。那么我们可以通过设置marker 来实现。示例代码如下:
x = np.linspace(0,20)y = np.sin(x)plt.plot(x,y,marker="o")
我们设置了marker 为o ,这样就是会在(x,y) 的坐标点上显示出来,并且显示的是圆点。其中o 跟之前的线条样式的简写是一样的。另外,还可以通过markerfacecolor 属性和markersize 来指定标记点的颜色和大小。示例代码如下:
plt.plot(x,y,marker="o",markerfacecolor='k',markersize=10)
设置注释文本:
有时候需要在图形中的某个点标记或者注释一下。那么我们可以使用plt.annotate(text,xy,xytext,arrowprops={}) 来实现,其中text 是注释的文本,xy 是需要注释的点的坐标,xytext 是注释文本的坐标,arrowprops 是箭头的样式属性。示例代码如下:
ax = plt.subplot(111)
x = np.arange(0.0, 5.0, 0.01)
y = np.cos(2*np.pi*t)
line, = plt.plot(x, y,linewidth=2)
plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops=dict(facecolor='black',shrink=0.05),
)
plt.ylim(-2, 2)
plt.show()
设置图形样式:
如果想要调整图片的大小和像素,可以通过plt.figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True) 来实现。 其中num 是图的编号,figsize 的单位是英寸,dpi 是每英寸的像素点,facecolor 是图片背景颜色,edgecolor 是边框颜色,frameon 代表是否绘制画板。 示例代码如下:
plt.figure(figsize=(20,8),dpi=80)
我们也可以使用grid 方法,来显示图片的网格:
plt.plot(x,y,color="r")
plt.grid()
保存图片:
可以调用plt.savefig(path) 来保存当前的图片。示例代码如下:
plt.savefig("./abc.png")
绘制多个图:
绘制多个图有两种形式,第一种形式是在一张图中绘制多跟线条,第二种形式是绘制多个子图形。以下分别进行讲解。
绘制多根折线:
绘制多根线条,只要准备好坐标,重新使用plt.plot 绘制即可。示例代码如下:
from matplotlib import font_managerx = np.linspace(0,20)y = np.sin(x)z = np.cos(x)font = font_manager.FontProperties(fname="C:\Windows\Fonts\msyh.ttc")plt.xlabel("x轴",fontproperties=font)plt.ylabel("y轴",fontproperties=font)_x = range(0,20,2)_xticks = ["%s点"%i for i in _x]plt.xticks(range(0,20,2),_xticks,fontproperties=font,rotation=45)_y = list(np.range(-1,1,0.25))_yticks = ["%.2f点"%i for i in _y]plt.yticks(_y,_yticks,fontproperties=font)plt.plot(x,y)plt.plot(x,z)
示例图如下:
绘制多个子图:
绘制子图的时候,我们可以使用plt.subplot 或plt.subplots 来实现。示例代码如下:
plt.subplot(221)
plt.plot(np.arange(10),c='r')
plt.subplot(222)
plt.plot(np.sin(np.arange(10)),c='b')
plt.subplot(223)
plt.plot(np.cos(np.arange(10)),c='y')
plt.subplot(224)
plt.plot(np.tan(np.arange(10)),c='g')
效果图如下:
其中subplot 中的211 和212 分别代表的意思是,第一个数表示这个大图中总共有2 行,第二个数表示总共有1 列,然后第三个数表示当前绘制第几个图。
也可以使用fig,axs=plt.subplots(rows,cols,*args,**kwargs) 来绘制多个图形,返回值是一个元组,其中的fig 参数是figure 对象,axs 是axes 对象的array 。示例代码如下:
figure,axes = plt.subplots(2,2)
axes[0,0].plot(np.sin(np.arange(10)),c='r')
axes[0,1].plot(np.cos(np.arange(10)),c='b')
axes[1,0].plot(np.tan(np.arange(10)),c='y')
axes[1,1].plot(np.arange(10),c='g')
效果图跟之前使用plt.subplot 一样。另外使用subplot 和subplots 都可以传递sharex/sharey 参数,这两个参数表示是否需要共享X轴和Y轴。示例代码如下:
figure,axes = plt.subplots(2,2,sharex=True,sharey=True)
axes[0,0].plot(np.sin(np.arange(10)),c='r')
axes[0,1].plot(np.cos(np.arange(10)),c='b')
axes[1,0].plot(np.tan(np.arange(10)),c='y')
axes[1,1].plot(np.arange(10),c='g')
风格设置:
matplotlib 图片默认内置了几种风格。我们可以通过plt.style.available 来查看内置的所有风格:
['bmh',
'classic',
'dark_background',
'fast',
'fivethirtyeight',
'ggplot',
'grayscale',
'seaborn-bright',
'seaborn-colorblind',
'seaborn-dark-palette',
'seaborn-dark',
'seaborn-darkgrid',
'seaborn-deep',
'seaborn-muted',
'seaborn-notebook',
'seaborn-paper',
'seaborn-pastel',
'seaborn-poster',
'seaborn-talk',
'seaborn-ticks',
'seaborn-white',
'seaborn-whitegrid',
'seaborn',
'Solarize_Light2',
'tableau-colorblind10',
'_classic_test']
在绘制的,可以使用plt.style.use 方法来使用不同的风格。示例代码如下:
plt.style.use("dark_background")
官方文档介绍:
plt.plot 使用详解:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plotmatplotlib.pyplot 使用详解:https://matplotlib.org/api/pyplot_summary.htmlmatplotlib 内置的样式:https://tonysyu.github.io/raw_content/matplotlib-style-gallery/gallery.html
3. 条形图
条形图的绘制方式跟折线图非常的类似,只不过是换成了plt.bar 方法。plt.bar 方法有以下常用参数:
x :一个数组或者列表,代表需要绘制的条形图的x轴的坐标点。height :一个数组或者列表,代表需要绘制的条形图y轴的坐标点。width :每一个条形图的宽度,默认是0.8的宽度。bottom :y 轴的基线,默认是0,也就是距离底部为0.align :对齐方式,默认是center ,也就是跟指定的x 坐标居中对齐,还有为edge ,靠边对齐,具体靠右边还是靠左边,看width 的正负。color :条形图的颜色。
返回值为BarContainer ,是一个存储了条形图的容器,而条形图实际上的类型是matplotlib.patches.Rectangle 对象。
更多参考:https://matplotlib.org/api/_as_gen/matplotlib.pyplot.bar.html#matplotlib.pyplot.bar
条形图的绘制:
比如现在有2019 年贺岁片票房的数据(数据来源:https://piaofang.maoyan.com/dashboard):
movies = {
"流浪地球":40.78,
"飞驰人生":15.77,
"疯狂的外星人":20.83,
"新喜剧之王":6.10,
"廉政风云":1.10,
"神探蒲松龄":1.49,
"小猪佩奇过大年":1.22,
"熊出没·原始时代":6.71
}
用条形图绘制每部电影及其票房的代码如下:
movies = {
"流浪地球":40.78,
"飞驰人生":15.77,
"疯狂的外星人":20.83,
"新喜剧之王":6.10,
"廉政风云":1.10,
"神探蒲松龄":1.49,
"小猪佩奇过大年":1.22,
"熊出没·原始时代":6.71
}
plt.bar(np.arange(len(movies)),list(movies.keys()))
plt.xticks(np.arange(len(movies)),list(movies.keys()),fontproperties=font)
plt.grid()
效果图如下:
其中xticks 和yticks 的用法跟之前的折线图一样。这里新出现的方法是bar ,bar 常用的有3个参数,分别是x (x轴的坐标点),y (y轴的坐标点)以及width (条形的宽度)。
横向条形图:
横向条形图需要使用plt.barh 这个方法跟bar 非常的类似,只不过把方向进行旋转。参数跟bar 类似,但也有区别。如下:
y :数组或列表,代表需要绘制的条形图在y 轴上的坐标点。width :数组或列表,代表需要绘制的条形图在x 轴上的值(也就是长度)。height :条形图的高度,默认是0.8。left :条形图的基线,也就是距离y轴的距离。- 其他参数跟
bar 一样。
返回值也是BarContainer 容器对象。
还是以以上数据为例,将电影名和票房反转一下。示例代码如下:
movies = {
"流浪地球":40.78,
"飞驰人生":15.77,
"疯狂的外星人":20.83,
"新喜剧之王":6.10,
"廉政风云":1.10,
"神探蒲松龄":1.49,
"小猪佩奇过大年":1.22,
"熊出没·原始时代":6.71
}
plt.barh(np.arange(len(movies)),list(movies.values()))
plt.yticks(np.arange(len(movies)),list(movies.keys()),fontproperties=font)
plt.grid()
效果图如下:
分组条形图:
现在有一组数据,是2019年春节贺岁片前五天的电影票房记录。 示例代码如下:
movies = {
"流浪地球":[2.01,4.59,7.99,11.83,16],
"飞驰人生":[3.19,5.08,6.73,8.10,9.35],
"疯狂的外星人":[4.07,6.92,9.30,11.29,13.03],
"新喜剧之王":[2.72,3.79,4.45,4.83,5.11],
"廉政风云":[0.56,0.74,0.83,0.88,0.92],
"神探蒲松龄":[0.66,0.95,1.10,1.17,1.23],
"小猪佩奇过大年":[0.58,0.81,0.94,1.01,1.07],
"熊出没·原始时代":[1.13,1.96,2.73,3.42,4.05]
}
plt.figure(figsize=(20,8))
width = 0.75
bin_width = width/5
movie_pd = pd.DataFrame(movies)
ind = np.arange(0,len(movies))
for index in movie_pd.index:
day_tickets = movie_pd.iloc[index]
xs = ind-(bin_width*(2-index))
plt.bar(xs,day_tickets,width=bin_width,label="第%d天"%(index+1))
for ticket,x in zip(day_tickets,xs):
plt.annotate(ticket,xy=(x,ticket),xytext=(x-0.1,ticket+0.1))
plt.legend(prop=font)
plt.ylabel("单位:亿",fontproperties=font)
plt.title("春节前5天电影票房记录",fontproperties=font)
plt.xticks(ind,movie_pd.columns,fontproperties=font)
plt.xlim
plt.grid(True)
plt.show()
示例图如下:
堆叠条形图:
堆叠条形图,是将一组相关的条形图堆叠在一起进行比较的条形图。比如以下案例:
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
groupNames = ('G1','G2','G3','G4','G5')
xs = np.arange(len(menMeans))
plt.bar(xs,menMeans)
plt.bar(xs,womenMeans,bottom=menMeans)
plt.xticks(xs,groupNames)
plt.show()
效果图如下:
在绘制女性得分的条形图的时候,因为要堆叠在男性得分的条形图上,所以使用到了一个bottom 参数,就是距离x 轴的距离。通过对贴条形图,我们就可以清楚的知道,哪一个队伍的综合排名是最高的,并且在每个队伍中男女的得分情况。
条形图应用场景:
- 数量统计。
- 频率统计。
4. 直方图
直方图(Histogram),又称质量分布图,是一种统计报告图,由一系列高度不等的条纹表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布情况。
直方图是数值数据分布的精确图形表示。为了构建直方图,第一步是将值的范围分段,即将整个值的范围分成一系列间隔,然后计算每个间隔中有多少值。这些值通常被指定为连续的,不重叠的变量间隔。间隔必须相邻,并且通常是(但不是必须的)相等的大小。
绘制直方图:
直方图的绘制方法,使用的是plt.hist 方法来实现,这个方法的参数以及返回值如下:
参数:
x :数组或者可以循环的序列。直方图将会从这组数据中进行分组。bins :数字或者序列(数组/列表等)。如果是数字,代表的是要分成多少组。如果是序列,那么就会按照序列中指定的值进行分组。比如[1,2,3,4] ,那么分组的时候会按照三个区间分成3组,分别是[1,2)/[2,3)/[3,4] 。range :元组或者None,如果为元组,那么指定x 划分区间的最大值和最小值。如果bins 是一个序列,那么range 没有有没有设置没有任何影响。density :默认是False ,如果等于True ,那么将会使用频率分布直方图。每个条形表示的不是个数,而是频率/组距 (落在各组样本数据的个数称为频数,频数除以样本总个数为频率)。cumulative :如果这个和density 都等于True ,那么返回值的第一个参数会不断的累加,最终等于1 。- 其他参数:请参考:
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.hist.html 。
返回值:
n :数组。每个区间内值出现的个数,如果density=True ,那么这个将返回的是频率/组距 。bins :数组。区间的值。patches :数组。每根条的对象,类型是matplotlib.patches.Rectangle 。
案例:
比如有一组电影票房时长,想要看下这组票房时长的数据,那么可以通过以下代码来实现:
durations = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]
plt.figure(figsize=(15,5))
nums,bins,patches = plt.hist(durations,bins=20,edgecolor='k')
plt.xticks(bins,bins)
for num,bin in zip(nums,bins):
plt.annotate(num,xy=(bin,num),xytext=(bin+1.5,num+0.5))
plt.show()
效果图如下:
另外,也可以通过density=True ,来实现频率分布直方图。示例代码如下:
nums,bins,patches = plt.hist(durations,bins=20,edgecolor='k',density=True)
plt.xticks(bins,bins)
for num,bin in zip(nums,bins):
plt.annotate("%.4f"%num,xy=(bin,num),xytext=(bin+0.2,num+0.0005))
而如果想要让nums 的总和为1 ,那么就需要设置cumulative=True 参数,示例代码如下:
nums,bins,patches = plt.hist(durations,bins=20,edgecolor='k',density=True,cumulative=True)
plt.xticks(bins,bins)
for num,bin in zip(nums,bins):
plt.annotate("%.4f"%num,xy=(bin,num),xytext=(bin+0.2,num+0.0005))
直方图的应用场景:
- 显示各组数据数量分布的情况。
- 用于观察异常或孤立数据。
- 抽取的样本数量过小,将会产生较大误差,可信度低,也就失去了统计的意义。因此,样本数不应少于50个。
5. 散点图
散点图也叫 X-Y 图,它将所有的数据以点的形式展现在直角坐标系上,以显示变量之间的相互影响程度,点的位置由变量的数值决定。
通过观察散点图上数据点的分布情况,我们可以推断出变量间的相关性。如果变量之间不存在相互关系,那么在散点图上就会表现为随机分布的离散的点,如果存在某种相关性,那么大部分的数据点就会相对密集并以某种趋势呈现。
数据的相关关系主要分为:正相关(两个变量值同时增长)、负相关(一个变量值增加另一个变量值下降)、不相关、线性相关、指数相关等,表现在散点图上的大致分布如下图所示。那些离点集群较远的点我们称为离群点或者异常点。
示例图如下:
绘制散点图:
散点图的绘制,使用的是plt.scatter 方法,这个方法有以下参数:
x,y :分别是x轴和y轴的数据集。两者的数据长度必须一致。s :点的尺寸。如果是一个具体的数字,那么散点图的所有点都是一样大小,如果是一个序列,那么这个序列的长度应该和x轴数据量一致,序列中的每个元素代表每个点的尺寸。c :点的颜色。可以为具体的颜色,也可以为一个序列或者是一个cmap 对象。marker :标记点,默认是圆点,也可以换成其他的。- 其他参数:
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.scatter.html#matplotlib.pyplot.scatter 。
比如有一组运动员身高和体重以及年龄的数据,那么可以通过以下代码来绘制散点图:
male_athletes = athletes[athletes['Sex'] == 'M']
female_athletes = athletes[athletes['Sex'] == 'F']
male_mean_height = male_athletes['Height'].mean()
female_mean_height = female_athletes['Height'].mean()
male_mean_weight = male_athletes['Weight'].mean()
female_mean_weight = female_athletes['Weight'].mean()
plt.figure(figsize=(10,5))
plt.scatter(male_athletes['Height'],male_athletes['Weight'],s=male_athletes['Age'],marker='^',color='g',label='男性',alpha=0.5)
plt.scatter(female_athletes['Height'],female_athletes['Weight'],color='r',alpha=0.5,s=female_athletes['Age'],label='女性')
plt.axvline(male_mean_height,color="g",linewidth=1)
plt.axhline(male_mean_weight,color="g",linewidth=1)
plt.axvline(female_mean_height,color="r",linewidth=1)
plt.axhline(female_mean_weight,color="r",linewidth=1)
plt.xticks(np.arange(140,220,5))
plt.yticks(np.arange(30,150,10))
plt.legend(prop=font)
plt.xlabel("身高(cm)",fontproperties=font)
plt.ylabel("体重(kg)",fontproperties=font)
plt.title("运动员身高和体重散点图",fontproperties=font)
plt.grid()
plt.show()
效果图如下:
绘制回归曲线:
有一组数据后,我们可以对这组数据进行回归分析,回归分析可以帮助我们了解这组数据的大体走向。
回归分析按照涉及的变量的多少,分为一元回归和多元回归分析;按照自变量的多少,可分为简单回归分析和多重回归分析;按照自变量和因变量之间的关系类型,可分为线性回归分析和非线性回归分析。如果在回归分析中,只包括一个自变量和一个因变量,且二者的关系可用一条直线近似表示,这种回归分析称为一元线性回归分析。如果回归分析中包括两个或两个以上的自变量,且自变量之间存在线性相关,则称为多重线性回归分析。
自变量数量 | 是否线性 | 回归类型 |
---|
1个 | 是 | 一元线性回归 | 多个 | 是 | 多元线性回归 | 1个 | 否 | 一元非线性回归 | 多个 | 否 | 多元非线性回归 |
通过以上运动员散点图的分析,我们总体上可以看出来是满足线性回归的,因此可以在图上绘制一个线性回归的线条。想要绘制线性回归的线条,需要先按照之前的数据计算出线性方程,假如x 是自变量,y 是因变量,那么线性回归的方程可以用以下几个来表示:
y = 截距+斜率*x+误差
只要把这个方程计算出来了,那么后续我们就可以根据x 的值,大概的估计出y 的取值范围,也就是预测。如果我们针对以上运动员的身高和体重的关系,只要有身高,那么就可以大概的估计出体重的值。
回归方程的绘制我们需要借助scikit-learn 库,这个库是专门做机器学习用的,我们需要使用里面的线性回归类sklearn.liear_regression.LinearRegression 。示例代码如下:
from sklearn.linear_model import LinearRegression
male_athletes = athletes[athletes['Sex'] == 'M'].dropna()
female_athletes = athletes[athletes['Sex'] == 'F'].dropna()
xtrain = male_athletes['Height']
ytrain = male_athletes['Weight']
model = LinearRegression()
model.fit(xtrain[:,np.newaxis],ytrain)
print(model.coef_)
print(model.intercept_)
line_xticks = xtrain
line_yticks = model.predict(xtrain[:,np.newaxis])
plt.plot(male_heights, line_yticks)
效果图如下:
6. 饼图
饼图是一个划分为几个扇形的圆形统计图表,用于描述量、频率或百分比之间的相对关系的。 在matplotlib 中,可以通过plt.pie 来实现,其中的参数如下:
x :饼图的比例序列。labels :饼图上每个分块的名称文字。explode :设置某几个分块是否要分离饼图。autopct :设置比例文字的展示方式。比如保留几个小数等。shadow :是否显示阴影。textprops :文本的属性(颜色,大小等)。- 其他参数:
https://matplotlib.org/api/_as_gen/matplotlib.pyplot.pie.html#matplotlib.pyplot.pie
返回值:
patches :饼图上每个分块的对象。texts :分块的名字文本对象。autotexts :分块的比例文字对象。
假如现在我们有一组数据,用来记录各个操作系统的市场份额的。那么用饼状图表示如下:
oses = {
'windows7':60.86,
'windows10': 18.46,
'windows8': 3.61,
'windows xp': 10.3,
'mac os': 6.78,
'其他': 1.12
}
names = oses.keys()
percents = oses.values()
patches,texts,autotexts = plt.pie(percents,labels=names,autopct="%.2f%%",explode=(0,0.05,0,0,0,0))
for text in texts+autotexts:
plt.setp(text,fontproperties=font)
text.set_fontsize(10)
for text in autotexts:
text.set_color("white")
效果图如下:
7. 箱线图
箱线图(Box-plot)又称为盒须图、盒式图或箱型图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。在各种领域也经常被使用,它主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比较。
箱线图的绘制方法是:先找出一组数据的上限值、下限值、中位数(Q2)和下四分位数(Q1)以及上四分位数(Q3);然后,连接两个四分位数画出箱子;再将最大值和最小值与箱子相连接,中位数在箱子中间。
中位数:把数据按照从小到大的顺序排序,然后最中间的那个值为中位数,如果数据的个数为偶数,那么就是最中间的两个数的平均数为中位数。 上下四分位数:同样把数据排好序后,把数据等分为4份。出现在25% 位置的叫做下四分位数,出现在75% 位置上的数叫做上四分位数。但是四分位数位置的确定方法不是固定的,有几种算法,每种方法得到的结果会有一定差异,但差异不会很大。
上下限的计算规则是: IQR=Q3-Q1 上限=Q3+1.5IQR 下限=Q1-1.5IQR
使用matplotlib绘制箱线图:
在matplotlib 中有plt.boxplot 来绘制箱线图,这个方法的相关参数如下:
x :需要绘制的箱线图的数据。notch :是否展示置信区间,默认是False 。如果设置为True ,那么就会在盒子上展示一个缺口。sym :代表异常点的符号表示,默认是小圆点。vert :是否是垂直的,默认是True ,如果设置为False 那么将水平方向展示。whis :上下限的系数,默认是1.5 ,也就是上限是Q3+1.5IQR ,可以改成其他的。也可以为一个序列,如果是序列,那么序列中的两个值分别代表的就是下限和上限的值,而不是再需要通过IQR 来计算。positions :设置每个盒子的位置。widths :设置每个盒子的宽度。labels :每个盒子的label 。meanline 和showmeans :如果这两个都为True ,那么将会绘制平均值的的线条。
示例代码如下:
data = np.random.rand(100)*100
data = np.append(data,np.array([-100,100]))
plt.boxplot(data,meanline=True,showmeans=True)
效果图如下:
如果有多组数据绘制箱型图,才能更好的提现出箱型图的优势。
假如我们想要获取奥林匹克运动会上不同国家运动员的身高情况,那么可以把每个国家的运动员身高数据绘制成一个箱线图,然后进行对比。示例代码如下:
athletes = pd.read_csv("athlete_events.csv")
countries = {
'CHN':'中国',
'JPN':"日本",
'KOR':'韩国',
'USA':"美国",
'CAN':"加拿大",
'BRA':"巴西",
'GBR':"英国",
'FRA':"法国",
'ITA':"意大利",
'ETH':"埃塞俄比亚",
'KEN':"肯尼亚",
'NIG':"尼日利亚",
}
dfs = []
for code in countries.keys():
df = athletes[(athletes['NOC'] == code)&(athletes['Age']>18)]['Height'].dropna()
dfs.append(df)
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=14)
plt.figure(figsize=(20,5))
plt.boxplot(dfs,showmeans=True,meanline=True,labels=countries.values())
plt.xticks(range(1,13),countries.values(),fontproperties=font)
plt.ylabel("身高(cm)",fontproperties=font)
plt.title("奥林匹克运动员身高箱线图",fontproperties=font)
效果图如下:
箱线图的应用场景:
- 直观明了地识别数据中的异常值。
- 利用箱线图判断数据的偏态。
- 利用箱线图比较几批数据的形状。
- 箱线图适合比较多组数据,如果知识要看一组数据的分布情况,建议使用直方图。
8. 雷达图
雷达图(Radar Chart)又被叫做蜘蛛网图,适用于显示三个或更多的维度的变量的强弱情况。比如英雄联盟中某个影响的属性(法术伤害,物理防御等),或者是某个企业在哪些业务方面的投入等,都可以用雷达图方便的表示。
使用plt.polar绘制雷达图:
在matplotlib.pyplot 中,可以通过plt.polar 来绘制雷达图,这个方法的参数跟plt.plot 非常的类似,只不过是x 轴的坐标点应该为弧度(2*PI=360°)。示例代码如下:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import font_manager
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
properties = ['输出','KDA','发育','团战','生存']
values = [40,91,44,90,95,40]
theta = np.linspace(0,np.pi*2,6)
plt.polar(theta,values)
plt.xticks(theta,properties,fontproperties=font)
plt.fill(theta,values)
效果图如下:
其中有几点需要注意:
- 因为
polar 并不会完成线条的闭合绘制,所以我们在绘制的时候需要在theta 中和values 中在最后多重复添加第0个位置的值,然后在绘制的时候就可以和第1个点进行闭合了。 polar 只是绘制线条,所以如果想要把里面进行颜色填充,那么需要调用fill 函数来实现。polar 默认的圆圈的坐标是角度,如果我们想要改成文字显示,那么可以通过xticks 来设置。
使用子图绘制雷达图:
在多子图中,绘图对象不再是pyplot 而是Axes ,而Axes 及其子类绘制雷达图则是通过将直角坐标转换成极坐标,然后再绘制折线图。示例代码如下:
-
使用plt.subplot 绘制的子图: properties = ['输出','KDA','发育','团战','生存']
values = [40,91,44,90,95,40]
theta = np.linspace(0,np.pi*2,6)
axes = plt.subplot(111,projection="polar")
axes.plot(theta,values)
axes.fill(theta,values)
-
使用plt.subplots 绘制的子图: properties = ['输出','KDA','发育','团战','生存']
values = [40,91,44,90,95,40]
theta = np.linspace(0,np.pi*2,6)
figure,axes = plt.subplots(1,1,subplot_kw={"projection":"polar"})
axes.plot(theta,values)
-
使用fig.add_subplot 绘制的子图: properties = ['输出','KDA','发育','团战','生存']
values = [40,91,44,90,95,40]
theta = np.linspace(0,np.pi*2,6)
fig = plt.figure(figsize=(10,10))
axes = fig.add_subplot(111,polar=True)
axes.plot(theta,values)
总结:
雷达图:用来清晰的表示多个维度的值的强弱关系。
绘制雷达图:
因为雷达图绘制的时候,不会自动的封闭,所以要在数据的最后多添加一个起始点的坐标。
plt.polar绘制。
plt.subplot(111,projection="polar")。
figure,axes = plt.subplots(1,1,subplot_kw={"projection":"polar"})
axes = fig.add_subplot(111,polar=True)
9. matplotlib绘图分析
解释:
Figure :图形绘制的画板,他就相当于一个黑板,所有的图都是绘制在Figure 上面。Axes :每个图都是Axes 对象。一个Figure 上可以有多个Axes 对象。Axis :x 轴、y 轴的对象。Tick :x 轴和y 轴上的刻度对象。每一个刻度都是一个Tick 对象。TickLabel :每个刻度上都要显示文字,这个文字的显示就是在TickLabel 上。AxisLabel :x 轴和y 轴的名称的文字显示。Legend :图例对象。Title :Axes 图的标题对象。Line2D :绘制在Axes 上的线条对象,比如折线图等。Reactangle :绘制在Axes 上的矩形对象,比如条形图等。Marker :标记点,比如绘制散点图上的每个点就是这个对象。Artist :只要是绘制在Figure 上的元素(包括Figure),都是Artist 的子类。
一、Figure容器:
Figure 容器是最顶层的容器,他几乎包含了这个图的所有对象。通过add_subplot 和add_axes 方法可以添加Axes 对象,这两个方法添加的都是Axes 及其子类的对象。添加完成后是存储在figure.axes 中。示例代码如下:
In [156]: fig = plt.figure()
In [157]: ax1 = fig.add_subplot(211)
In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
In [159]: ax1
Out[159]: <matplotlib.axes.Subplot instance at 0xd54b26c>
In [160]: print(fig.axes)
[<matplotlib.axes.Subplot instance at 0xd54b26c>, <matplotlib.axes.Axes instance at 0xd3f0b2c>]
1.1. 添加Axes对象:
Figure 只是一个黑板,如果想要绘图,需要先添加Axes 。添加Axes 可以通过add_axes 和add_subplot 来实现。示例代码如下:
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_axes([0.1,0.1,0.8,0.3])
1.2. 操作当前Axes对象:
可以通过figure.gca 以及figure.sca 来设置和获取当前的axes 对象。示例代码如下:
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_axes([0,0,1,0.3])
print(fig.gca())
print(fig.sca(ax1))
>> Axes(0,0;1x0.3)
>> AxesSubplot(0.125,0.536818;0.775x0.343182)
1.3. 删除Axes对象:
Figure 上的所有Axes 对象都是保存在fig.axes 中,但是如果想要删除某个Axes 对象,那么必须通过delaxes 来实现:
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_axes([0,0,1,0.3])
fig.delaxes(ax1)
print(fig.axes)
1.4. 获取所有的axes:
for ax in fig.axes:
ax.grid(True)
1.5. Figure 的属性有如下:
Figure 类定义介绍:https://matplotlib.org/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure
二、Axes容器:
Axes 容器是用来创建具体的图形的。比如画曲线,柱状图,都是画在上面。所以之前我们学的使用plt.xx 绘制各种图形(比如条形图,直方图,散点图等)都是对Axes 的封装。比如plt.plot 对应的是axes.plot ,比如plt.hist 对应的是axes.hist 。针对图的所有操作,都可以在Axes 上找到对应的API 。另外后面要讲到的Axis 容器,是轴的对象,也是绑定在Axes 上面。
Axes的类定义介绍:https://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes
2.1. 设置x和y轴的最大值和最小值:
设置完刻度后,我们还可以设置x轴和y轴的最大值和最小值。可以通过set_xlim/set_ylim 来实现:
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(np.random.randn(10))
axes.set_xlim(-2,12)
axes.set_ylim(-3,3)
2.2. 添加文本:
之前添加文本我们用的是annotate ,但是如果不是需要做注释,其实还有另外一种更加简单的方式,那就是使用text 方法:
data = np.random.randn(10)
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(data)
axes.text(0,0,"hello")
2.3. 绘制双Y 轴:
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.bar(np.arange(0,10,2),np.random.rand(5))
ax1.set_yticks(np.arange(0,1,0.25))
ax2 = ax1.twinx()
ax2.plot(np.random.randn(10),c="b")
plt.show()
效果图如下:
三、Axis容器:
Axis 代表的是x 轴或者y 轴的对象。包含Tick (刻度)对象,TickLabel 刻度文本对象,以及AxisLabel 坐标轴文本对象。axis 对象有一些方法可以操作刻度和文本等。
3.1. 设置x轴和y轴label的位置:
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(np.random.randn(10))
axes.set_xlabel("x coordate")
axes.xaxis.set_label_coords(0,-0.1)
3.2. 设置刻度上的刻度格式:
import matplotlib.ticker as ticker
fig = plt.figure()
axes = fig.add_subplot(111)
axes.plot(np.random.randn(10))
axes.set_xlabel("x coordate")
formatter = ticker.FormatStrFormatter('%.2f')
axes.yaxis.set_major_formatter(formatter)
3.3. 设置轴的属性:
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4])
ax1.set_facecolor('lightslategray')
for label in ax1.xaxis.get_ticklabels():
label.set_color('red')
label.set_rotation(45)
label.set_fontsize(16)
for line in ax1.yaxis.get_ticklines():
line.set_color('green')
line.set_markersize(25)
line.set_markeredgewidth(3)
plt.show()
四、Tick容器:
Tick 是用来做刻度的,包括刻度和网格对象。其中可操作的属性如下:
示例代码如下:
import matplotlib.ticker as ticker
np.random.seed(19680801)
fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))
formatter = ticker.FormatStrFormatter('$%.2f')
ax.yaxis.set_major_formatter(formatter)
for tick in ax.yaxis.get_major_ticks():
tick.label1On = False
tick.label2On = True
tick.label2.set_color('green')
plt.show()
更多请参考: https://matplotlib.org/api/axis_api.html#matplotlib.axis.Axis
参考:
https://matplotlib.org/tutorials/intermediate/artists.html#sphx-glr-tutorials-intermediate-artists-py
10. 多图布局
解决元素重叠的问题:
在一个Figure 上面,可能存在多个Axes 对象,如果Figure 比较小,那么有可能会造成一些图形元素重叠,这时候我们就可以通过fig.tight_layout 或者是fig.subplots_adjust 方法来帮我们调整。假如现在没有经过调整,那么以下代码的效果图如下:
import matplotlib.pyplot as plt
import numpy as np
def example_plot(ax, fontsize=12):
ax.plot([1, 2])
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
fig,axes = plt.subplots(2,2)
fig.set_facecolor("y")
example_plot(axes[0,0])
example_plot(axes[0,1])
example_plot(axes[1,0])
example_plot(axes[1,1])
效果图如下:
为了避免多个图重叠,可以使用plt.tight_layout 来实现:
plt.tight_layout()
效果图如下:
其中tight_layout 还有两个参数可以使用,分别是w_pad 和h_pad ,这两个参数分别表示的意思是在水平方向的图之间的间距,以及在垂直方向这些图的间距。
另外也可以通过fig.subplots_adjust(left=None,bottom=None,right=None,top=None,wspace=None,hspace=None) 来实现,效果如下:
fig.subplots_adjust(0,0,1,1,hspace=0.5,wspace=0.5)
效果图如下:
自定义布局方式:
如果布局不是固定的几宫格的方式,而是某个图占据了多行或者多列,那么就需要采用一些手段来实现。如果不是很复杂,那么直接可以通过subplot 等方法来实现。示例代码如下:
ax1 = plt.subplot(221)
ax2 = plt.subplot(223)
ax3 = plt.subplot(122)
效果图如下:
但是如果实现的布局比较复杂,那么就需要采用GridSpec 对象来实现。示例代码如下:
fig = plt.figure()
gs = fig.add_gridspec(3,3)
ax1 = fig.add_subplot(gs[0,0:3])
ax1.set_title("[0,0:3]")
ax2 = fig.add_subplot(gs[1,0:2])
ax2.set_title("[1,0:2]")
ax3 = fig.add_subplot(gs[1:3,2])
ax3.set_title("[1:3,2]")
ax4 = fig.add_subplot(gs[2,0])
ax4.set_title("[2,0]")
ax5 = fig.add_subplot(gs[2,1])
ax5.set_title("[2,1]")
plt.tight_layout()
效果图如下:
也可以设置宽高比例。示例代码如下:
widths = (1,2,1)
heights = (2,2,1)
fig = plt.figure()
gs = fig.add_gridspec(3,3,width_ratios=widths,height_ratios=heights)
for row in range(0,3):
for col in range(0,3):
fig.add_subplot(gs[row,col])
plt.tight_layout()
效果图如下:
手动设置位置:
通过fig.add_axes 的方式添加Axes 对象,可以直接指定位置。也可以在添加完成后,通过axes.set_position 的方式设置位置。示例代码如下:
fig = plt.figure()
fig.add_subplot(111)
fig.add_axes([0.2,0.2,0.4,0.4])
fig,axes = plt.subplots(1,2)
axes[1].set_position([0.2,0.2,0.4,0.4])
散点图和直方图合并实战:
fig = plt.figure(figsize=(8,8))
widths = (2,0.5)
heights = (0.5,2)
gs = fig.add_gridspec(2,2,width_ratios=widths,height_ratios=heights)
ax1 = fig.add_subplot(gs[0,0])
ax1.hist(male_athletes['Height'],bins=20)
for tick in ax1.xaxis.get_major_ticks():
tick.label1On = False
ax2 = fig.add_subplot(gs[1,0])
ax2.scatter('Height','Weight',data=male_athletes)
ax3 = fig.add_subplot(gs[1,1])
ax3.hist(male_athletes['Weight'],bins=20,orientation='horizontal')
for tick in ax3.yaxis.get_major_ticks():
tick.label1On = False
fig.tight_layout(h_pad=0,w_pad=0)
效果图如下:
11. matplotlib配置
修改默认的配置:
修改默认的配置可以通过matplotlib.rcParams 来设置,比如修改字体,修改线条大小和宽度等。示例代码如下:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['FangSong']
plt.rcParams['font.size'] = 20
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['axes.prop_cycle'] = plt.cycler('color', ['r', 'y'])
其中rcParams 中可以设置的属性为如下:
在Windows 上如果想要显示中文,那么可以通过设置font.sans-serif 来设置,示例代码如下:
plt.rcParams['font.sans-serif'] = ['FangSong']
这个属性可以设置以下字体都可以显示中文:
字体名 | 英文名称 |
---|
黑体 | SimHei | 仿宋 | FangSong | 楷体 | KaiTi | 宋体 | SimSun | 隶书 | LiSu | 幼圆 | YouYuan | 华文细黑 | STXihei | 华文楷体 | STKaiti | 华文宋体 | STSong | 华文中宋 | STZhongsong | 华文仿宋 | STFangsong | 方正舒体 | FZShuTi | 方正姚体 | FZYaoti | 华文彩云 | STCaiyun | 华文琥珀 | STHupo | 华文隶书 | STLiti | 华文行楷 | STXingkai | 华文新魏 | STXinwei |
Mac 和Linux 支持的字体可能会不同,如果不行,可以使用matplotlib.font_manager 来指定具体的字体。
自定义配置文件:
有时候我们可能需要设置一大堆参数,并且这个配置在后面很多项目中可能都会用到,那么这时候我们就可以把这些配置信息放到文件中(可配置项见下),文件的命名规则为[名称].mplstyle ,然后把这个文件放到matplotlib.get_configdir()/stylelib 的目录中,在写代码的时候根据名称加载这个配置文件,示例代码如下:
plt.style.use("名称")
可配置项:
更多可配置项请参考:https://raw.githubusercontent.com/matplotlib/matplotlib/master/matplotlibrc.template
12. matplotlib作业
一、折线图作业要求:
- 以下是长沙某一个月的天气数据,按照时间的顺序绘制成折线图,其中数据
highest 是最高温度,lowest 是最低温度。最高温度线条用红色,最低温度线条用蓝色。 - 具体的坐标点,用圆点marker表示。
- 把x轴的时间刻度按照
1-31 标记出来,并且标记x轴和y轴的标题。 - 图的标题是“长沙5月份气温走势”。
数据:
highest = [26,21,26,26,22,20,17,19,22,28,30,28,24,28,25,26,25,26,25,23,24,30,32,31,30,27,26,27,29,25,25]
lowest = [17,13,17,18,18,17,14,15,16,18,19,20,18,18,20,20,20,20,20,16,17,19,21,24,24,23,20,18,19,18,19]
效果图参考:
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import font_manager
highest = [26,21,26,26,22,20,17,19,22,28,30,28,24,28,25,26,25,26,25,23,24,30,32,31,30,27,26,27,29,25,25]
lowest = [17,13,17,18,18,17,14,15,16,18,19,20,18,18,20,20,20,20,20,16,17,19,21,24,24,23,20,18,19,18,19]
plt.figure(figsize=(15,5))
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
plt.plot(highest,color='r',marker='o')
plt.plot(lowest,color='b',marker='o')
plt.xticks(range(31),range(1,32),fontproperties=font)
plt.xlabel("日期(天)",fontproperties=font)
plt.yticks(range(10,40,5),range(10,40,5))
plt.ylabel("温度(℃)",fontproperties=font)
plt.title("长沙5月份气温走势",fontproperties=font)
for x in range(0,31):
temp = highest[x]
plt.annotate(temp,xy=(x,temp),xytext=(x-0.2,temp+0.5))
for x in range(0,31):
temp = lowest[x]
plt.annotate(temp,xy=(x,temp),xytext=(x-0.2,temp+0.5))
plt.grid()
plt.show()
二、条形图作业要求:
- 以下数据是三类学校(普通本科、中等职业教育、普通高中)在2014-2018(包含2018)的报名人数,用DataFrame构建。
- 把年份当做x轴,报名人数当做y轴的值。
- 绘制分组条形图,同一个年份的放在一个组。
- 图例横向排列(提示:用legend的ncol参数,ncol表示的是把图例分成多少列显示)。
- 把报名人数在图上绘制出来。
数据:
data = {
"普通本科":[721,738,749,761,791],
"中等职业教育": [620,601,593,582,557],
"普通高中": [797,797,803,800,793]
}
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import font_manager
data = {
"普通本科":[721,738,749,761,791],
"中等职业教育": [620,601,593,582,557],
"普通高中": [797,797,803,800,793]
}
df = pd.DataFrame(data=data)
df
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
plt.figure(figsize=(15,5))
bar_width = 0.2
xticks = np.arange(2014,2019)
for index,column in enumerate(df.columns):
values = df[column]
c_xticks = xticks+bar_width*(index-1)
plt.bar(c_xticks,values,width=bar_width,label=column)
for x,y in zip(c_xticks,values):
plt.annotate(y,xy=(x,y),xytext=(x-0.05,y+10))
plt.ylim(top=1000)
plt.ylabel("万人",fontproperties=font,rotation="horizontal")
plt.gca().yaxis.set_label_coords(-0.02,1.02)
plt.legend(prop=font,ncol=3,loc='upper right')
plt.title("2014-2018普通本科、中等职业教育、普通高中招生人数",fontproperties=font)
plt.show()
三、直方图作业要求:
- 用pandas从scores.csv读取出来,形成一个DataFrame对象。
- 绘制化学成绩的直方图(chem列)。
- 标记x轴的坐标。
- 标记每个条形上的具体数值。
数据: 在matplotlib代码->作业参考 文件夹的scores.csv 文件中。
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import font_manager
scores_df = pd.read_csv("scores.csv")
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=14)
plt.figure(figsize=(15,5))
nums,bins,_ = plt.hist(scores_df['chem'],bins=20,edgecolor="k")
for num,bin in zip(nums,bins):
plt.annotate("%d"%num,xy=(bin,num),xytext=(bin+0.8,num+1))
plt.xticks(bins,['%.2f'%x for x in bins])
plt.title("某班化学成绩直方图",fontproperties=font)
plt.show()
四、散点图作业要求:
- 把guazi_bj(北京)、guazi_gz(广州)、guazi_sh(上海)、guazi_sz(深圳)二手车的数据归类在一个DataFrame中。
- 新增车辆使用年份(use_year)与保值率(hedge_rate)两个字段。其中使用年份的计算是把当前的时间减去购买的时间,然后再转换成年;保值率的计算是将二手车的价格/新车的价格。
- 把二手车使用年份与保值率(二手车价/新车价格)绘制成散点图,观察他们的分布情况。
- 把二手车的行驶距离与保值率(二手车价/新车价格)绘制成散点图,观察他们的分布情况。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from datetime import datetime
guazi_bj = pd.read_csv("guazi_bj.csv")
guazi_gz = pd.read_csv("guazi_gz.csv")
guazi_sh = pd.read_csv("guazi_sh.csv")
guazi_sz = pd.read_csv("guazi_sz.csv")
guazi = pd.concat([guazi_bj,guazi_gz,guazi_sh,guazi_sz],axis=0)
def get_use_year(value):
if isinstance(value,str):
datetime_value = datetime.strptime(value,"%Y-%m")
now = datetime.now()
yeardelay = (now - datetime_value).total_seconds()/60/60/24/30/12
return yeardelay
return np.NAN
guazi['use_year'] = guazi['buy_time'].apply(get_use_year)
guazi['hedge_rate'] = guazi['es_price'] / guazi['new_price']
guazi[['use_year','km','hedge_rate']].head()
plt.figure(figsize=(15,5))
plt.scatter(guazi['km'],guazi['hedge_rate'],s=guazi['km'])
plt.figure(figsize=(15,5))
plt.scatter(guazi['use_year'],guazi['hedge_rate'],s=guazi['km'])
plt.xlabel("use year")
plt.ylabel("hedge rate")
guazi[(guazi['hedge_rate'] > 0.9) & (guazi['use_year'] > 3)][['new_price','es_price','use_year','km']].head()
guazi[(guazi['hedge_rate'] > 0.9) & (guazi['use_year'] > 6)][['new_price','es_price','use_year','use_year']].head()
观察结果:
- 通过以上分析,我们可以看到汽车的保值率是随着使用年份和行驶公里数的增加呈现线性下降的。
- 有一部分数据引起我们的注意,就是保值率大于0.9,并且使用年份和行驶公里数都比较大的数据,我们可以看出这类数据基本上可以算是异常数据了,因此以后在分析的时候就可以处理掉这部分数据了。
五、饼图作业要求:
- 把以下数据绘制成饼图。
- 把Chrome浏览器的模块分割开0.05。
- 设置阴影。
- 把百分数的颜色设置成白色,把浏览器的名字颜色设置成黑色。
- 把Edge和Safari浏览器的比例文字字体大小调成10,其他的12。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import font_manager
browsers = {
"Chrome": 0.6098,
"Internet Explorer": 0.1218,
"FireFox": 0.1147,
"Edge": 0.0415,
"Safari": 0.0372,
"其他浏览器": 0.075
}
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
patches,texts,autotexts = plt.pie(browsers.values(),explode=(0.05,0,0,0,0,0),labels=browsers.keys(),textprops={"fontproperties":font},autopct="%.2f%%",shadow=True)
for index,autotext in enumerate(autotexts):
autotext.set_color("w")
if index == 3 or index == 4:
autotext.set_size(10)
plt.show()
六、箱线图作业:
- 读取scores.csv文件。
- 把所有科目的成绩都在一张图上绘制箱线图。
- 观察这个图,你能发现什么信息。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import font_manager
scores = pd.read_csv("scores.csv").drop(["num","class"],axis=1)
scores.head()
plt.figure(figsize=(15,5))
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
plt.boxplot([scores[column] for column in scores.columns])
plt.xticks(range(1,11),scores.columns)
plt.title("某班成绩分布情况",fontproperties=font)
plt.xticks(range(1,11),["语文","数学","英语","物理","化学","政治","生物","历史","地理","体育"],fontproperties=font)
plt.xlabel("科目",fontproperties=font)
plt.ylabel("成绩",fontproperties=font)
plt.show()
结论:
- 语文成绩盒子比较小,说明其中50%的同学分数相差都不大,但是有许多下限的异常值,说明考得不好的也估计占了20%左右,并且在上限有一个异常值,这个人考得特别好,关注下这个人,分析下他平时的上课表现。
- 整体来说数学和英语的成绩是比较偏好的,但是也存在很多偏科的学生。
- 还是数学和英语成绩,数学有75%以上的学生都是在80分以上,英语有75%以上的学生在70分以上,但是剩下的25%的学生的成绩就差别很大了,直接从几分70几分,还有大部分的异常值,说明数学这两个学科有部分人是偏科很厉害的。
- PE课(体育课)成绩比较最集中,但是也不高,都是在60的边缘。出现这个问题,有可能是学生平时锻炼得少了,需要关注。
- chem(化学)没有出现异常值,并且盒子的高度也不高,整体的分数也都不高,说明这个学科大家考得都不好,要么是试卷太难,要么就是真的没太多人学好了。
七、雷达图作业:
- 读取scores.csv文件成DataFrame对象。
- 计算每个科目的平均成绩。
- 将每个科目的平均成绩绘制成雷达图。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib import font_manager
font = font_manager.FontProperties(fname=r"C:\\Windows\\Fonts\\msyh.ttc",size=12)
scores = pd.read_csv("scores.csv").drop(['num','class'],axis=1)
scores.head()
theta = np.linspace(0,2*np.pi,11)
means = np.append(scores.mean().values,scores['chn'].mean())
plt.polar(theta,means)
plt.xticks(theta,['语文','数学','英语','物理','化学','政治','生物','历史','地理','体育'],fontproperties=font)
plt.fill(theta,means)
plt.show()
加油!
感谢!
努力!
|