0. matplotlib入门

这篇笔记主要来自《利用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。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容