【问题标题】:Large scrollable figure in matplotlib is extremely slowmatplotlib 中的大型可滚动图形非常慢
【发布时间】:2018-05-28 18:42:24
【问题描述】:

我使用this post 中的方法创建了一个带有可滚动图形的 tkinter 窗口。基本上,我加载了一个相对较大的图像,我想使用 tk.Scale 调整其大小,但我希望包含该图形的窗口保持恒定大小。问题是,一旦我的身材达到约 16x16 英寸,程序就会变得慢得难以忍受。任何想法将不胜感激。

特别慢的线路是figure.set_size_inches([factor * s for s in oldSize])

下面是窗口的全部代码:

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
from tkinter import ttk

class MacroWindow(tk.Tk):
    def __init__(self, controller, *args, **kwargs):      
        tk.Tk.__init__(self, *args, **kwargs) #initialize regular Tk stuff

        #set properties for main window
        tk.Tk.wm_title(self, "Macro View")
        tk.Tk.geometry(self, newGeometry = '600x700+200+200')
        #define container for what's in the window
        self.controller = controller
        self.figSize_inches = [8,8]
        self.addScrollingFigure()
        frame_buttons = ttk.Frame(self)
        frame_buttons.grid(row = 1, column = 0, sticky = 'nsew')
        button_loadMacroImage = ttk.Button(frame_buttons,text = "Load Test Macro Image", command = 
                            lambda: self.loadMacroImage())
        button_loadMacroImage.grid(row = 0, column = 0, padx = 10, pady = 10, sticky = 'nw')
        self.scale_zoom = tk.Scale(self, orient = tk.VERTICAL)
        self.scale_zoom.grid(row = 2, column = 0, sticky = 'ew')
        self.scale_zoom.config(command = self.changeSize, from_=.1, to=5, resolution = .1)

    def addScrollingFigure(self):
        self.frame_canvas = ttk.Frame(self)
        self.frame_canvas.grid(row = 0, column = 0, sticky = 'nsew')
        # set up canvas with scrollbars
        canvas = tk.Canvas(self.frame_canvas)
        canvas.grid(row = 0, column = 0, sticky = 'nsew')
        xScrollbar = tk.Scrollbar(self.frame_canvas, orient = tk.HORIZONTAL)
        yScrollbar = tk.Scrollbar(self.frame_canvas, orient = tk.VERTICAL)
        xScrollbar.grid(row = 1, column = 0, sticky = 'ew')
        yScrollbar.grid(row = 0, column = 1, sticky = 'ns')
        canvas.config(xscrollcommand = xScrollbar.set)
        xScrollbar.config(command = canvas.xview)
        canvas.config(yscrollcommand = yScrollbar.set)
        yScrollbar.config(command = canvas.yview)

        #create figure and axis
        f_wholeCellFig = Figure(figsize = self.figSize_inches, dpi = fig_dpi)
        a=f_wholeCellFig.add_subplot(1,1,1)
        f_wholeCellFig.subplots_adjust(left = 0, right = 1,  bottom = 0, top = 1, wspace = 0.02, hspace = 0)

        self.wholeCellFig = f_wholeCellFig
        self.wholeCellAx = a

        #plug in the figure
        figAgg = FigureCanvasTkAgg(f_wholeCellFig,canvas)
        mplCanvas = figAgg.get_tk_widget()
        self.mplCanvas = mplCanvas
        self.canvas = canvas
        # and connect figure with scrolling region
        self.cwid = canvas.create_window(0, 0, window=mplCanvas, anchor='nw')
        self.changeSize(1.0)


    def changeSize(self,factor):
        if not isinstance(factor,float):
            factor = self.scale_zoom.get()
        figure = self.wholeCellFig
        oldSize = self.figSize_inches
        figure.set_size_inches([factor * s for s in oldSize])
        wi,hi = [i*figure.dpi for i in figure.get_size_inches()]
        self.mplCanvas.config(width = wi, height = hi)
        self.canvas.itemconfigure(self.cwid, width = wi, height = hi)
        self.canvas.config(scrollregion = self.canvas.bbox('all'), width = 500, height = 500)
        figure.subplots_adjust(left = 0, bottom = 0, top = 1, right = 1)
        figure.canvas.draw()

    def loadMacroImage(self):
        if simulation:
            image = io.imread('../testing/macroImage.tif')
        a = self.wholeCellAx
        a.clear()
        a.axis('equal')
        a.axis('off')
        self.volume = image
        self.multi_slice_viewer()

    def multi_slice_viewer(self):
        ax = self.wholeCellAx
        self.scale_z.config(command = self.scaleCallback, from_=0, to=self.volume.shape[0]-1)
        ax.index = self.volume.shape[0] // 2
        self.scale_z.set(ax.index)
        ax.imshow(self.volume[ax.index])
        self.wholeCellFig.canvas.draw()

root = tk.Tk()
window = MacroWindow(root)
root.mainloop()

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    所以我没有专门使用matplotlib,但通过阅读您的代码,看起来每次调用draw 命令时您都在缩放图像,这意味着图像每次移动时都会重新缩放。我可能是错的,但如果是这样的话,那也是你的问题。

    重新缩放是非常密集的过程,并且会减慢您的程序爬行速度。因此,将缩放后的图像保存为自己的对象,以便它缩放一次,然后在您想要调用绘图时随时参考缩放后的图像。

    但正如我所说,我没有与 matplotlib 合作过,所以我可能会误解你的代码在做什么,所以请随意忽略我 :)

    【讨论】:

      【解决方案2】:

      所以从四处浏览来看,Matplotlib 似乎不擅长快速处理事情,尤其是处理大图像。要在 Tkinter 中有一个大的、可滚动的图像,最好使用 PIL 和 TkImage。我处理了一个描述 here 的示例,我的结果有了很大的改进。

      这里是 Scott Harden 的代码示例(来自链接),用于创建带有可滚动图像的窗口:

      from Tkinter import *
      import Image, ImageTk
      
      class ScrolledCanvas(Frame):
           def __init__(self, parent=None):
                Frame.__init__(self, parent)
                self.master.title("Spectrogram Viewer")
                self.pack(expand=YES, fill=BOTH)
                canv = Canvas(self, relief=SUNKEN)
                canv.config(width=400, height=200)
                #canv.config(scrollregion=(0,0,1000, 1000))
                #canv.configure(scrollregion=canv.bbox('all'))
                canv.config(highlightthickness=0)
      
                sbarV = Scrollbar(self, orient=VERTICAL)
                sbarH = Scrollbar(self, orient=HORIZONTAL)
      
                sbarV.config(command=canv.yview)
                sbarH.config(command=canv.xview)
      
                canv.config(yscrollcommand=sbarV.set)
                canv.config(xscrollcommand=sbarH.set)
      
                sbarV.pack(side=RIGHT, fill=Y)
                sbarH.pack(side=BOTTOM, fill=X)
      
                canv.pack(side=LEFT, expand=YES, fill=BOTH)
                self.im=Image.open("./1hr_original.jpg")
                width,height=self.im.size
                canv.config(scrollregion=(0,0,width,height))
                self.im2=ImageTk.PhotoImage(self.im)
                self.imgtag=canv.create_image(0,0,anchor="nw",image=self.im2)
      
      ScrolledCanvas().mainloop()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多