Python Tkinter画布创建图像并创建椭圆优化 背景
我正在尝试并成功地使用Python Tkinter画布创建图像并创建椭圆优化 背景,python,python-3.x,plot,tkinter,tkinter-canvas,Python,Python 3.x,Plot,Tkinter,Tkinter Canvas,我正在尝试并成功地使用tkinter中的Canvas对象创建一个简单的绘图。我正在尽可能多地使用Python3安装的工具。Matplotlib和其他软件都很不错,但它们的安装量相当大,我正试图将其缩小一点 根据硬件设备的输入,每0.5s更新一次绘图。将删除之前的128个点,并绘制当前的128个点。请参见我的屏幕截图。我已经使用canvas.create_oval()成功地创建了绘图,但是当我运行它时,我听到我的电脑风扇有点加速(我有一个激进的热配置),并意识到我使用了15%的CPU,这似乎很奇怪
tkinter
中的Canvas
对象创建一个简单的绘图。我正在尽可能多地使用Python3安装的工具。Matplotlib和其他软件都很不错,但它们的安装量相当大,我正试图将其缩小一点
根据硬件设备的输入,每0.5s更新一次绘图。将删除之前的128个点,并绘制当前的128个点。请参见我的屏幕截图。我已经使用canvas.create_oval()成功地创建了绘图,但是当我运行它时,我听到我的电脑风扇有点加速(我有一个激进的热配置),并意识到我使用了15%的CPU,这似乎很奇怪
问题
在运行cProfile之后,我发现canvas.create_oval()
花费的累积时间比我预期的要多
在阅读了一些关于tkinter画布优化的内容后(除了“使用其他东西”之外,没有太多内容),我发现了一篇帖子,其中建议可以使用一个点的图像,并使用画布。create_images()
而不是画布。create_oval()
。我试过了,在create_image()
中的时间稍微少了一点,但仍然非常重要
为了完整性,我将包含代码片段。请注意,此方法是名为Plot4Q
的类的一部分,该类是tk.Canvas
的子类:
def plot_point(self, point, point_format=None, fill='green', tag='data_point'):
x, y = point
x /= self.x_per_pixel
y /= self.y_per_pixel
x_screen, y_screen = self.to_screen_coords(x, y)
if fill == 'blue':
self.plot.create_image((x_screen, y_screen), image=self.blue_dot, tag=tag)
else:
self.plot.create_image((x_screen, y_screen), image=self.green_dot, tag=tag)
简介
我是一个分析新手,所以谨慎的做法是包含该分析程序的部分输出。我已按“cumtime”排序,并强调了相关方法
callsupdate\u绘图
scatter
调用分散
(如上)绘图点
scatter
占用了总运行时间的11.6%
问题
有没有更有效的方法在画布上创建点(并删除点,尽管在tkinter中这不会花费很长时间)
如果没有,是否有更有效的方法创建绘图并将其嵌入tkinter接口
我对使用不同的库有点开放,但我想保持它的小型化和快速化。我原以为tk canvas会小而快,因为它在功率只有现代PC十分之一的机器上运行良好
更多信息
在运行了下面一个有用的答案(Brian Oakley)之后,我更新了结果
为了稍微解释一下更新后的代码,我再次使用了椭圆(我喜欢颜色控件)。我检查标签是否存在。如果该椭圆不存在,则在指定的点处创建新的椭圆。如果标记确实存在,则计算新坐标并调用move
函数
def plot_point(self, point, fill='green', tag='data_point'):
if not fill:
fill = self.DEFAULT_LINE_COLOR
point_width = 2
# find the location of the point on the canvas
x, y = point
x /= self.x_per_pixel
y /= self.y_per_pixel
x_screen, y_screen = self.to_screen_coords(x, y)
x0 = x_screen - point_width
y0 = y_screen - point_width
x1 = x_screen + point_width
y1 = y_screen + point_width
# if the tag exists, then move the point, else create the point
point_ids = self.plot.find_withtag(tag)
if point_ids != ():
point_id = point_ids[0]
location = self.plot.coords(point_id)
current_x = location[0]
current_y = location[1]
move_x = x_screen - current_x
move_y = y_screen - current_y
self.plot.move(point_id, move_x, move_y)
else:
point = self.plot.create_oval(x0,
y0,
x1,
y1,
outline=fill,
fill=fill,
tag=tag)
改进很小,分别为10.4%和11.6%。当创建许多项时(更具体地说,当创建新对象ID时),画布会出现性能问题。删除对象没有帮助,问题在于不断增加的对象ID永远不会被重用。这个问题通常不会出现,直到你有10的数以千计的项目。如果您创建的是256/秒,您将在一两分钟内开始遇到该问题
如果您一次在屏幕外创建128个对象,然后简单地移动它们,而不是销毁和重新创建它们,则可以完全消除此开销 好的,我来试一试。我可能要花一两天的时间才能恢复,但这很有道理,应该不难。当我得到结果时,我会写封信。谢谢你抽出时间!你的建议确实有帮助——10.4%对11.6%——但我必须说我在寻找更多的东西。我已经用更多的信息更新了我的问题。再次感谢@轻微混淆:看起来你仍然在做大量的工作来绘制每个像素。对我来说,
find_with tag
似乎没用——只要在启动时创建它们,就可以避免调用。如果你每半秒钟打128次电话,那似乎是不必要的开销。我想如果你把计算和作图分开,你就能更幸运地找出问题所在。计算所有点,而不进行任何绘制和纵断面。然后,简单地绘制128个点和轮廓。使用find_with tag
可以在同一画布上绘制(和删除)多组数据,并用标记对每组数据进行寻址。这允许我同时显示和删除多组数据,这在这个应用程序中非常有用。我意识到我在解释文档中没有很好地阐述这一点,所以我理解其中的困惑。我会按照你的建议去做。再次感谢@好吧,这是有道理的。