《用Python进行科学计算》——matplotlib

什么是matplotlib?

patplotlib是python最著名的绘图库,提供了一整套与matlab相似的命令API,十分适合交互地进行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用中。
在Gallery页面中有很多缩略图,打开之后都有源程序。如果你需要绘制某种类型的图,只需在这个页面中复制粘贴就基本可以搞定。

快速绘图

matplotlib的pyplot子库提供了和matlab类似的绘图API,方便用户绘制2D图表。

#coding:utf-8

import numpy as np
import matplotlib.pyplot as plt


x=np.linspace(0,10,1000)
y=np.sin(x)
z=np.cos(x**2)


plt.figure(figsize=(8,4))

#通过调用plot函数在当前的绘图对象中进行绘图
#用法:第一句将x,y数组传递给plot之后,用关键字指定各种属性。
	#label:给所绘制的曲线一个名字,此名字在图示legend中显示,只要在字符前后添加“$”符号,matplotlib就会使用其内嵌的latex引擎绘制的数学公式。
	#color:指定曲线颜色
	#linewidth:指定曲线的宽度
plt.plot(x,y,label="$sin(x)$",color="red",linewidth=2)
plt.plot(x,z,"b--",label="$cos(x^2)$")

#设置x轴的文字
plt.xlabel("Time(s)")

#设置Y轴的文字
plt.ylabel("Volt")

#设置图表的标题
plt.title("PyPlot First Example")

#设置Y轴的范围
plt.ylim(-1.2,1.2)

#显示图示
plt.legend()

#显示出创建的所有绘图对象
plt.show()

《用Python进行科学计算》——matplotlib_第1张图片
pylab模块
matplotlib提供了名为pylab的模块,其中包括了许多numpy和pyplot中常用的函数,方便用户快速进行计算和绘图,可以用于Ipython中的快速交互使用。

plt.figure(figsize=(8,4))

调用figure创建一个绘图对象,并且是它成为当前的绘图对象。
也可以不创建绘图对象直接调用plot,matplotlib会自动创建一个绘图对象。如果需要同时绘制多幅图表的话,可以是给figure传达一个整数参数指定图表的序号,如果所指定的序号的汇入对象已经存在的话,将不创建新的对象,而只是让它成为当前绘图对象。
通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;
dpi参数指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80.

配置属性
matplotlib所绘制的图的每个组成部分都应有一个对象。我们可以通过调用这些对象的属性设置方法set_*或者pyplot的属性设置函数setp设置其属性值。

In [2]: import numpy as np

In [3]: import matplotlib.pyplot as plt

In [4]: x=np.arange(0,5,0.1)

In [5]: line, =plt.plot(x,x*x) #plot返回一个列表,通过line获取其第一个元素

In [6]: #调用Line2D对象的set_*方法设置属性值

In [7]: line.set_antialiased(False)

In [8]: #同时绘制sin和cos两条曲线,lines是一个有两个Line2D对象的列表

In [9]: lines=plt.plot(x,np.sin(x),np.cos(x))

In [10]: #调用setp函数同时配置多个Line2D对象的多个属性值

In [11]: plt.setp(lines,color="r",linewidth=2.0)
Out[11]: [None, None, None, None]

通过调用Line2D对象line的set_antialiased方法,关闭对象的反锯齿效果。或者通过调用plt.setp函数配置多个Line2D对性的颜色和线宽属性。

使用get_*方法或取对象的属性。

In [12]: line.get_linewidth()
Out[12]: 1.5

In [13]: plt.getp(lines[0],"color") #返回color属性
Out[13]: 'r'

In [14]: plt.getp(lines[1]) #返回所有属性
    agg_filter = None
    alpha = None
    animated = False
    antialiased = True
...

getp方法只能对一个对象进行操作,它有两种用法:

  • 指定属性名:返沪对象的指定属性的值
  • 不指定属性名:打印出对象的所有属性和它们的值

matplotlib的整个图表为一个Figrue对象,此对象在调用plt.figrue函数时返回,我们可以通过plt.gcf函数获取当前的绘图对象。

In [16]: f=plt.gcf()

In [17]: plt.getp(f)
    agg_filter = None
    alpha = None
    animated = False
    axes = [

Figure对象中有一个axes属性,其值为AxesSubplot对象的列表,每个AxesSubplot对象代表图表中的一个子图,前面所绘制的图表只包含一个子图,当前子图可以通过plt.gca获得:

In [18]: plt.getp(f,"axes")
Out[18]: []
In [20]: plt.gca()
Out[20]: 

用plt.getp可以发现AxesSubplot对象有很多属性,例如它的lines属性为此子图所包含的Line2D对象列表:

In [21]: alllines=plt.getp(plt.gca(),"lines")

In [22]: alllines
Out[22]: 

In [23]: alllines[0]==line
Out[23]: True

In [24]: #其中第一条曲线就是最开始绘制的那条

绘制多轴图

一个绘图对象可以包含多个轴,在Matplotlib中用轴表示一个绘图区域,可以将其理解为子图。可以使用subplot函数快速绘制有多个轴的图表。subplot函数的调用形式如下:

subplot(numRows, numCols, plotNum)

subplot将整个绘图区域等分为numRows行*numCols列个子区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,左上的编号为1.如果numRows,numCols和plotNum这三个数都小于10的话,可以把它们缩写为一个整数。如subplot(323)和subplot(3,2,3)是相同的。subplot在plotNum指定的区域中创建一个轴对象。如果新创建的轴和之前创建的轴和之前创建的轴重叠的话,之前的轴将被删除。

plt.subplot(321) #第一行第一个
plt.subplot(323) #第二行第一个
plt.subplot(313) #第三行一整行

《用Python进行科学计算》——matplotlib_第2张图片
当绘图对象有多个轴的时候,可以通过工具栏中的Configure Subplots按钮,交互地调节轴之间的间距距离。如果希望在程序中调节的话,可以调用subplots_adjust函数,它有left, right, bottom, top, wspace, hspace等几个关键字参数,这些参数的值都是0到1之间的小数,它们是以绘图区域的宽高为1进行正规化之后的坐标或者长度。

配置文件
一幅图有许多需要配置的属性,例如颜色,字体,线型等。我们在绘图时并没有对这些属性进行配置,许多都直接采用Matplotlib的缺省配置。Matplotlib将缺省配置保存在一个文件中,通过该这个文件,我们可以修改这些属性值。
使用配置文件matplotlinrc时的搜索路径

  • 当前路径:程序的当前路径
  • 用户配置路径:通常为HOME/.matplitlib/可以通过改变MATPLOTLIBRC修改
  • 系统配置路径:保存在matplotlib的安装目录下的mpl-data下。

获取用户配置路径:

import matplotlib

print(matplotlib.get_configdir())

获取目前使用的配置文件路径:

print(matplotlib.matplotlib_fname())
# /home/kiosk/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc

系统配置路径下的配置文件,

import os
print(os.getcwd())
# /home/kiosk/Desktop/Project/Data

如果将matplotlibrc复制一份到脚本的当前目录下:

print(matplotlib.matplotlib_fname())
# /home/kiosk/Desktop/Project/Data/matplotlibrc

如果你用文本编辑器打开配置文件,你会发现它实际上是定义了一个字典。为了对众多的配置进行区分,关键字可以用点分开。
配置文件的读入可以使用rc_params函数,他返回一个配置字典:

print(matplotlib.rc_params())

"""
animation.avconv_path: avconv
animation.bitrate: -1
animation.codec: h264
animation.convert_args: []
animation.convert_path: convert
animation.embed_limit: 20.0
......
"""

在matplotlib模块载入的时候会调用rc_params,并把得到的配置字典保存到rcParams变量中:

In [26]: matplotlib.rcParams
Out[26]: 
RcParams({'_internal.classic_mode': False,
          'agg.path.chunksize': 0,
          'animation.avconv_args': [],
          'animation.avconv_path': 'avconv',
          'animation.bitrate': -1,
          'animation.codec': 'h264',
......

matplotlib将使用rcParams中的配置进行绘图。用户可以直接修改此字典中的配置,所做的改变会但应到此后所绘制的图中。
例如下面的脚本中所绘制的线将带有圆形的点标识符:
注意在此设置的配置不会真正的写入配置文件中。

matplotlib.rcParams["lines.marker"]="o"
import pylab
pylab.plot([1,2,3])
pylab.show()

《用Python进行科学计算》——matplotlib_第3张图片
为了方便配置,可以先使用rc函数,下面的例子同时配置点标识符、线宽和颜色:

matplotlib.rc("lines", marker="x", linewidth=2, color="red")

如果希望恢复到缺省配置(matplotlib载入时从配置文件读入的配置)的话,可以调用rcdefaluts函数。

matplotlib.rcParams["lines.marker"]="o"
import pylab
pylab.plot([1,2,3,4,5,6])

matplotlib.rcdefaults()
pylab.plot([-1,-2,-3])

pylab.show()

《用Python进行科学计算》——matplotlib_第4张图片
如果手工修改了配置文件,希望从配置文件重新载入最新的配置的话,可以调用:

matplotlib.rcParams.update( matplotlib.rc_params() )

Artist对象

matplotlib API包含有三层:

  • backend_bases.FigureCanvas:图表的绘制区域;
  • backend_bases.Renderer:知道如何在FigureCanvas上如何绘图;
  • artist.Artist:知道如何使用Renderer在FigureCanvas上绘图;

FigureCanvas和Render需要处理底层的绘图操作,Artist则处理所有的高层结构,例如处理图表、文字和曲线等的绘制和布局。通常我们只和Artist打交道,则不需要关心底层的绘制细节。

Artists分为简单类型和容器类型两种:
简单类型的Artists为标准的绘图元件例如Line2D、Rectangle、Text等

容器类型则可以包含许多简单类型的Artists,使它们组织一个整体,例如Axis、Axes、Figure等。
注意: Figure相当于一个桌面,Axes相当于上面的画纸

直接使用Artists创建图表的标准流程如下:

  • 创建Figure对象
  • 用Figure对象创建一个或者多个Axes和Subplot对象;
  • 调用Aexis等对象的方法创建各种简单类型的Artists;
#coding:utf-8

import matplotlib.pyplot as plt


# 1.调用pyplot.figure辅助函数创建figure对象
fig=plt.figure()

# 2.调用Figure对象的add_axes方法在其中创建一个Axes对象
#add_axes的参数是一个形如[left,bottom,width,height]的列表
# 这些数值分别指定所创建的Axes对象相对于fig的位置和大小,取值都在0~1之间
ax=fig.add_axes([0.15,0.1,0.7,0.3])

# 3.调用ax的plot方法绘图,创建一条曲线,并且返回此曲线对象(Line2D)
line, =ax.plot([1,2,3],[1,2,1])

print(ax.lines)

# []

print(line)

# Line2D(_line0)

# ax.lines是一个为包含ax的所有曲线的列表,后续的ax.plot调用会往此列表中
# 添加心的曲线。如果想删除某条曲线,直接从此列表中删除即可

Axes对象还包括许多其他的Artists对象
例如我们可以通过调用set_xlabel设置其x轴上的标题;

ax.set_xlabel("time")

如果查看set_xlabel的源代码,会发现它是通过调用下面的语句实现的:

self.xaxis.set_label_text(xlabel, fontdict, **kwargs)

如果一直跟踪下去会发现Axes的xaxis属性是一个XAxis对象;

self.xaxis = maxis.XAxis(self)
...
class XAxis(Axis):
...
print(ax.xaxis)
# XAxis(96.000000,48.000000)
#

XAxis的label属性是一个Text对象

print(ax.xaxis.label)
# Text(0.5, 0, 'time')
#

而Text对象的_text属性为我们设置的值:

print(ax.xaxis.label._text)
# time

这些对象都是Artists,因此也可以调用它们的属性获取函数来获得相应的属性:

print(ax.xaxis.label.get_text())
# time

Artist的属性
图表中的每个元素都用一个matplotlib的Artists对象表示,而每个Artist对象都有一大堆属性控制其显示效果。例如Figure对象和Aexs对象都有patch属性作为其背景,他是一个Rectangle对象。通过它的一些属性可以修改figure图表的背景颜色或者透明度等属性。

fig=plt.figure()
fig.patch.set_color("g")
fig.canvas.draw()

patch的color属性通过set_color函数进行设置,属性修改之后并不会立即反映到图表上,还需调用fig.canvas.draw()才能显示。
下面是Artists对象的一些属性:

属性 描述
alpha 透明度,值在0到1之间,0为完全透明,1为完全不透明
animated 布尔值,在绘制动画效果中使用
axes 此Artist对象所在的Axes对象,可能为None
clip_box 对象的裁剪框
clip_on 是否裁剪
clip_path 裁剪的路径
contains 判断指定点是否在对象上的函数
figure 所在的Figure对象可能为None
label 文本标签
picker 控制Artist对象的选取
transform 控制偏移旋转
visible 是否可见
zorder 控制绘图顺序

Artist对象的所有属性都通过相应的get_*和set_*函数进行读写,例如下面的语句将alpha(透明度)属性设置为当前值的一半:
缺省的alpha属性值为None

fig.patch.set_alpha(0.5*fig.patch.get_alpha())

如果你想用一条语句设置多个属性的话,可以使用set函数:

fig.patch.set(alpha=0.7,zorder=2)

使用前面介绍的matplotlib.pyplot.getp函数可以方便地输出Artist对象的所有属性名和值:

print(plt.getp(fig.patch))

"""
agg_filter = None
    alpha = None
    animated = False
    antialiased = False
    bbox = Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0)
    capstyle = butt
    children = []
    clip_box = None
    clip_on = True
    clip_path = None
    contains = None
    ...
"""

Figure容器
最大的Artist容器是matplotlib.figure.figure,它包括组成的所有元素。图表背景是一个Rectangle对象,用Figrue.patch属性表示。当你通过调用add_subplot或者add_axes方法往图表中添加轴(子图)时,这些子图都将添加到Figure.axes属性中,同时这两个方法也返回添加进axes属性的对象,注意返回值的类型有所不同,实际上AxesSubplot是Axes的子类。

import matplotlib.pyplot as plt

fig=plt.figure()

ax1=fig.add_subplot(211)
ax2=fig.add_axes([0.1,0.1,0.7,0.3])
plt.show()

print(ax1)
# AxesSubplot(0.125,0.53;0.775x0.35)

print(ax2)
# Axes(0.1,0.1;0.7x0.3)

print(fig.axes)
# [,
#  ]

为了支持pyplot中的gca()等函数,Figure对象内部保存有当前轴的信息,因此不建议直接对Figure.axes属性进行列表操作,而因该使用add_subplot, add_axes, delaxes等方法进行添加和删除操作。但是使用for循环对axes中的每个元素继续操作是没有问题的,下面的语句打开所有子图的栅格:

import matplotlib.pyplot as plt

fig=plt.figure()

ax1=fig.add_subplot(211)
ax2=fig.add_axes([0.1,0.1,0.7,0.3])

for ax in fig.axes:
    ax.grid(True)

plt.show()

《用Python进行科学计算》——matplotlib_第5张图片
Figure对象可以拥有自己的文字、线条以及图像等简单类型的Artist。缺省的坐标系统为像素点,但是可以通过设置Artsist对象的transform属性修改坐标系的转换方式。最常用的Figure对象的坐标系是以左下角为坐标原点(0,0),右上角为坐标(1,1)。下面的程序创建并添加两条直线到fig中:

#coding:utf-8

from matplotlib.lines import Line2D
import matplotlib.pyplot as plt

fig=plt.figure()
line1=Line2D([0,1],[0,1],transform=fig.transFigure,figure=fig,color="r")
line2=Line2D([0,1],[1,0],transform=fig.transFigure,figure=fig,color="g")

fig.lines.extend([line1,line2])
plt.show()

《用Python进行科学计算》——matplotlib_第6张图片

**注意:**为了让所创建的line2D对象使用fig的坐标,我们将fig.TransFigure赋给Line2D对象的transform属性;为了让line2D对象知道它是在fig对象中,我们还设置其figure属性为fig;最后还需要将创建的两个Line2D对象添加到fig.lines属性中去。

Figure对象有如下属性包含其他的Artist对象:

  • axes:Axes对象列表;
  • patch:作为背景的Rectangle对象;
  • images:FigureImage对象列表,用来显示图片;
  • legends:Legend(图例)对象列表;
  • lines:Line2D对象列表;
  • patchs:pacth对象列表;
  • texts:Text对象列表,用来显示文字;

Axes容器
Axes容器是整个matplotlib库的核心,它包含了自称众多Artist对象,并且有许多方法函数帮助我们创建、修改这些对象。和Figure一样,它有一个patch属性当作背景,当它是笛卡尔坐标时,patch属性是一个Rectangle对象,而它是极坐标时,patch属性则是Circle对象。
例如设置Axes对象的背景颜色为绿色,figure的背景为红色:

import matplotlib.pyplot as plt

fig=plt.figure()
fig.patch.set_color("r")
ax=fig.add_subplot(111)
ax.patch.set_facecolor("green")
plt.show()

当你调用Axes的绘图方法时,它将创建一组Line2D对象,并将所有的关键字参数传递给这个Line2D对象,并将它们添加进Axes.lines属性中,最后返回所创建的Line2D对象列表:

import numpy as np
x,y=np.random.rand(2,100)

line, =ax.plot(x,y,"-",color="blue",linewidth=2)
print(line)
# Line2D(_line0)

print(ax.lines)
# []

注意plot返回的是一个Line2D对象的列表,因为我们可以传递多组X,Y轴的数据,一次绘制多条曲线。
与plot方法类似,绘制直方图的方法bar和绘制柱状图的方法hist将创建一个Patch对象的列表,每个元素实际上都是Patch的子类Rectangle,并且将所创建的Patch对象都添加进Axes.patches属性中:

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()

ax=fig.add_subplot(111)
n,bins,rects=ax.hist(np.random.randn(1000),50,facecolor="blue")


print(rects)
# 

print(rects[0])
# Rectangle(xy=(-3.23021, 0), width=0.123145, height=2, angle=0)

print(ax.patches[0])
# Rectangle(xy=(-3.31238, 0), width=0.12749, height=1, angle=0)

一般我们不会直接对Axes.lines或者Axes.patches属性进行操作,而是调用add_line或者add_patch等方法,这些方法帮助我们完成许多属性设置工作:

import matplotlib.pyplot as plt
import matplotlib

fig=plt.figure()
ax=fig.add_subplot(111)
rect=matplotlib.patches.Rectangle((1,1),width=5,height=12)

print(rect.get_transform()) #rect的transform属性为缺省值

"""
CompositeGenericTransform(
    BboxTransformTo(
        Bbox(x0=1.0, y0=1.0, x1=6.0, y1=13.0)),
    Affine2D(
        [[1. 0. 0.]
         [0. 1. 0.]
         [0. 0. 1.]]))
"""

#将rect添加进ax
ax.add_patch(rect)

#rect的transform属性和ax的transData相同
print(rect.get_transform())

print(ax.transData)

可以看出,add_patch方法帮助我们设置了rect的axes和transform属性。

  • artists:Artist对象列表;
  • patch:作为Axes背景的Patch对象,可以是Rectangle或者Circle;
  • collections:Collection对象列表;
  • images:AxesImage对象列表;
  • legends:Legend对象列表;
  • lines:Line2D对象列表;
  • patches:Patch对象列表;
  • texts:Text对象列表;
  • xaxis:XAxis对象;
  • yaxis:YAxis对象;

下面列出Axes的创建Artist对象的方法:

Axes的方法 所创建的对象 添加进的列表
annotate(注释) Annotate texts
bars(柱形图) Rectangle patches
errorbar(误差条形图) Line2D,Rectangle lines,patches
fill Polygon patches
hist(直方图) Rectangle patches
imshow(显示图形) AxesImage images
legend Legend legends
plot Line2D lines
scatter(散点图) PolygonCollection collections
text Text texts

实例散点图:

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()

ax=fig.add_subplot(111)
t=ax.scatter(np.random.rand(20),np.random.rand(20))

# t的返回值为PathCollection对象
print(t)
# 

#返回的对象已经添加进collections列表中
print(ax.collections)
# []


plt.show()

《用Python进行科学计算》——matplotlib_第7张图片

Axis容器
Axis容器包括坐标轴上的刻度线、刻度文本、坐标网格以极坐标轴标题等内容。刻度包括主刻度和副刻度。分别通过Axis.get_major_ticks和Axis.get_minor_ticks方法获得。每个刻度线都是一个XTick或者YTick对象,它包括实际的刻度线和刻度文本。为了方便访问刻度线和文本,Axis对象提供了get_ticklabels和get_ticklines方法分别直接获得刻度线和刻度文本:

import matplotlib.pyplot as plt
import numpy as np

plt.plot([1,2,3],[4,5,6])
# plt.show()

axis=plt.gca().xaxis

#获取刻度的位置列表
print(axis.get_ticklocs())
# [0.75 1.   1.25 1.5  1.75 2.   2.25 2.5  2.75 3.   3.25]

#获得刻度标签列表
print(axis.get_ticklabels())
# 

print([x.get_text() for x in axis.get_ticklabels()])


#获得主刻度线列表,图的上下刻度线共10条
print(axis.get_ticklines())
# 

#获得副刻度线列表
print(axis.get_ticklines(minor=True))
# 

获得刻度线标签之后,可以设置其各种属性。

for label in axis.get_ticklabels():
    label.set_color("red")
    label.set_rotation(45)
    label.set_fontsize(16)

for line in axis.get_ticklines():
    line.set_color("green")
    line.set_markersize(25)
    line.set_markeredgewidth(3)

plt.show()

《用Python进行科学计算》——matplotlib_第8张图片

>>> axis.get_minor_locator() # 计算副刻度的对象

>>> axis.get_major_locator() # 计算主刻度的对象

我们可以使用程序为Axis对象设置不同的Locator对象,用来手工设置刻度的位置;设置Formatter对象用来控制刻度文本的显示。下面的程序设置X轴的主刻度以pi为单位:

#coding:utf-8

import matplotlib.pyplot as pl
from matplotlib.ticker import MultipleLocator,FuncFormatter
import numpy as np

x=np.arange(0,4*np.pi,0.01)
y=np.sin(x)

pl.figure(figsize=(8,4))
pl.plot(x,y)

ax=pl.gca()

def pi_formatter(x,pos):

    """将数值转换为以pi/4为单位的刻度文本"""

    m=np.round(x/(np.pi/4))
    n=4

    if m%2==0: m,n=m/2,n/2
    if m==0:
        return "0"
    if m==1 and n==1:
        return "$\pi$"
    if n==1:
        return r"$%d \pi$" %m
    if m==1:
        return r"$\frac{\pi}{%d}$" %n

    return r"$\frac{%d \pi}{%d}$" %(m,n)

#设置两个坐标轴的范围
pl.ylim(-1.5,1.5)
pl.xlim(0,np.max(x))

#设置图的底边距
pl.subplots_adjust(bottom=0.15)

pl.grid() #开启网格

#主格线为pi/4
ax.xaxis.set_major_locator(MultipleLocator(np.pi/4))

#主刻度文本用pi_formatter函数计算
ax.xaxis.set_major_formatter(FuncFormatter(pi_formatter))

#副刻度为pi/20
ax.xaxis.set_minor_locator(MultipleLocator(np.pi/20))

#设置刻度文本的大小
for tick in ax.xaxis.get_major_ticks():
    tick.label1.set_fontsize(16)

pl.show()

《用Python进行科学计算》——matplotlib_第9张图片

关于刻度的定位和文本格式的东西都在matploylib.ticker中定义,程序中使用到如下两个类:

  • MultipleLocator:以指定的整数倍为刻度线
  • FuncFormatter:使用指定的函数计算刻度文本,它会传递给所指定的函数两个参数:刻度值和刻度序号,程序通过比较笨的方法计算出刻度值所对应的刻度文本。

你可能感兴趣的:(数据分析)