Matplotlib——中级

 关于Matplotlib的愚见

初级中,我只是简单介绍了Matplotlib的使用方法,在中级部分,我系统地说一下我总结的内容。

 

上图是我画的关于Matplotlib几个对象之间的关系图。它们都来自于一个叫做Artist的基类。我们知道绘制图的基础是Canvas,它是我们真正进行绘图的后端。Artist只是在程序逻辑上的绘图,它必须连接后端绘图程序才能真正在屏幕上绘制出来(或者保存为文件)。我们可以将canvas理解为绘图的物理(或者说硬件)实现。对于每个Artist类的对象,都有findobj()方法,来显示该对象所包含的所有下层对象。

 Artist对象的所有属性都通过相应的get_*和set_*函数来读写。在后面的例子中,很多都不是对fig的操作,而是对ax的操作,这里要记住这种方法。

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

 如果要同时给多个属性进行设置的话,可以使用set函数: 

fig.set(alpha = 0.5, zorder=2)

 使用matplotlib.pyplot.getp 函数则可以方便地输出Artist对象的所有属性名和值。

plt.getp(fig.patch)

生成多张画布

比如

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 10)
print(x)
y = x*2+1
z = x**2

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

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

plt.show()

 运行效果为:

 和   

如果不写的话,默认是从1开始算。我们也可以在里面指定参数,用来给这个画布编号,比如:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = x*2+1
z = x**2

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

plt.figure(num=3, figsize=(8, 5))
plt.plot(x, z)

plt.show()

 运行效果为:

  和   

坐标轴常用设置

  • xlim、ylim方法设置坐标轴刻度取值范围
  • xlabel、ylabel方法设置x轴和y轴的标题
  • xticks,yticks方法设置x,y轴的刻度标签值

例子:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = x*2+1

plt.figure(1)
plt.plot(x, y)

plt.figure(2)
plt.plot(x, y)

# 设置坐标轴取值范围
plt.xlim((-2, 2))
plt.ylim((0, 3))

# 设置坐标轴标题
plt.xlabel("我是横坐标")
plt.ylabel("我是纵坐标")

# 设置刻度标签
new_ticks = np.linspace(-1, 4, 6)
plt.xticks(new_ticks)    # 将原有x轴刻度标注修改,图也会随着坐标改变而改变。
plt.yticks([1, 2, 3],
          ["", r"$I\ am\ middle$", ""])     # 用第二个参数的值一一替换第一个参数的值。


plt.show()

 运行效果为:

  和   

坐标轴边框设置及位置移动

这里我们需要认识的是:gca,它的意思是get current axis(获取当前轴)。

获取了当前绘图区(轴)之后我们再通过ax.spines对其进行操作,spines是脊柱的意思。

具体的操作如下例:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = x*2+1

plt.figure(1)
plt.plot(x, y)

plt.figure(2)
plt.plot(x, y)

# 去掉上和右边的边框线
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", 0))  # data表示用值来选择,这个句话的意思就是用X坐标轴上值为0的点作为坐标系原点。"data"只是一个参数,还有outward,axes等参数,它们都有不同的意义。
ax.spines["left"].set_position(("data", 0))   # 同上

plt.show()

  运行结果为:

  和     

图例的设置

在初级,我们说过简单的设置图例,这里我们在进行一些拓展的说明。

例子:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = x*2+1
z = x**2

plt.figure(1)
L1, = plt.plot(x, y, label="$x*2+1$")  # L1后面的逗号是matplotlib特殊的写法
L2, = plt.plot(x, z, label="$x^2$")

plt.legend(handles=[L1], labels=["a", "b"], loc="best") # handles是用来控制放入图例的内容。labels是用来给handles对应的图修改图例名。

plt.show()

 运行结果为:

在图片中添加注解

在讲解给图片添加注解之前呢,我们需要认识一下scattter函数,我们在绘制图像的时候使用的是plot,它是线的形式,如果我们使用scatter的话,它就会用点的形式来绘制。 

 下面是示例代码:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = x*2+1

plt.figure(1)
plt.plot(x, y)

plt.figure(2)
plt.plot(x, y)

# 去掉上和右边的边框线
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", 0))  # data表示用值来选择,这个句话的意思就是用X坐标轴上值为0的点作为坐标系原点。"data"只是一个参数,还有outward,axes等参数,它们都有不同的意义。
ax.spines["left"].set_position(("data", 0))   # 同上

# 设置标注
x0 = 1 
y0 = 2*x0 + 1
plt.scatter(x0, y0, s=50, color="b")      # 设置要标注的点,scatter和plot函数一样可以绘制图形,不过它是用点构成的图形。其中s是控制大小,color是控制颜色。
plt.plot([x0, x0], [y0, 0], "k--", lw=1)    # 设置一个黑色的虚线。

plt.annotate(r'$2x+1=%s$' % y0, xy=(x0, y0), xycoords='data', xytext=(+30, -30),
             textcoords='offset points', fontsize=16,
             arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2"))
"""
下面是annotate中每个参数设置的意思:
plt.annotate(r"$2x+1\ =\ %s$" % y0,  # 标注的文字描述
              xy=(x0, y0),           # xy是设置要标注的点。
              xycoords="data",       # xycoords表示前面xy设置的内容以"data"的值为基准。
              xytext=(+30, -30),      # 标注信息在要标注的点的横坐标加30,纵坐标减30的位置显示。
              textcoords="offset point",   # xtext设置的内容以"offset point",也就是偏移量为基准。
              fontsize=16,         # 设置字体的大小
              arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2")  # 设置箭头。arrowstyle的设置表示使用箭头,connectionstyle是用来设置弧度的。
             )      
"""

plt.text(-3.7, 3, r'$This\ is\ the\ some\ text. \mu\ \sigma_i\ \alpha_t$',
         fontdict={'size': 16, 'color': 'r'})

"""
下面是text中每个参数设置的意思:
plt.text(-3.7, 3,      # 文字显示的位置
        r'$This\ is\ the\ some\ text. \mu\ \sigma_i\ \alpha_t$',    # 显示的文字
         fontdict={'size': 16, 'color': 'r'})           # 文字的格式

"""

plt.show()

 运行结果如下:

  和   

当线遮挡刻度标注解决办法

示例代码:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y = 0.1*x

plt.figure()
# 在 plt 2.0.2 或更高的版本中, 设置 zorder 给 plot 在 z 轴方向排序
plt.plot(x, y, linewidth=10, zorder=1)
plt.ylim(-2, 2)
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))

for label in ax.get_xticklabels() + ax.get_yticklabels():
    label.set_fontsize(12)    # 设置字体大小

    label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.7, zorder=2))
    """
    set_bbox的参数说明:
     label.set_bbox(dict(facecolor='white',    # 背景颜色
                     edgecolor='None',    # 边框
                     alpha=0.7,        # 背景透明度
                     zorder=2))    # 在 plt 2.0.2 或更高的版本中, 设置 zorder 给 plot 在 z 轴方向排序
    """
plt.show()

 运行结果:

 同画布绘制多图

方式1:使用subplot来绘制

在初级中,我们说过我们画一个图是要在一个画布上,我们画的图在Matplotlib中被称为轴或者绘图区,一个画布中可以包含多个绘图区,每个绘图区都拥有自己坐标系统的绘图区域。我们可以通过subplot()函数来快速绘制有多个绘图区的画布。

它的格式为:

plt.subplot(numRows, numCols, plotNum)

 subplot将整个绘图区域划分为numRows行和numCols列个区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,如下图所示。

在使用的时候,有的人可能会看到subplot(324)这样的设置,这样也是正确的写法,它等效于subplot(3, 2, 3)。如果numRows、numCols、plotNum这三个数都小于10的话,可以把它们缩写为一个整数。

如果新建的轴和之前的轴位置重叠的话,原来的轴会被覆盖。

使用例子如下:

import matplotlib.pyplot as plt
plt.figure()

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

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

plt.subplot(223)
plt.plot([0, 1], [0, 3])

plt.subplot(224)
plt.plot([0, 1], [0, 4])

plt.show()

 运行效果为:

我们还可以自定义它们的跨列显示

import matplotlib.pyplot as plt
plt.figure()

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

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

plt.subplot(235)
plt.plot([0, 1], [0, 3])

plt.subplot(236)
plt.plot([0, 1], [0, 4])

plt.show()

 运行代码如下:

 

说明:

使用subplot是比较别扭的,要大概了解它的绘制顺序。在上面例子中,

(2, 1, 1),第一个参数表示figure分为两行,第二个参数表示分为一列,第三个表示它使用第一个图绘制。

(2, 3, 4),第一个参数表示figure分为两行,第二个参数表示分为三列,第三个表示它使用第四个图绘制(因为第一行是跨3列,所以这个是从第四个开始计算)。(2, 3, 5)和(2, 3, 6)同理。

 不同figure切换加figure切分的例子:

import numpy as np
import matplotlib.pyplot as plt 

plt.figure(1)
plt.figure(2)
ax1= plt.subplot(221)
ax2 = plt.subplot(222)
ax3 = plt.subplot(212)
x = np.linspace(0, 3, 100)
for i in range(5):
    plt.figure(1)
    plt.plot(x, np.exp(i*x/3))
    plt.sca(ax1)
    plt.plot(x, np.sin(i*x))
    plt.sca(ax2)
    plt.plot(x, np.cos(i*x))
    plt.sca(ax3)
    plt.plot(x, np.exp(i*x/3))
plt.show()

 它的效果如图:

 从上面的例子中我们可以看出:使用subplot()会返回它所创建的绘图区,通过变量保存后,我们可以使用sca()函数交替让它们成为当前绘图区,然后调用plot()函数在这个绘图区里面绘制图形。如果有多个画布,我们可以用figure()函数来指定一个画布。如果这个画布存在则将该画布变为当前画布,如果不存在则创建一个对应的画布。

方式2:使用subplot2grid来绘制

subplot2grid使用起来要比第一种subplot的方式要更直观和清晰些。我们来看看例子:

import matplotlib.pyplot as plt

plt.figure()
ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3, rowspan=1)   # 第一个参数是整个figure分为几个块,第一个为行,第二个为列;第二个参数为这个图形的起始位置,位置是从0开始计算的;第三个和第四个分别设置这个图形占据几列和几行。
ax1.plot([1, 2], [2, 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))

 运行结果:

方式3:使用gridspec来绘制

使用它之前我们要先导入:

import matplotlib.gridspec as gridspec

 让我们再看看实际的使用:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

plt.figure()
gs = gridspec.GridSpec(3, 3) # 将一个figure分成3*3的格子。

ax1= plt.subplot(gs[0, :])     # 占第0行和所有列
ax2 = plt.subplot(gs[1, :2])    # 占第1行和第2列前的所有列
ax3 = plt.subplot(gs[1:, 2])   # 占第1行后的所有行和第2列
ax4 = plt.subplot(gs[-1, 0])    # 占倒数第1行和第0列
ax5 = plt.subplot(gs[-1, -2])  # 占倒数第1行和倒数第2列.

 运行结果:

方式4:使用subplots来绘制

注意,这个和第一种方法不同,第一种创建方式我们使用的是subplot,这里我们使用的是subplots。

 使用例子:

import matplotlib.pyplot as plt

f,((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=False) 
plt.tight_layout()    # 不加会紧凑显示
ax1.plot([1, 2], [2, 2])   # ax1中绘制图像。
plt.show()

"""
说明:
使用plt.subplots建立一个2行2列的图像窗口,
sharex=True表示共享x轴坐标, 
sharey=True表示共享y轴坐标。
((ax11, ax12), (ax13, ax14))表示第1行从左至右依次放ax1和ax2, 第2行从左至右依次放ax3和ax4.
"""

 运行效果:

 绘制图内图

代码:

# 导入pyplot模块
import matplotlib.pyplot as plt

# 初始化figure
fig = plt.figure()

# 创建数据
x = [1, 2, 3, 4, 5, 6, 7]
y = [1, 3, 4, 2, 5, 8, 6]
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8    # 4个值都是占整个figure坐标系的百分比。在这里,假设figure的大小是10x10,那么大图左边距为1,底边距为1,宽8,高8的坐标系内。

# 绘制外围图
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y, 'r')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_title('title')

# 绘制内图
left, bottom, width, height = 0.2, 0.5, 0.3, 0.3
ax2 = fig.add_axes([left, bottom, width, height])   # 假设figure的大小是10x10,那么大图左边距为2,底边距为5,宽3,高3的坐标系内。
ax2.plot(y, x, 'b')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_title('title inside 1')

 运行结果为:

 

posted @ 2018-12-13 15:04  苦行僧95  阅读(572)  评论(0编辑  收藏  举报