2011-11-17 15 views
5

Quiero generar automáticamente una serie de gráficos recortados en parches. Si intento y reutilizo un objeto de parche, mueve la posición a través del lienzo.Reutilización de objetos de parche en matplotlib sin la posición en movimiento

Este script (basado en la respuesta a una pregunta anterior de Yann) demuestra lo que está sucediendo.

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) 

La primera parcela se ve así: Correct position of patch - first time plotted

Pero en la segunda '1.png', el parche se ha movido .. Wrong position of the patch

Sin embargo replotting de nuevo no se mueve el parche . '2.png' y '3.png' son exactamente iguales a '1.png'.

¿Alguien podría apuntarme en la dirección correcta de lo que estoy haciendo mal?

En realidad, los parches que uso son relativamente complejos y tardan un tiempo en generarlos. Preferiría no tener que volver a hacerlos en cada fotograma si es posible.

+1

La parte realmente bizarra es que esto solo ocurre si llama a 'savefig', y no si llama a' show' ... –

Respuesta

2

El problema se puede evitar utilizando los mismos ejes para cada trazado, con ax.cla() llamado para borrar el trazado después de cada iteración.

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) 
+0

¡Gracias @unutbu! Funciona perfectamente. –

+0

Genial; ¡me alegro de poder ayudar! No acepte esta respuesta, ya que me gustaría saber por qué el parche también se ha transformado en su código original. – unutbu

2

Una alternativa a la respuesta de unutbu, es utilizar el paquete copy, que puede copiar objetos. Es muy difícil ver cómo están cambiando las cosas después de que uno llama al add_patch, pero lo son. Se modifican las propiedades del parche axes, figure, extents, clip_box, transform y window_extent. Desafortunadamente, la impresión superficial de cada una de estas propiedades da como resultado la misma cuerda, por lo que parece que no están cambiando. Pero los atributos subyacentes de algunas o todas estas propiedades, por ejemplo, extents es un Bbox, probablemente hayan cambiado.

La llamada de copia le permitirá obtener un parche único para cada figura que haga, sin saber qué tipo de parche es. Esto todavía no responde por qué sucede esto, pero como he escrito anteriormente es una solución alternativa al problema:

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') 

También se puede usar fig.savefig(str(count) + '.png'). Esto guarda explícitamente la figura fig donde la llamada plt.savefig guarda la cifra actual, que es la que usted desea.

Cuestiones relacionadas