Unabhängiger Graph und interaktive Legende

Fragen zu Tkinter.
Antworten
tobi45f
User
Beiträge: 24
Registriert: Montag 22. Februar 2021, 14:31

Hallo zusammen,
ich bräuchte wieder einmal Hilfe..
Ich habe zwei anzeigende Elemente/Matplotlib-Graphen welche einzeln korrekt funktionieren, allerdings nicht, wenn beide gleichzeitig drin sind. Ich verstehe nicht, wo die Überschneidung ist.
Den Code der interaktiven Legende habe ich online gefunden und ist nicht von mir selbst erstellt worden.

Wenn ich den im Fenster eingebundenen Graph auskommentiere und nur den Graph über den Button aufrufe, so wird in dem neuen Fenster wunderbar jeder Plot selektierbar. Wenn ich den Code allerdings drin lasse, dann lädt er in den implementierten Graphen und in das neue Fenster alle Plots. Die interaktive Legende ist dann auf einmal beim eingesetzten Graphen und das neue Fenster ist wie eingefroren, obwohl die ganze Interaktion hier ablaufen sollte. Ich hatte auch schon versucht den Inhalt von def show_multigraph als neue plt.figure anzulegen. Hat aber auch nicht funktioniert.. Dann werden zwar die Graphen korrekt von einander getrennt, allerdings geht dann das ein- und ausblenden über die Legende nicht mehr, was ich nicht verstehe. Ich habe auch schon das legenden-Objekt mit übergeben, ebenso versucht das korrekte figure-Objekt zu übergeben statt legend.axes.figure. Ich verstehe leider nicht, wo der Fehler liegt.

Kann mir jemand erklären, wo das Problem liegt? Ich verstehe es leider nicht :(

Gruß Tobias

Code: Alles auswählen

import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from matplotlib.backends.backend_tkagg import FigureCanvasAgg, FigureCanvasTkAgg, NavigationToolbar2Tk

class InteractiveLegend(object):
    # Verwendung:
    # plt.legend(handles=plots, bbox_to_anchor=(1, 1), loc='left', prop=fontP)
    # leg = si.InteractiveLegend() #muss leg heißen! plt.legend() muss vorher initialisiert werdenE
    # plt.show()
    def __init__(self, legend=None):
        if legend == None:
            legend = plt.gca().get_legend()
        self.legend = legend
        self.fig = legend.axes.figure
        self.lookup_artist, self.lookup_handle = self._build_lookups(legend)
        self._setup_connections()
        self.update()
    def _setup_connections(self):
        for artist in self.legend.texts + self.legend.legendHandles:
            artist.set_picker(10) # 10 points tolerance
        self.fig.canvas.mpl_connect('pick_event', self.on_pick)
        self.fig.canvas.mpl_connect('button_press_event', self.on_click)
    def _build_lookups(self, legend):
        labels = [t.get_text() for t in legend.texts]
        handles = legend.legendHandles
        label2handle = dict(zip(labels, handles))
        handle2text = dict(zip(handles, legend.texts))
        lookup_artist = {}
        lookup_handle = {}
        for artist in legend.axes.get_children():
            if artist.get_label() in labels:
                handle = label2handle[artist.get_label()]
                lookup_handle[artist] = handle
                lookup_artist[handle] = artist
                lookup_artist[handle2text[handle]] = artist
        lookup_handle.update(zip(handles, handles))
        lookup_handle.update(zip(legend.texts, handles))
        return lookup_artist, lookup_handle
    def on_pick(self, event):
        handle = event.artist
        if handle in self.lookup_artist:
            artist = self.lookup_artist[handle]
            artist.set_visible(not artist.get_visible())
            self.update()
    def on_click(self, event):
        if event.button == 3:
            visible = False
        elif event.button == 2:
            visible = True
        else:
            return
        for artist in self.lookup_artist.values():
            artist.set_visible(visible)
        self.update()
    def update(self):
        for artist in self.lookup_artist.values():
            handle = self.lookup_handle[artist]
            if artist.get_visible():
                handle.set_visible(True)
            else:
                handle.set_visible(False)
        self.fig.canvas.draw()

class Application:
    def __init__(self):
        
        self.window = tk.Tk()
        self.mainFrame = tk.Frame(self.window)
        self.mainFrame.pack(side='top')
        myDict = {1:[1,4,2,1,3], 2:[1,1,2,1,3], 3:[1,4,7,1,3], 4:[1,4,2,7,3], 5:[1,0,2,1,3], 6:[1,4,2,11,3]}

        for id, plt_value in myDict.items():
            myFrame = tk.Frame(master = self.mainFrame)
            myFrame.pack(side='top', pady = 2, padx = 2)            
            myFrame.focus_set()

            lbl_sl_id = tk.Label(myFrame, text=str(id), width=4, bg='red')
            lbl_sl_id.pack(side='left')
            lbl_sl_id.bind("<Button-1>", lambda event, a=plt_value: self.update_graph(a)) 

        #Hier soll ein separates Fenster mit allen Plots mit der Möglichkeit zum an und abwählen erscheinen. 
        button = tk.Button(self.mainFrame, text = "Mehrfachdiagramm", command=lambda: self.show_multigraph(myDict))
        button.pack(side='top', pady=3, padx=3)

        #Die eingebundene Figure soll nur die Werte anzeigen, die angeklickt worden sind

        #### 1
        self.figure = plt.figure(num = 1, figsize=(6,5), dpi=100)
        self.diagram_obj = FigureCanvasTkAgg(self.figure, self.mainFrame)
        self.subplot = self.figure.add_subplot(111)
        nav = NavigationToolbar2Tk(self.diagram_obj, self.mainFrame)
        nav.pack(side='bottom')
        self.diagram_obj.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
        #### 1

    def show(self):
        self.window.mainloop()

    def update_graph(self, data):
        self.subplot.clear()
        self.subplot.plot(data, alpha=0.8, color='green', label='neu', lw = 2)
        self.figure.canvas.draw()

    
    # Funktioniert korrekt, wenn 1 auskommentiert ist.
    def show_multigraph(self, myDict):
        fontP = FontProperties()
        fontP.set_size('xx-small')

        #newfig = plt.figure(num=2)
        #sub = newfig.add_subplot(111)

        plots = []
        for id, data in myDict.items():  
            #plot, = sub.plot(data, alpha = 0.7, linewidth = 2.0, label=f"Plot {id}") 
            plot, = plt.plot(data, alpha = 0.7, linewidth = 2.0, label=f"Plot {id}") 
            plots.append(plot)
        
        #sub.legend(handles=plots, bbox_to_anchor=(1, 1), loc='upper left', prop=fontP)
        #leg = InteractiveLegend()
        #newfig.show()
        plt.legend(handles=plots, bbox_to_anchor=(1, 1), loc='upper left', prop=fontP)
        leg = InteractiveLegend()
        plt.show()       
        

def main():
    window = Application()
    window.show()    

if __name__ == "__main__":
    main()
Antworten