Matplotlib是Python中用的最多的2D图形绘图库,学好Matplotlib的用法可以帮助我们在统计分析中更灵活的展示各种数据的状态。这是数据可视化必学的库,好好学吧。
其支持以下几种数据可视化方式
本文就基于这几种方式对Matplotlib进行讲解。
安装和启动
安装Matplotlib可以借助pip,如果在ipython中使用需要用 $ipython --matplotlib 命令启动。这里没啥好说的,过。
开始之前
先通过一个折线图的例子让大家大概了解一下Matplotlib的常见用法吧
In [1]: import matplotlib.pyplot as plt
In [2]: import pandas as pd
In [3]: import numpy as np
In [4]: df = pd.DataFrame(np.random.rand(10,2),columns=['A','B'])
In [5]: fig = df.plot(figsize=(8,4)) # plot函数生成原始绘画图,figsize设置窗口大小
In [6]: plt.title('Title') # 设置绘图标题名称
In [7]: plt.xlabel('X axis') # 设置X轴名称
In [8]: plt.ylabel('Y axis') # 设置Y轴名称
In [9]: plt.legend(loc='upper right') # 显示折线的名称标签,loc设置显示位置
In [10]: plt.xlim([0,12]) # 设置x轴的边界
In [11]: plt.ylim([0,1.5]) # 设置y轴的边界
In [12]: plt.xticks(range(10)) # 设置X轴的刻度
In [13]: plt.yticks(np.linspace(0,1.2,7)) # 设置Y轴的刻度
In [14]: fig.set_xticklabels('%.1f' %i for i in range(10)) # 设置X轴刻度上的标签
In [16]: fig.set_yticklabels('%.2f' %i for i in np.linspace(0,1.2,7)) # 设置Y轴刻度上的标签
# 注意这里X轴设置了边界范围是0-12,但是刻度只有0-9,刻度标签显示1位小数
现在图形是下面这样
图是这样的
以上这些简单操作会帮助你对Matplotlib有一个大概的认识,下面就可以开始学习正式的绘图工作了。
折线图
我们已经在上面简单画过一个折线图了,想要为折线图添加更丰富的样式?没问题
In [9]: from matplotlib import style
In [10]: style.use('ggplot')
In [11]: x = [5,8,10]
In [12]: y = [12,16,6]
In [13]: x1 = [6,9,11]
In [14]: y1 = [6,15,7]
In [15]: plt.plot(x,y,'g',label='line one',linewidth=5) # 第三个参数指定颜色,第四个指定线的名称,第五个参数指定线宽
In [16]: plt.plot(x1,y1,'r',label='line two',linewidth=5)
In [17]: plt.title('Epic Info')
In [18]: plt.xlabel('X axis')
In [19]: plt.ylabel('Y axis')
In [20]: plt.legend()
In [21]: plt.grid(True,color='k') #开启显示背景网格线并设置颜色
这一步结束后图形变成了这样
这里可以看到没有借助其他函数,只是在plot函数里添加几个参数就让图形变得像那么回事了。其实想要修改图形的样式,主要是通过在plot函数中加入各种参数。
plot函数的参数其实有点多,这里只挑一些比较常用的说。具体如下:
plt.plot(kind='line', ax=None, figsize=None, use_index=True, title=None, grid=None, legend=False, style=None, logx=False, logy=False, loglog=False, xticks=None, yticks=None, xlim=None, ylim=None, rot=None, fontsize=None, colormap=None, table=False, yerr=None, xerr=None, label=None, secondary_y=False, **kwds)
series的index为横坐标
value为纵坐标
kind → line,bar,barh...(折线图,柱状图,柱状图-横...)
label → 图例标签,Dataframe格式以列名为label
style → 风格字符串,这里包括了linestyle(-),marker(.),color(g)
color → 颜色,有color指定时候,以color颜色为准
alpha → 透明度,0-1
use_index → 将索引用为刻度标签,默认为True
rot → 旋转刻度标签,0-360
grid → bool变量显示背景网格,一般直接用plt.grid函数
xlim,ylim → x,y轴界限
xticks,yticks → x,y轴刻度值
colormap → 指定颜色集
figsize → 图像大小
title → 图名
legend → 是否显示图例,一般直接用plt.legend()
动手能力强的同学可以自己试着修改参数来看看效果
In [22]: df = pd.DataFrame(np.random.randn(30, 4),columns=list('ABCD')).cumsum()
In [23]: draw = df.plot(style = '--.',alpha = 0.8,colormap = 'summer_r',grid=True)
In [24]: draw.text(20,5,'(20,5)',fontsize=12) # 设置注释标签,参数依次为x轴坐标、y轴坐标、文本内容、字体大小
学会了这些,折线图的画法基本就能搞定了。
条形图
条形图常用于多项分段数据比较的图形化显示,下面来看看怎么用
In [27]: plt.bar([0.25,1.25,2.25,3.25,4.25],[50,40,70,80,20],label="BMW", color='b', width=.5) # plt.bar就是打印直方图的函数,第一个参数指定每个柱子的起始,第二个参数是指定每个柱子的高度,第三个是名称标签,第四个指定颜色,第五个指定宽度
In [28]: plt.bar([.75,1.75,2.75,3.75,4.75],[80,20,20,50,60],label="Audi", color='r',width=.5)
In [29]: plt.legend()
In [30]: plt.xlabel('Day')
In [31]: plt.ylabel('Distance(kms)')
In [32]: plt.title('Information')
条形图的样式主要是在bar函数中设置,主要参数如下:
plt.bar(x,y,width,facecolor,left,align,xerr,yerr)
x,y参数:x,y值
width:宽度比例
facecolor:柱状图里填充的颜色、edgecolor是边框的颜色
left:每个柱x轴左边界
bottom:每个柱y轴下边界
align:决定整个bar图分布,默认left表示默认从左边界开始绘制,center会将图绘制在中间位置
xerr/yerr :x/y方向error bar
直方图
直方图与条形图基本类似,不过直方图通常用来对单个数据的单一属性进行描述,而不是用于比较
In [33]: population_age = [22,55,62,45,21,22,34,42,42,4,2,102,95,85,55,110,120,70,65,55,111,115,80,75,65,54,44,43,42,48]
In [34]: bins = [0,10,20,30,40,50,60,70,80,90,100]
In [35]: plt.hist(population_age, bins, histtype='bar', color='b', rwidth=0.8)
In [36]: plt.hist(population_age, bins, histtype='bar', color='b', rwidth=0.8)
In [37]: plt.xlabel('age groups')
In [38]: plt.ylabel('Number of people')
In [39]: plt.title('Histogram')
直方图主要是借助hist函数实现,参数如下:
plt.hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical',rwidth=None,
log=False, color=None, label=None, stacked=False, hold=None, data=None, **kwargs)
bins:箱子的宽度
normed 标准化
histtype 风格,bar,barstacked,step,stepfilled
orientation 水平还是垂直{‘horizontal’, ‘vertical’}
align : {‘left’, ‘mid’, ‘right’}, optional(对齐方式)
stacked:是否堆叠
散点图
在展示散列数据时通常会选择散点图,主要借助scatter函数,参数如下:
plt.scatter(x, y, s=20, c=None, marker='o', cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None,
verts=None, edgecolors=None, hold=None, data=None, **kwargs)
s:散点的大小
c:散点的颜色
vmin,vmax:亮度设置,标量
cmap:colormap
In [41]: x = [1,1.5,2,2.5,3,3.5,3.6]
In [42]: y = [7.5,8,8.5,9,9.5,10,10.5]
In [43]: x1=[8,8.5,9,9.5,10,10.5,11]
In [44]: y1=[3,3.5,3.7,4,4.5,5,5.2]
In [45]: plt.scatter(x,y,label='high income low saving', color='r')
In [46]: plt.scatter(x,y,label='high income low saving', color='r')
In [47]: plt.scatter(x1,y1,label='low income high savings',color='b')
In [48]: plt.xlabel('saving*100')
In [49]: plt.ylabel('income*1000')
In [50]: plt.title('Scatter Plot')
In [51]: plt.legend()
In [34]: plt.figure(figsize=(8,6))
In [35]: x = np.random.randn(1000)
In [36]: y = np.random.randn(1000)
In [37]: plt.scatter(x,y,marker='.',s=np.random.randn(1000)*100,cmap='Reds_r',c=y,alpha=0.5)
面积图
面积图和折线图较为类似,用于跟踪构成一个整体类别的两个或多个相关组的随时间推移所发生的比例变化。
In [53]: days = [1,2,3,4,5]
In [54]: sleeping =[7,8,6,11,7]
In [55]: eating = [2,3,4,3,2]
In [56]: working =[7,8,7,2,2]
In [57]: playing = [8,5,7,8,13]
In [58]: plt.plot([],[],color='m', label='Sleeping', linewidth=5)
In [60]: plt.plot([],[],color='c', label='Eating', linewidth=5)
In [61]: plt.plot([],[],color='r', label='Working', linewidth=5)
In [62]: plt.plot([],[],color='k', label='Playing', linewidth=5)
In [63]: plt.stackplot(days, sleeping,eating,working,playing, colors=['m','c','r','k'])
In [63]: plt.xlabel('x')
In [65]: plt.ylabel('y')
In [66]: plt.title('Stack Plot')
In [67]: plt.legend()
stacked参数指定是否堆叠,默认情况下区域图被堆叠。为了产生堆积面积图,每列必须是正值或全部为负值。
In [145]: fig,axes = plt.subplots(2,1,figsize=(8,6))
In [146]: df1 = pd.DataFrame(np.random.rand(10,4),columns=['a','b','c','d'])
In [147]: df2 = pd.DataFrame(np.random.randn(10,4),columns=['a','b','c','d'])
In [148]: df1.plot.area(colormap='Greens_r',alpha=0.5,ax=axes[0])
In [149]: df2.plot.area(stacked=False,colormap='Set2',alpha=0.5,ax=axes[1])
除了直接画面积图之外,还可以对函数图进行填充。
In [150]: fig,axes = plt.subplots(2,1,figsize=(8,6))
In [151]: x = np.linspace(0,1,500)
In [152]: y1 = np.sin(4*np.pi*x)*np.exp(-5*x)
In [153]: y2 = -np.sin(4*np.pi*x)*np.exp(-5*x)
In [155]: axes[0].fill(x,y1,'r',alpha=0.5,label='y1') # 将函数线与x轴之间的部分填充颜色
In [156]: axes[0].fill(x,y2,'g',alpha=0.5,label='y2')
In [157]: x = np.linspace(0,5*np.pi,1000)
In [158]: y1 = np.sin(x)
In [159]: y2 = np.sin(2*x)
In [160]: axes[1].fill_between(x,y1,y2,color='b',alpha=0.5,label='area') # 次函数可以将两条函数线中间的部分填充满颜色
In [161]: for i in range(2):
...: axes[i].legend()
...: axes[i].grid()
饼状图
饼状图又叫扇形图,能清晰表达各个对象在整体中所占百分比
In [68]: days = [1,2,3,4,5]
In [69]: sleeping =[7,8,6,11,7]
In [70]: eating = [2,3,4,3,2]
In [71]: working =[7,8,7,2,2]
In [72]: playing = [8,5,7,8,13]
In [73]: slices = [7,2,2,13]
In [74]: activities = ['sleeping','eating','working','playing']
In [75]: cols = ['c','m','r','b']
In [76]: plt.pie(slices,
...: labels=activities,
...: colors=cols,
...: startangle=90,
...: shadow= True,
...: explode=(0,0.1,0,0),
...: autopct='%1.1f%%')
...:
In [77]: plt.title('Pie Plot')
饼图只要使用的是pie函数,常用参数如下:
plt.pie(x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None, counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False, hold=None, data=None)
x:数据
explode:指定每部分的偏移量
labels:标签
colors:颜色
autopct:饼图上的数据标签显示方式
pctdistance:每个饼切片的中心和通过autopct生成的文本开始之间的比例
labeldistance:被画饼标记的直径,默认值:1.1
shadow:阴影
startangle:开始角度
radius:半径
frame:图框
counterclock:指定指针方向,顺时针或者逆时针
子图绘制
在一些场景中我们不希望把每个图一个一个单独显示在窗口中,而是合并到一个窗口显示,那么子图绘制功能就可以派上用场了。
子图绘制功能主要涉及到两个函数的使用:
plt.figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True, FigureClass=<class 'matplotlib.figure.Figure'>,clear, **kwargs)
这些参数的作用依次是 图形编号、图形尺寸、每英寸像素点、背景色、边界色、允许绘制画图框、使用自定义图实例、不清理该图
plt.subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, subplot_kw=None, gridspec_kw=None, **fig_kw)[source]
参数从左到右依次是 子图网格的行数、子图网格的列数、x轴在所有子图中属性共享的等级、y轴在所有子图中属性共享的等级、是否进行挤压操作、用字典的关键字创建每个子图、用字典的关键字创建子图放在网格里。
子图绘制主要分两种方法,先构建子图再填充到图表或者直接构建图表后操作子图
先构建子图然后填充图表
In [4]: fig1 = plt.figure(num=1,figsize=(8,6))
In [5]: plt.plot(np.random.rand(50).cumsum(),'k--')
In [6]: fig2 = plt.figure(num=2,figsize=(8,6))
In [7]: plt.plot(50-np.random.rand(50).cumsum(),'k--')
In [8]: fig = plt.figure(figsize=(10,6),facecolor='gray')
In [9]: ax1 = fig.add_subplot(2,2,1)
In [10]: plt.plot(np.random.rand(50).cumsum(),'k--')
In [11]: plt.plot(np.random.rand(50).cumsum(),'b--')
In [12]: ax2 = fig.add_subplot(2,2,2)
In [13]: ax2.hist(np.random.rand(50),alpha=0.5)
In [14]: ax4 = fig.add_subplot(2,2,4)
In [15]: df2 = pd.DataFrame(np.random.rand(10,4),columns=['a','b','c','d'])
In [16]: ax4.plot(df2,alpha=0.5,linestyle='--',marker='.')
使用subplots创建图表后修改子图
In [30]: fig,axes = plt.subplots(2,3,figsize=(10,4))
In [31]: ts = pd.Series(np.random.randn(1000).cumsum())
In [32]: print(axes,axes.shape,type(axes))
[[<matplotlib.axes._subplots.AxesSubplot object at 0x0000027770EB89E8>
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027773A846D8>
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027778B754E0>]
[<matplotlib.axes._subplots.AxesSubplot object at 0x00000277735ED588>
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027773605668>
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027778BBA4E0>]] (2, 3) <class 'numpy.ndarray'>
In [33]: ax1 = axes[0,1]
In [34]: ax1.plot(ts)
In [110]: fig,axes = plt.subplots(2,2,sharex=True,sharey=True)
In [111]: for i in range(2):
...: for j in range(2):
...: axes[i,j].hist(np.random.randn(500),color='k',alpha=0.5)
...:
In [112]: plt.subplots_adjust(wspace=0,hspace=0)
# wspace和hspace用于控制subplot之间的的间距
盒图
最后补充一个盒图,这也是度量数据分散情况比较常用的图。盒图可以展示出一组数据的最大值、最小值、上四分位数、下四分位数、异常值这些信息。
In [40]: fig,axes = plt.subplots(2,1,figsize=(10,6))
In [41]: df = pd.DataFrame(np.random.rand(10,5),columns=['A','B','C','D','E'])
In [42]: color = dict(boxes='DarkGreen',whiskers='DarkOrange',medians='DarkBlue',caps='Gr
...: ay')
# 箱型图着色
# boxes → 箱线
# whiskers → 分位数与error bar横线之间竖线的颜色
# medians → 中位数线颜色
# caps → error bar横线颜色
In [43]: df.plot.box(ylim=[0,1.2],grid=True,color=color,ax=axes[0])
In [44]: df.plot.box(vert=False,positions=[1,4,5,6,8],ax=axes[1],grid=True,color=color)
# vert:是否垂直,默认True
# position:箱型图占位
In [45]: df = pd.DataFrame(np.random.rand(10, 5), columns=['A', 'B', 'C', 'D', 'E'])
In [46]: plt.figure(figsize=(10,4))
In [47]: f = df.boxplot(sym = 'o', # 异常点形状,参考marker
...: vert = True, # 是否垂直
...: whis = 1.5, # IQR,默认1.5,也可以设置区间比如[5,95],代表
...: 强制上下边缘为数据95%和5%位置
...: patch_artist = True, # 上下四分位框内是否填充,True为填充
...: meanline = False,showmeans=True, # 是否有均值线及其形状
...: showbox = True, # 是否显示箱线
...: showcaps = True, # 是否显示边缘线
...: showfliers = True, # 是否显示异常值
...: notch = False, # 中间箱体是否缺口
...: return_type='dict' # 返回类型为字典
...: )
In [48]: plt.title('boxplot')
In [49]: for box in f['boxes']:
...: box.set( color='b', linewidth=1) # 箱体边框颜色
...: box.set( facecolor = 'b' ,alpha=0.5) # 箱体内部填充颜色
In [52]: for whisker in f['whiskers']:
...: whisker.set(color='k',linewidth=0.5,linestyle='-')
In [53]: for cap in f['caps']:
...: cap.set(color='gray',linewidth=2)
In [55]: for median in f['medians']:
...: median.set(color='DarkBlue',linewidth=2)
In [56]: for flier in f['fliers']:
...: flier.set(marker='o',color='y',alpha=0.5)
# boxes, 箱线
# medians, 中位值的横线,
# whiskers, 从box到error bar之间的竖线.
# fliers, 异常值
# caps, error bar横线
# means, 均值的横线,
网友评论