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()
效果如下
这里为了美观关闭了坐标轴的显示,如果打开坐标轴,就会发现横坐标的范围从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 的每个对象都有特定的渲染层级,而 Matplotlib 默认把图片的渲染层级放在比较靠下的位置。若要改变渲染层级,可参考文章后面的内容。
补充知识:用 Matplotlib 生成动画
众所周知,Matplotlib 不仅可以绘图, 还可以生成动画。负责生成动画的函数是 FuncAnimation
, 使用前需先将其导入:
from matplotlib.animation import FuncAnimation
关于动画生成,CSDN上的教程已经不计其数,这里不再赘述了。
指定位置嵌入图片
控制图片的位置和大小是由 origin
和 extent
两个参数来实现的。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 中,参数 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
方法来绘制图片,它既可以用来单纯展示,也可以充当某个图像的背景板。同时,我们还学会了如何设置图片的位置和渲染层级,给图片赋予了更多的灵活度。此外,我们用 FuncAnimation
制作了一些动画,来展示 imshow
的各个特性。还是挺有意思的,呵呵。
附录:本文所用图片
这里提供了本文中的代码所用的图片,方便大家下载学习。如有侵权,请及时联系我删除。