Related
import numpy as np
import matplotlib.pyplot as plt
r=20
h=1.7
num_of_steps=100
emp=3
phi = np.linspace(0, 4 * np.pi, num_of_steps)
theta = np.linspace(-np.pi / 4, np.pi / 4, num_of_steps)
x = r * np.cos(phi)
y = r * np.sin(phi) * np.cos(theta) - h * np.sin(theta)
z = r * np.sin(phi) * np.sin(theta) + h * np.cos(theta)
points = [x, y, z]
points = np.transpose(points)
n = len(points)
# Calculate the first and second derivative of the points
dX = np.apply_along_axis(np.gradient, axis=0, arr=points)
ddX = np.apply_along_axis(np.gradient, axis=0, arr=dX)
# Normalize all tangents
f = lambda m: m / np.linalg.norm(m)
T = np.apply_along_axis(f, axis=1, arr=dX)
# Calculate and normalize all binormals
B = np.cross(dX, ddX)
B = np.apply_along_axis(f, axis=1, arr=B)
# Calculate all normals
N = np.cross(B, T)
for t in range(len(theta)):
fig = plt.figure('Parametrinai blynai')
ax = fig.add_subplot(111, projection='3d')
ax.plot(x[1:t], y[1:t], z[1:t], '-r', linewidth=3)
ax.set_xlabel('X', fontweight='bold', fontsize=14)
ax.set_ylabel('Y', fontweight='bold', fontsize=14)
ax.set_zlabel('Z', fontweight='bold', fontsize=14)
ax.set_xlim([-20, 20])
ax.set_ylim([-20, 20])
ax.set_zlim([-10, 10])
plt.title('Parametrinis blynas', fontweight='bold', fontsize=16)
ax.quiver(x[t - 1], y[t - 1], z[t - 1], emp * T[t, 0], emp * T[t, 1], emp * T[t, 2], color='k')#juoda
ax.quiver(x[t - 1], y[t - 1], z[t - 1], emp * B[t, 0], emp * B[t, 1], emp * B[t, 2], color='b')#melyna
ax.quiver(x[t - 1], y[t - 1], z[t - 1], emp * N[t, 0], emp * N[t, 1], emp * N[t, 2], color='g')#zalia
# T, B ir N masyvai yra 100x3 dydio aka 3 dimensijos 100 iteraciju
# tuose masyvuose per 100 iteraciju yra deltaX, deltaY ir deltaZ normavimo konstantos tikslumu yra
# T, B arba N vektoriaus ilgis x, y ir z asyse
# Uncomment either option 1 or option 2
# Option 1
#plt.show()
# Option 2
#pavadinimas = str(t)
#plt.savefig(pavadinimas, dpi=300)
print(T[t]) #vektoriukas, judantis isilgai kartu su projekcijos tasku
print(B[t]) #
print(N[t])
#print("ciklas:" + str(t))
The code above plots a trajectory, defined by the three equations. How do i modify the code to produce a 3D Lissajous figure? For example both angles theta and phi should have frequencies and amplitudes and botha angles should be moving harmonically, i.e. angle theta should start at -pi/4, reach pi/4 and then go backwards to -pi/4 and so on like a pendulum. Is there any way to implement this into the above code or some way to change it?
I´m an mechanical engineering student and I'm trying to make a shear diagram of a portal frame.
In the code below I want to identify for each equation (4 in total) the maximum value and correspondent position on the plot. How can I do that? Is it possible to mark the location with a "x"?
The equations are vpilar 1, vpilar 2, vasna1 and vasna2.
Code:
import math as mt
import numpy as np
import matplotlib.pyplot as plt
v = 20 #(Vão em metros)
h = 6 #("Altura do pilar em metros:")
ht = 8 #("Altura total metros:")
alfa_rad = mt.atan((int(ht)-int(h))/(int(v)/2))
alfa_deg = alfa_rad*180/mt.pi
lasna = ((v/2) ** 2 + (ht-h) ** 2) ** 0.5
alfa = (mt.atan((int(ht)-int(h))/(int(v)/2)))*180/((mt.pi))
print("Ângulo da vertente:", round(alfa, 1), "º")
h1 = np.arange(0, h+1, 1)
ha1 = np.arange(0, lasna, 0.1)
ha2 = np.arange(0, lasna, 0.1)
hp2 = np.arange(0, h+1, 1)
R = lambda x, y, theta: np.array([
[np.cos(theta), np.sin(theta), x],
[-np.sin(theta), np.cos(theta), y],
[0, 0, 1],
])
Vx = np.array([
[1, 0, 0], [0, -1, 0], [0, 0, 1]
])
Vy = np.array([
[-1, 0, 0], [0, 1, 0], [0, 0, 1]
])
vpilar1 = (1000 * h1 ** 2 + 50)/ 1000
vasna1 = (50 *ha1 ** 2 + 5) / 1000
vasna2 = (100 * ha2 ** 2 + 7) / 1000
vpilar2 = (150 * hp2 ** 2 + 5) / 1000
def draw_line():
x_number_list = [0, 0, (v/2), v, v]
y_number_list = [0, h, ht, h, 0]
plt.plot(x_number_list, y_number_list, linewidth=3)
points1 = np.stack([h1, vpilar1 / max(abs(vpilar1)), np.ones_like(h1)])
points1 = np.matmul(R(0, 0, -np.pi/2), points1)
plt.plot(points1[0, :], points1[1, :], label="Vpilar1")
points2 = np.stack([h1, vpilar2 / max(abs(vpilar2)), np.ones_like(h1)])
points2 = np.matmul(R(v, 0, -np.pi/2), points2)
plt.plot(points2[0, :], points2[1, :], label="Vpilar2")
points3 = np.stack([ha1, vasna1 / max(abs(vasna1)), np.ones_like(ha1)])
points3 = np.matmul(R(0, h, -alfa_rad), points3)
plt.plot(points3[0, :], points3[1, :], label="Vasna1")
points4 = np.stack([ha1, vasna2 / max(abs(vasna2)), np.ones_like(ha1)])
points4 = np.matmul(np.matmul(R(v, h, alfa_rad), Vy), points4)
plt.plot(points4[0, :], points4[1, :], label="Vasna2")
plt.title("Esforço de Corte", fontsize=15)
plt.show()
draw_line()
With np.argmax you find the index of the maximum of an array. Then extract the coordinates of that position, and apply the same transformation matrix you previously applied to the moments. Finally, your mark this new position on the chart:
import math as mt
import numpy as np
import matplotlib.pyplot as plt
v = 20 #(Vão em metros)
h = 6 #("Altura do pilar em metros:")
ht = 8 #("Altura total metros:")
alfa_rad = mt.atan((int(ht)-int(h))/(int(v)/2))
alfa_deg = alfa_rad*180/mt.pi
lasna = ((v/2) ** 2 + (ht-h) ** 2) ** 0.5
alfa = (mt.atan((int(ht)-int(h))/(int(v)/2)))*180/((mt.pi))
print("Ângulo da vertente:", round(alfa, 1), "º")
h1 = np.arange(0, h+1, 1)
ha1 = np.arange(0, lasna, 0.1)
ha2 = np.arange(0, lasna, 0.1)
hp2 = np.arange(0, h+1, 1)
R = lambda x, y, theta: np.array([
[np.cos(theta), np.sin(theta), x],
[-np.sin(theta), np.cos(theta), y],
[0, 0, 1],
])
Vx = np.array([
[1, 0, 0], [0, -1, 0], [0, 0, 1]
])
Vy = np.array([
[-1, 0, 0], [0, 1, 0], [0, 0, 1]
])
vpilar1 = (1000 * h1 ** 2 + 50)/ 1000
vasna1 = (50 *ha1 ** 2 + 5) / 1000
vasna2 = (100 * ha2 ** 2 + 7) / 1000
vpilar2 = (150 * hp2 ** 2 + 5) / 1000
def draw_line():
plt.figure()
x_number_list = [0, 0, (v/2), v, v]
y_number_list = [0, h, ht, h, 0]
plt.plot(x_number_list, y_number_list, linewidth=3)
points1 = np.stack([h1, vpilar1 / max(abs(vpilar1)), np.ones_like(h1)])
points1 = np.matmul(R(0, 0, -np.pi/2), points1)
plt.plot(points1[0, :], points1[1, :], label="Vpilar1")
idx = np.argmax(vpilar1)
max_p = np.array([[h1[idx], (vpilar1 / max(abs(vpilar1)))[idx], 1]]).T
max_p_tranformed = np.matmul(R(0, 0, -np.pi/2), max_p)
plt.scatter(*max_p_tranformed[:-1], marker="x", color="k")
points2 = np.stack([h1, vpilar2 / max(abs(vpilar2)), np.ones_like(h1)])
points2 = np.matmul(R(v, 0, -np.pi/2), points2)
plt.plot(points2[0, :], points2[1, :], label="Vpilar2")
idx = np.argmax(vpilar2)
max_p = np.array([[h1[idx], (vpilar2 / max(abs(vpilar2)))[idx], 1]]).T
max_p_tranformed = np.matmul(R(v, 0, -np.pi/2), max_p)
plt.scatter(*max_p_tranformed[:-1], marker="x", color="k")
points3 = np.stack([ha1, vasna1 / max(abs(vasna1)), np.ones_like(ha1)])
points3 = np.matmul(R(0, h, -alfa_rad), points3)
plt.plot(points3[0, :], points3[1, :], label="Vasna1")
idx = np.argmax(vasna1)
max_p = np.array([[ha1[idx], (vasna1 / max(abs(vasna1)))[idx], 1]]).T
max_p_tranformed = np.matmul(R(0, h, -alfa_rad), max_p)
plt.scatter(*max_p_tranformed[:-1], marker="x", color="k")
points4 = np.stack([ha1, vasna2 / max(abs(vasna2)), np.ones_like(ha1)])
points4 = np.matmul(np.matmul(R(v, h, alfa_rad), Vy), points4)
plt.plot(points4[0, :], points4[1, :], label="Vasna2")
idx = np.argmax(vasna2)
max_p = np.array([[ha1[idx], (vasna2 / max(abs(vasna2)))[idx], 1]]).T
max_p_tranformed = np.matmul(np.matmul(R(v, h, alfa_rad), Vy), max_p)
plt.scatter(*max_p_tranformed[:-1], marker="x", color="k")
plt.title("Esforço de Corte", fontsize=15)
plt.show()
draw_line()
My data has Nan values but when I generate a plot the Nan values are considered as min values. I want those values are not shown on the plot.
from matplotlib import pyplot as plt
from matplotlib.tri import Triangulation
import numpy as np
M, N = 11, 1
valuesN = np.array([ np.nan, np.nan, 0.03572389, 0.884389, 0.5, 0.912367,
0.898027, 0.35744717, 0.42150131, np.nan, np.nan ])
valuesE = np.array([ np.nan, np.nan, 0.03572389, 0.02884389, 0.2, 0.312367,
0.55898027, 0.45744717, 0.62150131, np.nan, np.nan ])
valuesS = np.array([ np.nan, np.nan, 0.63572389, 0.02884389, 0.1, 0.14512367,
0.998027, 0.45744717, 0.62150131, np.nan, np.nan ])
valuesW = np.array([ np.nan, np.nan, 0.03572389, 0.02884389, 0., 0.612367,
0.598027, 0.15744717, 0.90131, np.nan, np.nan ])
values = [valuesN, valuesE, valuesS, valuesW]
xv, yv = np.meshgrid(np.arange(-0.5, M), np.arange(-0.5, N))# vertices of the little squares
xc, yc = np.meshgrid(np.arange(0, M), np.arange(0, N)) # centers of the little squares
x = np.concatenate([xv.ravel(), xc.ravel()])
y = np.concatenate([yv.ravel(), yc.ravel()])
cstart = (M + 1) * (N + 1) # indices of the centers
trianglesN = [(i + j * (M + 1), i + 1 + j * (M + 1), cstart + i + j * M) for j in range(N) for i in range(M)]
trianglesE = [(i + 1 + j * (M + 1), i + 1 + (j + 1) * (M + 1), cstart + i + j * M) for j in range(N) for i in range(M)]
trianglesS = [(i + 1 + (j + 1) * (M + 1), i + (j + 1) * (M + 1), cstart + i + j * M) for j in range(N) for i in range(M)]
trianglesW = [(i + (j + 1) * (M + 1), i + j * (M + 1), cstart + i + j * M) for j in range(N) for i in range(M)]
triangul = [Triangulation(x, y, triangles) for triangles in [trianglesN, trianglesE, trianglesS, trianglesW]]
fig, ax = plt.subplots()
imgs = [ax.tripcolor(t, val.ravel(), cmap="jet", vmin=0, vmax=1, ec='white' )
for t, val in zip(triangul, values)]
cbar = fig.colorbar(imgs[0], ax=ax)
ax.invert_yaxis()
ax.margins(x=0, y=0)
ax.set_aspect('equal', 'box') # square cells
plt.tight_layout()
plt.show
I get a plot below, as shown the Nan values are like min values. : ,
The task: calculate the angle between two lines
input:
float x1, y1 (starting point)
float x2, y2 (end point)
output:
float phi (angle in deg, between the lines)
additionally:
one line is parallel to the x-axis, and phi is 0° ≤ phi < 359°
Task Picture
option 1:
import math
rad_to deg = lambda x: 180.0/math.pi * x
# start-point
x1 = float(input("x1: "))
y1 = float(input("y1: "))
# end-point
x2 = float(input("x2: "))
y2 = float(input("y2: "))
# slope of one line (parallel to the x-axis)
m1 = 0
# slope between the start-point and end-point
# special-case: division with zero
if x1 == x2:
m2 = "Not defined!"
if y2 > y1: # end-point over start-point
phi = 90
elif y2 < y1: # end-point under start-point
phi = 270
else:
m2 = (y2 - y2) / (x2 - x1)
# angle between two lines (smaller angle: 0° < phi < 90°)
angle = rad_to_deg(math.atan(abs((m1 - m2) / (1 + m1 * m2))))
if x1 < x2 and y1 < y2: # 1. quadrant
phi = sw
elif x1 > x2 and y1 < y2: # 2. quadrant
phi = 180 - sw
elif x1 > x2 and y1 > y2: # 3. quadrant
phi = 180 + sw
elif x1 < x2 and y1 > y2: # 4. quadrant
phi = 360 - sw
elif y1 == y2 and x1 > x2: # end-point left from start-point
phi = 180
elif y1 == y2 and x1 < x2 : # end-point right from start-point
phi = 0
elif x1 == x2 and y1 == y2:
phi = "Error, start-point is end-point"
print("angle phi: " + str(phi))
or should be the special-case with try/except?
try:
m2 = (y2 - y2) / (x2 - x1)
except ZeroDivisionError: # x1 == x2
m2 = "Not defined!"
if y2 > y1: # end-point over start-point
phi = 90
elif y2 < y1: # end-point under start-point
phi = 270
option 2: with vectors
for math import sqrt, acos, pi
rad_to_deg = lambda x: 180.0/pi * x
x1 = float(input("x1: "))
y1 = float(input("y1: "))
x2 = float(input("x1: "))
y2 = float(input("x2: "))
# vectors
u = [1, 0] # start-point and (a point right from the start-point)
v = [x2 - x1, y2 - y1]
# calculation
u_scalar_v = u[0] * v[0] + u[1] * v[1]
u_amount = sqrt(u[0] * u[0] + u[1] * u[1])
v_amount = sqrt(v[0] * v[0] + v[1] * v[1])
# scalar product
phi = round(rad_to_deg(acos(u_scalar_v / (u_amount * v_amount))), 5)
if y2 >= y1:
pass
else:
phi = 360 - phi
print(phi)
option 3:
is to see the start-point, the end-point and a point right from s, as a triangle and to calculate over the cosine theorem
What is the most efficient way to calculate this and how can I decide it?
Find the Angle between three points from 2D using python provides a simple solution.
import math
def getAngle(a, b, c):
ang = math.degrees(math.atan2(c[1]-b[1], c[0]-b[0]) - math.atan2(a[1]-b[1], a[0]-b[0]))
return ang + 360 if ang < 0 else ang
# starting-point
x1 = float(input("x1: "))
y1 = float(input("y1: "))
# middle-point (intersection point)
x2 = float(input("x2: "))
y2 = float(input("y2: "))
# ending point of horizontal line
x3 = x2 + 1 # i.e. horizontal offset from mid-point (x2, y2)
y3 = y2
a = (x1, y1)
b = (x2, y2)
c = (x3, y3)
angle = getAngle(a, b, c)
Example
a = (5, 0)
b = (0, 0)
c = (0, 5)
print(getAngle(a, b, c)) # result 90.0
Example 2--test with random points
from random import randrange, sample
radius = 10
points = []
for i1 in range(10):
for i2 in range(10):
points.append((randrange(-radius, radius+1), randrange(-radius, radius+1)))
x1y1 = sample(points[:50], 10)
x2y2 = sample(points[50:], 10)
x3y3 = [(x+1, y) for x, y in x2y2]
for i in range(len(x1y1)):
a, b, c = x1y1[i], x2y2[i], x3y3[i]
angle = getAngle(a, b, c)
print(i, ": ", a, b, c, '=> ', angle)
Result
0 : (10, -6) (8, -10) (9, -10) => 296.565051177078
1 : (0, -9) (-4, -3) (-3, -3) => 56.309932474020215
2 : (-6, 10) (5, 9) (6, 9) => 185.1944289077348
3 : (0, 1) (-2, 1) (-1, 1) => 0.0
4 : (2, -1) (-3, 7) (-2, 7) => 57.9946167919165
5 : (2, -3) (-10, -8) (-9, -8) => 337.3801350519596
6 : (2, -6) (-10, 5) (-9, 5) => 42.510447078000844
7 : (7, 8) (7, 3) (8, 3) => 270.0
8 : (2, -2) (-4, 4) (-3, 4) => 45.0
9 : (1, -2) (-2, 7) (-1, 7) => 71.56505117707799
Here is my dataframe,
df = pd.DataFrame({'Id': [102,103,104,303,305],'ExpG_Home':[1.8,1.5,1.6,1.8,2.9],
'ExpG_Away':[2.2,1.3,1.2,2.8,0.8],
'HomeG_Time':[[93, 109, 187],[169], [31, 159],[176],[16, 48, 66, 128]],
'AwayG_Time':[[90, 177],[],[],[123,136],[40]]})
First, I need to create an array y, for a given Id number, it takes values from same row (ExpG_Home & ExpG_Away).
y = [1 - (ExpG_Home + ExpG_Away), ExpG_Home, ExpG_Away]
Second, I found this much harder, for the Id used in creating y, the function below takes the corresponding lists from HomeG_Time & AwayG_Time and creates an array. Unfortunately, my function takes one row at a time. I need to do this for a large dataset.
x1 = [1,0,0]
x2 = [0,1,0]
x3 = [0,0,1]
total_timeslot = 200 # number of timeslot per game.
k = 1 # constant
#For Id=102 with ExpG_Home=2.2 and ExpG_Away=1.8
HomeG_Time = [93, 109, 187]
AwayG_Time = [90, 177]
y = np.array([1-(2.2 + 1.8)/k, 2.2/k, 1.8/k])
# output of y = [0.98 , 0.011, 0.009]
def squared_diff(x1, x2, x3, y):
ssd = []
for k in range(total_timeslot):
if k in HomeG_Time:
ssd.append(sum((x2 - y) ** 2))
elif k in AwayG_Time:
ssd.append(sum((x3 - y) ** 2))
else:
ssd.append(sum((x1 - y) ** 2))
return ssd
sum(squared_diff(x1, x2, x3, y))
Out[37]: 7.880400000000012
This output is for the first row only.
Here is the complete snippet given,
>>> import numpy as np
>>> x1 = np.array( [1,0,0] )
>>> x2 = np.array( [0,1,0] )
>>> x3 = np.array( [0,0,1] )
>>> total_timeslot = 200
>>> HomeG_Time = [93, 109, 187]
>>> AwayG_Time = [90, 177]
>>> ExpG_Home=2.2
>>> ExpG_Away=1.8
>>> y = np.array( [1 - (ExpG_Home + ExpG_Away), ExpG_Home, ExpG_Away] )
>>> def squared_diff(x1, x2, x3, y):
... ssd = []
... for k in range(total_timeslot):
... if k in HomeG_Time:
... ssd.append(sum((x2 - y) ** 2))
... elif k in AwayG_Time:
... ssd.append(sum((x3 - y) ** 2))
... else:
... ssd.append(sum((x1 - y) ** 2))
... return ssd
...
>>> sum(squared_diff(x1, x2, x3, y))
4765.599999999989
Assuming this. Calculate y as (N,3) using pandas.DataFrame.apply
>>> y = np.array( df.apply(lambda row: [1 - (row.ExpG_Home + row.ExpG_Away),
... row.ExpG_Home, row.ExpG_Away ],
... axis=1).tolist() )
>>> y.shape
(5, 3)
Now calcualte squared error for a given x
>>> def squared_diff(x, y):
... return np.sum( np.square(x - y), axis=1)
In your case, if error2 is squared_diff(x2,y) you are adding this the number of occuerences of HomeG_Time
>>> n3 = df.AwayG_Time.apply(len)
>>> n2 = df.HomeG_Time.apply(len)
>>> n1 = 200 - (n2 + n3)
The final sum of squared error is (as per your calculation)
>>> squared_diff(x1, y) * n1 + squared_diff(x2, y) * n2 + squared_diff(x3, y) * n3
0 4766.4
1 2349.4
2 2354.4
3 6411.6
4 4496.2
dtype: float64
>>>
try this,
import pandas as pd
import numpy as np
df = pd.DataFrame({'Id': [102,103,104,303,305],'ExpG_Home':[1.8,1.5,1.6,1.8,2.9],
'ExpG_Away':[2.2,1.3,1.2,2.8,0.8],
'HomeG_Time':[[93, 109, 187],[169], [31, 159],[176],[16, 48, 66, 128]],
'AwayG_Time':[[90, 177],[],[],[123,136],[40]]})
x1 = [1,0,0]
x2 = [0,1,0]
x3 = [0,0,1]
k=1
total_timeslot = 200 # number of timeslot per game.
def squared_diff(x1, x2, x3,AwayG_Time,HomeG_Time, y):
ssd = []
for k in range(total_timeslot):
if k in HomeG_Time:
ssd.append(sum((x2 - y) ** 2))
elif k in AwayG_Time:
ssd.append(sum((x3 - y) ** 2))
else:
ssd.append(sum((x1 - y) ** 2))
return ssd
s=pd.DataFrame( pd.concat([df,1-(df['ExpG_Home']+df['ExpG_Away'])/k,df['ExpG_Home']/k,df['ExpG_Away']/k],axis=1).values)
df['res']=s.apply(lambda x: sum(squared_diff(x1,x2,x3,x[0],x[3],np.array([x[5],x[6],x[7]]))),axis=1)
del s
print df
Output:
AwayG_Time ExpG_Away ExpG_Home HomeG_Time Id res
0 [90, 177] 2.2 1.8 [93, 109, 187] 102 4766.4
1 [] 1.3 1.5 [169] 103 2349.4
2 [] 1.2 1.6 [31, 159] 104 2354.4
3 [123, 136] 2.8 1.8 [176] 303 6411.6
4 [40] 0.8 2.9 [16, 48, 66, 128] 305 4496.2
def squared_diff(row):
y = np.array([1 - (row.ExpG_Home + row.ExpG_Away), row.ExpG_Home, row.ExpG_Away])
HomeG_Time = row.HomeG_Time
AwayG_Time = row.AwayG_Time
x1 = np.array([1, 0, 0])
x2 = np.array([0, 1, 0])
x3 = np.array([0, 0, 1])
total_timeslot = 200
ssd = []
for k in range(total_timeslot):
if k in HomeG_Time:
ssd.append(sum((x2 - y) ** 2))
elif k in AwayG_Time:
ssd.append(sum((x3 - y) ** 2))
else:
ssd.append(sum((x1 - y) ** 2))
return sum(ssd)
df.apply(squared_diff, axis=1)
Out[]:
0 4766.4
1 2349.4
2 2354.4
3 6411.6
4 4496.2