How can build a bar graph in turtle using dictionaries? - python

I was just wondering how can I make a bar graph that uses the key-pair from a dictionary to use it for the x-axis and the key-value to draw the graph.
For example: dic = {'0-10': 24, '10-20': 20, '20-30': 22, '30-40': 27, '40-50': 150, '50-60': 0, '60-70': 231, '70-80': 467, '80-90': 443, '90-100': 86}
I want the '0-10' as the x-axis and the number as the height of the bar. Here's my my code so bar but I can't find a find to draw the x-axis for it. Also the y-axis will always be 100.
import turtle
from main import value_pairs, key_values
# Basic function to draw "bar graph", it takes the height as prameter
def drawBar(t, height):
t.begin_fill()
t.left(90)
t.forward(height)
t.write(str(height))
t.right(90)
t.forward(40)
t.right(90)
t.forward(height)
t.left(90)
t.end_fill()
xs = value_pairs
maxheight = max(xs)
numbars = len(xs)
border = 5
wn = turtle.Screen()
wn.setworldcoordinates(0-border, 0-border, 40*numbars+border, maxheight+border)
wn.bgcolor("white")
t = turtle.Turtle()
t.color("black")
t.fillcolor("white")
t.pensize(3)
for x in value_pairs:
drawBar(t, x)

I've reworked your attempt to roughly do what you describe, filling in missing pieces from your posted code:
from turtle import Screen, Turtle
FONT_HEIGHT = 18
FONT = ('Arial', FONT_HEIGHT, 'normal')
BORDER = FONT_HEIGHT
def drawBar(t, datum):
label, height = datum
t.left(90)
t.begin_fill()
t.forward(height)
t.right(90)
t.forward(20)
if height > FONT_HEIGHT:
t.write(height, align="center", font=FONT)
t.forward(20)
t.right(90)
t.forward(height)
t.end_fill()
t.left(90)
t.backward(40)
t.forward(20)
t.write(label, align="center", font=FONT)
t.forward(20)
data = {
'0-10': 24,
'10-20': 20,
'20-30': 22,
'30-40': 27,
'40-50': 150,
'50-60': 0,
'60-70': 231,
'70-80': 467,
'80-90': 443,
'90-100': 86
}
maxheight = max(data.values())
numbars = len(data)
screen = Screen()
screen.setworldcoordinates(-BORDER, -BORDER, 40 * numbars + BORDER, maxheight + BORDER)
turtle = Turtle()
turtle.speed('fastest') # because I have no patience
turtle.fillcolor('white')
turtle.pensize(3)
for datum in data.items():
drawBar(turtle, datum)
turtle.hideturtle()
screen.exitonclick()
Matplotlib is the gold standard for data visualization with Python, but it's always fun to try these things with turtle to get a better understanding of what's involved in drawing plots.
Warning: this approach assumes ordered dictionaries -- not a historically safe assumption.

Related

Labeling a game board in python using turtle graphics

I'm currently making a 5x5 grid for a snakes and ladder but can't figure out how to display the numbers on the grid in this formation;
21,22,23,24,25
20,19,18,17,16
11,12,13,14,15
10, 9, 8, 7, 6
1 , 2, 3, 4, 5
The code I've wrote makes the 5x5 grid, I'm juts note sure how to add the labels of if I should take a
different approach with the code.
thanks for any help.
import turtle
t = turtle.Turtle()
speed = turtle.speed()
t.speed(10)
x=250
y=250
t.penup()
t.goto(-x,y)
t.pendown()
turtle.hideturtle()
turtle.ht()
for a in range(5):
t.penup()
t.goto(-x,-y)
t.pendown()
y=y-100
for b in range(5):
for n in range(5):
t.speed(10)
t.fd(100)
if n!=4:
t.right(90) here
Here's a solution that uses much of your existing logic, tweaking it a bit, and adds the numbers:
from turtle import Screen, Turtle
FONT_SIZE = 18
FONT = ('Arial', FONT_SIZE, 'bold')
BOXES = 5
BOX_SIZE = 100
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
x = -BOX_SIZE * BOXES / 2
y = -BOX_SIZE * BOXES / 2
for i in range(BOXES):
turtle.penup()
turtle.goto(x, y)
turtle.pendown()
for j in range(BOXES):
for _ in range(4):
turtle.forward(BOX_SIZE)
turtle.left(90)
dx, dy = turtle.position()
turtle.penup()
turtle.goto(dx + BOX_SIZE/2, dy + BOX_SIZE/2 - FONT_SIZE / 2)
turtle.write(j + BOXES * i + 1, align='center', font=FONT)
turtle.setposition(dx, dy)
turtle.pendown()
turtle.forward(BOX_SIZE)
y += BOX_SIZE
screen.exitonclick()
Centering-wise, the vertical font correction (FONT_SIZE / 2) is an approximation that works fine on my system but if you want an accurate solution for all systems, see this answer

How to make this wheel spin?

I have created the wheel, but when I try to make code to spin it will not work.
I have already tried to make it using a loop but that was near impossible for me. I am basically drawing the wheel over. Here is some code from the spinning wheel part:
turtle.listen()
if turtle.onkeypress("space"):
colors = ['#880000','#884400','#884400','#888800',
'#888800','#008800','#008800','#008800',
'#008800','#008800','#008888','#008888',
'#008888','#008888','#008888','#000088',
'#000088','#000088','#000088','#000088']
for color in colors:
slice_angle = 360 / len(colors)
heading, position = 90, (center[0] + radius, center[1])
turtle.color(color, color)
turtle.speed(0)
turtle.penup()
turtle.goto(position)
turtle.setheading(heading)
turtle.pendown()
turtle.begin_fill()
turtle.circle(radius, extent=slice_angle)
heading, position = turtle.heading(), turtle.position()
turtle.penup()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
time.sleep(0.2)
colors = ['#884400','#884400','#888800',
'#888800','#008800','#008800','#008800',
'#008800','#008800','#008888','#008888',
'#008888','#008888','#008888','#000088',
'#000088','#000088','#000088','#000088','#880000']
for color in colors:
slice_angle = 360 / len(colors)
heading, position = 90, (center[0] + radius, center[1])
turtle.color(color, color)
turtle.speed(0)
turtle.penup()
turtle.goto(position)
turtle.setheading(heading)
turtle.pendown()
turtle.begin_fill()
turtle.circle(radius, extent=slice_angle)
heading, position = turtle.heading(), turtle.position()
turtle.penup()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
time.sleep(0.2)
The code keeps on going to make the wheel 'spin'.
This is what I get:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/turtle.py", line 701, in eventfun
fun()
TypeError: 'str' object is not callable
My impression is that you're not trying to make the wheel spin but rather make it look like it's spinning by cycling its colors. Here's my example of doing such which uses tracer() and update() to turn off drawing while remaking the circle with the colors shifted. It uses a timer event to trigger redraws. Rather than your fixed list of colors, I'm going to use continuous hues, but you should be able to use any colors you wish:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
RADIUS = 100
NUMBER_OF_WEDGES = 20
SLICE_ANGLE = 360 / NUMBER_OF_WEDGES
screen = Screen()
screen.tracer(False)
turtle = Turtle(visible=False)
turtle.penup()
center = turtle.position()
turtle.sety(turtle.ycor() - RADIUS)
hues = [color / NUMBER_OF_WEDGES for color in range(NUMBER_OF_WEDGES)] # precompute hues
index = 0
def draw_circle():
global index
for hue in range(NUMBER_OF_WEDGES):
turtle.color(hsv_to_rgb(hues[(hue + index) % NUMBER_OF_WEDGES], 1.0, 1.0))
turtle.pendown()
turtle.begin_fill()
turtle.circle(RADIUS, extent=SLICE_ANGLE)
position = turtle.position()
turtle.goto(center)
turtle.end_fill()
turtle.penup()
turtle.goto(position)
screen.update()
index = (index + 1) % NUMBER_OF_WEDGES
screen.ontimer(draw_circle, 40)
draw_circle()
screen.exitonclick()
This works, but, on my system, inexplicably slows down over time.
Let's try a different approach that doesn't redraw anything at the Python level during the cycling of colors. We're going to design a new cursor shape, "wedge" and build our circle out of turtles! All the wedges will be prepositioned and not move nor be redrawn. The timer event handler will simply ask each turtle to take on the color of its neighbor:
from turtle import Screen, Turtle
from colorsys import hsv_to_rgb
RADIUS = 100
NUMBER_OF_WEDGES = 20
SLICE_ANGLE = 360 / NUMBER_OF_WEDGES
screen = Screen()
screen.tracer(False)
# create a pie wedge-shaped cursor
turtle = Turtle(visible=False)
turtle.begin_poly()
turtle.sety(turtle.ycor() - RADIUS)
turtle.circle(RADIUS, extent=SLICE_ANGLE)
turtle.home()
turtle.end_poly()
screen.register_shape("wedge", turtle.get_poly())
# create a turtle for each wedge in the pie
turtles = []
for hue in range(NUMBER_OF_WEDGES):
turtle = Turtle("wedge")
turtle.color(hsv_to_rgb(hue / NUMBER_OF_WEDGES, 1.0, 1.0))
turtle.setheading(hue * SLICE_ANGLE)
turtles.append(turtle)
def draw_circle():
# have each turtle take on the color of its neighbor
for index, turtle in enumerate(turtles):
turtle.color(*turtles[(index + 1) % NUMBER_OF_WEDGES].color())
screen.update()
screen.ontimer(draw_circle, 40)
draw_circle()
screen.exitonclick()
Notice how much simpler our main loop, draw_circle(), is and that the spinning doesn't slow down.

Use a while loop to control game in Python turtle

I am trying to make a random game in which whichever character reaches the end first wins. I have basically the entire code made, but I need help with the end to determine who crosses the finish line first. So how would I do that? My code is:
from turtle import Turtle
from random import randint
t = Turtle()
t.speed(0)
t.up()
t.goto(-200,0)
t.down()
t.forward(900)
t.up()
t.goto(-200,100)
t.down()
t.forward(900)
t.up()
t.goto(-200,200)
t.down()
t.forward(1000)
t.up()
t.goto(-200,-100)
t.down()
t.forward(900)
t.up()
t.goto(-200,-200)
t.down()
t.forward(1000)
t.up()
t.goto(-200,200)
t.down()
t.right(90)
t.forward(400)
t.left(90)
t.up()
t.goto(-100, -200)
t.left(90)
t.down()
t.forward(400)
t.up()
t.goto(800,-200)
t.down()
t.forward(400)
t.up()
t.goto(700,-200)
t.down()
t.forward(400)
d = Turtle()
d.speed(5)
d.color('red')
d.shape('arrow')
d.up()
d.goto(-155,150)
d.right(360)
c = Turtle()
c.speed(5)
c.color('blue')
c.shape('turtle')
c.up()
c.goto(-155,50)
c.right(360)
b = Turtle()
b.speed(5)
b.color('yellow')
b.shape('arrow')
b.up()
b.goto(-155,-50)
b.right(360)
a = Turtle()
a.speed(5)
a.color('green')
a.shape('turtle')
a.up()
a.goto(-155,-150)
a.right(360)
for i in range(350):
a.forward(randint(1,6))
b.forward(randint(1,6))
d.forward(randint(1,6))
c.forward(randint(1,6))
Any suggestions to make the code smaller would also be appreciated. I am trying to use a while loop so that I can stop the game as soon as the finish line is crossed.
We can test if a turtle's .xcor() value is greater than the x coordinate of the finish line to see if someone has won the race. I've reworked your code accordingly below along with some code compacting (but not as much as I could do, just to keep things nicely simple):
from turtle import Screen, Turtle
from random import randint
START_LINE = -300
FINISH_LINE = 300
screen = Screen()
screen.setup(1000, 600)
t = Turtle(visible=False)
t.speed('fastest')
# Race Lanes
for y in range(-200, 300, 100):
t.up()
t.goto(START_LINE - 100, y)
t.down()
t.forward((FINISH_LINE + 90) - (START_LINE - 100))
# Starting and Finishing Gates
for x in [START_LINE - 100, FINISH_LINE - 10]:
t.up()
t.goto(x, 200)
t.right(90)
t.down()
t.forward(400)
t.left(90)
t.forward(100)
t.left(90)
t.forward(400)
t.right(90)
d = Turtle('arrow')
d.color('red')
d.speed(5)
d.up()
d.goto(START_LINE - 50, 150)
d.right(360)
c = Turtle('turtle')
c.color('blue')
c.speed(5)
c.up()
c.goto(START_LINE - 50, 50)
c.right(360)
b = Turtle('arrow')
b.color('yellow')
b.speed(5)
b.up()
b.goto(START_LINE - 50, -50)
b.right(360)
a = Turtle('turtle')
a.color('green')
a.speed(5)
a.up()
a.goto(START_LINE - 50, -150)
a.right(360)
while a.xcor() < FINISH_LINE and b.xcor() < FINISH_LINE and c.xcor() < FINISH_LINE and d.xcor() < FINISH_LINE:
a.forward(randint(1, 6))
b.forward(randint(1, 6))
c.forward(randint(1, 6))
d.forward(randint(1, 6))
# The race is over
screen.mainloop()
It's good to define key locations with variables so that you don't have to work out numbers for every step in the code -- you can instead calculate and adjust as needed.

Changing bar graph colors in Python

I am new to Python and I am struggling with a lesson in our book where we have to change the colors in a bar graph. I am not sure what I am doing wrong. There is no error message the colors are just printing black.
import turtle
tess = turtle.Turtle()
def draw_bar(t, height):
t.begin_fill()
t.left(90)
t.forward(height)
t.write(" "+ str(height))
t.right(90)
t.forward(40)
t.right(90)
t.forward(height)
t.penup()
t.left(90)
t.end_fill()
t.forward(10)
t.pendown()
tess.pensize(3)
if xs is 48:
tess.color("blue")
if xs is 117:
tess.color("yellow")
wn = turtle.Screen()
wn.bgcolor("lightgreen")
xs = [48,117,200,240,160,260,220]
for a in xs:
draw_bar(tess, a)
wn.mainloop()
This is what I have so far.
Thanks for the help!
I think you need to have a color assigned before you begin_fill(). Because the computer is like: "Well, I'll fill the box, but I don't have a color", so it uses the default of black.
The if statement you provided doesn't make sense, so I moved it up in the function and modified it where you can examine the height within the function. Instead of using if/else, I'd recommend dictionaries.
This new code works:
import turtle
tess = turtle.Turtle()
def draw_bar(t, height):
# Select Color
if height is 48:
color = "blue"
elif height is 117:
color = "yellow"
else:
color = "black"
# Assign color
t.color(color)
# The rest of your code
t.begin_fill()
t.left(90)
t.forward(height)
t.write(" "+ str(height))
t.right(90)
t.forward(40)
t.right(90)
t.forward(height)
t.penup()
t.left(90)
t.end_fill()
t.forward(10)
t.pendown()
tess.pensize(3)
wn = turtle.Screen()
wn.bgcolor("lightgreen")
xs = [48,117,200,240,160,260,220]
for a in xs:
draw_bar(tess, a)
wn.mainloop()

Change appearance of turtle

I am programming in python 3.2.2 turtle. I am able to make the turtle follow my cursor when I clack but now I have trouble changing the appearance of the turtle. In my code you will see a tank, and I want the image of the tank to be my turtle.
Here is my code:
#importing modules
from turtle import Turtle
from turtle import *
#Setting up variables
unVar1 = 25
unVar2 = 100
unVar3 = 90
unVar4 = 150
unVar5 = -30
unVar6 = 75
unVar7 = 50
screen = Screen() # create the screen
#first part in making the turtle move
turtle = Turtle()
t = Turtle() # create the first turtle
t2 = Turtle() # create the second turtle
screen.onscreenclick(turtle.goto) # set up the callback for moving the first turtle
#defining shapes and objects
def drawSquare(t , xPrime, yPrime, sideLength):
t.up()
t.hideturtle()
t.goto(xPrime, yPrime)
t.setheading(270)
t.down()
for count in range(4):
t.forward(sideLength)
t.left(90)
t.end_fill()
def drawRectangle(t, x2, y2, sideLength1, sideLength2):
t.up()
t.hideturtle()
t.goto(x2, y2)
t.setheading(270)
t.down()
for count in range(2):
t.forward(sideLength1)
t.left(90)
t.forward(sideLength2)
t.left(90)
t.end_fill()
def drawTank():
t.pencolor("black")
t.fillcolor("gray")
t.begin_fill()
tire1 = drawRectangle(t, int("10"), unVar1, unVar6, int("30")) #Tire
t.begin_fill()
tire2 = drawRectangle(t, int("110"), unVar1, unVar6, int("30")) #Tire
t.begin_fill()
tire3 = drawRectangle(t, int("110"), unVar2, unVar6, int("30")) #Tire
t.begin_fill()
tire4 = drawRectangle(t, int("10"), unVar2, unVar6, int("30")) #Tire
t.pencolor("gray")
t.fillcolor("black")
t.begin_fill()
bodyTank = drawRectangle(t, int("20"), unVar3, int("130"), int("110"))
t.begin_fill()
gunTank = drawRectangle(t, int("65"), unVar4, int("100"), int("20")) #Gun
t.begin_fill()
exhaustTank = drawRectangle(t, int("50"), unVar5, int("20"), int("10"))
t.fillcolor("red")
t.begin_fill()
turretTank = drawSquare(t, int("50"), unVar7, int("50")) #Turret
t.end_fill()
drawTank()
screen.mainloop() # start everything running
You can create a tank cursor with the code you have, you just need to rearrange it. The drawing functions need to create polygons rather than draw directly to the screen. The following will create your tank cursor and drive it around the screen a bit. See the comments on tankCursor() about how you can also used fixed polygons instead -- you don't have to make a bitmap image to do this:
import turtle
unVar1 = 25
unVar2 = 100
unVar3 = 90
unVar4 = 150
unVar5 = -30
unVar6 = 75
unVar7 = 50
def polySquare(t, x, y, length):
t.goto(x, y)
t.setheading(270)
t.begin_poly()
for count in range(4):
t.forward(length)
t.left(90)
t.end_poly()
return t.get_poly()
def polyRectangle(t, x, y, length1, length2):
t.goto(x, y)
t.setheading(270)
t.begin_poly()
for count in range(2):
t.forward(length1)
t.left(90)
t.forward(length2)
t.left(90)
t.end_poly()
return t.get_poly()
def tankCursor():
"""
Create the tank cursor. An alternate solution is to toss the temporary turtle
and use the commented out polygon assignments instead of the poly* function calls
"""
temporary = turtle.Turtle()
screen = turtle.getscreen()
delay = screen.delay()
screen.delay(0)
temporary.hideturtle()
temporary.penup()
tank = turtle.Shape("compound")
# tire1 = ((10, unVar1), (10, unVar1 - unVar6), (10 + 30, unVar1 - unVar6), (10 + 30, unVar1))
tire1 = polyRectangle(temporary, 10, unVar1, unVar6, 30) # Tire #1
tank.addcomponent(tire1, "gray", "black")
# tire2 = ((110, unVar1), (110, unVar1 - unVar6), (110 + 30, unVar1 - unVar6), (110 + 30, unVar1))
tire2 = polyRectangle(temporary, 110, unVar1, unVar6, 30) # Tire #2
tank.addcomponent(tire2, "gray", "black")
# tire3 = ((110, unVar2), (110, unVar2 - unVar6), (110 + 30, unVar2 - unVar6), (110 + 30, unVar2))
tire3 = polyRectangle(temporary, 110, unVar2, unVar6, 30) # Tire #3
tank.addcomponent(tire3, "gray", "black")
# tire4 = ((10, unVar2), (10, unVar2 - unVar6), (10 + 30, unVar2 - unVar6), (10 + 30, unVar2))
tire4 = polyRectangle(temporary, 10, unVar2, unVar6, 30) # Tire #4
tank.addcomponent(tire4, "gray", "black")
# bodyTank = ((20, unVar3), (20, unVar3 - 130), (20 + 110, unVar3 - 130), (20 + 110, unVar3))
bodyTank = polyRectangle(temporary, 20, unVar3, 130, 110)
tank.addcomponent(bodyTank, "black", "gray")
# gunTank = ((65, unVar4), (65, unVar4 - 100), (65 + 20, unVar4 - 100), (65 + 20, unVar4))
gunTank = polyRectangle(temporary, 65, unVar4, 100, 20) # Gun
tank.addcomponent(gunTank, "black", "gray")
# exhaustTank = ((50, unVar5), (50, unVar5 - 20), (50 + 10, unVar5 - 20), (50 + 10, unVar5))
exhaustTank = polyRectangle(temporary, 50, unVar5, 20, 10)
tank.addcomponent(exhaustTank, "black", "gray")
# turretTank = ((50, unVar7), (50, unVar7 - 50), (50 + 50, unVar7 - 50), (50 + 50, unVar7))
turretTank = polySquare(temporary, 50, unVar7, 50) # Turret
tank.addcomponent(turretTank, "red", "gray")
turtle.addshape("tank", shape=tank)
del temporary
screen.delay(delay)
tankCursor() # creates and registers the "tank" cursor shape
turtle.shape("tank")
turtle.up() # get rid of the ink
# show our tank in motion
turtle.setheading(90)
turtle.forward(100)
turtle.left(90)
turtle.forward(100)
turtle.left(45)
turtle.forward(100)
turtle.done()
Since the tank is a shape you created using turtle, you can always simply take a screenshot of your tank and set that screenshot as the shape of the turtle using the turtle module's register_shape and shape functions like so:
turtle.register_shape("INSERT PATH OF SCREENSHOT HERE")
t.shape("INSERT PATH OF SCREENSHOT HERE")
However, if you want to do something harder, you can use the turtle.register_shape() method shown above, but instead of supplying the path of some image, you will instead have to supply a name, and then some coordinates to create the shape. In short, the syntax for that would be:
turtle.register_shape(name, (coordinates))
t.shape(name)
However, that would be very tedious seeing as how complex your tank already is, so I would recommend going on with the method above, where you just take a screenshot of the tank and use that screenshot as a shape for the turtle.
Also, some issues I see with your code:
The following:
from turtle import Turtle
from turtle import *
You are importing the turtle module twice. There is no need for that! from turtle import * already imports the Turtle() function, so the first import command is not needed. Therefore, change the import command to just:
from turtle import *
# The rest of your code...
When the user clicks on the screen to go somewhere, your turtle creates a line wherever it goes. There is a way to avoid this. However, I don't know if you want this, but if you do and decide to keep it, it does result in a lot of the lines going to places they were not supposed to and could eventually start hogging up a lot of memory until your program crashes. So I do recommend taking this step, but whether or not you do is up to you. However, if you do decide to take this step, then to start, define the following function after t2 = Turtle():
def Go(x, y):
# Turn the animation completely off
screen.tracer(0, 0)
# Pick the pen up so no lines are created as the turtle moves
turtle.penup()
# Go to the clicked position on the canvas
turtle.goto(x, y)
# Put the pen back down
turtle.pendown()
# Turn animation back on
screen.tracer(1, 1)
And then change:
screen.onscreenclick(turtle.goto)
To:
screen.onscreenclick(Go)
And that's it! I hope this helps! :)

Categories

Resources