美文网首页
0. matplotlib入门

0. matplotlib入门

作者: ydlstartx | 来源:发表于2018-05-16 18:13 被阅读0次

    这篇笔记主要来自《利用python进行数据分析》的第八章第一节,对matplotlib的基本使用介绍的特别清晰。关于matplotlib的基本概念(figure, subplot, axes)的介绍还可以看这里

    • Figure和Subplot
    • 颜色、标记和线型
    • 刻度、标签和图例
    • 注解
    • 保存到文件

    pyplot模块的API文档,这里

    1. Figure和Subplot

    plt.figure()

    matplotlib的图像都位于Figure对象中,可以使用plt.figure()创建一个新的figure:

    >>> fig = plt.figure()
    

    在ipython中,执行后会弹出一个空窗口:

    一个Figure

    该窗口的大小可以通过在plt.figure()中传递参数figsize=(width,height)来指定。

    可以看到窗口的标题为“Figure 1”,要想设定Figure编号为3,则可执行:

    >>> fig = plt.figure(3)
    

    可通过plt.gcf()来获得最后一次创建的Figure对象的引用。

    Figure.add_subplot()

    现在虽然有了一个Figure对象fig,但是还不能在其上画图。必须使用add_subplot()在fig上创建一个或多个subplot才行:

    # 等价于fig.add_subplot(221)
    # 意思是将fig划分为2x2,指定第一个为画图位置
    # 这里的subplot从1开始编号
    # 其实就是在fig中固定位置创建了一个Axes对象。
    >>> ax1 = fig.add_subplot(2, 2, 1)
    

    执行后会得到:

    Figure中有一个subplot(Axes对象)

    若接着执行:

    # 执行后fig中就有了三个Axes对象
    >>> ax2 = fig.add_subplot(2, 2, 2)
    >>> ax3 = fig.add_subplot(2, 2, 3)
    

    得到:

    Figure中有三个subplot(Axes对象)

    fig.add_subplot(2, 2, 1)并不意味着对于该fig,固定划分了2x2个subplot,这只是指出一个固定的位置来确定要创建的Axes对象。比如还可以接着执行下面的代码再创建个小的Axes对象:

    >>> ax4 = fig.add_subplot(339)
    

    结果为:

    也可将其放到其他位置,放这里方便看

    可以看到Figure.add_subplot()的功能是将Axes对象创建于规则的网格(grid)上的,如果想要在Figure中的任意位置创建任意大小的Axes对象可使用Figure.add_axes()

    plot()

    如果这时发出一条绘图命令,matplotlib会在最后一个用过的Axes对象上(如果没有则自动创建一个)进行绘制。

    # 绘制黑色'k'虚线'--'
    >>> plt.plot(np.random.randn(50).cumsum(), 'k--')
    

    结果为:

    可见是在最后一个创建的Axes对象上绘制的

    如果想要在其他的axes中绘图,则可以调用之前的Axes对象中的绘图方法

    # hist方法有三个返回值,不想显示就将其赋给以变量
    >>> _ = ax1.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
    >>> ax2.scatter(np.arange(30), np.arange(30) + 3*np.random.randn(30))
    

    结果如下:

    plt.subplots()

    有一条语句可以快速的建立Figure和一组subplots,也就是plt.subplots()。它可以创建一个新的Figure,并返回一个含有已创建的Axes对象的numpy数组:

    # 创建一个Figure对象fig2,并在其上绘制2x3个subplots
    # fig2为新创建的Figure对象
    # axess为一2x3数组,其中元素为Axes对象。
    >>> fig2, axess = plt.subplots(2,3)
    

    执行上述语句,会弹出一个新的Figure窗口:

    与之前不同,这里直接画出了2x3个subplot

    之前使用plt.figure()创建Figure对象时,可以传递figsize参数来指定Figure对象的大小。在plt.subplots()中也可以传递该参数,见文档中对**fig_kw参数的描述。
    但是如果在创建完Figure对象后想改变figure size该怎么办呢?可调用Figure类的方法set_figheight()set_figweight()来分别设置Figure对象的长和宽。可见Figure类的文档说明

    可以看axess的内容:

    >>> axess
    array([[<matplotlib.axes._subplots.AxesSubplot object at 0x1178f9240>,
            <matplotlib.axes._subplots.AxesSubplot object at 0x117920438>,
            <matplotlib.axes._subplots.AxesSubplot object at 0x117947710>],
           [<matplotlib.axes._subplots.AxesSubplot object at 0x117b28438>,
            <matplotlib.axes._subplots.AxesSubplot object at 0x117b50748>,
            <matplotlib.axes._subplots.AxesSubplot object at 0x117b7a9e8>]], dtype=object)
    

    可以通过指定参数sharex=True使各列Axes对象使用同一个x轴(这样,调整某列的xlim将会影响对应的axes),而设置sharey=True使各行Axes对象使用同一个y轴(这样,调整某行的ylim将会影响对应的axes)。

    >>> plt.close(2)
    >>> fig2, axess = plt.subplots(2,3, sharex=Ture, sharey=Ture)
    

    结果为:

    plt.subplots_adjust()

    默认情况下(matplotlib有默认的配置文件),matplotlib会在subplot外围留下一定的边距,并在subplot之间留下一定的间距。利用plt.subplots_adjust()Figure.subplots_adjust()可以修改这些间距。两个函数的参数都是一样的(见文档),但前者是在当前Figure中操作,而后者是在指定的Figure中操作的。

    # 操作的是fig2
    >>> plt.subplots_adjust(wspace=0, hspace=0)
    

    结果为:

    可以看到matplotlib中的画图是很自由的,并不会检查坐标的重叠。

    # 操作的是上面的Figure 1
    >>> fig.subplots_adjust(wspace=0, hspace=0)
    

    结果为:

    当画完图之后,要记得使用plt.close()关掉对应的Figure,释放内存。有多种关闭方式,可看文档。

    # 关闭所有Figure。
    >>> plt.close('all')
    

    总结一下,Figure对象就相当于一个巨大的画板,可以在画板上放置多个画纸,各个画纸也就是Axes对象,画图就是画在Axes对象上的。各个Axes对象都有自己的坐标轴,可以分别控制。文档中对这几个概念的描述在这里。其中有张图可以很好的理解Figure与Axes的各部分。

    下面都以plot画线来介绍。

    2. 颜色、标记和线型

    上一节中调用plot()画线时(plt.plot()axes.plot()),传递了一个参数'k--',指出画的线为黑色虚线,这是对线的颜色和形式一种便捷的设置,这种简便写法中还可以加入一个标记的形式控制(也就是(x,y)点的形式)。

    注意,plot()的字典参数**kwargs用于指定要画的Line2D线对象的各种属性。

    控制格式为,注意顺序不能变:
    fmt = '[color][marker][line]'

    如:

    >>> fig, ax = plt.subplots(1,1)
    # 相当于,这种显示控制:
    # ax.plot(np.random.randn(20), linestyle='-', color='r', marker='o')
    >>> ax.plot(np.random.randn(20), 'ro-')
    

    得到下图:


    fmt中的三项都是可选的,各项可配置的值可看这里的Notes部分。

    但是要注意,fmt这种简便设置方式与显示参数的设置还是不同的。

    # 只设置颜色和marker形式,则只画点,不画线
    >>> ax.plot(np.random.randn(20), 'bo‘)
    
    # 虽只设置颜色和marker形式,依然画出了线
    >>> ax.plot(np.random.randn(20), color='g', marker='o')
    

    另外使用color参数设置颜色时,或fmt中只设置颜色时,可以使用更多的颜色设置方式,具体可看这里

    在线型图中,非实际的数据点默认是按照线性方式插值的。可以通过plot()的参数drawstyle来修改插值方式:

    # 清除axes上的绘制
    >>> ax.clear()
    >>> ax.plot(np.random.randn(20), 'ko-', drawstyle='steps-post')
    

    3. 刻度、标签和图例

    这一节讲解的就是对坐标轴的控制,包括轴标签、轴刻度的标签、轴刻度、轴刻度范围、图例。下面都是显示指定要控制的Axes对象,使用Axes类中的方法。

    先绘制一个简单的图像,并在其上举例。

    >>> fig, ax = plt.subplots(1,1)
    >>> np.random.seed(985)
    >>> ax.plot(np.random.randn(30), 'ro-')
    
    # 设置标题
    >>> ax.set_title('random plot')
    # 设置xy轴标签
    >>> ax.set_xlabel('x')
    >>> ax.set_ylabel('y')
    

    对应的,可以通过Axes.get_title()Axes.get_xlabel()Axes.get_ylabel()来得到对应的值。

    >>> ax.get_title()
    'random plot'
    >>> ax.get_xlabel()
    'x'
    >>> ax.get_ylabel()
    'y'
    
    • 轴的范围
      由于没有指定要画线的x值,所以默认为range(0,30),而看图上的x轴坐标范围,其在左右明显要小于0并大于29,我们可以使用Axes.get_xlim()Axes.get_ylim()来分别得到x轴和y轴的坐标范围。
    >>> ax.get_xlim()
    (-1.4500000000000002, 30.449999999999999)
    >>> ax.get_ylim()
    (-1.271508964835969, 2.6919009419421762)
    

    可见画图时默认增加了些冗余,当然我们可以对其更改。

    可以使用Axes.set_xlim()Axes.set_ylim()来分别设置轴的范围:

    >>> ax.set_xlim(-10, 40)
    

    同样也可以缩小:

    >>> ax.set_xlim(10, 20)
    

    两次缩放了轴的范围,与原始图对比下可发现,在缩放中,x坐标(只操作了x轴)刻度也在自动变化。这是因为我们没有显示设置x轴的坐标刻度值,所以matplotlib自动设置的。如果显示设置了,那么会一直使用我们设置好的,不论如何缩放轴范围。

    # 接着上面执行代码。
    >>> ax.get_xticks()
    array([ 10.,  12.,  14.,  16.,  18.,  20.])
    >>> ax.get_yticks()
    array([-1.5, -1. , -0.5,  0. ,  0.5,  1. ,  1.5,  2. ,  2.5,  3. ])
    

    可见也就是轴上的坐标值,同样的可以使用Axes.set_xticks()Axes.set_yticks()来更改:

    # 会返回一个列表,包含11个创建的XTick对象。
    >>> ticks = ax.set_xticks(range(0,33,3))
    
    可见自动按我们设置的x坐标来放大了x轴范围

    此时x轴的坐标刻度也就固定了,再放大x轴范围也不会改变坐标刻度,而只是缩放了图像。如:

    # 设置为最初的x轴范围
    >>> ax.set_xlim(-1.4500000000000002, 30.449999999999999)
    
    • 轴刻度标签的控制
      目前在x轴上有11个刻度,都是数字表示的,还可以使用Axes.set_xticklabels()将其他任何值用做标签:
    # 改为其他数值
    >>> labels = ax.set_xticklabels(range(10,43,3))
    
    # 改为字符串
    >>> labels = ax.set_xticklabels([i for i in 'abcdefghijk'])
    
    # 指定的字符串还可以为LateX数学表达式。
    >>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)])
    

    此外,可以对函数Axes.set_xticklabels()的**kwargs传入其他参数来控制Text对象的属性。如字体角度rotation和字体大小fontsize(其他属性可看文档):

    >>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,12)], rotation = 30, fontsize='large')
    

    此外,因为我们使用了Axes.set_xticks()设置了11个坐标刻度,所以在Axes.set_xticklabels()中需要传递长度11的列表指定这11刻度的label。如果列表长度小于11的话,如5,那么,只改变前5个刻度的label,后6个刻度的label为空,也就啥也没有。如果列表中的元素多于11个,那么只用前11个。

    >>> labels = ax.set_xticklabels([r'$x^{%s}$'%i for i in range(1,5)], rotation = 30, fontsize='large')
    
    • 图例
      可以使用Axes.legend()在Axes中添加图例,对绘制进行说明。

    对于上面画的红线,现在加入一个图例:

    # 返回Legend对象
    >>> l1 = ax.legend(['red'])
    

    这种方法是不推荐的,因为当Axes中绘制了多条线后,需要在legend()中传入对应着画线顺序的label,而该顺序很容易搞混的。

    常用的一种加入图例方法是在画图是传入label参数,然后在使用legend():

    >>> np.random.seed(211)
    >>> ax.plot(np.random.randn(30), 'ko--', label='black')
    >>> ax.legend()
    
    这时只有一个图例了,因为画红线时没有传入label

    还用一种更为全面的控制方式,即指出需要图例的那条线和其对应的字符串,清除掉这两条线,重画下:

    >>> ax.clear()
    >>> np.random.seed(233)
    # 注意,plot()返回的是包含Line2D对象的列表,如果不加',‘,那么l1是列表。
    >>> l1, = ax.plot(np.random.randn(30), 'ko-')
    >>> np.random.seed(666)
    >>> l2, = ax.plot(np.random.randn(30), 'ro--')
    # 将Line2D对象放入第一个列表中,第二个列表中的字符串顺序要一致。
    >>> ax.legend([l1,l2], ['black', 'red'])
    

    关于图例的控制(位置、字体等),可看文档Axes.legend()

    4. 注解

    • 文本的绘制

    在Axes对象中绘制文本可使用函数Axes.text()。该函数的使用很简单,传入坐标和文本,就会将文本绘制在对应的坐标上。可以向函数传入Text属性来控制文本的显示。

    >>> fig, ax = plt.subplots(1,1)
    >>> x = np.linspace(-np.pi,np.pi,100, endpoint=True)
    >>> y = np.sin(x)
    >>> ax.plot(x,y, 'k-')  
    >>> ax.set_xticks(np.arange(-np.pi,np.pi+1,np.pi/4))
    # 这些tick labels本身就是Text对象。该函数会返回包含对应的9个Text对象的列表。
    >>> ax.set_xticklabels([r'$-\pi$', r'$-\frac{3}{4}\pi$', r'$-\frac{1}{2}\pi$', r'$-\frac{1}{4}\pi$', r'0', r'$\frac{1}{4}\pi$', r'$\frac{1}{2}\pi$',r'$\frac{3}{4}\pi$', r'$\pi$'])
    # 在原点绘制文本,后面的参数设置文本的显示属性。
    # ha和va设置的是文本相对(0,0)的位置,‘center'是以点为中心。
    >>> ax.text(0,0, r'hello world!', color='r', ha='center', va='center',rotation=30, size='medium', style = 'italic' )
    
    • 注释

    在图上绘制注释使用的是Axes.annotate)()。关于该函数的使用例子可看这里

    # 在坐标(-1,0.5)处写Text对坐标(0,0)进行注释。
    >>> ax.annotate(s=r'origin', xy=(0,0), xytext=(-1,0.5), arrowprops={'arrowstyle':'->'})
    

    5. 保存到文件

    使用plt.save()可将当前Figure中的内容保存到文件(也可以是file-like object)中。

    文件的类型可以通过给定的文件名扩展名推断出来,或者指定函数参数format。

    相关文章

      网友评论

          本文标题:0. matplotlib入门

          本文链接:https://www.haomeiwen.com/subject/ayfpdftx.html