Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析

Matplotlib 是一个用于绘制图表的 Python 标准库,可以用来完成可视化、数据分析、动画制作、科研制图等任务。本文介绍如何在 Matplotlib 的图表中嵌入图片。Matplotlib 中用来显示图片的基本函数是 plt.imshow,根据不同的用途,该函数有多种用法,本文将一一介绍。本文内容按照知识点的递进关系先后展开叙述,适合顺序阅读。

目录

单纯展示图片

如果只是想单纯展示一张图片,只需先用 pillow 库读取图片,再调用 plt.imshow(img_data) 即可。

import matplotlib.pyplot as plt
from PIL import Image

plt.axis('off')
plt.imshow(Image.open('JOJO_stone_free.jpg'))
plt.show()

效果如下
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
这里为了美观关闭了坐标轴的显示,如果打开坐标轴,就会发现横坐标的范围从0到图片的宽度,而纵坐标的范围从图片的高度到0。

充当背景板

使用 imshow 方法不仅可以单纯展示图片,还可以将图片当成背景板,在上面进行一些其它的绘制。在刚刚的展示图片基础上,让我们再绘制一些其它的图形,代码如下:

import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

jojo = Image.open('JOJO_stone_free.jpg')

print(jojo.width, jojo.height) # 输出为 (854, 480)

# 显示范围为图片的大小
plt.xlim(0, jojo.width)
plt.ylim(jojo.height, 0)
plt.axis('off')

## draw a heart
t = np.linspace(600, 680, 1000)
k = 0.3
g = 10

y = - (g * (t - 640) * (t - 640)) ** (1/3) + (1600 - (t - 640)**2) ** 0.5 * np.sin(k * np.pi * (t - 640)) + 100
plt.plot(t, y, c='r')

# draw background
plt.imshow(jojo)

plt.show()

效果如下:
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
注意到我们这里的代码把背景渲染的代码放在了爱心的后面,而最终的显示结果仍然是爱心在背景的上面。这是因为 Matplotlib 的每个对象都有特定的渲染层级,而 Matplotlib 默认把图片的渲染层级放在比较靠下的位置。若要改变渲染层级,可参考文章后面的内容。

补充知识:用 Matplotlib 生成动画

众所周知,Matplotlib 不仅可以绘图, 还可以生成动画。负责生成动画的函数是 FuncAnimation, 使用前需先将其导入:

from matplotlib.animation import FuncAnimation

关于动画生成,CSDN上的教程已经不计其数,这里不再赘述了。

指定位置嵌入图片

控制图片的位置和大小是由 originextent 两个参数来实现的。origin 有 “upper” 和 “lower” 两个取值,决定了图片是正着的还是倒着的。extent=(L, R, B, T) 则决定了图片的边界坐标,L, R, B, T 分别代表了图片的最左端,最右端,最底端,最上端的坐标。

下面一个 demo 演示了如何设置图片的指定位置。超级马里奥位于一个 10x10的格子中,他需要从左下角走到右上角,从而吃到能让自己变大变强的蘑菇。

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
from PIL import Image

# 读取图片
mario_img = Image.open('mario.png')
mushroom_img = Image.open('mushroom.png')

# 设置画布
fig, ax = plt.subplots()
plt.axis('off')

ax.set_xlim(-0.5, 10.5)
ax.set_ylim(-0.5, 10.5)

ax.vlines(np.arange(11), 0, 10)
ax.hlines(np.arange(11), 0, 10)

# 画蘑菇
mushroom = ax.imshow(mushroom_img, extent=(9, 10, 9, 10))

# 画马里奥
mario_x = 1
mario_y = 1
mario = ax.imshow(mario_img, extent=(mario_x - 1, mario_x, mario_y - 1, mario_y))


def move():
    global mario_x, mario_y
    if mario_x == 10 == mario_y: # 吃到蘑菇了噢
        mario_x = mario_y = 1
        return True
    elif mario_x == 10:
        mario_y += 1
    elif mario_y == 10:
        mario_x += 1
    else:
        if np.random.random() < 0.5:
            mario_x += 1
        else:
            mario_y += 1

    return False # 还没吃到蘑菇呢!


def init():
    pass

def update(frame):
    mario.set_extent((mario_x - 1, mario_x, mario_y - 1, mario_y))

	# 若吃到蘑菇则隐藏蘑菇,避免两张图片重叠,更好看一点
    if move():
        mushroom.set_alpha(0)
    else:
        mushroom.set_alpha(1)



ani = FuncAnimation(fig, update, frames=range(180), blit=False, interval=300,
                              repeat=False, init_func=init)

ani.save('mario_like_mushroom.gif')

效果如下:
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析

设置渲染层级

在 Matplotlib 中,参数 zorder 被用来控制对象的渲染层级,它的值越大,对象在渲染时就处在越上面。这里运用 Matplotlib 的动画模块,写了一个简单的小 demo,来展示 zorder 的作用。代码如下:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from PIL import Image

# 读取图片
gold_sword = Image.open('golden_sword.png')
diamond_sword = Image.open('diamond_sword.png')
tony_stark = Image.open('tony_stark.png')
cap_am     = Image.open('cap_am.png')

# 画布设置
fig, ax = plt.subplots()
plt.axis('off')

ax.set_xlim(0, 1000)
ax.set_ylim(0, 600)

# 显示图片
gs = plt.imshow(gold_sword, extent=(376, 576, 200, 300))
ds = plt.imshow(diamond_sword, extent=(424, 624, 200, 300))
ca = plt.imshow(cap_am, extent=(50, 350, 100, 500))
im = plt.imshow(tony_stark, extent=(650, 950, 100, 500))


# 初始化函数,这里不需要任何操作
def init():
    pass


# 更新函数,帧数为奇数时金剑在上面,偶数时钻石剑在上面
def update(frame):
    if frame % 2 == 0:
        gs.set_zorder(0)
        ds.set_zorder(1)
    else:
        gs.set_zorder(1)
        ds.set_zorder(0)


# 设置动画
ani = FuncAnimation(fig, update, frames=range(100), blit=False, 
					interval=300, repeat=False, init_func=init)

# 保存为 gif 图片
ani.save('fighting.gif')

效果如下:
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析

总结

好了,以上就是本文的全部内容。在本文中,我们学会了使用 Matplotlib 的 imshow 方法来绘制图片,它既可以用来单纯展示,也可以充当某个图像的背景板。同时,我们还学会了如何设置图片的位置和渲染层级,给图片赋予了更多的灵活度。此外,我们用 FuncAnimation 制作了一些动画,来展示 imshow 的各个特性。还是挺有意思的,呵呵。

附录:本文所用图片

这里提供了本文中的代码所用的图片,方便大家下载学习。如有侵权,请及时联系我删除。
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析

Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析
Matplotlib 在图表中嵌入图片 -- `imshow` 的各种用法解析

上一篇:python使用matplotlib可视化多子图线图(subplots line plot)、在matplotlib中为所有的子图添加一个统一的图例(single legend)


下一篇:第一次打卡