Reputation: 205
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
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
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()
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
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