2012-09-12 21 views
6

escribí una función que traza una figura que consiste en dos subtramas de diferentes tamaños:Matplotlib "diccionario cambió el tamaño durante la iteración" error al crear subtrama

def draw_plot(data, function, sigma_value): 

    gs = gridspec.GridSpec(1, 5) 
    ax1 = subplot(gs[0, 0:3]) 
    ax2 = subplot(gs[0, 3:5], sharey=ax1)     
    gs.update(wspace=0.05) 
    ... 

debo mencionar que esta es una función de nivel de módulo, por lo que en la parte superior de ese módulo hago importaciones

from pylab import * 
import matplotlib.gridspec as gridspec 

Cuando corro myplot.draw_plot(...), consigo RuntimeError. El caso es que este comportamiento es inconsistente. Puedo llamar a la función, por ejemplo, tres veces, y las dos primeras veces recibo el error, mientras que la tercera vez funciona bien.

El Rastreo es

Traceback (most recent call last): 
File "<interactive input>", line 1, in <module> 
File "myplot.py", line 105, in draw_plot 
    ax1 = subplot(gs[0, 0:3])     
File "C:\Python32\lib\site-packages\matplotlib\pyplot.py", line 766, in subplot 
    a = fig.add_subplot(*args, **kwargs) 
File "C:\Python32\lib\site-packages\matplotlib\figure.py", line 779, in add_subplot 
    a = subplot_class_factory(projection_class)(self, *args, **kwargs) 
File "C:\Python32\lib\site-packages\matplotlib\axes.py", line 8380, in __init__ 
    self._axes_class.__init__(self, fig, self.figbox, **kwargs) 
File "C:\Python32\lib\site-packages\matplotlib\axes.py", line 467, in __init__ 
    self.cla() 
File "C:\Python32\lib\site-packages\matplotlib\axes.py", line 910, in cla 
    self._shared_y_axes.clean() 
File "C:\Python32\lib\site-packages\matplotlib\cbook.py", line 1493, in clean 
    for key, val in mapping.items(): 
RuntimeError: dictionary changed size during iteration 

Gracias por cualquier ayuda!

EDITAR

Obviamente he estado tratando de averiguar a mí mismo lo que está pasando, por lo que después de la Traceback he comprobado la función clean() en cbook.py.

def clean(self): 
    """ 
    Clean dead weak references from the dictionary 
    """ 
    mapping = self._mapping 
    for key, val in mapping.items(): 
     if key() is None: 
      del mapping[key] 
      val.remove(key) 

En la función que añade una línea que imprimiría mapping.items() y me di cuenta de que el error se produce cuando hay entradas similares a <weakref at 0480EBA0; dead> entre esos elementos. No estoy familiarizado con las referencias débiles, así que estoy atascado de nuevo.

EDIT 2 Ciertamente, no es una buena solución, pero comentando el cuerpo clean() función de ayuda en mi caso sin producir nuevos errores.

+0

Excelente trabajo para encontrar la solución. Debe agregarlo usted mismo como respuesta y aceptarlo (para que esto pueda eliminarse de la página de preguntas sin respuesta). –

+0

Acabo de tener la misma idea :-) – petru

Respuesta

3

Acabo de encontrar una publicación muy reciente Safely iterating over WeakKeyDictionary and WeakValueDictionary que ayuda con un problema muy similar.

Así, utilizando respuesta dada por Bakuriu edité close() función como siguiendo

def clean(self): 
    """ 
    Clean dead weak references from the dictionary 
    """ 

    mapping = self._mapping 
    for key, val in list(mapping.items()): # iterate over list now   
     if key() is None: 
      del mapping[key] 
      val.remove(key) 

y parece estar funcionando muy bien!

EDITAR

que he acabo de enterar que en una nueva versión de matplotlib la función se ve así:

def clean(self): 
    """ 
    Clean dead weak references from the dictionary 
    """ 
    mapping = self._mapping 
    to_drop = [key for key in mapping if key() is None] 
    for key in to_drop: 
     val = mapping.pop(key) 
     val.remove(key) 

Fuente:

https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/cbook.py

1

Sólo una breve explicación de lo que está sucediendo:

Usted bucle sobre un iterable (list, dict, lo que sea) como esto:

for somevalue in someiterable: 
    #do something 

Y dentro del bucle que trataron de modificar estructuralmente el iterable, lo que significa que ha añadido o eliminado los valores. Esto no está permitido porque podría interferir con el ciclo for.La solución a esto suele ser iterar sobre una copia del iterable, dejándolo libre para alterar el original.

+0

Me pregunto por qué los chicos matplolib lo dejaron así? – petru

+0

Oh, no reconocí que es una función de biblioteca que causa este error ... Definitivamente deberían arreglar esto. Creo que la versión python3 de muchas bibliotecas aún no es estable, podría ser un problema introducido durante la migración. – l4mpi

Cuestiones relacionadas