2010-03-29 18 views
37

Estoy dibujando una leyenda sobre un objeto de ejes en matplotlib pero el posicionamiento predeterminado que dice colocarlo en un lugar inteligente no parece funcionar. Idealmente, me gustaría que la leyenda sea arrastrable por el usuario. ¿Cómo puede hacerse esto?Cómo crear una leyenda arrastrable en matplotlib?

+0

Adam: dado que este era sustancial, completa y suficientemente relevante para incluir en la distribución Matplotlib, y dado que (creo) que retiró su pregunta original, ¿le importaría que incluye un par de frases en la parte superior de esta Q para que los usuarios puedan hacerse una idea de para qué sirve este código (para evitar que tengan que leer el código en sí). Y buen trabajo, por cierto +1 de mi parte. – doug

+0

Gracias doug. Formulé la pregunta en la parte superior como sugirió. Espero que esto sea útil. :] –

+0

¿se puede extender esto para el eje secundario? – denfromufa

Respuesta

28

Nota: Esto ahora está integrado en matplotlib

leg = plt.legend() 
if leg: 
    leg.draggable() 

funcionará como se espera


Bueno, he encontrado fragmentos de la solución esparcieron entre las listas de distribución. Yo he llegado con un buen trozo de código modular que se puede soltar y usar ... aquí está:

class DraggableLegend: 
    def __init__(self, legend): 
     self.legend = legend 
     self.gotLegend = False 
     legend.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) 
     legend.figure.canvas.mpl_connect('pick_event', self.on_pick) 
     legend.figure.canvas.mpl_connect('button_release_event', self.on_release) 
     legend.set_picker(self.my_legend_picker) 

    def on_motion(self, evt): 
     if self.gotLegend: 
      dx = evt.x - self.mouse_x 
      dy = evt.y - self.mouse_y 
      loc_in_canvas = self.legend_x + dx, self.legend_y + dy 
      loc_in_norm_axes = self.legend.parent.transAxes.inverted().transform_point(loc_in_canvas) 
      self.legend._loc = tuple(loc_in_norm_axes) 
      self.legend.figure.canvas.draw() 

    def my_legend_picker(self, legend, evt): 
     return self.legend.legendPatch.contains(evt) 

    def on_pick(self, evt): 
     if evt.artist == self.legend: 
      bbox = self.legend.get_window_extent() 
      self.mouse_x = evt.mouseevent.x 
      self.mouse_y = evt.mouseevent.y 
      self.legend_x = bbox.xmin 
      self.legend_y = bbox.ymin 
      self.gotLegend = 1 

    def on_release(self, event): 
     if self.gotLegend: 
      self.gotLegend = False 

... y en su código ...

def draw(self): 
    ax = self.figure.add_subplot(111) 
    scatter = ax.scatter(np.random.randn(100), np.random.randn(100)) 


legend = DraggableLegend(ax.legend()) 

Envié un correo electrónico al grupo de usuarios de Matplotlib y John Hunter tuvo la amabilidad de agregar mi solución a SVN HEAD.

En Jue 28 Ene 2010 a las 15:02, Adam Fraser escribió:

pensé que me gustaría compartir una solución al problema de la leyenda se puede arrastrar desde me tomó por siempre para asimilar todo el conocimiento disperso en las listas de correo ...

Genial ejemplo. Agregué el código a legend.py. Ahora usted puede hacer

pierna = ax.legend()
leg.draggable()

para habilitar el modo que pueden arrastrarse. Puede llamar repetidamente a este func para alternar el estado que se puede arrastrar.

Espero que esto sea útil para las personas que trabajan con matplotlib.

13

En las versiones más nuevas de Matplotlib (v1.0.1), esto está incorporado.

def draw(self): 
    ax = self.figure.add_subplot(111) 
    scatter = ax.scatter(np.random.randn(100), np.random.randn(100)) 
    legend = ax.legend() 
    legend.draggable(state=True) 

Si está utilizando matplotlib de forma interactiva (por ejemplo, en el modo pylab de IPython).

plot(range(10), range(10), label="test label") 
plot(range(10), [5 for x in range(10)], label="another test") 
l = legend() 
l.draggable(True) 
Cuestiones relacionadas