matplotlib中的大型可滚动图形非常慢

时间:2017-12-14 15:51:46

标签: python matplotlib

我使用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()

2 个答案:

答案 0 :(得分:0)

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

重新扩展是一个非常耗费流程的过程,可能会使您的程序变慢。因此,将缩放后的图像保存为自己的对象,以便缩放一次,然后在您想要调用绘图时随时参考缩放图像。

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

答案 1 :(得分:0)

因此,通过浏览,似乎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()