UNEXPOSED = '~'
POKEMON = "☺"
FLAG = "♥"
EXPOSED = "0"
possible_adjacent_amount = ["0", "1", "2" "3", "4", "5", "6", "7", "8"]
def draw_board(self, board):
self.delete()
index = 0
print(board)
for row in range(self._grid_size):
for column in range(self._grid_size):
x1 = column*self._cell_size
y1 = row * self._cell_size
x2 = x1 + self._cell_size
y2 = y1 + self._cell_size
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
#bounding_box = ((int (x1), int (y1)), (int (x2), int (y2)))
centre_pixel = (x1 + (x2 - x1) // 2, y1 + (y2 - y1) // 2)
self.pos_to_pixel[(row, column)] = centre_pixel
#tp = self.create_text((100, 100), text='1')
print(board[index])
if board[index] ==UNEXPOSED:
self.create_rectangle (x1, y1, x2, y2, fill="dark green", tags="rect")
if board[index] in possible_adjacent_amount :
# TODO why doesn't this work...?
self.create_text(self.position_to_pixel ((row, column)), text = board[index])
self.create_rectangle (x1, y1, x2, y2, fill="light green", tags="rect")
if board[index] == FLAG:
self.create_rectangle (x1, y1, x2, y2, fill="red", tags="rect")
if board[index] == POKEMON:
self.create_text ((centre_pixel), text=board[index])
self.create_rectangle (x1, y1, x2, y2, fill="yellow", tags="rect")
index += 1
The board input will be something like 0~~~1~~12~~3
The idea is that it will take the board index and then create text at the center pixel of the board index that will be the numbers which in this case would be 0, 1, 1, 2, 3
You if you want the numbers to be drawn on the rectangles you need to create the text after you create the rectangles otherwise you will create text behind the rectangles.
Related
I am trying to make a fill between two datasets of different length using Matplotlib in Python.
Datasets are as follows
x1 = [0.00137221, 0.01372213, 0.02607204, 0.03910806, 0.05351629,
0.07066895, 0.08713551, 0.10634648, 0.12761578, 0.14888508,
0.17221269, 0.19691252, 0.2271012 , 0.25797599, 0.28747856,
0.31766724, 0.34373928, 0.36569468, 0.38559177]
y1 = [1.03307393, 1.04661479, 1.05875486, 1.07182879, 1.08723735,
1.10544747, 1.11945525, 1.13299611, 1.14607004, 1.15540856,
1.15680934, 1.15680934, 1.15354086, 1.14513619, 1.13346303,
1.12085603, 1.10964981, 1.09891051, 1.08677043]
x2 = [0.00960549, 0.03773585, 0.06929674, 0.11595197, 0.15574614,
0.18113208, 0.20994854, 0.2380789 , 0.27101201]
y2 = [1.00645914, 1.02233463, 1.03821012, 1.05315175, 1.05688716,
1.05595331, 1.04894942, 1.04054475, 1.01579767]
I followed the procedure suggested here:
fill between two lines lacking common x values
xfill = np.linspace(0,0.4,10)
y1fill = np.interp(xfill, x1,y1)
y2fill = np.interp(xfill, x2,y2)
plt.plot(x1,y1)
plt.plot(x2,y2)
plt.fill_between(xfill, y1fill,y2fill,color = "lightgray")
When I apply the suggested code, I am getting wrong fill_between:
Using pgfplots in LaTeX I am getting somewhat that I want
You can add an extra start/end point with the terminal values of the outside line:
x_start = min(x1[0], x2[0])
x_end = max(x1[-1], x2[-1])
y_start = y1[0] if x_start == x1[0] else y2[0]
y_end = y1[-1] if x_end == x1[-1] else y2[-1]
xfill = np.linspace(x_start, x_end, 100)
y1fill = np.interp(xfill, np.r_[x_start, x1, x_end], np.r_[y_start, y1, y_end])
y2fill = np.interp(xfill, np.r_[x_start, x2, x_end], np.r_[y_start, y2, y_end])
plt.plot(x1,y1)
plt.plot(x2,y2)
plt.fill_between(xfill, y1fill, y2fill, color="lightgray")
Output:
As a function:
def fill_between_ends(x1, x2, y1, y2, **kwargs):
x_start = min(x1[0], x2[0])
x_end = max(x1[-1], x2[-1])
y_start = y1[0] if x_start == x1[0] else y2[0]
y_end = y1[-1] if x_end == x1[-1] else y2[-1]
xfill = np.linspace(x_start, x_end,100)
y1fill = np.interp(xfill, np.r_[x_start, x1, x_end], np.r_[y_start, y1, y_end])
y2fill = np.interp(xfill, np.r_[x_start, x2, x_end], np.r_[y_start, y2, y_end])
plt.fill_between(xfill, y1fill, y2fill, **kwargs)
plt.plot(x1,y1)
plt.plot(x2,y2)
fill_between_ends(x1, x2, y1, y2, color="lightgray")
In the Python implementation of the Xiaolin Wu's line algorithm, a function is defined while being nested in another function. Part of the code:
def draw_line(img, p1, p2, color):
"""Draws an anti-aliased line in img from p1 to p2 with the given color."""
x1, y1 = p1
x2, y2 = p2
dx, dy = x2-x1, y2-y1
steep = abs(dx) < abs(dy)
p = lambda px, py: ((px,py), (py,px))[steep]
if steep:
x1, y1, x2, y2, dx, dy = y1, x1, y2, x2, dy, dx
if x2 < x1:
x1, x2, y1, y2 = x2, x1, y2, y1
grad = dy/dx
intery = y1 + _rfpart(x1) * grad
def draw_endpoint(pt):
x, y = pt
xend = round(x)
yend = y + grad * (xend - x)
xgap = _rfpart(x + 0.5)
px, py = int(xend), int(yend)
putpixel(img, p(px, py), color, _rfpart(yend) * xgap)
putpixel(img, p(px, py+1), color, _fpart(yend) * xgap)
return px
How does this work? Why didn't the programmer just define the code somewhere else and then call it in this function? If this function where to be called in a loop to draw multiple lines, wouldn't it be more efficient to just, as I said, define the nested function somewhere else?
try this:
class Humans():
def health(self, weight, height, age):
self.weight = weight
self.height = height
self.age = age
def health_health(self):
print(f'''This human is {self.age} years old; weighs {self.weight},
and has a height of {self.height}''')
Harar = Humans()
Harar.health(1,2,3)
Harar.health_health()
The reason why is because you are calling the function from the class definition, as opposed to the initialized object. You can do two things to fix this:
Call the function from the object that has been initialized:
class Foo:
def bar(x):
print(x)
a = Foo()
a.bar(10)
Or, define the function as a staticmethod:
class Foo:
#staticmethod
def bar(x):
print(x)
Foo.bar(10)
Both will output:
10
I have 3 points p1(x1, y1), p2(x2, y2) and p3(x3, y3). I am trying to calculate angle (in anti-clockwise direction) between these 3 points. I am using following dot product method as provided in multiple blogs and SE sites (like this).
def angle_between(p1, p2, p3):
x1, y1 = p1
x2, y2 = p2
x3, y3 = p3
v21 = (x1 - x2, y1 - y2)
v23 = (x3 - x2, y3 - y2)
dot = v21[0] * v23[0] + v21[1] * v23[1]
det = v21[0] * v23[1] - v21[1] * v23[0]
theta = np.rad2deg(np.arctan2(det, dot))
print(theta)
It is giving me correct angle for any points which are not on the straight line. For example
p1 = (0, 0)
p2 = (1, 0)
p3 = (1, 1)
angle_between(p1, p2, p3) # Prints -90
angle_between(p3, p2, p1) # Prints +90
However, if points are on the straight line, it is giving me same answer
p1 = (0, 0)
p2 = (1, 0)
p3 = (2, 0)
angle_between(p1, p2, p3) # Prints +180
angle_between(p3, p2, p1) # Prints +180
Here I was expecting (p3, p2, p1) to give -180. What am I missing here? If the method I am using is not correct, can someone help me point towards the correct method?
I have tried to use direct cosine law (as given here) but it only provides me angle without any sense of direction of the angle.
Check out this solution. It always provides positive angles, measured in anti-clockwise direction:
from math import atan2, degrees
def angle_between(p1, p2, p3):
x1, y1 = p1
x2, y2 = p2
x3, y3 = p3
deg1 = (360 + degrees(atan2(x1 - x2, y1 - y2))) % 360
deg2 = (360 + degrees(atan2(x3 - x2, y3 - y2))) % 360
return deg2 - deg1 if deg1 <= deg2 else 360 - (deg1 - deg2)
I'm new to python and learned a ton over the past 2 weeks. I have just started learning and experimenting with matplotlib.pylot. In my code, I have 3 seperate simple graphs on the same plot, in the third graph there are 2 lines. I am trying to have a green fill_between when y2 > y3, and red fill_between when y3 > y2. I have taken a look at other code, and they look identical to mine, but for some reason it doesn't work.
Any help?
There are a few commented lines, they are just experimentation.
import matplotlib.pyplot as plt
import random
from matplotlib import style
style.use('fivethirtyeight')
def create_points(nPoints):
xs = []
ys = []
for i in range(nPoints):
rand = random.randrange(0,3*nPoints)
xs.append(i)
ys.append(rand)
return xs, ys
x,y = create_points(200)
x1,y1 = create_points(200)
x2, y2 = create_points(200)
x3, y3 = create_points(200)
fig = plt.figure()
ax1 = plt.subplot2grid((6,1), (0,0), rowspan = 1, colspan = 1)
plt.title('Subplot2grid Method')
plt.ylabel('Plot 1')
ax2 = plt.subplot2grid((6,1), (1,0), rowspan = 4, colspan = 1, sharex = ax1)
plt.ylabel('Plot 2')
ax2_xtwin = ax2.twinx()
ax3 = plt.subplot2grid((6,1), (5,0), rowspan = 1, colspan = 1, sharex = ax1)
plt.xlabel('x')
plt.ylabel('Plot 3')
ax2_xtwin.fill_between(x,0,y, facecolor = '#0079a3', alpha = 0.4)
#ax2v.axes.yaxis.set_ticklables([])
ax2_xtwin.grid(False)
ax2_xtwin.set_ylim(0, 1.5*max(y))
ax3.plot(x2, y2, x2, y3, linewidth = 1, label = 'x2y2 plot', color = 'k')
#ax3.plot(x3, y3, linewidth = 1, label = 'x3y3 plot', color = 'firebrick')
ax3.fill_between(x2, y2, y3, where = (y2 >= y3), facecolor = 'darkgreen',
edgecolor = 'g', alpha = 0.5, interpolate = True)
ax3.fill_between(x2, y2, y3, where = (y2 <= y3), facecolor = 'firebrick',
edgecolor = 'r', alpha = 0.5, interpolate = True)
#Print Points
ax1.plot(x, y, linewidth = 1, label = 'xy plot', color = 'gold')
ax2.plot(x1, y1, linewidth = 1, label = 'x1y1 plot', color = 'sandybrown')
#ax3.plot(x2, y2, linewidth = 1, label = 'x2y2 plot', color = 'darkgreen')
#ax3.plot(x3, y3, linewidth = 1, label = 'x3y3 plot', color = 'firebrick')
plt.subplots_adjust(left = 0.15, bottom = 0.1, right = 0.9, top = 0.9,
wspace = 0.2, hspace = 0)
plt.show()
Edit:
Sorry I miss-understood your question.
If you delete color='k' in ax3.plot and mask the y2 after the first fill_between it works fine.
Change to...
ax3.plot(x2, y2, x2, y3, linewidth = 1, label = 'x2y2 plot')
ax3.fill_between(x2, y2, y3, where = (y2 >= y3), color = "g",
edgecolor = 'g', alpha = 0.5, interpolate = True)
y2 = np.ma.masked_greater(y2, y3)
ax3.fill_between(x2, y2, y3, where = (y2 <= y3), color="r",
edgecolor = 'r', alpha = 0.5, interpolate = True)
I'm not sure why but the facecolor didn't work on my side, so I changed to color.
Hope this helps.
Is there a way to make a function that just adds motion to an object like the motion_add function from Game Maker?
Like: motion_add(speed1, direction1, speed2, direction2)
... where speed1 and direction1 is the current values of the object and
speed2 and direction2 is the additive.
I've figured it out myself.
def CoordsToDir(x1, y1, x2, y2):
return atan2(y2 - y1, x2 - x1)*180/pi
def DirToCoords(direction, length):
return [cos((direction) * pi / 180) * length, sin((direction) * pi / 180) * length]
def motion_add(speed1, direction1, speed2, direction2):
[x1, y1] = DirToCoords(direction1, speed1)
[x2, y2] = map(sum, zip([x1, y1], DirToCoords(direction2, speed2)))
speed = hypot(x2, y2)
direction = CoordsToDir(0, 0, x2, y2)
return [speed, direction]