'Turtle slowing down for larger drawings
I have created some code in order to simulate sierpinski's triangle. For this, in my code, I set it so that it can simulate any number of points on the triangle, but I've noticed that increasing this to a large number, it ends up with the turtle taking an amount of time that increases as it goes on.
I did a sample output with 100 000 dots and this is what I got
0% done
Time since last update: 0.0019948482513427734
5.0% done
Time since last update: 1.2903378009796143
10.0% done
Time since last update: 1.8589198589324951
15.000000000000002% done
Time since last update: 2.325822114944458
20.0% done
Time since last update: 2.9351391792297363
25.0% done
Time since last update: 3.4773638248443604
30.0% done
Time since last update: 4.152036190032959
35.0% done
Time since last update: 4.7314231395721436
40.0% done
Time since last update: 5.260996103286743
44.99999999999999% done
Time since last update: 5.988528490066528
49.99999999999999% done
Time since last update: 6.804485559463501
54.99999999999999% done
Time since last update: 7.768667221069336
60.0% done
Time since last update: 8.379971265792847
65.0% done
Time since last update: 8.995774745941162
70.0% done
Time since last update: 15.876121282577515
75.00000000000001% done
Time since last update: 17.292492151260376
80.00000000000001% done
Time since last update: 29.57323122024536
85.00000000000001% done
Time since last update: 65.96741080284119
90.00000000000003% done
Time since last update: 148.21749567985535
95.00000000000003% done
the code in question to run the main loop of the program is this
t = turtle.Turtle()
t.penup()
curr_time = time()
for x in range(iterations):
#The code will take a while should the triangle be large, so this will give its % completion
if x / iterations > percent_done:
print(percent_done * 100, r"% done", sep='')
percent_done += 0.05
window.update()
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
c = determine_point(t, init_c)
make_point(t, c)
determine_point and make_point do not iterate at all, so I can't find a reason for turtle to slow down this considerably. Why does turtle slow down as more points are being created? (screen tracer has already been set to (0,0) and the code itself works as intended
make point:
def make_point(turt: turtle.Turtle, point):
'''
Basically does turt.goto(*point) where point is a list of length 2, then places a dot at that place
I did not use goto because I forgot what the function was, and instead of doing a 2 second google search to find out,
I did a 15 second google search to find out how to set the angle of the turtle, and use trigonometry and pythagorean
theorem in order to move the turt to the right position
'''
if point[0] != turt.xcor():
y = point[1] - turt.ycor()
x = point[0] - turt.xcor()
if x > 0:
turt.setheading(math.degrees(math.atan(y / x)))
else:
turt.setheading(math.degrees(math.pi + math.atan(y / x)))
else:
turt.setheading(0 if point[1] < turt.ycor() else 180)
turt.fd(pythag(turt.xcor(), turt.ycor(), point[0], point[1]))
turt.dot(3)
determine_point:
def determine_point(turt: turtle.Turtle, initial_cords):
'''
Returns the midpoint between the turt's current coordinates and a random one of the of the 3 starting points
'''
coord = initial_cords[random.randint(0, 2)]
result = []
result.append((coord[0] - turt.xcor()) / 2 + turt.xcor())
result.append((coord[1] - turt.ycor()) / 2 + turt.ycor())
return result
pythag:
def pythag(a, b, x, y):
'''
Does pythagorean theorem to find the length between 2 points
'''
return math.sqrt((x - a) ** 2 + (y - b) ** 2)
Solution 1:[1]
Although your code doesn't require more resources on each iteration, your program does because it is built atop libraries that do. This is true of both turtle and tkinter.
Although we think of turtle dot() as putting up dead ink, as opposed to stamp which can be selectively removed, to the underlying tkinter graphics, everything is live ink and adds to its (re)display lists.
I couldn't completely remove the increase in time for each iteration, but by optimizing the code, I believe I've reduced it to no longer being an issue. Some of my optimizations: put turtle into radians mode to avoid calls to math.degrees(); reduce calls into turtle, eg. by getting x and y in one step via position() rather than calling xcor() and ycor(); turn off turtle's undo buffer as it keeps a growing list of graphic commands:
from turtle import Screen, Turtle
from time import time
from random import choice
from math import sqrt, atan, pi
iterations = 100_000
init_c = [(300, -300), (300, 300), (-300, -300)]
def make_point(t, point):
'''
Basically do turtle.goto(*point) where point is a list of length 2,
then places a dot at that place
I did not use goto() because I forgot what the function was, and instead
of doing a 2 second google search to find out, I did a 15 second google
search to find out how to set the angle of the turtle, and use trigonometry
and pythagorean theorem in order to move the turtle to the right position
'''
x, y = t.position()
if point[0] != x:
dx = point[0] - x
dy = point[1] - y
if dx > 0:
t.setheading(atan(dy / dx))
else:
t.setheading(pi + atan(dy / dx))
else:
t.setheading(0 if point[1] < y else pi)
t.forward(pythag(x, y, point[0], point[1]))
t.dot(2)
def determine_point(t, initial_cords):
'''
Return the midpoint between the turtles's current coordinates
and a random one of the of the 3 starting points
'''
coord = choice(initial_cords)
x, y = t.position()
return [(coord[0] - x) / 2 + x, (coord[1] - y) / 2 + y]
def pythag(a, b, x, y):
'''
Do pythagorean theorem to find the length between 2 points
'''
return sqrt((x - a) ** 2 + (y - b) ** 2)
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.setundobuffer(None)
turtle.radians()
turtle.penup()
fraction_done = 0
curr_time = time()
for iteration in range(iterations):
# The code will take a while should the triangle be large, so this will give its % completion
if iteration / iterations > fraction_done:
screen.update()
print(fraction_done * 100, r"% done", sep='')
fraction_done += 0.05
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
make_point(turtle, determine_point(turtle, init_c))
screen.update()
screen.exitonclick()
CONSOLE
% python3 test.py
0% done
Time since last update: 0.024140119552612305
5.0% done
Time since last update: 1.2522082328796387
10.0% done
Time since last update: 1.619455099105835
15.000000000000002% done
Time since last update: 1.9793877601623535
20.0% done
...
Time since last update: 9.460317373275757
85.00000000000001% done
Time since last update: 10.161489009857178
90.00000000000003% done
Time since last update: 10.585438966751099
95.00000000000003% done
Time since last update: 11.479820966720581
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | cdlane |
