I want to automatically generate a series of plots which are clipped to patches. If I try and reuse a patch object, it moves position across the canvas.
This script (based on an answer to a previous question by Yann) demonstrates what is happening.
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)
The first plot looks like this:
But in the second '1.png', the patch has moved..
However replotting again doesn't move the patch. '2.png' and '3.png' look exactly the same as '1.png'.
Could anyone point me in the right direction of what I'm doing wrong??
In reality, the patches I'm using are relatively complex and take some time to generate - I'd prefer to not have to remake them every frame if possible.
The problem can be avoided by using the same axes for each plot, with ax.cla()
called to clear the plot after each iteration.
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)
An alternative to unutbu's answer, is to use the copy
package, which can copy objects. It is very hard to see how things are changing after one calls add_patch
, but they are. The axes
, figure
, extents
,clip_box
,transform
and window_extent
properties of the patch are changed. Unfortantely the superficial printing of each of these properties results in the same string, so it looks like they are not changing. But the underlying attributes of some or all of these properties, eg extents
is a Bbox
, are probably changed.
The copy call will allow you to get a unique patch for each figure you make, without know what kind of patch it is. This still does not answer why this happens, but as I wrote above it's an alternative solution to the problem:
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')
Also you can use fig.savefig(str(count) + '.png')
. This explicitly saves the figure fig
where as the plt.savefig
call saves the current figure, which happens to be the one you want.