【问题标题】:(Python) tkinter figures (with colorbar) overlap when using slider(Python) tkinter 图形(带颜色条)在使用滑块时重叠
【发布时间】:2021-12-30 10:54:11
【问题描述】:

以下代码是从tkinter 上的五个(滑块:0 ~ 4).xlsx 文件绘制轮廓。每个文件只包含矩阵 12X6 中的数值数据,例如

from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')

root = Tk()
root.title('TEST')
root.geometry("800x800")

def plot_noise():
    rec = np.shape(dfs[0])
    rmm = np.concatenate([dfs[0], dfs[1]])
    for jj in range(2,num):
        rmm = np.concatenate([rmm, dfs[jj]])
    # =================================================PLOT===========================================
    fig = plt.Figure()                       
    canvas = FigureCanvasTkAgg(fig, root)     
    canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0) 
    
    # ===============================================contourf=========================================
    ax = fig.add_subplot(111)                 
    fig.subplots_adjust(bottom=0.25)          
    X = np.arange(1,rec[1]+1,1)
    Y = np.arange(1,rec[0]+1,1)
    x , y = np.meshgrid(X,Y)  
    # ==============================================color bar=========================================
    cbar_max = math.floor(np.min(rmm))
    cbar_min = math.ceil(np.max(rmm))
    cbar_num_colors = 200
    cbar_num_format = "%d"
    levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
    # ============================================Initial plot======================================== 
    con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)   
    cbar = fig.colorbar(con,ax = ax)
    ax.axis([1, 12, 1, 6])
    # ================================================Slider==========================================
    global slider_de
    slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])     
    slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f',  valstep=1)
    num_on_slider = []
    def update(val):
        num_on_slider.append(slider_de.val)
        for ii in range(0,num):
            if num_on_slider[-1] == ii:
                con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
                cbar = fig.colorbar(con,ax = ax)
                ax.axis([1, 12, 1, 6])
                
    slider_de.on_changed(update)            
                
    
# =================================================GUI - Tkinter======================================= 
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)

root.mainloop()

运行时,我得到了

现在,如果我使用fig.clf,例如

fig.clf()
con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
cbar = fig.colorbar(con,ax = ax)

我明白了

轮廓消失了。我还尝试了from matplotlib.figure import Figure 而不是 pyplot;但是,它不起作用。

如何解决这个奇怪的问题?

请大家多多指教,谢谢!

【问题讨论】:

  • 如果您已经解决了原始问题,我建议您将解决方案作为答案发布,然后针对您的其他问题提出新问题。就目前而言,查看标题和大部分问题正文,您似乎仍然有重叠的问题。由于有一天它可能对某人有用,我建议您从问题中删除新问题并为原始问题写一个答案,然后针对您的新问题提出一个新问题。
  • @Matiiss 当然!谢谢提醒。

标签: python matplotlib tkinter colorbar


【解决方案1】:

将代码重构为一个类并添加了选择文件夹的功能。其他想法在 cmets 中。

#Do not use wild imports
import tkinter as tk
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')


class MyPlot(ttk.Frame):
    def __init__(self, parent):
        super().__init__()

        #put widgets in frame(self)
        resultButton = ttk.Button(self, text = 'Select Folder', command = self.select_dir)
        resultButton.grid(column=0, row=1, pady=15, sticky=tk.W)

        # show frame in root
        self.grid(column=0, row=0)

    def select_dir(self):
        selected_dir = tk.filedialog.askdirectory(parent=self, title='Select a directory')
        # print(selected_dir)
        if selected_dir:
            self.plot_noise(selected_dir)
        else:
            tk.messagebox.showerror('Select', 'Select a directory', parent=self)

    def plot_noise(self, folder):
        # ============================================Read .xlsx file=====================================
        files = os.listdir(folder)
        dfs = {}
        # Prepare for scenarios where files(other than the expected .xlsx) are in the folder passed
        # when that is the case the enumerated i previously being used to create dict keys will get all messed up
        index = 0
        for file in files:
            if file.endswith('.xlsx'):
                dfs[index] = pd.read_excel(os.path.join(folder,file), sheet_name='Z=143', header = None, skiprows=[0], usecols = "B:M")
                index += 1

        if dfs:
            num = len(dfs)
            rec = np.shape(dfs[0])
            rmm = np.concatenate([dfs[0], dfs[1]])
            for jj in range(2,num):
                rmm = np.concatenate([rmm, dfs[jj]])
            # =================================================PLOT===========================================
            fig, ax = plt.subplots()                
            canvas = FigureCanvasTkAgg(fig, self)     
            canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=tk.W+tk.E+tk.N+tk.S, padx=0, pady=0) 
            # ===============================================contourf=========================================          
            fig.subplots_adjust(bottom=0.25)          
            X = np.arange(1,rec[1]+1,1)
            Y = np.arange(1,rec[0]+1,1)
            x , y = np.meshgrid(X,Y)  
            # ==============================================color bar=========================================
            cbar_max = math.floor(np.min(rmm))
            cbar_min = math.ceil(np.max(rmm))
            cbar_num_colors = 200
            cbar_num_format = "%d"
            levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
            # ============================================Initial plot======================================== 
            con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)  
            cbar = fig.colorbar(con,ax = ax)
            ax.axis([1, 12, 1, 6])
            # ================================================Slider==========================================
            slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])     
            slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f',  valstep=1)
            num_on_slider = []

            def update(val):
                num_on_slider.append(slider_de.val)
                for ii in range(0,num):
                    if num_on_slider[-1] == ii:
                        con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
                        ax.axis([1, 12, 1, 6])
                        
            slider_de.on_changed(update)

        else:
            tk.messagebox.showerror('No File', 'No .xlsx file found')            
                
    
# =================================================GUI - Tkinter======================================= 
root = tk.Tk()
root.title('TEST')
root.geometry("800x800")
MyPlot(root)
root.mainloop()

【讨论】:

  • 太棒了!这也让用户选择文件夹,更方便。 oop 风格使代码更加高级。
【解决方案2】:

这是我刚刚根据@Kat 的提示得出的一个答案

from tkinter import *
import tkinter.ttk as ttk
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import ipywidgets as wg
import os
import pandas as pd
from matplotlib.ticker import MaxNLocator
from matplotlib.colors import BoundaryNorm
import math
from matplotlib.ticker import LinearLocator
%matplotlib widget
from matplotlib.widgets import Slider
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
matplotlib.use('TkAgg')

root = Tk()
root.title('TEST')
root.geometry("800x800")

cbar = None
def plot_noise():
    # ============================================Read .xlsx file=====================================
    folder = r'C:\Users\Dian-Jing Chen\Desktop\Work\test_read'
    files = os.listdir(folder)
    dfs = {}
    for i, file in enumerate(files):
        if file.endswith('.xlsx'):
            dfs[i] = pd.read_excel(os.path.join(folder,file), sheet_name='Z=143', header = None, skiprows=[0], usecols = "B:M")

    num = i + 1
    rec = np.shape(dfs[0])
    rmm = np.concatenate([dfs[0], dfs[1]])
    for jj in range(2,num):
        rmm = np.concatenate([rmm, dfs[jj]])
    # =================================================PLOT===========================================
    fig, ax = plt.subplots()                       
    canvas = FigureCanvasTkAgg(fig, root)     
    canvas.get_tk_widget().grid(row=3, column=0, columnspan=3, rowspan=3, sticky=W+E+N+S, padx=0, pady=0) 
    # ===============================================contourf=========================================          
    fig.subplots_adjust(bottom=0.25)          
    X = np.arange(1,rec[1]+1,1)
    Y = np.arange(1,rec[0]+1,1)
    x , y = np.meshgrid(X,Y)  
    # ==============================================color bar=========================================
    cbar_max = math.floor(np.min(rmm))
    cbar_min = math.ceil(np.max(rmm))
    cbar_num_colors = 200
    cbar_num_format = "%d"
    levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
    # ============================================Initial plot======================================== 
    con = ax.contourf(x,y,dfs[1], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)  
    cbar = fig.colorbar(con,ax = ax)
    ax.axis([1, 12, 1, 6])
    # ================================================Slider==========================================
    slider_bar = fig.add_axes([0.12, 0.1, 0.78, 0.03])     
    slider_de = Slider(slider_bar, 's_bar', 0, num-1, valinit=1,valfmt='%0.0f',  valstep=1)
    num_on_slider = []
    def update(val):
        num_on_slider.append(slider_de.val)
        for ii in range(0,num):
            if num_on_slider[-1] == ii:
                con = ax.contourf(x,y,dfs[ii], levels = levels, cmap=cm.jet, alpha = 0.5, antialiased = True)
                ax.axis([1, 12, 1, 6])
                
    slider_de.on_changed(update)            
                
    
# =================================================GUI - Tkinter======================================= 
resultButton = ttk.Button(root, text = 'show', command = plot_noise)
resultButton.grid(column=0, row=1, pady=15, sticky=W)

root.mainloop()

我删除了update() 函数中的 cbar,因为颜色条始终是固定的。

所以我现在正在寻找另一种高级方法(因为由于赏金我无法删除此问题),这也是我了解更多信息的机会。例如,使用class 是一种非常高级的方法。

50分将给予最佳答案。

【讨论】:

    猜你喜欢
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-27
    • 2021-10-06
    相关资源
    最近更新 更多