1

I'm making a recursive drawing of a tree using repl.it py turtle. This is my code

import turtle
import random
def about(x): return x * random.uniform(0.95,1.05)

# recursively draw a tree
def tree(t,a,s):
    if s<2: return
    t.left(a)
    t.fd(s)
    tree(t.clone(),about(30), s * about(.7))
    tree(t,about(-30), s * about(.7))

t = turtle.getpen()
t.ht(); t.speed(0); t.tracer(0)
tree(t,90,40)
t.update()

Also here. But it only draws part of the tree. If I change it to

t.tracer(150)

then it works! Also tracer(10) works, but tracer(200) does not work. Is there a limit to how high tracer can go?

cdlane
  • 40,441
  • 5
  • 32
  • 81
John Henckel
  • 10,274
  • 3
  • 79
  • 79

1 Answers1

2

First, let's discuss your drawing code. Your tree consists of about 500 lines drawn by 500 different turtles! This seems excessive, so let's rewrite your code to use a single turtle that undoes it's movements rather clone itself:

from turtle import Screen, Turtle
from random import uniform

def about(x):
    return x * uniform(0.95, 1.05)

# recursively draw a tree
def tree(t, a, s):
    if s < 2:
        return

    t.forward(s)
    t.left(a)
    tree(t, about(30), s * about(0.7))
    t.right(2 * a)
    tree(t, about(-30), s * about(0.7))
    t.left(a)
    t.backward(s)

screen = Screen()
screen.tracer(0)

turtle = Turtle()
turtle.hideturtle()
turtle.setheading(90)

tree(turtle, 15, 50)

screen.tracer(1)
screen.mainloop()

As far as tracer() is concerned, I wasn't able to reproduce your results but the image never completed either. The argument to tracer() specifies that you only want to update the image on every nth graphic operation. This is very specialized and I only recommend values of 0 and 1. First, it's difficult to calculate what every nth update should be, based on the algorithm, and what makes sense visually to the user. Second, in standard Python turtle, there are some operations that cause an update regardless of tracer() setting which throws off this calculation, unless you know when these extra update occur.

In your case, for speed purposes, set tracer(0) when the intense drawing begins, and set tracer(1) when you're done drawing. Then everything should work fine.

cdlane
  • 40,441
  • 5
  • 32
  • 81
  • Thanks for the advice to make the turtle "undo its movements" instead of cloning. That is much faster. However, `tracer(0)` still crashes half way through the tree (on repl.it) whilst `tracer(50)` does not crash. I'm pretty sure that tracer is queueing up all the actions, and not performing them until `update`. If the queue gets full, the program dies. That's why tracer(50) works, but tracer(0) does not. The parameter to tracer puts a limit on the size needed for the queue. But that's just speculation. I have no idea how it is implemented. – John Henckel Apr 28 '20 at 02:41
  • @JohnHenckel, I don't know what the repl.it turtle implementation (which is not standard Python) does tracer-wise, but on standard Python turtle, I don't believe that `tracer()` queues up anything. (Unlike the turtle undo buffer which does queue up graphic actions.) I believe that graphics are drawn to a backing store image and that `tracer()` controls how often (automatically and/or manually) that backing store is copied to the user screen as an `update()`. – cdlane Apr 28 '20 at 05:21
  • Thanks @cdlane I now suspect that repl.it has a limit on CPU cycles (for each time you press "Run") and that is why the tree is sometimes only partially drawn. – John Henckel Apr 30 '20 at 17:40