# Chronogram drawing by Michael Goldwasser import turtle #turtle.screensize(400,1000) def draw(tree, xScale, yScale, parentTime): reset() drawRecurse(tree, xScale, yScale, parentTime) def drawRecurse(tree, xScale, yScale, parentTime): """Draw the tree centered to the right of the current position, such that leaves end up separated vertically by yScale, and levels separated horizontally by xScale. The evolutionary time of the parent is the final parameter. """ # name the three pieces of the tuple label,first,second = tree isInternal = (first != ()) # by convention myTime = label if isInternal else 0 distance = (parentTime-myTime) * xScale # advance to node and draw label advance(distance) if isInternal: # if there are subtrees, draw those a = leafCount(first) b = leafCount(second) n = a + b lateral(-b/2 * yScale) drawRecurse(first, xScale, yScale, label) # recurse lateral(n/2 * yScale) drawRecurse(second, xScale, yScale, label) # recurse lateral(-a/2 * yScale) drawLabel(yScale, label) # remember to retreat from the node advance(-distance) #============================================================== def advance(distance): """Move forward given distance in current direction.""" turtle.forward(distance) def lateral(distance): """Assuming turtle starts (and ends) with rightward orientation, implement a vertical move of given distance. Positive value should be upward. """ turtle.right(90) turtle.forward(distance) turtle.left(90) #=========== some utility functions we've written ============= def drawLabel(yScale,label): fontSize = min(20,round(0.9*yScale)) if isinstance(label, float): label = '%5.2f' % label fontSize //= 2 turtle.penup() turtle.right(90) turtle.forward(fontSize/2) turtle.left(90) turtle.write( ' '+str(label), font=("Arial", fontSize, "normal")) turtle.right(90) turtle.backward(fontSize/2) turtle.left(90) turtle.pendown() def leafCount(tree): """Return number of leaves of the tree.""" root,first,second = tree # unpack the tuple if first == second == (): return 1 # tree with one node else: return leafCount(first) + leafCount(second) def savePostscript(filename): turtle.getscreen().getcanvas().postscript(file=filename) def reset(): """Reset the state of the turtle canvas and position.""" turtle.speed(0) turtle.clear() turtle.up() turtle.goto(-0.5*turtle.window_width(), 0) turtle.down() turtle.setheading(0) #==============================================================