Tkinter canvas create_image 和 create_oval 优化
Tkinter canvas create_image and create_oval optimization
背景
我正在尝试并成功地使用 tkinter
中的 Canvas
对象创建了一个简单的绘图。我正在尝试使用尽可能多的随 Python3 安装的工具。 Matplotlib 和其他的都很棒,但对于我试图保持较小的东西来说,它们的安装量相当大。
图表根据硬件设备的输入每 0.5 秒更新一次。删除之前的 128 个点,绘制当前的 128 个点。请参阅我的 most recent blog post 以获取几个屏幕截图。我已经使用 canvas.create_oval()
成功地创建了绘图,但是当我使用 运行 时,我听到我的 PC 风扇稍微升高了一点(我让它们处于激进的热配置文件中)并意识到我正在使用15% CPU,这看起来很奇怪。
问题
在 运行ning cProfile 之后,我发现 canvas.create_oval()
花费的累积时间比我预期的要长。
在 tkinter canvas 中阅读了一些关于优化的内容后(除了 'use something else' 之外没有太多内容),我遇到了一个 post 建议可以使用点的图像并使用 canvas.create_images()
而不是 canvas.create_oval()
。我试过了 create_image()
中的时间有点少,但仍然很重要。
为了完整起见,我将包含代码片段。请注意,此方法是称为 Plot4Q
的 class 的一部分,它是 tk.Canvas
:
的子 class
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' 排序并突出显示了相关方法。
update_plots
呼叫 scatter
scatter
呼叫 plot_point
(以上)
请注意,scatter
消耗了总 运行 时间的 11.6%。
问题
是否有更有效的方法在 canvas 上创建点(并删除它们,尽管在 tkinter 中这不会花费很长时间)?
如果没有,是否有更有效的方法来创建绘图并将其嵌入到 tkinter 界面中?
我对使用不同的库持开放态度,但我希望它保持小而快。我原以为 tk canvas 会小而快,因为它可以在现代 PC 的 1/10 功率的机器上正常运行。
更多信息
在 运行得到以下有用的答案后 (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%。
canvas 在创建许多项目时会出现性能问题(更具体地说,在创建新对象 ID 时)。删除对象无济于事,问题在于不断增加的对象 ID,这些 ID 永远不会被重用。这个问题通常不会出现,直到你有 10 的几千个项目。如果您正在创建 256/秒,您将在一两分钟内开始遇到该问题。
如果您一次在屏幕外创建 128 个对象,然后简单地移动它们而不是销毁并重新创建它们,则可以完全消除这种开销。
背景
我正在尝试并成功地使用 tkinter
中的 Canvas
对象创建了一个简单的绘图。我正在尝试使用尽可能多的随 Python3 安装的工具。 Matplotlib 和其他的都很棒,但对于我试图保持较小的东西来说,它们的安装量相当大。
图表根据硬件设备的输入每 0.5 秒更新一次。删除之前的 128 个点,绘制当前的 128 个点。请参阅我的 most recent blog post 以获取几个屏幕截图。我已经使用 canvas.create_oval()
成功地创建了绘图,但是当我使用 运行 时,我听到我的 PC 风扇稍微升高了一点(我让它们处于激进的热配置文件中)并意识到我正在使用15% CPU,这看起来很奇怪。
问题
在 运行ning cProfile 之后,我发现 canvas.create_oval()
花费的累积时间比我预期的要长。
在 tkinter canvas 中阅读了一些关于优化的内容后(除了 'use something else' 之外没有太多内容),我遇到了一个 post 建议可以使用点的图像并使用 canvas.create_images()
而不是 canvas.create_oval()
。我试过了 create_image()
中的时间有点少,但仍然很重要。
为了完整起见,我将包含代码片段。请注意,此方法是称为 Plot4Q
的 class 的一部分,它是 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' 排序并突出显示了相关方法。
update_plots
呼叫scatter
scatter
呼叫plot_point
(以上)
请注意,scatter
消耗了总 运行 时间的 11.6%。
问题
是否有更有效的方法在 canvas 上创建点(并删除它们,尽管在 tkinter 中这不会花费很长时间)?
如果没有,是否有更有效的方法来创建绘图并将其嵌入到 tkinter 界面中?
我对使用不同的库持开放态度,但我希望它保持小而快。我原以为 tk canvas 会小而快,因为它可以在现代 PC 的 1/10 功率的机器上正常运行。
更多信息
在 运行得到以下有用的答案后 (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%。
canvas 在创建许多项目时会出现性能问题(更具体地说,在创建新对象 ID 时)。删除对象无济于事,问题在于不断增加的对象 ID,这些 ID 永远不会被重用。这个问题通常不会出现,直到你有 10 的几千个项目。如果您正在创建 256/秒,您将在一两分钟内开始遇到该问题。
如果您一次在屏幕外创建 128 个对象,然后简单地移动它们而不是销毁并重新创建它们,则可以完全消除这种开销。