Turtle graphics speed(). Seems broken

Alf P. Steinbach alfps at start.no
Sun Feb 28 06:49:22 CET 2010


* Dr. Phillip M. Feldman:
> 
> Stefan Behnel-3 wrote:
>> Alexander.Oot at gmail.com wrote:
>>> I think the speed function may be broken from the turtle graphics package
>>>
>>>
>>> "from turtle import *
>>>
>>> speed('fastest')
>>>
>>> forward(50)"
>>>
>>>
>>> I have tried all of the different speed settings, but I get no change
>>> in the turtle's speed.... does anyone know how to fix this?
>> Use "xturtle"? :)
>>
>> http://ada.rg16.asn-wien.ac.at/~python/xturtle/
>>
>> Stefan
>> -- 
>> http://mail.python.org/mailman/listinfo/python-list
>>
>>
> 
> The Python library's implementation of turtle graphics is slow to the point
> that many applications are simply impractical.  I recently converted a
> program to Python/turtle graphics that was originally written by my son
> using Processing; the result of the conversion is that the time to draw the
> balls increased by a factor of roughly 50!  (The Processing version takes
> less than 0.1 seconds to generate the image, while the Python version takes
> almost 5 seconds on the same computer).  It would be good if this
> performance problem can be fixed, either by patching the current
> implementation of turtle graphics, or by replacing it with xturtle if that
> is better. http://old.nabble.com/file/p27732940/balls.py balls.py 

Try to add

   turtle.tracer( 0 )

before generating the graphics, and

   turtle.update()

after.

It sort of speeds things up. :-)

To test it I had to rewrite your code a little, getting rid of the numpy 
dependency since I don't have numpy installed. Looks like this:


<code>
#from numpy import *
def array( data, dtype ): return data       # Emulate numpy array constructor

import random
from math import *
import sys
from time import time
import turtle # turtle graphics module

class Timer:
    """Track and record elapsed time, allowing an arbitrary number of timers."""

    from time import time

    # Constructor:
    def __init__(self):
       self.start= time()

    # Report elapsed time:
    def time(self):

       # Compute elapse time:
       elapsed= time() - self.start

       # Print elapsed time in seconds:
       print str(elapsed) + ' s',

       # If total elapsed time exceeds 60 seconds, also print time as
       # as minutes and seconds:
       if elapsed >= 60.0:
          minutes= numpy.floor(elapsed / 60.0)
          elapsed-= 60 * minutes
          print '= ' + num2str(minutes,0) + ' m ' + num2str(elapsed,3) + ' s'
       else:
          print

def main():


    # Section 1: User inputs.  All four arrays should have the same dimensions.

    balls_of_type = array([20, 20], dtype=int)
    radius_of_type= array([35, 25], dtype=float)
    mass_of_type  = array([4 ,  2], dtype=float)
    color_of_type = array([0 ,  1], dtype=int)

    canvas_width = 1000 # canvas width in pixels
    canvas_height= 800  # canvas height in pixels


    # Section 2: Setup.


    # Section 2.1: Initialize graphics.

    turtle.setup(width=canvas_width, height=canvas_height)

    # Use units of pixels for specifying locations on the screen:
    turtle.setworldcoordinates(0.0, 0.0, canvas_width, canvas_height)

    # Set background color to black:
    turtle.bgcolor("black")

    # We want to specify R, G, and B using whole numbers from 0 to 255:
    turtle.colormode(255)

    # Turn off animation and hide the turtle to get maximum drawing speed:
    turtle.speed('fastest')
    turtle.tracer( 0 )
    turtle.hideturtle()


    # Section 2.2: Preliminaries.

    ball_types= len(balls_of_type)

    max_tries= 1000
    tries= 0

    # The following variable counts the number of time ticks:
    tick= 0

    colors= [
      (255,    0,    0), # red
      ( 64,   64,  230), # blue, cobalt blue
      (125,    0,    0), # maroon
      (  0,  255,  255), # cyan,baby blue
      (255,  140,    0), # orange
      (  0,  255,    0), # green, light green
      (204,  128,    0), # brown
      (255,  200,  120), # light orange
      (255,  255,  140), # cream
      (0,    128,    0), # dark green, forest green
      (255,  128,  128), # peach
      (255,  255,    0), # yellow
      (0,      0,  204), # dark blue, navy blue
      (150,  355,  150), # light green
      (128,    0,  230), # purple
      (77,   204,    0), # avocado
      (255,  128,  255), # magenta, pink
      (0,    204,  204), # aqua, turquoise
      (230,  192,    0), # gold
      (255,  255,  255), # white
    ]

    # Allocate 2-element lists for basis and velocity vectors:
    u_hat= [0,0]
    v_hat= [0,0]
    uv_speed1b= [0,0]; # before the collision
    uv_speed2b= [0,0]; # before the collision
    uv_speed1a= [0,0]; # after the collision
    uv_speed2a= [0,0]; # after the collision


    # Section 2.3: Calculate the number of balls and allocate arrays whose sizes
    # depend on this.

    # `balls` is the total number of balls:
    balls= sum( balls_of_type )

    x         = balls*[0.0]  #zeros(balls, dtype=float)
    y         = balls*[0.0]  #zeros(balls, dtype=float)
    x_speed   = balls*[0.0]  #zeros(balls, dtype=float)
    y_speed   = balls*[0.0]  #zeros(balls, dtype=float)

    radius    = balls*[0.0]  #zeros(balls, dtype=float)
    mass      = balls*[0.0]  #zeros(balls, dtype=float)

    ball_type = balls*[0]    #zeros(balls, dtype=int)
    ball_color= [] # empty list


    # Section 2.4: Assign a ball type, radius, mass, color, initial position,
    # and initial velocity to each ball.

    n= -1

    for i in range(ball_types):

       # Valid color numbers are 0-19.  If the color number of a ball type is
       # greater than 19, the following line of code fixes the problem by randomly
       # assigning acolor number.
       if color_of_type[i] >= 20: color_of_type[i]= random.randint(0, 20)

       # In the following loop, j is the ball number for the ith type of ball:
       for j in range(balls_of_type[i]):

          # After the following statement executes, `n` will be one less than the
          # number of balls generated.
          n+= 1

          ball_type[n]= i

          radius[n]= radius_of_type[i]
          mass  [n]= mass_of_type  [i]

          ball_color.append( colors[color_of_type[i]] )

          # Continue loop until center coordinates for ball[n] are such that this
          # ball does not overlap any previously generated ball.  If the number of
          # iterations exceeds max_tries, then the program stops the loop if this
          # happens, the program doesn't work because there is not enough space
          # for all the balls in the container.

          for tries in range(max_tries):

             # generate random ball center coordinates:
             keepout= radius[n] + 2.0
             x[n]= random.uniform(keepout, canvas_width  - keepout)
             y[n]= random.uniform(keepout, canvas_height - keepout)

             # Check to see if two balls have been generated on top of each other.
             # First, we set good to True.  True means that this ball does not
             # overlap any of the other balls that we have checked so far.  At the
             # end of the inner loop, if good= False, this means that the ball did
             # overlap at least one of the previous balls, and the program goes back
             # to the top of the outer loop and generates new coordinates for the
             # current ball.

             good= True

             for m in range(n): # innermost loop
                dx= x[m] - x[n]
                dy= y[m] - y[n]
                d= sqrt(dx*dx + dy*dy)
                if (d <= radius[m] + radius[n] + 10):
                   good= False
                   break

             # end for inner for loop

             if good: break

          # end of loop over tries

          if not good:
            print "\nERROR: Not enough space for balls.\n"
            sys.exit()

          # Assign a random initial velocity to the current ball:
          theta= random.uniform(0.0, 2.0*pi)
          x_speed[n]= 2. * cos(theta)
          y_speed[n]= 2. * sin(theta)

       # end of loop over j (number of ball of current ball type)
    # end of loop over i (number of ball type)


    # Section 3: Draw the balls.

    # Initialize timer:
    t= Timer()

    for n in range(balls):

       turtle.penup()
       turtle.goto(x[n], y[n])
       turtle.pendown()

       turtle.color(ball_color[n])
       turtle.begin_fill()
       turtle.circle(radius[n])
       turtle.end_fill()

    turtle.update()

    # Display elapsed time:
    print "Total drawing time: ",
    t.time()
    raw_input('Hit Enter to close figure window.')

if __name__ == "__main__":
    msg = main()
    print(msg)
</code>


Cheers & hth.,

- Alf



More information about the Python-list mailing list