Understanding Tkinter Canvas Performance Limitations

I created a simple application to display a scatter chart using the Tkinter Canvas widget (see a simple example below). After building 10,000 data points, the application becomes very slow, which can be seen trying to resize the window.

I understand that every element added to the Canvas is an object, so at some point there may be some performance issues, however I expected the level to be much higher than 10,000 simple oval objects. In addition, I could accept some delays when drawing points or interacting with them, but after drawing them, why not just resize the window so slowly?

After reading the problems with the effbot effect with Canvas widgets, it seems that when resizing, unused continuous inactivity tasks may be required:

The Canvas widget implements a direct image of the damage / repair model. Changes to the canvas and external events, such as Expose, are all seen as “damage” to the screen. The widget supports a dirty rectangle to track the damaged area.

When the first corruption event occurs, the canvas registers an unoccupied task (using after_idle), which is used to “repair” the canvas when the program returns to the main Tkinter loop. You can force updates by calling the update_idletasks method.

So the question is, is there a way to use update_idletasks to make the application more responsive after the data has been built? If so, how?

The following is the simplest working example. Try resizing the window after loading to see how slow the application is.

Update

I initially observed this problem on Mac OS X (Mavericks), where I get a significant surge in CPU usage with a simple window resizing. Encouraged by Ramchandra's comments, I tested this on Ubuntu and this does not seem to be happening. Perhaps this is a Mac Python / Tk issue? It would not be the first I came across, see my other question:

PIL PNG display broken on OS X Mavericks?

Can someone try on Windows (I do not have access to the Windows window)?

I can try running on a Mac with my own compiled version of Python and see if the problem persists.

Minimum working example:

 import Tkinter import random LABEL_FONT = ('Arial', 16) class Application(Tkinter.Frame): def __init__(self, master, width, height): Tkinter.Frame.__init__(self, master) self.master.minsize(width=width, height=height) self.master.config() self.pack( anchor=Tkinter.NW, fill=Tkinter.NONE, expand=Tkinter.FALSE) self.main_frame = Tkinter.Frame(self.master) self.main_frame.pack( anchor=Tkinter.NW, fill=Tkinter.NONE, expand=Tkinter.FALSE) self.plot = Tkinter.Canvas( self.main_frame, relief=Tkinter.RAISED, width=512, height=512, borderwidth=1) self.plot.pack( anchor=Tkinter.NW, fill=Tkinter.NONE, expand=Tkinter.FALSE) self.radius = 2 self._draw_plot() def _draw_plot(self): # Axes lines self.plot.create_line(75, 425, 425, 425, width=2) self.plot.create_line(75, 425, 75, 75, width=2) # Axes labels for i in range(11): x = 75 + i*35 y = x self.plot.create_line(x, 425, x, 430, width=2) self.plot.create_line(75, y, 70, y, width=2) self.plot.create_text( x, 430, text='{}'.format((10*i)), anchor=Tkinter.N, font=LABEL_FONT) self.plot.create_text( 65, y, text='{}'.format((10*(10-i))), anchor=Tkinter.E, font=LABEL_FONT) # Plot lots of points for i in range(0, 10000): x = round(random.random()*100.0, 1) y = round(random.random()*100.0, 1) # use floats to prevent flooring px = 75 + (x * (350.0/100.0)) py = 425 - (y * (350.0/100.0)) self.plot.create_oval( px - self.radius, py - self.radius, px + self.radius, py + self.radius, width=1, outline='DarkSlateBlue', fill='SteelBlue') root = Tkinter.Tk() root.title('Simple Plot') w = 512 + 12 h = 512 + 12 app = Application(root, width=w, height=h) app.mainloop() 
+8
python osx-mavericks tkinter macos
source share
2 answers

There is actually a problem with some TKinter and OS Mavericks distributions. Obviously, you need to install ActiveTcl 8.5.15.1. There is a bug with TKinter and OS Mavericks. If it's still not too fast, there are a few more tricks below.

You could save several points in one image. If you do not change it very often, it should still be faster. If you change them more often, here are a few other ways to speed up your python program. This other thread talks about using cython to create a faster class. Since most of the slowdown is probably related to graphics, it probably won't make it much faster, but it can help.

Suggestions on how to speed up distance calculations

you can also speed up the for loop by defining an iterator (ex: iterator = (s.upper () for s in list_to_iterate_through)) in advance, but this is called to draw the window, and not permanently, since the window is supported, so it doesn't really matter . In addition, another way to speed up the process taken from python docs is to reduce the frequency of checking python background:

"The Python interpreter performs some periodic checks. In particular, it decides whether to allow another thread and start a waiting call (usually the call set by the signal handler). Do nothing, so performing these checks every pass around the interpreter loop can slow down There is a function in the sys module, setcheckinterval, that you can call to tell the interpreter how often to perform these periodic checks. Python 2.3 was by default 10. In 2.3, this was raised to 100. If you are not working with threads and you don’t expect to catch a lot of signals, setting this to a higher value can improve the performance of the interpreter, sometimes significantly. "

Another thing I found on the Internet is that for some reason, setting the time by changing os.environ ['TZ'] will speed up the program by a small amount.

If this still does not work, it is possible that TKinter is not the best program for this. Pygame may be faster or a program using a graphics card such as open GL (I don't think it's available for python, however)

+3
source share

Tk should loop on all of these ovals. I didn’t always have so many objects on canvas.

One solution is to draw your plot into an image object, and then put the image in your canvas.

0
source share

All Articles