Laura
Laura

Reputation: 205

How to move text around when using turtle.write in Python?

I am trying to solve Exercise 9 from Chapter 5 of 'Think Python' ( version: http://openbookproject.net/thinkcs/python/english3e/conditionals.html ). It involves moving text from turtle.write around so it doesn't overlap with the barchart when the values are negative. I have tried using triple quotation marks """like this""" in order to add an extra row before the text, but the extra row goes in the wrong place. Please help?

import turtle
wn=turtle.Screen()
wn.bgcolor("lightgreen")
wn.title("Barcharts FTW")
pen=turtle.Turtle()
pen.hideturtle()
pen.color("blue","red")
pen.pensize(2)
pen.penup()
pen.goto(-300,-100)

def draw_bar (t,height):
    t.pendown()
    t.begin_fill()
    t.lt(90)
    t.fd(height)
    t.write("   " + str(height))
    t.rt(90)
    t.fd(40)
    t.rt(90)
    t.fd(height)
    t.end_fill()
    t.lt(90)
    t.penup()
    t.fd(10)

xs = [48, 117, 200, 240, -160, 260, 220]
for v in xs:
    draw_bar(pen,v)

wn.mainloop()

Upvotes: 1

Views: 13881

Answers (3)

Dave Zabel
Dave Zabel

Reputation: 1

Note the if height < 0 part, which checks if the bar height is negative. In that case, the turtle moves back (tur_pen.forward(-15)) so that when it writes the value the text is not overlapping the bar.

# Modified turtle pie chart II
# By Dave Zabel  3/29/2017 - 3/31/2017
# Import turtle and random modules
import turtle
import random

values = random.sample(range(-250, 250), 15)  # Initiate a list of 15 random values


def draw_bar(tur_pen, height):
    """Get turtle to draw one bar of height"""
    tur_pen.begin_fill()  # Begins color fill
    tur_pen.left(90)  # Starts a bar whose height is a value from the variable "values"
    tur_pen.forward(height)
    tur_pen.penup()  # Sequence checks for negative value so as to print value UNDER the line
    if height < 0:
        tur_pen.forward(-15)
    tur_pen.write('    ' + str(height))  # Prints the value of the bar height
    if height < 0:
        tur_pen.forward(15)
    tur_pen.pendown()  # Continues to complete one bar
    tur_pen.right(90)
    tur_pen.forward(40)
    tur_pen.right(90)
    tur_pen.forward(height)
    tur_pen.left(90)
    tur_pen.end_fill()  # Stops the fill process
    tur_pen.penup()  # Has the pen skip between bars
    tur_pen.forward(10)
    tur_pen.pendown()

bar_screen = turtle.Screen()  # Sets the attributes of the screen
bar_screen.title('Bar Graph')
bar_screen.bgcolor('light green')

bar = turtle.Turtle()  # Sets the attributes of the pen
bar.pensize(3)
bar.speed(5)
bar.penup()
bar.goto(-360, 0)
bar.pendown()
fill_color = ''  # Changes the fill color by height
for v in values:
    if v >= 200:
        fill_color = 'green'
    elif v >= 100 < 200:
        fill_color = 'yellow'
    elif v > 0 < 100:
        fill_color = 'gray'
    elif v < 0:
        fill_color = 'red'
    bar.color('blue', fill_color)
    draw_bar(bar, v)  # Starts the process

bar_screen.mainloop()  # Holds the screen open until the user closes it

Upvotes: 0

cdlane
cdlane

Reputation: 41872

@Laura, below is a different approach to building your bar chart using stamping instead of drawing. It also has some other features that might be of use to you whether you draw or stamp: it calculates where to center the graph in the window based on the data itself; it uses the align="center" feature of turtle.write() to align the labels with the bars; it explicitly sets the font rather than use the nearly unreadable default:

from turtle import Turtle, Screen

BAR_WIDTH = 40
BAR_SPACING = 10

FONTSIZE = 12
FONT = ('Arial', FONTSIZE, 'bold')

STAMP_UNIT = 20

xs = [48, -117, 200, 240, -160, 260, 220]

def draw_bar(t, height):
    y_baseline = t.ycor()

    t.turtlesize(abs(height) / STAMP_UNIT, BAR_WIDTH / STAMP_UNIT, 2)  # size the bar
    t.left(90)
    t.forward(height / 2)  # move to the center of the bar
    t.right(90)
    t.stamp()

    t.left(90)
    t.forward(height / 2 + (-3 * FONTSIZE / 2 if height < 0 else 0))  # adjust font position when negative
    t.right(90)
    t.write(str(height), align="center", font=FONT)  # center text on bar

    t.forward(BAR_WIDTH + BAR_SPACING)  # move to the next bar center x-wise
    t.sety(y_baseline)  # return to our calculated baseline y-wise

wn = Screen()
wn.bgcolor("lightgreen")
wn.title("Barcharts FTW")

pen = Turtle(shape="square", visible=False)
pen.color("blue", "red")
pen.penup()

pen.goto(len(xs) * (BAR_SPACING + BAR_WIDTH) / -2, -max(xs) - min(xs))  # center graph based on data

for value in xs:
    draw_bar(pen, value)

wn.exitonclick()

enter image description here

Another function to look into is turtle.setworldcoordinates(). Although it can be unwieldy for most applications, I've seen it used quite successfully in graphing problems as it lets you redefine the turtle's coordinate system to match your data needs.

Upvotes: 1

furas
furas

Reputation: 142651

Simply move turtle to write text in different place

ie.

t.penup()
if height < 0: 
   t.fd(-15)
t.write("   " + str(height))
if height < 0: 
   t.fd(15)
t.pendown()

Full code

import turtle

# --- functions ---

def draw_bar(t, height):
    t.pendown()
    t.begin_fill()
    t.lt(90)
    t.fd(height)

    t.penup()
    if height < 0:
        t.fd(-15)
    t.write("   " + str(height))
    if height < 0:
        t.fd(15)
    t.pendown()

    t.rt(90)
    t.fd(40)
    t.rt(90)
    t.fd(height)
    t.end_fill()
    t.lt(90)
    t.penup()
    t.fd(10)

# --- main ---

wn = turtle.Screen()
wn.bgcolor("lightgreen")
wn.title("Barcharts FTW")

pen = turtle.Turtle()
pen.hideturtle()
pen.color("blue","red")
pen.pensize(2)
pen.penup()
pen.goto(-300,-100)

xs = [48, -117, 200, 240, -160, 260, 220]
for v in xs:
    draw_bar(pen, v)

wn.mainloop()

Upvotes: 2

Related Questions