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

这里写图片描述

  • 简介
    • 安装Matplotlib
  • Matplotlib的使用
    • 基本用法
    • Figure图像
      • 关于Figure类的参数注释
      • 关于plot函数的参数注释
    • 绘制多个子图
      • 使用subplot绘制子图
      • 使用subplot2grid绘制子图
    • 坐标轴设置
      • 坐标轴的基本设置
      • 设置坐标轴的样式和位置
      • 程序注解
      • 修改ticks的能见度
    • 图例与标注
      • 图例案例
      • 程序注解
      • 注解案例
      • 程序注解
  • 其他形状的数据图
    • 散点图
      • 程序详解
    • 柱状图
      • 程序详解
    • 饼图
      • 程序详解
    • 等高线图
      • 程序详解
    • 绘制3D图像
      • 程序详解
  • 从面向对象角度再看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入门)_第1张图片

注意到在输出的图像中,还有一些分析图像的操作:局部放大操作,修改边框等(类似于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入门)_第2张图片

NumPy实战:Chapter-2(Matplotlib入门)_第3张图片

可以看到,我们可以创建多个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入门)_第4张图片

使用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入门)_第5张图片


坐标轴设置

上面说完了如何创建图像和绘制不同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入门)_第6张图片


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

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

NumPy实战:Chapter-2(Matplotlib入门)_第7张图片


设置坐标轴的样式和位置

先看一下的一段程序:

 #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入门)_第8张图片


程序注解:

  • 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入门)_第9张图片

修改ticks的能见度

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

NumPy实战:Chapter-2(Matplotlib入门)_第10张图片

输入下面一段程序:

 #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入门)_第11张图片



图例与标注

图例案例

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

NumPy实战:Chapter-2(Matplotlib入门)_第12张图片

输入下面一段程序:

 #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入门)_第13张图片


程序注解:

可以注意到:这里应用了一个新的函数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入门)_第14张图片


注解案例

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

NumPy实战:Chapter-2(Matplotlib入门)_第15张图片

输入下面一段程序:

 #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入门)_第16张图片


程序注解:

  • 使用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入门)_第17张图片


程序详解:

这里主要看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入门)_第18张图片


程序详解:

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入门)_第19张图片


程序详解:

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入门)_第20张图片


程序详解:

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入门)_第21张图片


程序详解:

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入门)_第22张图片

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

理解对象之间的关系

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

NumPy实战:Chapter-2(Matplotlib入门)_第23张图片

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

NumPy实战:Chapter-2(Matplotlib入门)_第24张图片

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

NumPy实战:Chapter-2(Matplotlib入门)_第25张图片

虽然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入门)_第26张图片

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



参考资料

莫烦Pyton教程莫烦教程主页

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

你可能感兴趣的:(NumPy)