Related
I would like to animate points that are changing position in a 3D scatterplot.
At the first timepoint the points in the scatterplot have the coordinates from the entry scatter[0][1] and then at the next timepoint the coordinates are scatter[1][2] and so on.
I have already set up the animation function from mathplotlib but it doesn't update.
Any help with this issue would be greatly appreciated.
from matplotlib import pyplot as plt
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
from matplotlib import animation
fig = plt.figure()
ax = p3.Axes3D(fig)
ax.set_xlim3d([0, 100])
ax.set_xlabel('X')
ax.set_ylim3d([0, 100])
ax.set_ylabel('Y')
ax.set_zlim3d([0, 100])
ax.set_zlabel('Z')
scatter=[
np.array([9.956433493781429,
np.array([[50, 50, 50],
[53, 54, 55],
[50, 51, 50],
[52, 52, 52],
[50, 50, 52]])]),
np.array([10.189591392765704,
np.array([[50, 50, 50],
[73, 74, 75],
[70, 71, 70],
[72, 72, 72],
[70, 70, 72]])]),
np.array([10.40490011215984,
np.array([[80, 80, 80],
[83, 84, 75],
[80, 81, 60],
[82, 82, 42],
[88, 80, 52],
[89, 81, 29]])])
]
x=scatter[0][1][:,0]
y=scatter[0][1][:,1]
z=scatter[0][1][:,2]
points, = ax.plot(x, y, z, '*')
txt = fig.suptitle('')
def update_points(num,x, y, z, points):
for i in np.arange(0,len(scatter)):
txt.set_text('time={:f}'.format(scatter[i][0]))
new_x = scatter[i][1][:,0]
new_y = scatter[i][1][:,1]
new_z = scatter[i][1][:,2]
points.set_data(new_x,new_y)
points.set_3d_properties(new_z, 'z')
return points,txt
ani=animation.FuncAnimation(fig, update_points, frames=len(scatter), fargs=(x, y, z, points))
plt.show()
I found the solution. The code needs to be like this:
from matplotlib import pyplot as plt
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
from matplotlib import animation
fig = plt.figure()
ax = p3.Axes3D(fig)
ax.set_xlim3d([0, 100])
ax.set_xlabel('X')
ax.set_ylim3d([0, 100])
ax.set_ylabel('Y')
ax.set_zlim3d([0, 100])
ax.set_zlabel('Z')
scatter=[
np.array([9.956433493781429,
np.array([[50, 50, 50],
[53, 54, 55],
[50, 51, 50],
[52, 52, 52],
[50, 50, 52]])]),
np.array([10.189591392765704,
np.array([[50, 50, 50],
[73, 74, 75],
[70, 71, 70],
[72, 72, 72],
[70, 70, 72]])]),
np.array([10.40490011215984,
np.array([[80, 80, 80],
[83, 84, 75],
[80, 81, 60],
[82, 82, 42],
[88, 80, 52],
[89, 81, 29]])])
]
x=scatter[0][1][:,0]
y=scatter[0][1][:,1]
z=scatter[0][1][:,2]
points, = ax.plot(x, y, z, '*')
txt = fig.suptitle('')
def update_points(num,x, y, z, points):
#for i in range(len(scatter)):
print(num,range(len(scatter)))
txt.set_text('time={:f}'.format(scatter[num][0]))
new_x = scatter[num][1][:,0]
new_y = scatter[num][1][:,1]
new_z = scatter[num][1][:,2]
print(new_x,new_y,new_z)
points.set_data(new_x,new_y)
points.set_3d_properties(new_z, 'z')
return points,txt
ani=animation.FuncAnimation(fig, update_points, frames=3, fargs=(x, y, z, points))
plt.show()
I had two python files one for all the data that made previously and the other file of functions to display the data properly on screen using pygame.
--Functioning--
My idea is that the display of the segments is named alphabetically A,B,C,D,E,F,G
Here, till now every segment is displaying but if you see in my data.py code you can see there is a dictionary called 'final_data' where each number has it's binary code which simply means "How many segments had to glow..." Note:- '1' means to glow and '0' means to not glow, you can say these are buttons. each button has a list of [x,y,width,height] to get display on the screen. I also give the binaries and there positions. The dictionary is working properly the problem is in it's implementation in my second file 'functions.py'.
--Code--
My first file is data.py and the code is......
nums = (0,1,2,3,4,5,6,7,8,9)
binaries = ([1,1,1,1,1,1,0],[1,1,0,0,0,0,0],[1,0,1,1,0,1,1],[1,1,1,0,0,1,1],
[1,1,0,0,1,0,1],[0,1,1,0,1,1,1],[0,1,1,1,1,0,1],[1,1,0,0,0,1,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1])
positions = ([200,110,10,50],[200,170,10,50],[150,220,50,10],[140,170,10,50],[140,110,10,50],[150,100,50,10],[150,160,50,10])
final_data = {'0':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10]], "0": [[150, 160, 50, 10]]},
'1':{"1": [[200, 110, 10, 50], [200, 170, 10, 50]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]]},
'2':{"1": [[200, 110, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[200, 170, 10, 50], [140, 110, 10, 50]]},
'3':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[140, 170, 10, 50], [140, 110, 10, 50]]},
'4':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [150, 100, 50, 10]]},
'5':{"1": [[200, 170, 10, 50], [150, 220, 50, 10], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]],"0": [[200, 110, 10, 50], [140, 170, 10, 50]]},
'6':{"1": [[200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]],"0": [[200, 110, 10, 50], [150, 100, 50, 10]]},
'7':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 100, 50, 10]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]]},
'8':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]]},
'9':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[140, 170, 10, 50]]}
}
"""
A,B,C,D,E,F,G
1,1,1,1,1,1,0
1,1,0,0,0,0,0
1,0,1,1,0,1,1
1,1,1,0,0,1,1
1,1,0,0,1,0,1
0,1,1,0,1,1,1
0,1,1,1,1,0,1
1,1,0,0,0,1,0
1,1,1,1,1,1,1
1,1,1,0,1,1,1
"""
My second file functions.py
import pygame, sys
pygame.init()
size = width,height = 400,400
running = True
segments = []
screen = pygame.display.set_mode(size)
def draw_rect(x,y,width,height):
pygame.draw.rect(screen,(0,0,0),(x,y,width,height))
def digits():
#A
draw_rect(200,110,10,50)
#B
draw_rect(200,170,10,50)
#C
draw_rect(150,220,50,10)
#D
draw_rect(140,170,10,50)
#E
draw_rect(140,110,10,50)
#F
draw_rect(150,100,50,10)
#G
draw_rect(150,160,50,10)
while running:
screen.fill((148,241,251))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
if key[pygame.K_q]:
run = False
sys.exit()
digits()
pygame.display.update()
**please tell me in comments do you like my idea? and is the format of asking question is correct. **
You don't need final_data at all. Just write a function draw_digit:
def draw_digit(surf, color, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, positions[j])
And call it like this:
draw_digit(screen, "black", 0)
Add an additional offset argument to display multiple digits in a row:
def draw_digit(surf, color, offset, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, pygame.Rect(positions[j]).move(offset, 0))
draw_digit(screen, "black", 0, 2)
draw_digit(screen, "black", 100, 3)
Minimal example:
repl.it/#Rabbid76/PyGame-7SegementDisplay
data.py
binaries = ([1,1,1,1,1,1,0],[1,1,0,0,0,0,0],[1,0,1,1,0,1,1],[1,1,1,0,0,1,1],
[1,1,0,0,1,0,1],[0,1,1,0,1,1,1],[0,1,1,1,1,0,1],[1,1,0,0,0,1,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1])
positions = ([200,110,10,50],[200,170,10,50],[150,220,50,10],[140,170,10,50],[140,110,10,50],[150,100,50,10],[150,160,50,10])
functions.py
import pygame, sys
from data import *
pygame.init()
size = width,height = 400,400
run = True
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
def draw_digit(surf, color, offset, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, pygame.Rect(positions[j]).move(offset, 0))
count = 0
while run:
clock.tick(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((148,241,251))
draw_digit(screen, "black", 0, count // 10)
draw_digit(screen, "black", 100, count % 10)
count += 1
if count >= 100:
count = 0
pygame.display.update()
I have list of lists:
[[[10, 15, 200, 220], [10, 15, 200, 220], 0.0],
[[10, 15, 200, 220], [20, 25, 200, 230], 17.320508075688775],
[[110, 150, 240, 300], [10, 15, 200, 220], 190.3286631067428],
[[110, 150, 240, 300], [100, 150, 230, 300], 14.142135623730951],
[[110, 150, 240, 300], [110, 150, 240, 300], 0.0]]
I want to get maximum value of each element in a list, if the third real number is less than a threshold (let's say 50). In other words in the above case, the desired resulst would be:
1) filter results based on the threshold, e.g.
[[[10, 15, 200, 220], [10, 15, 200, 220], 0.0],
[[10, 15, 200, 220], [20, 25, 200, 230], 17.320508075688775],
[[110, 150, 240, 300], [100, 150, 230, 300], 14.142135623730951],
[[110, 150, 240, 300], [110, 150, 240, 300], 0.0]]
2) get maximum of each element in list:
[20, 25, 200, 230]
[110, 150, 240, 300]
>>> L = [[[10, 15, 200, 220], [10, 15, 200, 220], 0.0],
... [[10, 15, 200, 220], [20, 25, 200, 230], 17.320508075688775],
... [[110, 150, 240, 300], [10, 15, 200, 220], 190.3286631067428],
... [[110, 150, 240, 300], [100, 150, 230, 300], 14.142135623730951],
... [[110, 150, 240, 300], [110, 150, 240, 300], 0.0]]
You can filter the lists of lists on the last element with a list comprehension:
>>> [M for M in L if M[-1]<50]
[[[10, 15, 200, 220], [10, 15, 200, 220], 0.0], [[10, 15, 200, 220], [20, 25, 200, 230], 17.320508075688775], [[110, 150, 240, 300], [100, 150, 230, 300], 14.142135623730951], [[110, 150, 240, 300], [110, 150, 240, 300], 0.0]]
Now, to merge the previous lists, you can use a zip (I added a filter on 0 that is implied by the desired output):
>>> [[max(*xs) for xs in zip(*M[:-1])] for M in L if 0<M[-1]<50]
[[20, 25, 200, 230], [110, 150, 240, 300]]
Explanation: the idea is to zip the lists, e.g.:
>>> list(zip([10, 15, 210, 220], [10, 25, 200, 250]))
[(10, 10), (15, 25), (210, 200), (220, 250)]
And to take the greatest element of tuples:
>>> [max(x,y) for x,y in zip([10, 15, 210, 220], [10, 25, 200, 250])]
[10, 25, 210, 250]
I used the star operator to make the code more flexible: it doesn't rely on the number of lists:
>>> list(zip([10, 15, 210, 220], [10, 25, 200, 250], [15, 20, 210, 260]))
[(10, 10, 15), (15, 25, 20), (210, 200, 210), (220, 250, 260)]
>>> [max(*xs) for xs in zip([10, 15, 210, 220], [10, 25, 200, 250], [15, 20, 210, 260])]
[15, 25, 210, 260]
Try this:
a = [[[10, 15, 200, 220], [10, 15, 200, 220], 0.0],
[[10, 15, 200, 220], [20, 25, 200, 230], 17.320508075688775],
[[110, 150, 240, 300], [10, 15, 200, 220], 190.3286631067428],
[[110, 150, 240, 300], [100, 150, 230, 300], 14.142135623730951],
[[110, 150, 240, 300], [110, 150, 240, 300], 0.0]]
filtered = [i for i in a if i[2] < 50.0]
[get_maximum( i ) for i in filtered]
Which will work once you explain what does "2) get maximum of each element in list:" means or implement it yourself.
I have been trying to figure this out but could'nt find a solution, here is the situation:
I have a list of tuples like this:
list = [(5,8,3)
,(4,5,6)
,(7,8,9)]
and I have another list holding values, like this one:
#the lists inside list2 are user supplied lists
list2 = [[10,20,30]
,[40,50,60]
,[70,80,90]]
I want the output to be as follows:
5*10, 5*20, 5*30
8*40, 8*50, 8*60
3*70, 3*80, 3*90
4*10, 4*20, 4*30
5*40, 5*50, 5*60
6*70, 6*80, 6*90
7*10, 7*20, 7*30
8*40, 8*50, 8*60
9*70, 9*80, 9*90
You can use list comprehensions. But given these are array manipulations, I suggest you use a specialist 3rd party library such as NumPy. Here's one way:
import numpy as np
L1 = np.array([(5, 8, 3),
(4, 5, 6),
(7, 8, 9)])
L2 = np.array([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
res = np.transpose((L1[:, None, :] * L2[:, :, None].T), axes=[0, 2, 1])
Result:
array([[[ 50, 100, 150],
[320, 400, 480],
[210, 240, 270]],
[[ 40, 80, 120],
[200, 250, 300],
[420, 480, 540]],
[[ 70, 140, 210],
[320, 400, 480],
[630, 720, 810]]])
nested list comprehensions
In [15]: [[[c*d for d in b] for c in a ] for a in list for b in list2]
Out[15]:
[[[50, 100, 150], [80, 160, 240], [30, 60, 90]],
[[200, 250, 300], [320, 400, 480], [120, 150, 180]],
[[350, 400, 450], [560, 640, 720], [210, 240, 270]],
[[40, 80, 120], [50, 100, 150], [60, 120, 180]],
[[160, 200, 240], [200, 250, 300], [240, 300, 360]],
[[280, 320, 360], [350, 400, 450], [420, 480, 540]],
[[70, 140, 210], [80, 160, 240], [90, 180, 270]],
[[280, 350, 420], [320, 400, 480], [360, 450, 540]],
[[490, 560, 630], [560, 640, 720], [630, 720, 810]]]
I have a problem with generating map. It uses several lists which contain list of vectors. There is also list of lists of wall set(which set represent maze in place pointed by vector). So I have problem with random. When I pick random item from list of mazes. Program is going crazy, and creates something which doesn't make much sense. I tried to pick manually each maze and it worked perfectly. I tried to find solution to this problem but there wasn't answer for this kind of problem. There is definitelly something wrong with taking random item from list of mazes in this loop.`
EDIT: Here is program which can be run to see results.
import pygame, random, sys
WIDTH= 640
HEIGHT = 480
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
clock = pygame.time.Clock()
screen= pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(WHITE)
wall_list = pygame.sprite.Group()
all_sprite_list = pygame.sprite.Group()
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
def ran_map():
walls_1 = [ [0, 0, 40, 20],
[60, 0, 30, 20],
[0, 40, 40, 10],
[60, 40, 30, 10]
]
walls_2 = [ [0, 0, 60, 10],
[40, 10, 20, 10],
[0, 30, 20, 20],
[20, 40, 70, 10],
[80, 0, 10, 40]
]
walls_3 = [ [0, 0, 10, 50],
[10, 0, 80, 10],
[80, 10, 10, 40],
[30, 30, 30, 20]
]
s_maze = [walls_1, walls_2, walls_3]
vectors = [[60, 60], [170, 60], [380, 60], [490, 60], [60, 370], [170, 370], [380, 370], [490, 370]]
for item in vectors:
v1 = item[0]
v2 = item[1]
random_item = random.choice(s_maze)
for item in random_item:
w1 = item[0]
w2 = item[1]
s1 = w1+ v1
s2 = w2+ v2
wall = Wall(s1, s2, item[2], item[3])
wall_list.add(wall)
all_sprite_list.add(wall)
def xz():
done = False
while not done:
pygame.init()
clock.tick(45)
ran_map()
all_sprite_list.draw(screen)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
def main():
xz()
main()
The "going crazy" is most likely due to this duplicated iteration variable:
for *item* in vectors:
...
for *item* in random_item:
I suggest you simplify the middle section of your code as follows:
...
mazes = { # a dictionary of mazes
'walls_1': [ [0, 0, 40, 20],
[60, 0, 30, 20],
[0, 40, 40, 10],
[60, 40, 30, 10]
],
'walls_2': [ [0, 0, 60, 10],
[40, 10, 20, 10],
[0, 30, 20, 20],
[20, 40, 70, 10],
[80, 0, 10, 40]
],
'walls_3': [ [0, 0, 10, 50],
[10, 0, 80, 10],
[80, 10, 10, 40],
[30, 30, 30, 20]
]
}
vectors = [[60, 60], [170, 60], [380, 60], [490, 60], [60, 370], [170, 370], [380, 370], [490, 370]]
for v1, v2 in vectors:
random_item = random.choice(list(mazes.values()))
for w1, w2, w3, w4 in random_item:
s1 = w1 + v1
s2 = w2 + v2
wall = Wall(s1, s2, w3, w4)
wall_list.add(wall)
all_sprite_list.add(wall)
...