2010-03-29 10 views
37

Sto disegnando una legenda su un oggetto axes in matplotlib ma il posizionamento predefinito che pretende di posizionarlo in un posto intelligente non sembra funzionare. Idealmente, mi piacerebbe che la leggenda fosse trascinabile dall'utente. Come si può fare?Come creare una legenda trascinabile in matplotlib?

+0

Adam: dato che questo è stato notevole, approfondita, e abbastanza rilevanti da includere nella distro Matplotlib, e dato che (credo) è stato rimosso tua domanda iniziale, ti dispiacerebbe tra cui un paio di frasi in alto di questo Q in modo che gli utenti possano avere un'idea di cosa è questo codice (per salvarli dal dover leggere il codice stesso). E bel lavoro, tra l'altro +1 da me. – doug

+0

Grazie doug. Ho formulato la domanda in alto come suggerito. Speriamo che questo sia utile. :] –

+0

può essere esteso per l'asse secondario? – denfromufa

risposta

28

Nota: Questo è ora integrato in matplotlib

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

funzionerà come previsto


Beh, ho trovato i pezzi della soluzione disperso fra le mailing list. Mi è venuta in mente un pezzo modulare bella di codice che si può cadere in ed usare ... eccolo:

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 

... e nel codice ...

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


legend = DraggableLegend(ax.legend()) 

Ho mandato un'email al gruppo Matplotlib-users e John Hunter è stato così gentile da aggiungere la mia soluzione a SVN HEAD.

On Gio 28 Gen, 2010 alle 15:02, Adam Fraser ha scritto:

ho pensato di condividere una soluzione al problema leggenda draggable poiché mi ha preso per sempre per assimilare tutte le conoscenze sparse sulle mailing list ...

Cool - bel esempio. Ho aggiunto il codice a legend.py. Ora si può fare

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

per abilitare la modalità trascinabile. È possibile chiamare ripetutamente questa funzione per attivare lo stato trascinabile dello .

Spero che questo sia utile per le persone che lavorano con matplotlib.

13

Nelle versioni più recenti di Matplotlib (v1.0.1), questo è integrato.

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) 

Se si utilizza in modo interattivo matplotlib (ad esempio, in modalità pylab di 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) 
Problemi correlati