Python. Detect changes in vector direction - python

I have a vector y that either increments or decrements by 1. What I want is to create a another vector y2 that shows when y1 changed direction.
I can't figure out how to do this in numpy.
EDIT updated plot, due to missing comma in y
import matplotlib.pyplot as plt
import numpy as np
EDIT: Fixed missing comma in y
import matplotlib.pyplot as plt
import numpy as np
y = np.array([0,0,1,1,2,2,1,0,-1,-1,0,0,1])
x = np.arange(len(y))
y2 = np.array([0,0,1,0,0,0,-1,0,0,0,1,0,0])
plt.plot(x, y, label='y - Actual')
plt.plot(x, y2, label='y2 - Desired')
plt.legend()
plt.show()

Edit: Now also handles out of spec inputs (increments outside -1, 0, 1).
Here's a slightly faster (for the time being) way (pp is me, D is #Divakar):
# n = 10
# pp 0.02363790 ms
# D 0.03705720 ms
# n = 1000
# pp 0.03609150 ms
# D 0.05877410 ms
# n = 1000000
# pp 22.63471480 ms
# D 36.92147740 ms
Code including benchmarking:
import numpy as np
import types
from timeit import timeit
def setup_data(n, allow_out_of_spec=True):
if allow_out_of_spec:
data = {'y': np.cumsum(np.random.randint(0, 10, (n,))
* np.random.randint(-1, 2, (n,)))}
else:
data = {'y': np.cumsum(np.random.randint(-1, 2, (n,)))}
return data
# mine
def f_pp(y, allow_out_of_spec=True):
if allow_out_of_spec:
d = np.sign(np.diff(y))
else:
d = np.diff(y)
ud = np.flatnonzero(d)
uds = d[ud]
chng = ud[np.r_[True, uds[1:] != uds[:-1]]]
out = np.zeros(len(y), dtype=int)
out[1:][chng] = d[chng]
return out
# #Divakar's
def f_D(y):
s0 = np.flatnonzero(y[1:] > y[:-1])+1
s1 = np.flatnonzero(y[1:] < y[:-1])+1
idx0 = np.searchsorted(s1,s0,'right')
s0c = s0[np.r_[True,idx0[1:] > idx0[:-1]]]
idx1 = np.searchsorted(s0c,s1,'right')
s1c = s1[np.r_[True,idx1[1:] > idx1[:-1]]]
out = np.zeros(len(y),dtype=int)
out[s0c] = 1
out[s1c] = -1
return out
for n in (10, 1000, 1000000):
data = setup_data(n)
ref = np.array(f_pp(**data))
print(f'n = {n}')
for name, func in list(globals().items()):
if not name.startswith('f_') or not isinstance(func, types.FunctionType):
continue
try:
assert np.allclose(ref, func(**data))
print("{:16s}{:16.8f} ms".format(name[2:], timeit(
'f(**data)', globals={'f':func, 'data':data}, number=10)*100))
except:
print("{:16s} apparently failed".format(name[2:]))

Here's one way -
def detect_ups_downs(y):
s0 = np.flatnonzero(y[1:] > y[:-1])+1
s1 = np.flatnonzero(y[1:] < y[:-1])+1
idx0 = np.searchsorted(s1,s0,'right')
s0c = s0[np.r_[True,idx0[1:] > idx0[:-1]]]
idx1 = np.searchsorted(s0c,s1,'right')
s1c = s1[np.r_[True,idx1[1:] > idx1[:-1]]]
out = np.zeros(len(y),dtype=int)
out[s0c] = 1
out[s1c] = -1
return out
Sample run -
In [92]: y = np.array([0,0,1,2,3,4,1,0,-1-1,0,0,1,0,8,8,9,-4,-6,4,-2,2])
In [93]: np.c_[y, detect_ups_downs(y)]
Out[93]:
array([[ 0, 0],
[ 0, 0],
[ 1, 1],
[ 2, 0],
[ 3, 0],
[ 4, 0],
[ 1, -1],
[ 0, 0],
[-2, 0],
[ 0, 1],
[ 0, 0],
[ 1, 0],
[ 0, -1],
[ 8, 1],
[ 8, 0],
[ 9, 0],
[-4, -1],
[-6, 0],
[ 4, 1],
[-2, -1],
[ 2, 1]])

Try taking a derivative:
dy = y[1:] - y[:-1]
Then check if adjacent points have switched derivative signs:
increasing = dy > 0
decreasing = dy < 0
saddle = dy == 0
change_increasing = increasing[1:] and decreasing[:-1]
change_decreasing = decreasing[1:] and increasing[:-1]
Bring all that information together:
changes = np.zeros_like(dy)
changes[0] = (1 * increasing[0]) + (-1 * decreasing[0])
changes[1:][change_increasing] = 1
changes[1:][change_decreasing] = -1
changes[saddle] = 0
print(changes)

Related

How to use numpy in matrices iterations like Matlab

I am used to make my discrete time control systems simulations in Matlab and now I'm trying python and numpy.
So, my code bellow is working, but I would like to iterate over the numpy vector instead appending values into a list. Is it possible?
In other words, instead of using
xl.append(xt)
ul.append(uc)
I would like to use some Matlab equivalent like x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*uc, but it's not working on my code. If I do that, instead of obtaining a two line column vector that is the expected, I got a 2x2 matrix and an error.
Another question: Why it's neccessary to use plt.plot(tk, u[:, 0], label='u') instead plt.plot(tk, u, label='u') ?
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
#x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
xt = [[1.0], [0.12]] # initial states
xl = []
ul = []
for k in range(0, N):
tk[k] = k*Ts
uc = -K.dot(xt)
xt = np.dot(Ad, xt) + Bd*uc
xt[1, 0] += v[k]
xl.append(xt)
ul.append(uc)
x = np.array(xl)
u = np.array(ul)
#x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
what I want is the code like this:
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
for k in range(0, N):
tk[k] = k*Ts
u[k] = -K.dot(x[:, k])
x[1, k] += v[k]
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
But it results in a following error:
Traceback (most recent call last):
File "C:\Users\ ... \np_matrices_v1.py", line 46, in <module>
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
ValueError: could not broadcast input array from shape (2,2) into shape (2,)
I don't know why, but if you try:
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
xa[:, 2] = A.dot(x)
You'll get:
Traceback (most recent call last):
File "C:\Users\eletr\.spyder-py3\temp.py", line 19, in <module>
xa[:, 2] = A.dot(x)
ValueError: could not broadcast input array from shape (2,1) into shape (2,)
But if you do:
import numpy as np
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
# xa[:, 2] = A.dot(x)
xa[:, [2]] = A.dot(x)
print(xa)
You'll get the correct answer:
[[4.5]
[7. ]]
[[0. 0. 4.5 0. 0. 0. 0. 0. 0. 0. ]
[0. 0. 7. 0. 0. 0. 0. 0. 0. 0. ]]
Can anyone explain it?
In [248]: A = np.array([[1, 2], [2, 3]])
...: x = np.array([[0.5], [2.0]])
In [249]: A.shape, x.shape
Out[249]: ((2, 2), (2, 1))
In [250]: y = A.dot(x)
In [251]: y.shape
Out[251]: (2, 1)
Note the shapes. x is (2,1), and as a result y is too. y can be assigned to a (2,1) slot, but not a (2,) shape.
In [252]: xa = np.zeros((2,5),int)
In [253]: xa
Out[253]:
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
In [254]: xa[:,2]
Out[254]: array([0, 0]) # (2,) shape
In [255]: xa[:,[2]]
Out[255]:
array([[0], # (2,1) shape
[0]])
In contrast to MATLAB numpy arrays can be 1d, e.g. (2,). Also leading dimensions are the outermost, as opposed to trailing. MATLAB readily reduces a (2,3,1) shape to (2,3), but a (2,1,1) only becomes (2,1).
broadcasting the way numpy uses arrays that can differ in shape. The two basic rules are that
- leading size 1 dimensions can added automatically to match
- size 1 dimensions can be adjusted to match
Thus a (2,) can become a (1,2).
If you remove the inner [] from x, you get a 1d array:
In [256]: x = np.array([0.5, 2.0])
In [257]: x.shape
Out[257]: (2,)
In [258]: A.dot(x)
Out[258]: array([4.5, 7. ]) # (2,) shape
This can then be assigned to a row of xa: xa[:,2] = A.dot(x)
reshape and ravel can be used to remove dimensions. Also indexing A.dot(x)[:,0]

Pygame won't draw quads in the right order

I have been trying to make a 3d engine with python for some time, and I have gotten pretty far, however I have found a problem in when I try and sort items in a list, the sorting flips when you are close enough to the cube.
main.py:
import os
os.environ["SDL_VIDEO_CENTERED"] = '1'
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = '1'
import pygame
from pygame import gfxdraw
import math
from matrix import matrix_multiplication
import mesh
from random import randint as random
import time
startTime = time.time()
black, white, blue = (20, 20, 20), (230, 230, 230), (0, 154, 255)
width, height = 700, 700
pygame.init()
pygame.display.set_caption("3D Engine")
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
frames = 60
outline = False
rs, gs, bs = [random(0, 255) for i in range(len(mesh.faces))], [random(0, 255) for i in
range(len(mesh.faces))], [random(0, 255) for i in range(len(mesh.faces))]
angle_x = 0
angle_y = 0
angle_z = 0
pos_x = 0
pos_y = 0
pos_z = 0
cube_position = [width//2, height//2]
scale = 600
speed = 0.001
points = [[[i] for i in j] for j in mesh.verts]
movSpeed = 0.001
font = pygame.font.SysFont("Corbel", 23)
def avarageX(i):
return (new_points[mesh.faces[i][0]][0][0] + new_points[mesh.faces[i][1]][0][0] + new_points[mesh.faces[i][2]][0][0] + new_points[mesh.faces[i][3]][0][0]) / 4
def avarageY(i):
return (new_points[mesh.faces[i][0]][1][0] + new_points[mesh.faces[i][1]][1][0] + new_points[mesh.faces[i][2]][1][0] + new_points[mesh.faces[i][3]][1][0]) / 4
def avarageZ(i):
return (new_points[mesh.faces[i][0]][2][0] + new_points[mesh.faces[i][1]][2][0] + new_points[mesh.faces[i][2]][2][0] + new_points[mesh.faces[i][3]][2][0]) / 4
def distToCam(i):
a = [0, 0, 0]
b = [avarageX(i), avarageY(i), avarageZ(i)]
return math.dist(a, b)
print("It took: {} seconds".format(time.time() - startTime))
run = True
while run:
dt = clock.tick(frames)
fps = clock.get_fps()
screen.fill(white)
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
index = 0
projected_points = [j for j in range(len(points))]
rotation_x = [[1, 0, 0],
[0, math.cos(angle_x), -math.sin(angle_x)],
[0, math.sin(angle_x), math.cos(angle_x)]]
rotation_y = [[math.cos(angle_y), 0, -math.sin(angle_y)],
[0, 1, 0],
[math.sin(angle_y), 0, math.cos(angle_y)]]
rotation_z = [[math.cos(angle_z), -math.sin(angle_z), 0],
[math.sin(angle_z), math.cos(angle_z), 0],
[0, 0, 1]]
new_points = []
for point in points:
rotated_2d = matrix_multiplication(rotation_y, point)
rotated_2d = matrix_multiplication(rotation_x, rotated_2d)
rotated_2d = matrix_multiplication(rotation_z, rotated_2d)
new_point = [[rotated_2d[0][0] + pos_x], [rotated_2d[1][0] + pos_y], [rotated_2d[2][0] - pos_z]]
new_points.append(new_point)
distance = 5
z = 1 / (distance - new_point[2][0])
projection_matrix = [[z, 0, 0],
[0, z, 0]]
projected_2d = matrix_multiplication(projection_matrix, new_point)
x = int(projected_2d[0][0] * scale) + cube_position[0]
y = int(projected_2d[1][0] * scale) + cube_position[1]
projected_points[index] = [x, y]
index += 1
zs = [[distToCam(i), i] for i in range(len(mesh.faces))]
zs.sort(reverse=True)
faces = [[mesh.faces[zs[i][1]], zs[i][1]] for i in range(len(mesh.faces))]
fi = 0
for f in faces:
gfxdraw.filled_polygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
gfxdraw.aapolygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
fi += 1
angle_x += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed * dt
angle_y += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed * dt
pos_x += (keys[pygame.K_d] - keys[pygame.K_a]) * movSpeed * dt
pos_z += (keys[pygame.K_w] - keys[pygame.K_s]) * movSpeed * dt
text = font.render(str(round(fps, 1)), False, black)
screen.blit(text, (0, 0))
pygame.display.update()
pygame.quit()
The matrix multiplication
matrix.py:
def matrix_multiplication(a, b):
columns_a = len(a[0])
rows_a = len(a)
columns_b = len(b[0])
rows_b = len(b)
result_matrix = [[j for j in range(columns_b)] for i in range(rows_a)]
if columns_a == rows_b:
for x in range(rows_a):
for y in range(columns_b):
sum = 0
for k in range(columns_a):
sum += a[x][k] * b[k][y]
result_matrix[x][y] = sum
return result_matrix
else:
print("columns of the first matrix must be equal to the rows of the second matrix")
return None
The mesh data.
mesh.py:
verts = [
[1, 1, 1],
[1, 1, -1],
[1, -1, 1],
[1, -1, -1],
[-1, 1, 1],
[-1, 1, -1],
[-1, -1, 1],
[-1, -1, -1]
]
faces = [
[0, 4, 6, 2],
[3, 2, 6, 7],
[7, 6, 4, 5],
[5, 1, 3, 7],
[1, 0, 2, 3],
[5, 4, 0, 1]
]
WARNING: There might be flashing lights on startup
You have to compute the distance of the camera position ([0, 0, distance]) to the points in world space (new_points), instead of the points in model space (points):
def distToCam(i):
a = [0, 0, distance]
b = [sum(new_points[mesh.faces[i][pi]][j][0] for pi in range(4)) / 4 for j in range(3)]
return math.dist(a, b)

Division operator overloading parameters have same values

I'm having some problems with operator overloading. If you could check please.
The code:
import math
class Mat4:
cells = [ [0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0] ]
#staticmethod
def DET2(a, b, c, d):
return a * d - b * c
#staticmethod
def DET3(a,b,c, d,e,f, g,h,i):
return a * Mat4.DET2(e,f,h,i) - b * Mat4.DET2(d,f,g,i) + c * Mat4.DET2(d,e,g,h)
#staticmethod
def DET4(a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p):
return ( a * Mat4.DET3(f,g,h,j,k,l,n,o,p) - b * Mat4.DET3(e,g,h,i,k,l,m,o,p) + c * Mat4.DET3(e,f,h,i,j,l,m,n,p) - d * Mat4.DET3(e,f,g,i,j,k,m,n,o))
#staticmethod
def Scale(factor):
res = Mat4()
res.cells = [ [factor,0, 0, 0],
[0, factor, 0, 0],
[0, 0, factor, 0],
[0, 0, 0, 1] ]
return res
def __mul__(self, other):
if isinstance(other, Mat4):
print(self.cells)
print(other.cells)
print("h\n")
out = Mat4()
for row_left in range(4):
for col_right in range(4):
out.cells[row_left][col_right] = 0
for k in range(4):
out.cells[row_left][col_right] += self.cells[row_left][k] * other.cells[k][col_right]
return out
if isinstance(other, int) or isinstance(other, float):
for i in range(4):
for j in range(4):
self.cells[i][j] *= other
return self
def __truediv__(self, other):
print(self.cells)
print(other.GetInversed().cells)
print("pl\n")
return self * other.GetInversed()
#staticmethod
def Identity():
return Mat4.Scale(1)
#staticmethod
def RotationX(angle):
sinTheta = math.sin(angle)
cosTheta = math.cos(angle)
res = Mat4()
res.cells = [ [1, 0, 0, 0],
[0, cosTheta, -sinTheta, 0],
[0, sinTheta, cosTheta, 0],
[0, 0, 0, 1] ]
return res
def GetInversed(self):
a = self.cells[0][0]
b = self.cells[0][1]
c = self.cells[0][2]
d = self.cells[0][3]
e = self.cells[1][0]
f = self.cells[1][1]
g = self.cells[1][2]
h = self.cells[1][3]
i = self.cells[2][0]
j = self.cells[2][1]
k = self.cells[2][2]
l = self.cells[2][3]
m = self.cells[3][0]
n = self.cells[3][1]
o = self.cells[3][2]
p = self.cells[3][3]
min_a = Mat4.DET3(f,g,h,j,k,l,n,o,p)
min_b = Mat4.DET3(e,g,h,i,k,l,m,o,p)
min_c = Mat4.DET3(e,f,h,i,j,l,m,n,p)
min_d = Mat4.DET3(e,f,g,i,j,k,m,n,o)
det_m = a * min_a - b * min_b + c * min_c - d * min_d
res = Mat4()
res.cells[0][0] = min_a
res.cells[1][0] = -min_b
res.cells[2][0] = min_c
res.cells[3][0] = -min_d
res.cells[0][1] = -Mat4.DET3(b,c,d,j,k,l,n,o,p)
res.cells[1][1] = Mat4.DET3(a,c,d,i,k,l,m,o,p)
res.cells[2][1] = -Mat4.DET3(a,b,d,i,j,l,m,n,p)
res.cells[3][1] = Mat4.DET3(a,b,c,i,j,k,m,n,o)
res.cells[0][2] = Mat4.DET3(b,c,d,f,g,h,n,o,p)
res.cells[1][2] = -Mat4.DET3(a,c,d,e,g,h,m,o,p)
res.cells[2][2] = Mat4.DET3(a,b,d,e,f,h,m,n,p)
res.cells[3][2] = -Mat4.DET3(a,b,c,e,f,g,m,n,o)
res.cells[0][3] = -Mat4.DET3(b,c,d,f,g,h,j,k,l)
res.cells[1][3] = Mat4.DET3(a,c,d,e,g,h,i,k,l)
res.cells[2][3] = -Mat4.DET3(a,b,d,e,f,h,i,j,l)
res.cells[3][3] = Mat4.DET3(a,b,c,e,f,g,i,j,k)
return res * ( 1.0 / det_m)
def main():
rotMat = Mat4().RotationX(50)
scaMat = Mat4().Scale(3)
mRes = (rotMat * scaMat) / rotMat
print(mRes.cells)
if __name__ == "__main__":
main()
The result I'm getting:
mRes = [[0.0, 0.0, 0.0, 0.0], [0.0, -0.068840563856158, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]
The result I should get, because rotation gets subtracted and only the scaling has left:
mRes = [[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 3, 0], [0, 0, 0, 1]]
The problem is with __mul__ operator because it's having other and self parameters to store same values, but address is not the same:
For some reasons the first time multiplication happens mRes = (rotMat * scaMat) is okay, but the problems comes when the resulted matrix from the division calls division operator, which also calls multiplication operator.

Replace in array of zeros with other values in certain cells_updated question

I need to solve a problem in which I have spent hours, with the data from my excel sheet I have created a 6x36 '' zeros '' matrix of zeros and a 6x6 '' matrix_tran '' coordinate transformation matrix [image 1].
My problem is that I can't find a way to replace the zeros of the '' zeros '' matrix with the values that the matrix '' matrix_tran '' dictates, and whose location must be in the columns (4,5,6, 7,8,9) that are given by the connection vector (4,5,6,7,8,9) of element 15 of the Excel sheet, that is, the last row of the for loop iteration [image 2].
In summary: Below I show how it fits and how it should look [image 3 and 4 respectively].
I would very much appreciate your help, and excuse my English, but it is not my native language, a big greeting.
import pandas as pd
import numpy as np
ex = pd.ExcelFile('matrix_tr.xlsx')
hoja = ex.parse('Hoja1')
cols = 36
for n in range(0,len(hoja)):
A = hoja['ELEMENT #'][n]
B = hoja['1(i)'][n]
C = hoja['2(i)'][n]
D = hoja['3(i)'][n]
E = hoja['1(j)'][n]
F = hoja['2(j)'][n]
G = hoja['3(j)'][n]
H = hoja['X(i)'][n]
I = hoja['Y(i)'][n]
J = hoja['X(j)'][n]
K = hoja['Y(j)'][n]
L = np.sqrt((J-H)**2+(K-I)**2)
lx = (J-H)/L
ly = (K-I)/L
zeros = np.zeros((6, cols))
counters = hoja.loc[:, ["1(i)", "2(i)", "3(i)", "1(j)", "2(j)", "3(j)"]]
for _, i1, i2, i3, j1, j2, j3 in counters.itertuples():
matrix_tran = np.array([[lx, ly, 0, 0, 0, 0],
[-ly, lx, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, lx, ly, 0],
[0, 0, 0, -ly, lx, 0],
[0, 0, 0, 0, 0, 1]])
zeros[:, [i1 - 1, i2 - 1, i3 - 1, j1 - 1, j2 - 1 , j3 - 1]] = matrix_tran
Try with a transposed zeros matrix
import pandas as pd
import numpy as np
ex = pd.ExcelFile('c:/tmp/SO/matrix_tr.xlsx')
hoja = ex.parse('Hoja1')
counters = hoja.loc[:, ["1(i)", "2(i)", "3(i)", "1(j)", "2(j)", "3(j)"]]
# zeros matrix transposed
cols = 36
zeros_trans = np.zeros((cols,6))
# last row only
for n in range(14,len(hoja)):
Xi = hoja['X(i)'][n]
Yi = hoja['Y(i)'][n]
Xj = hoja['X(j)'][n]
Yj = hoja['Y(j)'][n]
X = Xj-Xi
Y = Yj-Yi
L = np.sqrt(X**2+Y**2)
lx = X/L
ly = Y/L
matrix_tran = np.array([[lx, ly, 0, 0, 0, 0],
[-ly, lx, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, lx, ly, 0],
[0, 0, 0, -ly, lx, 0],
[0, 0, 0, 0, 0, 1]])
i = 0
for r in counters.iloc[n]:
zeros_trans[r-1] = matrix_tran[i]
i += 1
print(np.transpose(zeros_trans))

Convert a 2D array to 3D array by multiplying vector in numpy

Suppose I have an 2D numpy array a=[[1,-2,1,0], [1,0,0,-1]], but I want to convert it to an 3D numpy array by element-wise multiply a vector t=[[x0,x0,x0,x0],[x1,x1,x1,x1]] where xi is a 1D numpy array with 3072 size. So the result would be a*t=[[x0,-2x0,x0,0],[x1,0,0,-x1]] with the size (2,4,3072). So how should I do that in Python numpy?
Code:
import numpy as np
# Example data taken from bendl's answer !!!
a = np.array([[1,-2,1,0], [1,0,0,-1]])
xi = np.array([1, 2, 3])
b = np.outer(a, xi).reshape(a.shape[0], -1, len(xi))
print('a:')
print(a)
print('b:')
print(b)
Output:
a:
[[ 1 -2 1 0]
[ 1 0 0 -1]]
b:
[[[ 1 2 3]
[-2 -4 -6]
[ 1 2 3]
[ 0 0 0]]
[[ 1 2 3]
[ 0 0 0]
[ 0 0 0]
[-1 -2 -3]]]
As i said: it looks like an outer-product and splitting/reshaping this one dimension is easy.
You can use numpy broadcasting for this:
a = numpy.array([[1, -2, 1, 0], [1, 0, 0, -1]])
t = numpy.arange(3072 * 2).reshape(2, 3072)
# array([[ 0, 1, 2, ..., 3069, 3070, 3071], # = x0
# [3072, 3073, 3074, ..., 6141, 6142, 6143]]) # = x1
a.shape
# (2, 4)
t.shape
# (2, 3072)
c = (a.T[None, :, :] * t.T[:, None, :]).T
# array([[[ 0, 1, 2, ..., 3069, 3070, 3071], # = 1 * x0
# [ 0, -2, -4, ..., -6138, -6140, -6142], # = -2 * x0
# [ 0, 1, 2, ..., 3069, 3070, 3071], # = 1 * x0
# [ 0, 0, 0, ..., 0, 0, 0]], # = 0 * x0
#
# [[ 3072, 3073, 3074, ..., 6141, 6142, 6143], # = 1 * x1
# [ 0, 0, 0, ..., 0, 0, 0], # = 0 * x1
# [ 0, 0, 0, ..., 0, 0, 0], # = 0 * x1
# [-3072, -3073, -3074, ..., -6141, -6142, -6143]]]) # = -1 * x1
c.shape
# (2, 4, 3072)
Does this do what you need?
import numpy as np
a = np.array([[1,-2,1,0], [1,0,0,-1]])
xi = np.array([1, 2, 3])
a = np.dstack([a * i for i in xi])
The docs for this are here:
https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.dstack.html

Categories

Resources