【问题标题】:Embedding a MatPlotLib Graph in Tkinter [.grid method], and Customizing MatPlotLib's Navigation Toolbar在 Tkinter [.grid 方法] 中嵌入 MatPlotLib 图形,并自定义 MatPlotLib 的导航工具栏
【发布时间】:2020-04-20 09:03:21
【问题描述】:

我在将我的 MatPlotLib Graph 嵌入 Tkinter 时遇到了问题,在 Google 和 MatPlotLib 网站上进行了一些搜索之后,我能得到的最好的方法是标准方法:

import tkinter

from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)

fig = Figure(figsize=(5, 4), dpi=100)

canvas = FigureCanvasTkAgg(fig, master=root)

canvas.draw()

canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)

toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update()

canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)

现在,如果我尝试用 .grid 替换包装布局(并删除 .pack() 参数),我会得到一堆错误,无论我尝试了多少 Google 搜索,所有的方法在 Tkinter 中嵌入 MatPlotLib 图仅使用 pack 方法。有人可以帮我解决这个问题吗?我想嵌入图表,但使用网格方法,因为我的 GUI 应用程序的其余布局是 .grid 布局。

我在 Tkinter 中使用导航工具栏时遇到的另一个问题是导航工具栏显然可以自定义(至少根据 SentDex [5:18])。他似乎没有详细说明我是如何做到这一点的,这对我来说很困难,因为我对 MatPlotLib 的按钮不太满意(它们看起来非常过时和过时)。

有人可以帮我解决这个问题吗?当我只将图表放入时,它似乎工作得很好,但是当我尝试放入带有图表的导航工具栏时也会遇到问题。对此的任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: python matplotlib tkinter graph tkinter-canvas


    【解决方案1】:

    这是一个简单的 plotnavigation toolbar 内部 tkinter window 仅使用 grid 几何管理器。

    import tkinter as tk
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
    
    window = tk.Tk()
    
    btn = tk.Label(window, text='A simple plot')
    btn.grid(row=0, column=0, padx=20, pady=10)
    
    x = ['Col A', 'Col B', 'Col C']
    
    y = [50, 20, 80]
    
    fig = plt.figure(figsize=(4, 5))
    plt.bar(x=x, height=y)
    
    # You can make your x axis labels vertical using the rotation
    plt.xticks(x, rotation=90)
    
    # specify the window as master
    canvas = FigureCanvasTkAgg(fig, master=window)
    canvas.draw()
    canvas.get_tk_widget().grid(row=1, column=0, ipadx=40, ipady=20)
    
    # navigation toolbar
    toolbarFrame = tk.Frame(master=window)
    toolbarFrame.grid(row=2,column=0)
    toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)
    
    window.mainloop()
    

    输出图形界面

    我还没有定制导航工具栏,所以我没有为这部分提供任何解决方案。但如果我发现有用的东西,我肯定会调查并更新你。希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      我设法获得了一个简单的应用程序来控制带有窗口大小调整的 matplotlib 图形。

      我没有使用导航栏功能,所以这可能是这个框架的补充

      import tkinter as tk
      from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
      from matplotlib.figure import Figure
      from google.cloud import bigquery
      import os, json, sys
      from time import time
      import pandas as pd
      
      
      class SliderGraph:
      
          def __init__(self, master):
              self.master = master
              # with open(self.resource_path(config_file)) as fp:
              #     self.config = json.load(fp)
              # os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = self.resource_path(creds_file)
              # self.projectID = self.config['projectID']
              # self.datasetID = self.config['datasetID']
              # last_used_freq = self.config['last_used_frequency']
              # last_used_delta = self.config['last_used_delta']
      
              self.bounds = 1
              self.frame = tk.Frame(master)
              self.fig = Figure()
              row = 0
      
              self.ax = self.fig.add_subplot(111)
              self.ax.set_xlabel("Run Numbers")
              self.ax.set_ylabel("UDD")
              self.ax.set_ylim([-self.bounds,self.bounds])
      
              self.canvas = FigureCanvasTkAgg(self.fig, master=master)  # , width=win_width, height=(win_height-50))
              self.canvas.draw()
              self.canvas.get_tk_widget().grid(row=row, columnspan=2, sticky='nsew')
              row+=1
      
              self.table_label = tk.Label(master, text="Enter BigQuery Table Name")
              self.table_label.grid(row=row, column=0)
              # row += 1
      
              self.table_name = tk.Entry(master)
              # self.table_name.insert(0,self.config['last_used_table'])
              self.table_name.grid(row=row, column=1, sticky='ew')
              row += 1
      
              self.get_table_button = tk.Button(master, text="Get Table Data and Plot", command=self.plot_data)
              self.get_table_button.grid(row=row, columnspan=2)
              row += 1
      
              self.frequency_slider = tk.Scale(master, from_=400, to=4500, orient=tk.HORIZONTAL, command=self.update_plot)
              # self.frequency_slider.set(last_used_freq)
              self.frequency_slider.grid(row=row,columnspan=2, sticky="nsew")
              row += 1
      
              self.frequency_entry = tk.Entry(master)
              # self.frequency_entry.insert(0,last_used_freq)
              self.frequency_entry.grid(row=row, columnspan=2)
              row += 1
      
              self.delta_slider = tk.Scale(master, from_=-500, to=500, orient=tk.HORIZONTAL, command=self.update_plot)
              # self.delta_slider.set(last_used_delta)
              self.delta_slider.grid(row=row, columnspan=2, sticky="ensw")
              row += 1
      
              self.delta_entry = tk.Entry(master)
              # self.delta_entry.insert(0, last_used_delta)
              self.delta_entry.grid(row=row, columnspan=2)
              row += 1
      
              self.get_table_button = tk.Button(master, text="Autoscale", command=self.autoscale)
              self.get_table_button.grid(row=row,columnspan=2)
              row += 1
      
              tk.Grid.columnconfigure(master, 0, weight=1)
              tk.Grid.columnconfigure(master, 1, weight=1)
              tk.Grid.rowconfigure(master, 0, weight=5)
              for x in range(1,row):
                  tk.Grid.rowconfigure(master, x, weight=0)
      
              master.protocol('WM_DELETE_WINDOW', self.close)
      
              self.df = None
              self.frequency_list = []
              self.series = None
              self.elapsed = time()*1000
      
          def plot_data(self):
              self.ax.clear()
              self.client = bigquery.Client(project=self.projectID)
              self.tableID = f"`{self.datasetID}.{self.table_name.get()}`"
      
              QUERY = (
                  f"SELECT * EXCEPT (testCount,elapsed_run_time_ms_,moleculeValue,onboardTemp1,onboardTemp2,temp,tempControl,\
                   logamp, txrx,timestamp) FROM {self.tableID} ORDER BY runCount ASC;"
              )
              # query_job = self.client.query(QUERY)
              # rows = query_job.result()
              self.df = pd.read_gbq(QUERY,self.projectID)
      
              for col in self.df.columns:
                  if 'runCount' in col:
                      continue
                  self.frequency_list.append(int(col.replace('_','')))
              self.frequency_slider.configure(from_=min(self.frequency_list),to=max(self.frequency_list))
              self.delta_slider.configure(from_=-max(self.frequency_list),to=max(self.frequency_list))
      
              freq = f'_{self.frequency_slider.get()}'
              freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
              self.series = self.df[freq] - self.df[freq2]
              self.series.plot(ax=self.ax)
              self.ax.set_ylim([-self.bounds,self.bounds])
      
              self.fig.canvas.draw()
              self.fig.canvas.flush_events()
              pass
      
          def update_plot(self, newslider):
              try:
      
                  self.ax.clear()
                  freq = f'_{self.frequency_slider.get()}'
                  freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
                  self.series = self.df[freq] - self.df[freq2]
                  self.series.plot(ax=self.ax)
                  zero = self.series.mean()
                  self.ax.set_ylim([zero-self.bounds, zero+self.bounds])
                  self.fig.canvas.draw()
                  self.fig.canvas.flush_events()
                  # self.master.update_idletasks()
      
                  if ((time()*1000)-self.elapsed > 100):
                      self.elapsed = time()*1000
                      self.frequency_entry.delete(0,'end')
                      self.frequency_entry.insert(0,freq.replace('_',''))
                      self.delta_entry.delete(0,'end')
                      self.delta_entry.insert(0,self.delta_slider.get())
              except:
                  pass
      
          def play_runs(self):
              pass
      
          def autoscale(self):
              self.ax.clear()
              self.series.plot(ax=self.ax)
              self.ax.relim()
              self.ax.autoscale()
              zero = self.series.mean()
              self.bounds = self.series.max() - self.series.min()
              self.ax.set_ylim([zero-self.bounds,zero+self.bounds])
              self.fig.canvas.draw()
              self.fig.canvas.flush_events()
      
          def close(self):
      
              self.master.destroy()
      
      if __name__=="__main__":
          root = tk.Tk()
          slider_fig = SliderGraph(root)
          root.mainloop()
      

      【讨论】:

        猜你喜欢
        • 2018-11-03
        • 1970-01-01
        • 1970-01-01
        • 2013-09-03
        • 1970-01-01
        • 2019-03-23
        • 1970-01-01
        • 2012-10-06
        • 2020-10-17
        相关资源
        最近更新 更多