欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NumPy实战:Chapter-2(Matplotlib入门)

程序员文章站 2022-07-14 21:00:29
...

NumPy实战:Chapter-2(Matplotlib入门)

简介

用过Matlab的小伙伴应该对Matlab内的绘图工具记忆犹新,python作为一门强大的胶水语言,自然也有对应的绘图库。Matplotlib是一个非常有用的绘图库,常用数据可视化,Matplotlib依赖于Numpy的存在,在此之前你需要安装Numpy.

安装Matplotlib

直接使用python自带pip工具:

pip install numpy # 如果没有安装Numpy
pip install matplotlib  
# pip3 install matplotlib   # 如果是python3的话


Matplotlib的使用

基本用法

先来一个demo,绘制一条直线,输入下面的小段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(1,10,50)  # 在1到10之间产生50组数据(数据之间呈等差数列)
 y= 2 * x + 1

 plt.plot(x, y)
 plt.show()

这里我们使用的np.linspace函数产生等一组等差的数据(即x,也就是自变量),接下来运算出应变量y,然后使用plt.plot绘制该曲线。

程序运行,输出下面的’Figure 1’:

NumPy实战:Chapter-2(Matplotlib入门)

注意到在输出的图像中,还有一些分析图像的操作:局部放大操作,修改边框等(类似于Matlab,参见上图)


Figure图像

在知道plot的基本使用场景后,下面我们考虑一下这个问题:如何同时绘制多条曲线?
这又可以分为两种情况:

  • 在同一张图像上绘制多条曲线
  • 在多张图像上绘制对应的曲线

基于上面的思考,我们看看如果在matplotlib上实现。

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 # 在1到10之间产生50组数据(数据之间呈等差数列)
 x = np.linspace(1,10,50)  
 y1= 2 * x + 1
 y2 = x**2

 # 创建一个fig对象,在下一个fig对象创建前管理所有绘图资源
 plt.figure()   
 plt.plot(x, y1)  
 plt.show()

 # 创建新fig对象,管理下面的操作的绘图资源
 plt.figure(num=3, figsize=(8, 5))  # 设置当前图像序号和大小
 plt.plot(x, y1)
 plt.plot(x, y2, color='red',linewidth=3.0,linestyle='--') # 线条为红色,线宽为3,style为虚线

 plt.show()

程序运行,输出下面两张图像:

NumPy实战:Chapter-2(Matplotlib入门)

NumPy实战:Chapter-2(Matplotlib入门)

可以看到,我们可以创建多个figure对象,从而创建不同的图像。同时可以主要到figure接收多个属性设置,plot也接收多个属性设置。


关于Figure类的参数注释

class matplotlib.figure.Figure(num=None,figsize=None, dpi=None, facecolor=None, edgecolor=None, linewidth=0.0, frameon=None, subplotpars=None, tight_layout=None)
参数 description
num figure对象的标识符
figsize w,h tuple in inches. 当前图像的大小
dpi 每英寸的点数
facecolor 图像的背景颜色
edgecolor 图像的边框颜色
linewidth 线宽

关于plot函数的参数注释

matplotlib.pyplot.plot(*args, **kwargs)

可以看到,plot接收参数是一个可变元组args,和一个列表kwargs.

  • 参数args
    args就是我们要绘制的data,args可以为x,y对,也可以是单个y,常见的形式如下:

    plot(x, y) # plot x and y using default line style and color
    plot(x, y, 'bo') # plot x and y using blue circle markers
    plot(y) # plot y using x as index array 0..N-1
    plot(y, 'r+') # ditto, but with red plusses
    

    如果x and/or y是2维的,则会直接绘制对应的列。

  • 参数kwargs
    kwargs是用来控制我们绘图线的属性.例如label属性、color属性、linestyle属性、linewidth属性、antialiased(抗锯齿)属性等.这里设置的属性就是Line2D内包含的属性。

    color属性常见取值

    标识 含义 标识 含义 标识 含义 标识 含义
    b 蓝色 g green m magenta y yellow
    r red c cyan k black w white
    (1,2,3) 即rgb (1,2,3,4) 即rgba

    linestyle属性常见取值

    标识 含义 标识 含义 标识 含义 标识 含义
    ‘-‘ solid line style ‘–’ dashed line style ‘-.’ dash-dot line style ‘:’ dotted line style
    ‘.’ point marker ‘,’ pixel marker ‘<’ triangle_left marker ‘>’ triangle_right marker
    ‘1’ tri_down marker ‘2’ tri_up marker ‘*’ star marker ‘_’ hline marker


绘制多个子图

有的时候,我们需要在一张图片上绘制多个图像。

使用subplot绘制子图

输入下面一段程序:

 #coding:utf8
 # 绘制子图
 import numpy as np
 import matplotlib.pyplot as plt

 plt.figure()

 # 绘制一个子图,一共分为row=2,col=2 ,该子图占第1个位置
 plt.subplot(2, 2, 1)  
 plt.plot([0, 1], [0, 1])

 # 绘制一个子图,一共分为row=2,col=2 ,该子图占第2个位置
 plt.subplot(2, 2, 2)
 plt.plot([0, 1], [2, 2])

 plt.subplot(2, 2, 3)
 plt.plot([1, 1], [2, 3])

 plt.subplot(2, 2, 4)
 plt.plot([1, 2], [2, 1])

 plt.show()

NumPy实战:Chapter-2(Matplotlib入门)

使用subplot2grid绘制子图

需要导入gridspec包。

 #coding:utf8
 # 绘制子图
 import numpy as np
 import matplotlib.pyplot as plt
 import matplotlib.gridspec as gridspec

 plt.figure()

 # 创建一个3*3大小的子图格,该子图的起始位置为(0,0) 列跨度为3 行跨度为1
 ax1 = plt.subplot2grid((3,3),(0,0),colspan=3,rowspan=1)
 ax1.plot([1,2],[1,2])
 ax1.set_title('ax1_title')

 # 创建一个3*3大小的子图格,该子图的起始位置为(1,0) 列跨度为2
 ax2 = plt.subplot2grid((3,3),(1,0),colspan=2,)
 ax3 = plt.subplot2grid((3,3),(1,2),rowspan=2,)
 ax4 = plt.subplot2grid((3,3),(2,0),)
 ax5 = plt.subplot2grid((3,3),(2,1),)

 plt.show()

NumPy实战:Chapter-2(Matplotlib入门)


坐标轴设置

上面说完了如何创建图像和绘制不同style的线,本小节我们看看如何设置图像的坐标轴。

坐标轴的基本设置

先看下面程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(-3,7,50)  
 y1= x

 plt.figure()   
 plt.plot(x, y1)

 plt.xlim((-1, 2)) # 设置x轴显示的范围
 plt.ylim((-2, 3))

 plt.xlabel('I am x !') # 设置x轴的label
 plt.ylabel('y am I !')

 new_ticks = np.linspace(-1, 2 , 10)  
 plt.xticks(new_ticks)      # 设置x轴的刻度
 plt.yticks([-2, -1, 0, 1, 2, 3],   # 设置y轴的刻度 
    ['level0','level1',         # 可以看到坐标轴的刻度可以设置为字符串 
    r'$ \ mid$',               # 这里设置的对应的字符串规则就是常见Latex格式
    r'$ \ \alpha $',           # 这样的规则很适合在论文表现数据
    r'$ \ \pi $',
    r'$ \frac{\alpha} {\theta}  $'])  # 设置一个分子式

 plt.show()

输出图像为:

NumPy实战:Chapter-2(Matplotlib入门)


分析一下上面调用的一系列plt方法.

  • plt.xlim() 用来设置x轴的显示范围 (我们依旧可以在显示图片内拖拽)
  • plt.xlabel() 设置x轴的标签.
  • plt.xticks() 设置x轴的刻度.可以为数值tuple,也可以为两个tuple(值和字符标签 对,这里的字符标签可以为Latex公式关于Latex可以我写的这个Blog。)

NumPy实战:Chapter-2(Matplotlib入门)


设置坐标轴的样式和位置

先看一下的一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(-3,7,50)  
 y1= x

 plt.figure()   
 plt.plot(x, y1)

 plt.xlim((-1, 2)) # 设置x轴显示的范围
 plt.ylim((-2, 3))

 plt.xlabel('I am x !') # 设置x轴的label
 plt.ylabel('y am I !')

 new_ticks = np.linspace(-1, 2 , 10)  
 print('new_ticks:',new_ticks)
 plt.xticks(new_ticks)      # 设置x轴的刻度
 plt.yticks([-2, -1, 0, 1, 2, 3],   # 设置y轴的刻度 
    ['level0','level1',         # 可以看到坐标轴的刻度可以设置为字符串 
    r'$ \ mid$',               # 这里设置的对应的字符串规则就是常见Latex格式
    r'$ \ \alpha $',           # 这样的规则很适合在论文表现数据
    r'$ \ \pi $',
    r'$ \frac{\alpha} {\theta}  $'])  # 设置一个分子式

 # gca = 'get current axis'
 ax = plt.gca()
 ax.spines['right'].set_color('none')  # 设置右边的坐标轴不显示
 ax.spines['top'].set_color('none')  # 设置上边的坐标轴不显示
 ax.xaxis.set_ticks_position('bottom') # 设置当前坐标的默认x轴
 ax.yaxis.set_ticks_position('left') # 设置当前坐标的默认y轴

 ax.spines['bottom'].set_position(('data',-1))  # 将x轴绑定在y轴的-1的位置  data,outward,axes
 ax.spines['left'].set_position(('data',0))   # 将y轴绑定在x轴的0的位置

 plt.show()

输出:

NumPy实战:Chapter-2(Matplotlib入门)


程序注解:

  • plt.gca() 获取当前figure上的Axes对象。
  • ax.splines[‘xxx’]表示坐标线集合,xxx可以为’top’,’bottom’,’left’,’right’.找到对应的坐标线,我们可以改变其属性。
    • set_color() 设置坐标线的颜色
    • set_position() 设置坐标线的位置 设置方式有’data’(数值位置),’axes’(百分比位置)等
  • ax.Xaxis.set_ticks_position(‘xxx’)设置X坐标轴的tick标注的位置。xxx可以为[ ‘top’ | ‘bottom’ | ‘both’ | ‘default’ | ‘none’ ]
  • ax.Yaxis.set_ticks_position(‘xxx’)设置Y坐标轴的tick标注的位置。xxx可以为[ ‘left’ | ‘right’ | ‘both’ | ‘default’ | ‘none’ ]

如果你对ax.Xaxis.set_ticks_position不是很理解,将上面程序对应部分改为下面的程序:

 # gca = 'get current axis'
 ax = plt.gca()
 ax.xaxis.set_ticks_position('top') # 设置当前坐标的默认x轴
 ax.yaxis.set_ticks_position('right') # 设置当前坐标的默认y轴

 ax.spines['top'].set_position(('data',-1))  # 将x轴绑定在y轴的-1的位置  data,outward,axes
 ax.spines['right'].set_position(('data',0))   # 将y轴绑定在x轴的0的位置

 plt.show()

NumPy实战:Chapter-2(Matplotlib入门)

修改ticks的能见度

在绘制曲线时候,有时候会因为曲线过多或者过于宽阔,覆盖了坐标轴的刻度(ticks).示意图如下。
又或是如果我们想修改坐标轴的ticks样式,该怎么办?

NumPy实战:Chapter-2(Matplotlib入门)

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(-4,5,10)  
 y1= x
 y2 =x**2 -2

 plt.figure()   
 l1, = plt.plot(x, y1)
 l2, = plt.plot(x, y2, label='you',linewidth=10) 

 ax  = plt.gca()

 plt.xlim((-2, 2)) # 设置x轴显示的范围
 plt.ylim((-2, 2))

 ax.spines['right'].set_color('none')  # 设置右边的坐标轴不显示
 ax.spines['top'].set_color('none')  # 设置上边的坐标轴不显示

 ax.spines['bottom'].set_position(('data',-1))  # 将x轴绑定在y轴的-1的位置  
 ax.spines['left'].set_position(('data',0))   # 将y轴绑定在x轴的0的位置

 # 下面设置x/y轴的ticks属性
 for label in ax.get_xticklabels() +ax.get_yticklabels():  # 获取到x/y轴的ticks对象,并设置属性
    label.set_fontsize(12)
    label.set_bbox(dict(facecolor='r',edgecolor='None',alpha=0.2)) # bbox就是ticks的工作区域

 plt.show()

程序输出图像如下:

NumPy实战:Chapter-2(Matplotlib入门)



图例与标注

图例案例

如果我们在同一张figure上绘制多条曲线,需要对每条曲线做一个标注,就和每条马路都有对应的路牌。曲线标注示意图如下:

NumPy实战:Chapter-2(Matplotlib入门)

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(-1,5,10)  
 y1= x
 y2 =x**2 -1

 plt.figure()   
 l1, = plt.plot(x, y1)
 l2, = plt.plot(x, y2, label='you') 

 # 如果要对一个数据线做标注,需要使用legend
 #plt.legend(handles=[l1,l2])   # plot时候已经标明的label传入legend不需要再配对labels
 plt.legend(handles=[l1,], labels=['me',], loc='best')

 plt.show()

程序输出图像:

NumPy实战:Chapter-2(Matplotlib入门)


程序注解:

可以注意到:这里应用了一个新的函数pyplot.legend()。这里的**legend翻译过来是图例,不是LOL里面的legend**.
**matplotlib.pyplot.legend(*args, **kwargs)**
  • 在axes对象上放置一个图例。说白了就是为曲线添加一个图例(这需要通过在axes对象上已存在的plot对象来操作),通常在绘制多条曲线时候,我们使用如下方法获取每条曲线的实例,并将实例传到legend中.

    lines1, = plt.plot(x,y,label='I am line1')
    lines2, = plt.plot(x,z,label='I am line2')
    plt.legend()   适用于原曲线已经设定label了
    # plt.legend(handles=[lines1,line2],labels=['line1','line2'])
    
  • 我们可以在legend()函数内配置参数,为所有绘制的曲线统一配置label,还可以设定label的样式.常见的设置属性如下:

属性 description
loc 设置图例的显示位置,一般选择’best’,程序会帮你找个合适的位置。默认是:’upper right’,该参数的可选项有
{‘best’, ‘upper right’, ‘upper left’, ‘lower left/right’, ‘right’, ‘center left/right’, ‘lower/upper center’, ‘center’ }
title 图例的标题
ncol 图例中每行显示多少个
fontsize 图例的字体大小,可设置为int or float or
{‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’}
facecolor/edgecolor 背景/边框颜色

看下面的程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(-1,5,10)  
 y1= x
 y2 =x**2 -1

 plt.figure()   
 l1, = plt.plot(x, y1)
 l2, = plt.plot(x, y2, label='line2') 

 plt.legend(handles=[l1,l2], labels=['me','you'], title='I am legend',
    loc='lower right',ncol=2, fontsize='large',facecolor='r',edgecolor='b')

 plt.show()

输出图像:
NumPy实战:Chapter-2(Matplotlib入门)


注解案例

上面我们说了如何对图像做图例注解,如果我们需要坐标系内做一些标注,或者是对图上的某些点做解释,该怎么办? 该需求示意图如下:

NumPy实战:Chapter-2(Matplotlib入门)

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 x = np.linspace(0,2,10)  
 y1= x
 y2 =x**2

 plt.figure()   
 l1, = plt.plot(x, y1)
 l2, = plt.plot(x, y2, label='you') 

 # 限制坐标轴显示范围
 plt.ylim(0,2)
 plt.xlim(0,2)

 # 找到需要标注的点
 y0 = x0 = 1
 plt.scatter(x0, y0, s=50, color='b') # 设置大小为50,蓝色
 plt.plot([1,1],[0,1],'k--')  # 绘制标注点到x轴之间的虚线 'k--'是'black'和'--'简写
 plt.plot([0,1],[1,1],'k--')  # 绘制标注点到y轴之间的虚线

 # 使用annotate进行注解描述
 plt.annotate(r'$ k_i=%s $'% y0,  # 指定注解内容 可以使用Latex
            xy=(x0, y0), xycoords='data', xytext=(+30, -30), # xy为基准坐标  coords设置偏移坐标
            textcoords='offset points', fontsize=16, # 设置字体大小
            arrowprops=dict(arrowstyle='->',    # 设置箭头类型
            connectionstyle='arc3,rad=.2'))

 # 使用text指定注解
 x1 = 0.25
 y1 = 1.5
 plt.text(x1, y1,       # 设置基准坐标
         r'$function : y={x_i}^2 $',  # 设置显示内容,可以使用Latex
         fontdict={'size':18, 'color':'r'}) # 设置字体

 plt.show()

输出图像:

NumPy实战:Chapter-2(Matplotlib入门)


程序注解:

  • 使用plt.scatter()可以绘制单个点
  • 使用plt.plot([x0,x1],[y0,y1])绘制一条从(x0,y0)到(x1,y1)的直线
  • plt.annotate()注解支持多种功能,当然对应的参数较多,操作也比较复杂,有需要的可以查查文档( 案例代码够一般用了)
  • plt.text()对指定位置作文字注解.



其他形状的数据图

上面说了figure,坐标轴设置、图例与注解等,这大多数都是和曲线相关。在许多科学计算中,需要使用到散点图,柱状图等其他不同形式的图形。下面就看看这些图形如果在matplotlib中实现。

散点图

使用matplotlib绘制散点图的方法类似于绘制曲线图,关键的在于使用的绘制函数由pyplot.plot()转为pyplot.scatter().看看一个实例就知道怎么整了。

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 n = 1024
 X = np.random.normal(0, 1, n) # 散点数据
 Y = np.random.normal(0, 1, n)

 T = np.arctan2(Y,X) # 设置一个点对应的color值,只是为了好看

 plt.scatter(X, Y, s=75, c=T, alpha=0.5) # 绘制散点图,并设置对应的颜色关系

 plt.xlim(-1.5,1.5)  # 设置x轴显示刻度范围
 plt.ylim(-1.5,1.5)

 plt.xticks(())  # 设置不显示刻度
 plt.yticks(())
 plt.show()

输出图像如下:

NumPy实战:Chapter-2(Matplotlib入门)


程序详解:

这里主要看scatter()函数.

matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None,
    vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None,
    hold=None, data=None, **kwargs)

绘制一个x和y的散点图。散点的大小由s决定,散点的颜色由c的映射(mapping)决定。

参数 description
x, y 要绘制的数据
s 要绘制的点的大小
c color, sequence, or sequence of color, optional, default: ‘b’.
可以为单一颜色,也可以为一组序列,如果为一组序列,配合cmap和norm获得映射颜色关系
marker 绘制点风格
cmap,norm 配置参数c使用
vmin, vmax 配置参数norm完成标准化亮度
alpha 透明度设置
linewidths 线宽
verts 用于构成marker
edgecolors 边框色


柱状图

按照散点图的套路,使用matplotlib绘制柱状图的方法是使用的绘制函数为pyplot.bar().下面看一个实例。

输入一下一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 # 产生数据
 n = 12
 X = np.arange(n)
 Y1 = (1-X/float(n)) * np.random.uniform(0.5, 1.0, n)
 Y2 = -((1-X/float(n)) * np.random.uniform(0.5, 1.0, n))

 # 使用bar函数绘制多个柱状图,并设置不同的颜色
 plt.bar(X, Y1, facecolor='#9999ff', edgecolor='white')
 plt.bar(X, Y2, facecolor='#ff9999', edgecolor='white')

 # 为所有柱状图标注图解 这里使用text来绘制(感觉text方便点)
 for x,y in zip(X,Y1):   # 使用zip同时传递X,Y1到x,y上
    plt.text(x, y+0.05, '%.2f'%y, ha='center',va='bottom') # ha: horizontal alignment

 for x,y in zip(X,Y2):   
    plt.text(x, y-0.05, '%.2f'%y, ha='center',va='top') # ha: horizontal alignment


 plt.xlim(-0.5,n)  # 设置x轴显示刻度范围
 plt.ylim(-1.25,1.25)

 plt.xticks(())  # 设置不显示刻度
 plt.yticks(())
 plt.show()

程序输出图像:

NumPy实战:Chapter-2(Matplotlib入门)


程序详解:

matplotlib.pyplot.bar(left, height, width=0.8, bottom=None, hold=None, data=None, **kwargs)

绘制一个柱状图。
绘制的区域为left, left + width, bottom, bottom + height (left, right, bottom and top edges)

参数 description
left,height 需要绘制的序列
width,bottom 绘制的柱状图的矩形区域大小参数
color 矩形区域的颜色
edgecolor 边缘颜色
linewidth 边缘线宽
tick_label 刻度label
xerr,yerr,ecolor 和error bar相关
align {‘center’, ‘edge’}, optional
bar的对齐方式
orientation {‘vertical’, ‘horizontal’}, optional
bars的方向


饼图

使用matplotlib绘制饼状图的方法是使用的绘制函数为pyplot.pie().下面看一个实例。

输入下面一段程序:

 #coding:utf8
 import numpy as np
 import matplotlib.pyplot as plt

 X = [1,2,3,4]

 plt.pie(X, # 要绘制的数据
    labels=['me','you','cat','dog'],  # 输入数据对应的labels
    explode=(0.2,0,0,0),  # 每个部分离中心点的距离
    #shadow=True,       # 饼状图是否有阴影
    autopct='percent:%1.1f%%',  # 每个部分所占的比例标签 支持字符串格式
    pctdistance=0.6,    # 每个部分所占比例的标签离中心点距离
    labeldistance=1.2,  # 每个部分labels离中心点的距离
    radius = 1.2,   # 饼状图的半径
    startangle=90)  # 第一个部分在饼状图上的起始角

 plt.axis('equal')  # 防止饼状图被压缩成椭圆
 plt.show()

程序输出图像:

NumPy实战:Chapter-2(Matplotlib入门)


程序详解:

matplotlib.pyplot.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)
参数 description
x 要绘制成饼状图的数据
explode 设置每个部分离中点的偏移距离
labels 每个部分设置的labels
colors 每个部分设置颜色
autopct 对每个部分所占的比例进行描述,接受的一个字符串格式,也可以是一个Latex公式
pctdistance 设置的pct描述离中心点的距离
shadow 饼状图是否有阴影
labeldistance 每个部分设置的labels离中心点的距离
startangle 绘制的第一个部分在饼状图上的起始角
radius 饼状图的半径大小


等高线图

使用matplotlib可以绘制等高线,参考下面的例子。

输入下面一段程序:

 #coding:utf8
 # 等高线
 import numpy as np
 import matplotlib.pyplot as plt

 def calcHigh(x, y):
    '''  计算高度值  '''
    return (1-x/2+ x**5 + y**3 ) * np.exp(-x**2-y**2)

 n = 256
 x = np.linspace(-3, 3, n)
 y = np.linspace(-3, 3, n)
 X, Y = np.meshgrid(x,y) # 将xy放置网格中

 # 使用contourf填充等高线内颜色 
 # 颜色映射使用hot 使用8表示分为10部分  0表示2部分
 plt.contourf(X, Y, calcHigh(X, Y), 8, alpha=0.75, cmap=plt.cm.hot) 
 #plt.contourf(X, Y, calcHigh(X, Y), 8, alpha=0.75, cmap=plt.cm.hot) # 颜色映射使用cold

 # 使用contour函数绘制等高线
 C = plt.contour(X, Y, calcHigh(X, Y), 8, colors='k', linewidth=0.5) 

 # 使用clabel对等高线做label描述
 plt.clabel(C, inline=True, fontsize=10) 

 #plt.xticks(()) # 隐藏刻度
 #plt.yticks(())

 plt.show()

输出图像为:

NumPy实战:Chapter-2(Matplotlib入门)


程序详解:

matplotlib.pyplot.contourf(*args, **kwargs)

绘制一个等高线图。使用contour()绘制等高线 and contourf() 填充等高区。
X and Y must both be 2-D with the same shape as Z, or they must both be 1-D such that len(X) is the number of columns in Z and len(Y) is the number of rows in Z

参数 description
X,Y,Z 绘制的数据和高度值
colors 颜色
alpha 透明度
cmap 颜色映射关系,有plt.cmp.hot/cold等


绘制3D图像

说了很长时间的二位图像了,matplotlib可以绘制3D图像,这需要引入一个新的模块Axes3D.

输入下面一段程序:

 #coding:utf8
 # 绘制3D图像
 import numpy as np
 import matplotlib.pyplot as plt
 from mpl_toolkits.mplot3d import Axes3D

 fig = plt.figure()
 ax = Axes3D(fig)  # 创建一个三维的ax对象

 # 创建数据
 X = np.arange(-4, 4, 0.25)
 Y = np.arange(-4, 4, 0.25)
 X, Y = np.meshgrid(X,Y)
 Z = np.sin(np.sqrt(X**2 + Y**2))

 # 将数据绘制到坐标轴上 颜色映射为rainbow
 ax.plot_surface(X, Y, Z, 
        rstride=1, cstride=1, cmap=plt.get_cmap('rainbow'))
 # 绘制等高线,选择的绘制方向是z轴视角
 ax.contourf(X,Y,Z,zdir='z',offset=-2,cmap='rainbow')
 ax.set_zlim(-2, 2)
 fig.colorbar(suf,shrink=0.5)  # 添加颜色bar
 plt.show()

输出图像为:

NumPy实战:Chapter-2(Matplotlib入门)


程序详解:

Axes3D.plot_surface(X, Y, Z, *args, **kwargs)
创建一个surface图,支持使用cmap. 使用rstride and cstride参数决定了图像分割的尺度。
参数 description
X, Y, Z Data values as 2D arrays
rstride/cstride Array row stride (step size)/ Array column stride (step size)
rcount/ccount Use at most this many rows, defaults to 50
Use at most this many columns, defaults to 50
color Color of the surface patches
cmap A colormap for the surface patches.
facecolors Face colors for the individual patches
norm/vmin/vmax An instance of Normalize to map values to colors
shade Whether to shade the facecolors



从面向对象角度再看matplotlib

前面我们讲了一堆如何使用matplotlib,这些操作应付一般的绘图任务是没问题的,但是如果想深入了解并系统的学习下Matplotlib,可以看看下面的内容。

学过Java中的Swing、VC中的MFC、Qt的小伙伴们对画布、容器这些词应该不陌生,在Matplotlib同样也有自己的一套对象逻辑。

本节内容参考Vamei-绘图: matplotlib核心剖析

先看下面的例子:

 from matplotlib.figure import Figure
 from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

 fig   = Figure()
 canvas= FigureCanvas(fig)
 ax    = fig.add_axes([0.1, 0.1, 0.8, 0.8])

 line,  = ax.plot([0,1], [0,1])
 ax.set_title("a straight line (OO)")
 ax.set_xlabel("x value")
 ax.set_ylabel("y value")

 canvas.print_figure('demo.jpg')

 print(fig.__class__.__name__)
 print(canvas.__class__.__name__)
 print(ax.__class__.__name__)
 print(line.__class__.__name__)

 '''
 输出:

 Figure
 FigureCanvasAgg
 Axes
 Line2D

 '''

运行程序,输出下面的demo.jpg图:

NumPy实战:Chapter-2(Matplotlib入门)

在上面的程序,我们声明了Figure对象,FigureCanvas对象,还有ax对象和line对象。这分别属于Figure类,FigureCanvas类,Axes类和Line2D类。这几个对象之间有啥关系呢?

理解对象之间的关系

我们先来看什么是Figure和Axes对象。在matplotlib中,整个图像为一个Figure对象。在Figure对象中可以包含一个,或者多个Axes对象。每个Axes对象都是一个拥有自己坐标系统的绘图区域。其逻辑关系如下

NumPy实战:Chapter-2(Matplotlib入门)

转过头来看demo.jpg,整个图像是fig对象。我们的绘图中只有一个坐标系区域,也就是只有一个ax对象。此外还有以下对象。(括号中表示对象的基本类型)

NumPy实战:Chapter-2(Matplotlib入门)

Title为标题。Axis为坐标轴,Label为坐标轴标注。Tick为刻度线,Tick Label为刻度注释。各个对象之间有下面的对象隶属关系:

NumPy实战:Chapter-2(Matplotlib入门)

虽然Data是数据绘图的关键部分,也就是数据本身的图形化显示,但是必须要有xaxis, yaxis, title一起,才能真正构成一个绘图区域axes。一个单纯的,无法读出刻度的线是没有意义的。xaxis, yaxis, title合起来构成了数据的辅助部分(data guide)。

上面元素又包含有多种图形元素。比如说,我们的data对象是一条线(Line2D)。title, tick label和label都是文本(Text),而tick是由短线(Line 2D)和tick label构成,xaxis由坐标轴的线和tick以及label构成,ax由xaxis, yaxis, title, data构成,ax自身又构成了fig的一部分。上面的每个对象,无论是Line2D, Text还是fig,它们都来自于一个叫做Artist的基类。

OO绘图的原程序还有一个canvas对象。它代表了真正进行绘图的后端(backend)。Artist只是在程序逻辑上的绘图,它必须连接后端绘图程序才能真正在屏幕上绘制出来(或者保存为文件)。我们可以将canvas理解为绘图的物理(或者说硬件)实现。

在OO绘图程序中,我们并没有真正看到title, tick, tick label, xaxis, yaxis对象,而是使用ax.set_*的方法间接设置了这些对象。但这些对象是真实存在的,你可以从上层对象中找到其“真身”。比如,fig.axes[0].xaxis就是我们上面途中的xaxis对象。我们可以通过fig -> axes[0] (也就是ax) -> xaxis的顺序找到它。因此,重复我们刚才已经说过的,一个fig就构成了一个完整的图像。对于每个Artist类的对象,都有findobj()方法,来显示该对象所包含的所有下层对象。

坐标

坐标是计算机绘图的基础。计算机屏幕是由一个个像素点构成的。想要在屏幕上显示图像,计算机必须告诉屏幕每个像素点上显示什么。所以,最贴近硬件的坐标体系是以像素为单位的坐标体系。我们可以通过具体说明像素位置来标明显示器上的某一点。这叫做显示坐标(display coordinate),以像素为单位。

然而,像素坐标不容易被纳入绘图逻辑。相同的程序,在不同的显示器上就要调整像素值,以保证图像不变形。所以一般情况下,还会有图像坐标和数据坐标。

图像坐标将一张图的左下角视为原点,将图像的x方向和y方向总长度都看做1。x方向的0.2就是指20%的图像在x方向的总长,y方向0.8的长度指80%的y方向总长。(0.5, 0.5)是图像的中点,(1, 1)指图像的右上角。比如下面的程序,我们在使用add_axes时,传递的参数中,前两个元素为axes的左下角在fig的图像坐标上的位置,后两个元素指axes在fig的图像坐标上x方向和y方向的长度。fig的图像坐标称为Figure坐标,储存在为fig.transFigure

(类似的,每个axes,比如ax1,有属于自己的图像坐标。它以ax1绘图区域总长作为1,称为Axes坐标。也就是ax1.transAxes。(0.5, 0.5)就表示在Axes的中心。Axes坐标和Figure坐标原理相似,只是所用的基准区域不同。)

 # object-oriented plot
 from matplotlib.figure import Figure
 from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

 fig    = Figure()
 canvas = FigureCanvas(fig)

 # first axes
 ax1    = fig.add_axes([0.1, 0.1, 0.2, 0.2])
 line,  = ax1.plot([0,1], [0,1])
 ax1.set_title("ax1")

 # second axes
 ax2    = fig.add_axes([0.4, 0.3, 0.4, 0.5])
 sca    = ax2.scatter([1,3,5],[2,1,2])
 ax2.set_title("ax2")

 canvas.print_figure('demo.jpg')

我们在绘图,比如使用plot的时候,绘制了两点间的连线。这两点分别为(0, 0)和(1, 1)。(plot中的第一个表为两个x坐标,第二个表为两个y坐标)。这时使用的坐标系为数据坐标系(ax1.transData)。我们可以通过绘出的坐标轴读出数据坐标的位置。

NumPy实战:Chapter-2(Matplotlib入门)

如果绘制的是具体数据,那么数据坐标符合我们的需求。如果绘制的是标题这样的附加信息,那么Axes坐标符合符合我们的需求。如果是整个图像的注解,那么Figure坐标更符合需求。每一个Artist对象都有一个transform属性,用于查询和改变所使用的坐标系统。如果为显示坐标,transform属性为None。



参考资料

莫烦Pyton教程莫烦教程主页

作者:Vamei 出处:http://www.cnblogs.com/vamei