Kyle Carow
Kyle Carow

Reputation: 194

Tkinter with matplotlib - Heatmap colorbar not clearing with rest of axes

I'm building a GUI using tkinter and matplotlib (and seaborn) to show a heatmap from a user chosen csv. I want the heatmap to update each time it's loaded, with the appropriate colorbar. I clear my axes each time I load new data in, but the colorbar never goes away, and the new heatmap squishes off to the side. I want the old colorbar to be cleared as well so the new heatmap can fill the space properly.

I made a MWE to show off my problem:

import numpy as np
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import seaborn as sns

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.state('zoomed')
        self.winfo_toplevel().title('App')

        frame = tk.Frame(self)
        frame.pack()

        button_reload = tk.Button(frame, text='Reload data', command=self.reload_data)
        button_reload.pack()

        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)

        self.fig.tight_layout()  # Small margins
        self.ax.axis('off')  # Disable axis lines
        self.canvas_heatmap = FigureCanvasTkAgg(self.fig, master=frame)
        self.canvas_heatmap.get_tk_widget().pack(expand=True, fill='both')

    def reload_data(self):
        # dummy data for example
        data = np.random.rand(3,3)

        # Clear old heatmap from axes
        self.ax.clear()

        # Set up new heatmap
        self.ax = sns.heatmap(data, ax=self.ax, linewidth=0.1)
        self.canvas_heatmap.draw()
        self.canvas_heatmap.get_tk_widget().pack(expand=True, fill='both')  # necessary?
    
def quit_GUI():
    root.quit()
    root.destroy()

if __name__ == '__main__':
    root = App()
    root.protocol('WM_DELETE_WINDOW', quit_GUI)  # Kill process on clicking 'X'
    root.mainloop()

Here are some photos where you can see the colorbars sticking around when I don't want them to.

GOOD SO FAR: first heatmap

BAD: second heatmap

WORSE: enter image description here

I could keep going like this until my heatmap is a sliver.

Upvotes: 2

Views: 597

Answers (1)

Novel
Novel

Reputation: 13729

You need to clear the figure and remake the ax.

import numpy as np
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import seaborn as sns

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.state('zoomed')
        self.winfo_toplevel().title('App')

        frame = tk.Frame(self)
        frame.pack()

        button_reload = tk.Button(frame, text='Reload data', command=self.reload_data)
        button_reload.pack()

        self.fig = Figure()
        self.canvas_heatmap = FigureCanvasTkAgg(self.fig, master=frame)
        self.canvas_heatmap.get_tk_widget().pack(expand=True, fill='both')

    def reload_data(self):
        data = np.random.rand(3,3)
        self.fig.clear()
        ax = self.fig.add_subplot(111)
        ax.axis('off')  # Disable axis lines
        line = sns.heatmap(data, ax=ax, linewidth=0.1)
        self.fig.tight_layout()  # Should go after the drawing
        self.canvas_heatmap.draw()
        # ~ self.canvas_heatmap.get_tk_widget().pack(expand=True, fill='both')  # not necessary
        
if __name__ == '__main__':
    root = App()
    # ~ root.protocol('WM_DELETE_WINDOW', quit_GUI)  # not needed
    root.mainloop()

Upvotes: 1

Related Questions