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()
Related
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.
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:
I want to plot a truncated cone by using exactly the same method used in
Plotting a solid cylinder centered on a plane in Matplotlib; which plots a cylinder when two points on the center of each base and the radius are known. On the other hand, I want to plot a truncated cone when the coordinates of the two points on the center of its bases and the radius of each base are known.
It seems that I just should change the second last line of the function in the following program which plots a cylinder, but I could not do this in all of my efforts.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from scipy.linalg import norm
import pylab as pllt
fig = pllt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
#ax = pllt.subplot2grid((2,2), (0,0), rowspan=2, projection='3d')
#axis and radius
def cylinder(p0,p1,R,ccc):
#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, 1, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
#make vector perpendicular to v
n1 = np.cross(v, not_v)
#print n1,'\t',norm(n1)
#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, 80)
theta = np.linspace(0, 2 * np.pi, 80)
#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]]
ax.plot_surface(X, Y, Z,color=ccc,linewidth=0, antialiased=False)
A0 = np.array([1, 3, 2])
A1 = np.array([8, 5, 9])
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax.set_zlim(0,10)
cylinder(A0,A1,1,'blue')
pllt.show()
I think I should change the radius as a function of v=p1-p0 as mentioned in:
http://mathworld.wolfram.com/ConicalFrustum.html to be able to do this.
Please let me know if there is any way to do this.
Instead of a constant radius, R, make it change from R0 to R1:
R = np.linspace(R0, R1, n)
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from scipy.linalg import norm
import pylab as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
def truncated_cone(p0, p1, R0, R1, color):
"""
Based on https://stackoverflow.com/a/39823124/190597 (astrokeat)
"""
# 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, 1, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
# make vector perpendicular to v
n1 = np.cross(v, not_v)
# print n1,'\t',norm(n1)
# 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
n = 80
t = np.linspace(0, mag, n)
theta = np.linspace(0, 2 * np.pi, n)
# use meshgrid to make 2d arrays
t, theta = np.meshgrid(t, theta)
R = np.linspace(R0, R1, n)
# 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]]
ax.plot_surface(X, Y, Z, color=color, linewidth=0, antialiased=False)
A0 = np.array([1, 3, 2])
A1 = np.array([8, 5, 9])
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.set_zlim(0, 10)
truncated_cone(A0, A1, 1, 5, 'blue')
plt.show()
I use matplot3d(ax.bar3d() and ax.plot) to plot two lines around a cuboid, when looking in bird viewbird view, this figure shows the read 3d relationship of all the objects. When looking from sideside view, some part of blue line that behind the green cylinder should be hidden, but this part still can be seen. I tried using parameter alpha, and it failed too. Does any body know how to deal with this ?
My matplotlib version is 2.1.0, and my python version is 3.4.7
# import
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# global set
XMAX = 4
ZMAX = 15
mpl.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
print(mpl.__version__)
z = np.linspace(0, ZMAX, 5)
if True:
arrowstartt = np.zeros((3))
arrowstartx = np.zeros((3))
arrowstarty = np.zeros((3))
arrowendt = np.zeros((3))
arrowendx = np.zeros((3))
arrowendy = np.zeros((3))
arrowcolor= 'black'
fontsizes = 25
# x cors
x = (XMAX + 1) / np.max(z) * z
y = 0. * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[0] = x[-1]
arrowstarty[0] = y[-1]
arrowstartt[0] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "x", color='k', fontsize=fontsizes)
# y cors
x = 0. * z
y = 2 * XMAX / np.max(z) * z
zz = 0. * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[1] = x[-1]
arrowstarty[1] = y[-1]
arrowstartt[1] = zz[-1]
ax.text(x[-1], y[-1], zz[-1]-1, "y", color='k', fontsize=fontsizes)
#z cor
x = 0. * z
y = 0. * z
zz = (XMAX) / np.max(z) * z
ax.plot(x, y, zz, color=arrowcolor, linewidth=1)
arrowstartx[2] = x[-1]
arrowstarty[2] = y[-1]
arrowstartt[2] = zz[-1]
ax.text(x[-1], y[-1], zz[-1], "z", color='k', fontsize=fontsizes)
# arrow end
arrowendx = arrowstartx + [1, 0, 0]
arrowendy = arrowstarty + [0, 1, 0]
arrowendt = arrowstartt + [0, 0, 1]
ax.quiver(arrowstartx, arrowstarty, arrowstartt, arrowendx, arrowendy, arrowendt,2, color=arrowcolor, linewidth=1)
# ax.set_xlabel('x')
# ax.set_ylabel('y')
# ax.set_zlabe('z')
# ax.arrow()
''' draw bar as a cylinder '''
if True:
# draw bar
xpos = 0.
ypos = 30.
dx = 1.4
dy = 2
ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, color='g', zsort='average')
#ax.bar3d(xpos, ypos, 0, dx, dy, ZMAX, alpha=0.8, color='g',zsort='average')
''' draw two lines'''
if True:
# the blue line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * (-2)
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'b')
#ax.plot(x, y, z, 'b',alpha=0.8)
# the red line
y = np.arange(0, 50, 1)
x = np.ones(len(y)) * 2
z = np.linspace(0, ZMAX, len(y))
ax.plot(x, y, z, 'r')
plt.axis('off')
ax.legend()
plt.show()
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: