Fit 3d coordinates into a parabola - python

I would like to predict a ball trajectory by fitting its 3d coordinates into a parabola. Below is my code. But instead of a parabola, I got a straight line. If you have any clue about it, please let me know. Thanks!
# draw scatter coordiante
fig = plt.figure()
ax = plt.axes(projection = '3d')
x_list = []
y_list = []
z_list = []
for x in rm_list:
x_list.append(x[0][0])
y_list.append(x[0][1])
z_list.append(x[0][2])
x = np.array(x_list)
y = np.array(y_list)
z = np.array(z_list)
ax.scatter(x, y, z)
# curve fit
def func(x, a, b, c, d):
return a * x[0]**2 + b * x[1]**2 + c * x[0] * x[1] + d
data = np.column_stack([x_list, y_list, z_list])
popt, _ = curve_fit(func, data[:,:2].T, ydata=data[:,2])
a, b, c, d = popt
print('y= %.5f * x ^ 2 + %.5f * y ^ 2 + %.5f * x * y + %.5f' %(a, b, c, d))
x1 = np.linspace(0.3, 0.4, 100)
y1 = np.linspace(0.02, 0.06, 100)
z1 = a * x1 ** 2 + b * y1 ** 2 + c * x1 * y1 + d
ax.plot(x1, y1, z1, color='green')
plt.show()
Update 1
After changing the func to ax^2 + by^2 + cxy + dx + ey + f, I got a parabola but not fitting to the coordinate.

That you have your underlying timestamp data makes the fitting procedure easier:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
from numpy.polynomial import Polynomial
# test data generation with some noise
# here read in your data
np.random.seed(123)
n = 40
x_param = [ 1, 21, -1]
y_param = [12, -3, 0]
z_param = [-3, 0, -2]
px = Polynomial(x_param)
py = Polynomial(y_param)
pz = Polynomial(z_param)
t = np.random.choice(np.linspace (-3000, 2000, 1000)/500, n)
x = px(t) + np.random.random(n)
y = py(t) + np.random.random(n)
z = pz(t) + np.random.random(n)
# here start the real calculations
# draw scatter coordinates of raw data
fig = plt.figure()
ax = plt.axes(projection = '3d')
ax.scatter(x, y, z, label="raw data")
# curve fit function
def func(t, x2, x1, x0, y2, y1, y0, z2, z1, z0):
Px=Polynomial([x2, x1, x0])
Py=Polynomial([y2, y1, y0])
Pz=Polynomial([z2, z1, z0])
return np.concatenate([Px(t), Py(t), Pz(t)])
# curve fit
# start values are not necessary for this example
# but make it your rule to always provide start values for curve_fit
start_vals = [ 1, 10, 1,
10, 1, 1,
-1, -1, -1]
xyz = np.concatenate([x, y, z])
popt, _ = curve_fit(func, t, xyz, p0=start_vals)
print(popt)
#[ 1.58003630e+00 2.10059868e+01 -1.00401965e+00
# 1.25895591e+01 -2.97374035e+00 -3.23358241e-03
# -2.44293562e+00 3.96407428e-02 -1.99671092e+00]
# regularly spaced fit data
t_fit = np.linspace(min(t), max(t), 100)
xyz_fit = func(t_fit, *popt).reshape(3, -1)
ax.plot(xyz_fit[0, :], xyz_fit[1, :], xyz_fit[2, :], color="green", label="fitted data")
ax.legend()
plt.show()
Sample output:

Related

I want to Plot Circle and its Solid Revolution (Sphere) but get Error: loop of ufunc does not support argument 0 o

I have add the assumption of nonnegative for variables x and r so why I can't plot this?
this is my code:
# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)
def f(x):
return sy.sqrt(r**2 - x**2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
# Plot the circle
y = np.sqrt(r ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = np.sqrt(r ** 2 - y_inverse ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
That's because at this line of code:
y = np.sqrt(r ** 2 - x ** 2)
r is still a Sympy's symbol. You need to assign a number to r.

fit multiple parametric curves with scipy python

I am trying to fit two curve into one equation. y = (a * exp(b * (T^-1)))cexp(d100)(x^0.5)
for y1, T =10,
for y2, T =25.
how do a get a,b,c,d
I have a code that simplified to fit one data. I don't know how to do both.
I find a similar question with solution but I can't follow.. fit multiple parametric curves with scipy
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from scipy.optimize import leastsq
import numpy as np
import pandas as pd
from math import exp
def func(params,x,y):
a, b, c, d = params[0], params[1], params[2],params[3]
return y-(a*exp(b*(10**-1)))*c*exp(d*100)*(x**0.5)
x = [0,33,65,98,135,261,374]
y = [0.000,0.006,0.010,0.018,0.023,0.033,0.035]
y2 = [0.000,0.013,0.032,0.036,0.042,0.046,0.051]
plt.scatter(x,y, label='y1')
plt.scatter(x,y2, label='y1')
params=[0, 0, 0, 0]
result = leastsq(func, params, (x, y))
a, b, c, d = result[0][0], result[0][1], result[0][2], result[0][3]
yfit1 = (a*exp(b*(25**-1)))*c*exp(d*100)*(x**0.5)
plt.plot(x, yfit1, color="red")
print (b,c,d)
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid()
plt.show()
You need to include T in the independent variable being passed to curve_fit. Also, you should use numpy mathematical functions in func.
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import numpy as np
def func(xT, a, b, c, d,):
x = xT[0,:]
T = xT[1,:]
return a * np.exp(b * np.power(T, -1)) * c * np.exp(d * 100.0) * np.power(x, 0.5)
x0 = np.array([0,33,65,98,135,261,374])
y1 = np.array([0.000,0.006,0.010,0.018,0.023,0.033,0.035])
T1 = 10.0 * np.ones(len(x0))
y2 = np.array([0.000,0.013,0.032,0.036,0.042,0.046,0.051])
T2 = 25.0 * np.ones(len(x0))
x = np.concatenate((x0, x0))
y = np.concatenate((y1, y2))
T = np.concatenate((T1, T2))
popt, _ = curve_fit(func, np.vstack((x, T)), y)
N = 101 # number of points for parametric curves
x_ = np.linspace(np.min(x0), np.max(x0), N)
y1_ = func(np.vstack((x_, 10.0 * np.ones(N))), *popt)
plt.plot(x0, y1, 'k.')
plt.plot(x_, y1_, 'k-')
y2_ = func(np.vstack((x_, 25.0 * np.ones(N))), *popt)
plt.plot(x0, y2, 'b.')
plt.plot(x_, y2_, 'b-')

Find Points where Embedded Time Series Matrix Intersects Hyperplane

I have a 3-dimensional embedded time series. How can I find the points/coordinates (x, y, z) where the 3d matrix of the time series intersects an arbitrary hyperplane. The problem is I don't have an equation for my embedded time series. Do I either find the closest points to the hyperplane and project them onto my hyperplane or do I find where one point crosses onto the other side to another point and then find the equation of that line and plug in my z-value to find the (x, y) coords? My plot looks like this:
Here's my current code for replicability:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from teaspoon.SP.tsa_tools import takens
import seaborn as sns
from datetime import datetime
import pandas_datareader.data as pdr
sns.set_style("darkgrid")
def fetch_data(symbol, from_date, to_date, cols_to_drop):
""" Fetch OHLC data."""
df = pdr.DataReader(symbol, "yahoo", from_date, to_date)
df.drop(columns=cols_to_drop, inplace=True)
return df
if __name__ == "__main__":
# Fetch OHLC Data #
symbol = "EURUSD=X" # ticker
from_date = datetime(2000, 1, 1)
to_date = datetime.now()
drop_columns = ["Adj Close", "Volume"]
df = fetch_data(symbol=symbol, from_date=from_date,
to_date=to_date, cols_to_drop=drop_columns)
# TAKEN'S EMBEDDING THEOREM #
taken_matrix = takens(np.array(df.Close), n=3, tau=62) # emb_dim =3, time delay=62
x_min, x_max = np.min(taken_matrix[:, 0]), np.max(taken_matrix[:, 0]) # x_min and x_max
y_min, y_max = np.min(taken_matrix[:, 1]), np.max(taken_matrix[:, 1]) # y_min and y_max
z_min, z_max = np.min(taken_matrix[:, 2]), np.max(taken_matrix[:, 2]) # z_min and z_max
# Method 1
x = np.array([x_min, x_max])
y = np.array([y_min, y_max])
xx, yy = np.meshgrid(x, y)
z = np.array([[1.4, 1.4], [1.4, 1.4]])
hyperplane = np.array([xx, yy, z])
hyperplane = np.reshape(hyperplane.T, (4, 3)) # 4 co-ords
fig = plt.figure(dpi=50)
ax = plt.axes(projection="3d")
ax.set_xlabel("x"); ax.set_ylabel("y"); ax.set_zlabel("z")
ax.plot(taken_matrix[:, 0], taken_matrix[:, 1], taken_matrix[:, 2], c="black", lw=0.6, alpha=0.8) # phase space
ax.plot_surface(xx, yy, z, alpha=0.2, color="seagreen") # Hyperplane
plt.show()
# Method 2
hyperplane1 = hyperplane[:-1, :] # 3 coordinates
p0, p1, p2 = hyperplane1
x0, y0, z0 = p0
x1, y1, z1 = p1
x2, y2, z2 = p2
ux, uy, uz = u = [x1 - x0, y1 - y0, z1 - z0] # first vector
vx, vy, vz = v = [x2 - x0, y2 - y0, z2 - z0] # second vector
u_cross_v = [uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx] # cross product
point1 = np.array(p1)
normal1 = np.array(u_cross_v) # hyerplane normal vector
d1 = -point1.dot(normal1) # computed for equation of plane
print('plane equation:\n{:1.4f}x + {:1.4f}y + {:1.4f}z + {:1.4f} = 0'.format(normal1[0], normal1[1], normal1[2], d1))
xx, yy = np.meshgrid(x, y)
z1 = (-normal1[0] * xx - normal1[1] * yy - d1) * 1. / normal1[2]
fig = plt.figure()
ax = plt.axes(projection="3d")
ax.plot_surface(xx, yy, z1, color="orange")
ax.plot(taken_matrix[:, 0], taken_matrix[:, 1], taken_matrix[:, 2], c="black", lw=0.6, alpha=0.8)
plt.show()
So here's my solution to find the intersection of points that pass from above to below an arbitrary hyperplane. In my code, after I have created the taken matrix, here's my new implementation:
x = np.array([1, 1.6])
y = ([1, 1.6])
xx, yy = np.meshgrid(x, y)
z = np.array([[1, 1.3], [1.3, 1.6]])
hyperplane = np.array([xx, yy, z])
hyperplane2 = np.reshape(hyperplane.T, (4, 3))
hyperplane2 = hyperplane2[:-1, :] # we only need 3 points
p0, p1, p2 = hyperplane2
x0, y0, z0 = p0
x1, y1, z1 = p1
x2, y2, z2 = p2
ux, uy, uz = u = [x1 - x0, y1 - y0, z1 - z0] # first vector
vx, vy, vz = v = [x2 - x0, y2 - y0, z2 - z0] # second vector
u_cross_v = [uy*vz - uz*vy, uz*vx - ux*vz, ux*vy - uy*vx] # cross product
point1 = np.array(p1)
normal1 = np.array(u_cross_v)
d1 = -point1.dot(normal1)
print('\nplane equation:\n{:1.4f}x + {:1.4f}y + {:1.4f}z + {:1.4f} = 0'.format(normal1[0], normal1[1], normal1[2], d1))
xx, yy = np.meshgrid(x, y)
z1 = (-normal1[0] * xx - normal1[1] * yy - d1) * 1. / normal1[2]
from sympy import symbols, Eq
from sympy.solvers import solve
t = symbols("t")
x, y, z = symbols("x, y, z")
g = symbols("g")
plane = Eq(normal1[0] * x + normal1[1] * y + normal1[2] * z + d1, g) # create plane
print(plane)
# Points that pass from above to below the plane (not below to above because I want it to be transveral)
above_or_below = np.array([solve(plane.subs([(x, taken_matrix[i][0]),
(y, taken_matrix[i][1]),
(z, taken_matrix[i][2])]), g) \
for i in tqdm(range(len(taken_matrix)))])
above1, below1 = [], []
for i in tqdm(range(1, len(above_or_below))):
if above_or_below[i-1] >= 0 and above_or_below[i] < 0:
above1.append(taken_matrix[i-1])
below1.append(taken_matrix[i])
above1 = np.array(above1)
below1 = np.array(below1)
# Parametric Equations for x_coords, y_coords and z_coords
xs1 = [Eq((above1[i][0] - below1[i][0])*t + below1[i][0] - x, 0) for i in range(len(above1))]
ys1 = [Eq((above1[i][1] - below1[i][1])*t + below1[i][1] - y, 0) for i in range(len(above1))]
zs1 = [Eq((above1[i][2] - below1[i][2])*t + below1[i][2] - z, 0) for i in range(len(above1))]
# Solve Equations
xs1 = np.array([solve(i, x) for i in xs1])
ys1 = np.array([solve(i, y) for i in ys1])
zs1 = np.array([solve(i, z) for i in zs1])
ts1 = np.array([solve(plane.subs([(g, 0), (x, np.squeeze(i)),
(y, np.squeeze(j)), (z, np.squeeze(k))]), t) \
for i, j, k in zip(xs1, ys1, zs1)]) # plug x, y and z eqn's into plane to get t
# Get x, y and z co-ordinates
xs1 = np.array([solve(Eq(np.squeeze(i), x).subs(t, np.squeeze(j)), x) for i, j in zip(xs1, ts1)])
ys1 = np.array([solve(Eq(np.squeeze(i), y).subs(t, np.squeeze(j)), y) for i, j in zip(ys1, ts1)])
zs1 = np.array([solve(Eq(np.squeeze(i), z).subs(t, np.squeeze(j)), z) for i, j in zip(zs1, ts1)])
points_on_plane1 = np.concatenate([xs1, ys1, zs1], axis=1) # put coordinates together
fig = plt.figure()
ax = plt.axes(projection="3d")
ax.plot_surface(xx, yy, z1, alpha=0.2, color="seagreen")
ax.plot(taken_matrix[:, 0], taken_matrix[:, 1], taken_matrix[:, 2], c="black", lw=0.6, alpha=0.5)
ax.scatter(points_on_plane1[:, 0], points_on_plane1[:, 1], points_on_plane1[:, 2], c="red")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
plt.show()

Animating a 3d vector - ValueError: too many values to unpack (expected 2)

I am trying to animate a rotating 3d vector. everything more or less works, expect my update-funtion for the "FuncAnimation"-part of the code. When I run the code, I get the following error message:
"Error in line "the line with the code "vector.set_data(u[i], v[i], w[i])" ValueError: too many values to unpack (expected 2)"
I have no idea what i am doing wrong, can anybody help?
from matplotlib import animation, rc
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 10))
ax = fig.gca(projection='3d')
t_end = 20
u0 = [1 / np.sqrt(2)]
v0 = [1 / np.sqrt(2)]
w0 = [0]
y0 = u0 + v0 + w0
print(y0)
def ode45(t, y):
u = np.array(y[0])
v = np.array(y[1])
w = np.array(y[2])
omega = np.pi / 2
delta = 0
dudt = delta * v
dvdt = -delta * u + omega * w
dwdt = - omega * v
return [dudt, dvdt, dwdt]
mysol = solve_ivp(ode45, [0, t_end], y0)
u = mysol.y[0]
v = mysol.y[1]
w = mysol.y[2]
r = np.mean(u ** 2 + v ** 2 + w ** 2)
print(r)
theta = np.linspace(0, 2 * np.pi, 101)
phi = np.linspace(0, np.pi, 101)
z = r * np.outer(np.ones(np.size(theta)), np.cos(phi))
x = r * np.outer(np.cos(theta), np.sin(phi))
y = r * np.outer(np.sin(theta), np.sin(phi))
ax.plot_surface(x, y, z, alpha=0.2, color='gray')
vector, = ax.plot([], [], [])
def update(i):
vector.set_data(u[i], v[i], w[i])
return vector
ax.plot([0], [0], [0], 'ro')
ax.plot(u, v, w, color='blue')
steps = 100 * t_end
anim = animation.FuncAnimation(fig, update, frames=t_end, interval=1, blit=True)
anim
plt.show()
This line is creating a tuple:
vector, = ax.plot([], [], [])
Pyplot .plot() returns a list (typically of lines or markers) to plot or adjust. I don't think it returns a tuple. So, in
def update(i):
vector.set_data(u[i], v[i], w[i])
return vector
The vector.set_data(u[i], v[i], w[i]) is calling set_data on a tuple of (ax.plot.lines, None). I think this might be the problem.
EDIT:
You should be able to fix it with this:
vector = ax.plot([], [], [])

How to close the ends of a cylinder in matplotlib

I am trying to make a 'closed' cylinder in matplotlib but I am not sure how to go about doing this. So far I have a cylinder with the ends open, the code for this is as follows:
#make a cylinder without the ends closed
import numpy as np
from matplotlib import cm
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.linalg import norm
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
import math
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
origin = [0,0,0]
#radius = R
p0 = np.array(origin)
p1 = np.array([8, 8, 8])
origin = np.array(origin)
R = 4
#vector in direction of axis
v = p1 - p0
#find magnitude of vector
mag = norm(v)
#unit vector in direction of axis
v = v / mag
#make some vector not in the same direction as v
not_v = np.array([1, 0, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
#make vector perpendicular to v
n1 = np.cross(v, not_v)
#normalize n1
n1 /= norm(n1)
#make unit vector perpendicular to v and n1
n2 = np.cross(v, n1)
#surface ranges over t from 0 to length of axis and 0 to 2*pi
t = np.linspace(0, mag, 600)
theta = np.linspace(0, 2 * np.pi, 100)
#use meshgrid to make 2d arrays
t, theta = np.meshgrid(t, theta)
#generate coordinates for surface
X, Y, Z = [p0[i] + v[i] * t + R * np.sin(theta) * n1[i] + R * np.cos(theta) * n2[i] for i in [0, 1, 2]]
#make the color for the faces
col1 = plt.cm.autumn(np.ones(600)) # linear gradient along the t-axis
col1 = np.repeat(col1[np.newaxis,:, :], 100, axis=0) # expand over the theta-axis
ax.plot_surface(X, Y,Z, facecolors = col1, shade = True,edgecolors = "None", alpha = 0.4, linewidth = 0)
plt.show()
Running this code produces the following image
How would I close the ends of the cylinder with a solid circle (i.e. disk)?
A quick and easy way that's similar to your other code is to generate a surface using strips from r=0 to r=R. Right before plt.show() add the following lines:
R = np.array([0,R])
# cap at t=0
X, Y, Z = [p0[i] + np.outer(R, np.sin(theta)) * n1[i] + np.outer(R, np.cos(theta))*n2[i] for i in [0, 1, 2]]
ax.plot_surface(X, Y, Z, edgecolors = "r", alpha=.4, linewidth = .1)
# cap at t=mag
X, Y, Z = [p0[i] + v[i]*mag + np.outer(R, np.sin(theta)) * n1[i] + np.outer(R, np.cos(theta))*n2[i] for i in [0, 1, 2]]
ax.plot_surface(X, Y, Z, edgecolors = "r", alpha=.4, linewidth = .1)
Here the colors are more for illustrative purposes, mostly so you can see the strips. The result looks like:

Categories

Resources