在matplotlib中重复使用补丁对象而不改变位置

6 投票
2 回答
1887 浏览
提问于 2025-04-17 06:30

我想自动生成一系列图形,并且这些图形要被限制在特定的区域内。如果我尝试重复使用一个区域对象,它在画布上的位置就会移动。

这个脚本(基于Yann之前问题的回答)展示了发生了什么。

import pylab as plt
import scipy as sp
import matplotlib.patches as patches

sp.random.seed(100)
x = sp.random.random(100)
y = sp.random.random(100)
patch = patches.Circle((.75,.75),radius=.25,fc='none')


def doplot(x,y,patch,count):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    im = ax.scatter(x,y)
    ax.add_patch(patch)
    im.set_clip_path(patch)
    plt.savefig(str(count) + '.png')


for count in xrange(4):
    doplot(x,y,patch,count)

第一个图看起来是这样的:第一次绘制时区域的位置正确

但是在第二个图'1.png'中,区域的位置就移动了.. 区域位置错误

不过再次绘制时,区域并没有移动。'2.png'和'3.png'看起来和'1.png'完全一样。

有没有人能告诉我,我哪里做错了??

实际上,我使用的区域比较复杂,生成这些区域需要一些时间——如果可以的话,我希望每一帧都不必重新制作它们。

2 个回答

2

另一种方法是使用 copy 这个包,它可以用来复制对象。调用 add_patch 后,事情的变化很难看出来,但实际上是有变化的。比如,axesfigureextentsclip_boxtransformwindow_extent 这些属性都发生了变化。不幸的是,直接打印这些属性的值时,结果都是一样的字符串,所以看起来好像没有变化。但实际上,这些属性的一些底层特征,比如 extents 是一个 Bbox,可能已经改变了。

使用 copy 可以让你为每个图形创建一个独特的补丁,而不需要知道这个补丁具体是什么类型。虽然这仍然没有解释为什么会这样,但正如我上面所说的,这是一种解决问题的替代方法:

import copy 

def doplot(x,y,patch,count):
    newPatch = copy.copy(patch)
    fig = plt.figure(dpi=50)
    ax = fig.add_subplot(111)
    im = ax.scatter(x,y)
    ax.add_patch(newPatch)
    im.set_clip_path(newPatch)
    plt.savefig(str(count) + '.png')

另外,你可以使用 fig.savefig(str(count) + '.png')。这个方法明确地保存了图形 fig,而 plt.savefig 则是保存当前的图形,恰好是你想要的那个。

2

这个问题可以通过对每个图使用相同的坐标轴来避免。在每次绘图后,调用 ax.cla() 来清空图表。

import pylab as plt
import scipy as sp
import matplotlib.patches as patches

sp.random.seed(100)
patch = patches.Circle((.75,.75),radius=.25,fc='none')

fig = plt.figure()
ax = fig.add_subplot(111)

def doplot(x,y,patch,count):
    ax.set_xlim(-0.2,1.2)
    ax.set_ylim(-0.2,1.2)
    x = sp.random.random(100)
    y = sp.random.random(100)
    im = ax.scatter(x,y)
    ax.add_patch(patch)
    im.set_clip_path(patch)
    plt.savefig(str(count) + '.png')
    ax.cla()

for count in xrange(4):
    doplot(x,y,patch,count)

撰写回答