2010-03-29 10 views
37

Rysuję legendę na obiekcie osi w matplotlib, ale domyślne pozycjonowanie, które twierdzi, że umieszcza je w inteligentnym miejscu, nie działa. Idealnie, chciałbym, aby legenda była przeciągalna przez użytkownika. Jak to zrobić?Jak utworzyć przeciągalną legendę w matplotlib?

+0

Adam: zważywszy, że ten był znaczny, dokładne i wystarczająco istotne, aby dołączyć do dystrybucji matplotlib, a biorąc pod uwagę, że (chyba) usunięto oryginalne pytanie, czy mogłabyś w tym kilka zdań na szczycie tego Q, aby użytkownicy mogli zorientować się, do czego służy ten kod (aby nie musieli czytać samego kodu). I miła praca, przy okazji +1 ode mnie. – doug

+0

Dzięki Doug. Utworzyłem pytanie na górze, zgodnie z sugestią. Mam nadzieję, że będzie to pomocne. :] –

+0

czy można to przedłużyć na drugą oś? – denfromufa

Odpowiedz

28

Uwaga: To jest teraz wbudowany w matplotlib

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

będzie działać zgodnie z oczekiwaniami


Cóż, znalazłem kawałki roztworu rozrzucone wśród listach dyskusyjnych. Mam wymyślić ładnym modułowej kawałek kodu, który można wpaść i wykorzystać ... to jest tutaj:

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 

... iw kodzie ...

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


legend = DraggableLegend(ax.legend()) 

Wysłałem e-mail do grupy użytkowników Matplotlib, a John Hunter był na tyle uprzejmy, aby dodać moje rozwiązanie do SVN HEAD.

On Thu, sty 28, 2010 3:02 PM w Adam Fraser napisał:

myślałem, że dzielić rozwiązanie problemu Draggable legendy od zajęło mi wieki przyswoić całą rozproszoną wiedzę z list adresowych ...

Fajnie - ładny przykład. Dodałem kod do legend.py. Teraz można zrobić

nóg = ax.legend()
leg.draggable()

aby włączyć tryb Draggable. Możesz wielokrotnie wywoływać ten func, aby przełączać stan przeciągalny.

Mam nadzieję, że jest to pomocne dla osób pracujących z matplotlib.

13

W nowszych wersjach Matplotlib (v1.0.1) jest to wbudowane.

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) 

Jeśli używasz matplotlib interaktywnie (na przykład w trybie pylab ipython za).

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)