Given a 3D scatter plot with 7 points. These 7 points, geometrically make a double tetrahedron. I am able to connect all of the bottom points(z=0) to the apex(z=4/3 * sqrt(3)).
The base is made two triangles that have a common centroid(middle point), which is directly under the apex.
How do I outline the two triangles that make up the base?
In my number arrays, the points for the base would be [index0,1,2] for the first triangle and [index3,4,5] for the second and the [index7] would be the apex of the double pyramid(tetrahedron).
The image below shows what I would like to see. The missing lines are in red.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import math as m
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
tr = m.sqrt(3.)
sx = m.sqrt(6.)
x = np.array([4.,2.,6.,4.,6.,2.,4.])
y = np.array([1.,1.+2*tr,1.+2*tr,1+(8*tr)/3,1+(2*tr)/3,1+(2*tr)/3,1+(4*tr)/3])
z = np.array([0.,0.,0.,0.,0.,0.,(4*sx)/3])
ax.scatter(x,y,zs = z, s=100)
for r, s, t in zip(x, y, z):
X = np.array([r, 4.])
Y = np.array( [s, 1+(4*tr)/3])
Z = np.array([t, (4*sx)/3])
ax.plot3D(X, Y, Z, 'b')
ax.set_ylim([0,8])
ax.set_xlim([8,0])
ax.set_zlim([0,8])
plt.show()
Some Code:
To plot the missing vertices:
for index in range(6):
import math
next_idx = (index+1) % 3 + math.floor(index / 3) * 3
X = (x[index], x[next_idx])
Y = (y[index], y[next_idx])
Z = (z[index], z[next_idx])
ax.plot3D(X, Y, Z, 'r')
A Small Explanation:
The operative code is:
next_idx = (index+1) % 3 + math.floor(index / 3) * 3
this uses the fact that the data comes in triads. It selects the next index based on the current index plus one but staying in a group of 3. This effectively chooses all three elements of the triangles, in all possible sequences.
This works because (index+1) % 3 will only take the values 0, 1, 2, while math.floor(index / 3) * 3 takes the values 0, 3, 6.... So it ends up being:
index, next_idx
0 1
1 2
2 0
3 4
4 5
5 3
Alternate Ending:
This can also be done without the loop, using a list comprehension:
X = [x[i] for i in (0, 1, 2, 0)]
Y = [y[i] for i in (0, 1, 2, 0)]
Z = [z[i] for i in (0, 1, 2, 0)]
ax.plot3D(X, Y, Z, 'r')
X = [x[i] for i in (3, 4, 5, 3)]
Y = [y[i] for i in (3, 4, 5, 3)]
Z = [z[i] for i in (3, 4, 5, 3)]
ax.plot3D(X, Y, Z, 'r')
Picture:
Related
My code:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
y = np.tan(x)
y2 = 4 + x*0
y3 = -4 + x*0
fig = plt.figure(figsize=(8,5))
ax = fig.add_subplot(111)
diffs = np.sqrt(np.diff(x)**2+np.diff(y)**2)
length = diffs.sum()
numbers = [2, 4, 6, 8, 10]
p2 = []
for i in range(len(numbers)):
cumlenth = np.cumsum(diffs)
s = np.abs(np.diff(np.sign(cumlenth-numbers[i]))).astype(bool)
c = np.argwhere(s)[0][0]
p = x[c], y[c]
p2.append(p)
ax.cla()
ax = fig.add_subplot(111)
for j in range(len(p2)):
ax.scatter(p2[j][0],p2[j][1], color="crimson", s=5)
plt.plot(np.tan(x))
plt.plot(y2)
plt.plot(y3)
plt.ylim(-10, 10)
I'm trying to find the length of the tan() function cut off by two lines y2, y3 in a certain compartment. This means that only the part marked in red below should be taken to the total length of the chart:
Next, I try to mark the position of a points from list numbers = [] on this the graph, which are lying in the distance equal to the value of these points, starting from the beginning of the graph in point (x,y)=(0,0), and I want get their coordinates. Which for my sample list numbers = [] would give something like this:
What am I missing? Can this be achieved?
I will be grateful for any tips.
plt.plot takes two arguments, an x array and a y array; without providing both, pyplot assumes that you wanted to plot them against the index of the value in the array. So, your first hurdle is to change the lines at the bottom to:
plt.plot(x, np.tan(x))
plt.plot(x, y2)
plt.plot(x, y3)
Now we have the issue of the fact that your calculation is taking the whole graph into account, not just the parts between -4 and 4. You could solve this by filtering the x array by your thresholds:
x_all = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
x_above = x_all[ -4 < np.tan(x_all) ]
x = x_above[ np.tan(x_above) < 4 ]
Finally, we have the issue that the diff calculation seems to be taking the jump from +4 to -4 into account. We can mitigate this by filtering out anywhere the diff in y is negative:
y_up = np.diff(y) > 0
y_diff = np.where( y_up, np.diff(y), 0 )
x_diff = np.where( y_up, np.diff(x), 0 )
diffs = np.sqrt( x_diff**2 + y_diff**2 )
My final code looks like this, and seems to be working as you expect it to:
import matplotlib.pyplot as plt
import numpy as np
x_all = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
x_above = x_all[ -4 < np.tan(x_all) ]
x = x_above[ np.tan(x_above) < 4 ]
y = np.tan(x)
y2 = 4 + x*0
y3 = -4 + x*0
y_up = np.diff(y) > 0
y_diff = np.where( y_up, np.diff(y), 0 )
x_diff = np.where( y_up, np.diff(x), 0 )
diffs = np.sqrt( x_diff**2 + y_diff**2 )
length = diffs.sum()
numbers = [2, 4, 6, 8, 10]
p2 = []
for i in range(len(numbers)):
cumlenth = np.cumsum(diffs)
s = np.abs(np.diff(np.sign(cumlenth-numbers[i]))).astype(bool)
c = np.argwhere(s)[0][0]
p = x[c], y[c]
p2.append(p)
for j in range(len(p2)):
plt.scatter( p2[j][0], p2[j][1], color="crimson", s=5)
plt.plot(x, np.tan(x))
plt.plot(x, y2)
plt.plot(x, y3)
plt.ylim(-10, 10)
plt.show()
Using a 2d matrix in python, how can I create a 3d surface plot, where columns=x, rows=y and the values are the heights in z?
I can't understand how to creat 3D surface plot using matplotlib.
Maybe it's different from MatLab.
example:
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
def p(eps=0.9, lmd=1, err=10e-3, m=60, n=40):
delta_phi = 2 * np.pi / m
delta_lmd = 2 / n
k = 1
P0 = np.zeros([m + 1, n + 1])
P = np.zeros([m + 1, n + 1])
GAP = 1
while GAP >= err:
k = k + 1
for i in range(0, m):
for j in range(0, n):
if (i == 1) or (j == 1) or (i == m + 1) or (i == n + 1):
P[i,j] = 0
else:
A = (1+eps*np.cos((i+1/2)*delta_phi))**3
B = (1+eps*np.cos((i-1/2)*delta_phi))**3
C = (lmd*delta_phi/delta_lmd)**2 * (1+eps*np.cos((i)*delta_phi))**3
D = C
E = A + B + C + D
F = 3*delta_phi*((1+eps*np.cos((i+1/2)*delta_phi))-(1+eps*np.cos((i-1/2)*delta_phi)))
P[i,j] = (A*P[i+1,j] + B*P[i-1,j] + C*P[i,j+1] + D*P[i,j-1] - F)/E
if P[i,j] < 0:
P[i,j] = 0
S = P.sum() - P0.sum()
T = P.sum()
GAP = S / T
P0 = P.copy()
return P, k
def main():
start = time.time()
eps = 0.9
lmd = 1
err = 10e-8
m = 60
n = 40
P, k = p()
fig = figure()
ax = Axes3D(fig)
X = np.linspace(0, 2*np.pi, m+1)
Y = np.linspace(-1, 1, n+1)
X, Y = np.meshgrid(X, Y)
#Z = P[0:m, 0:n]
#Z = Z.reshape(X.shape)
ax.set_xticks([0, np.pi/2, np.pi, np.pi*1.5, 2*np.pi])
ax.set_yticks([-1, -0.5, 0, 0.5, 1])
ax.plot_surface(X, Y, P)
show()
if __name__ == '__main__':
main()
ValueError: shape mismatch: objects cannot be broadcast to a single
shape
And the pic
pic by matplotlic
And I also use MatLab to generate,the pic:
pic by MatLab
I should think this is a problem of getting the notaton straight. A m*n matrix is a matrix with m rows and n columns. Hence Y should be of length m and X of length n, such that after meshgridding X,Y and P all have shape (m,n).
At this point there would be no need to reshape of reindex and just plotting
ax.plot_surface(X, Y, P)
would give your the desired result.
Let's assume if you have a matrix mat.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
h, w = mat.shape
plt.figure(figsize=(16, 8))
ax = plt.axes(projection='3d')
X, Y = np.meshgrid(np.arange(w), np.arange(h))
ax.plot_surface(X, Y, mat, rstride=1, cstride=1, cmap='viridis', edgecolor='none', antialiased=False)
I need to plot every iteration in a loop of Kachmarz algorithm. But when i try there is a error:
ValueError: x and y can be no greater than 2-D, but have shapes (2, 1, 1) and (2,)
Threre is my code (we have matrix A, where every row give a plane and it has to solve Ax = f by Kaczmarz algorithm and animate it):
import os
import matplotlib.pyplot as plt
import numpy as np
from numpy import linalg as la
x = np.linspace(-100, 15, 100)
A = np.matrix([[2, 3], [1, -1],[6, 1]]);
f = np.matrix([4, 2, 15]);
resh = la.pinv(A).dot(np.transpose(f))
e1 = (1 - 2*x)/3;
e2 = (x - 2);
e3 = 15 - 6*x;
plt.plot(x, e1, color="black")
plt.plot(x, e2, color="black")
plt.plot(x, e3, color="black")
plt.axis([-0, 4, -4, 4])
[m , n] = np.shape(A)
precision = 0.01
iteration = 100
lmbd = 0.8
nrm=[]
for i in range(0, m):
nrm.append(la.norm(A[i][:]));
approx = np.zeros((n, 1))
predx =
np.zeros((n, 1))
print(np.shape(approx))
for i in range(0, iteration):
j = (i-1) % m
predx = approx
approx = approx + np.multiply((f[:,j] - A[j,:].dot(approx)),(np.transpose(A[j, :])))
plt.plot([predx[0], approx[0]], [predx[1], 2], "r-")
# c = plt.plot([predx[1], 2], [predx[2], 2], "g-")
# pause(0.01)
if(la.norm(predx - approx) <= precision):
break
plt.show()
I have no idea how to fix it, in the end it should be like this: Kaczmarz animation
How I can fix this loop? What I do wrong?
I am trying to animate an octahedron. Here is the code for that. A simpler version of this code would be found on this different question on SO. Using the code there and the style of the animate object as used here I tried to make a functional animation. The only problem is- the animation hangs up the plot window!
import numpy as np
import mayavi.mlab as ML
import math
import time
def produce_verts(A,t):
delta=lambda A,t:A*math.sin(t)
verts =lambda d: [(1+d,0,0), (0,1+d,0), (-1-d,0,0), (0,-1-d,0), (0,0,1+d), (0,0,-1-d)]
return zip(*verts(delta(A,t)))
t=0.
dt=0.01
A=0.5
ML.clf()
nverts=6
x, y, z = produce_verts(A,t)
# Each triangle is a 3-tuple of indices. The indices are indices of `verts`.
triangles = [(i, (i+1)%4, j) for i in range(4) for j in (4,5)]
colorval = [x[i]**2+y[i]**2+z[i]**2 for i in range(nverts)]
mesh=ML.triangular_mesh(x, y, z, triangles, scalars=colorval, opacity=1,representation='mesh')
MS=mesh.mlab_source
Bool=True
while Bool:
t=(t+dt)%(2*math.pi)
x,y,z=produce_verts(A,t)
colorval = [x[i]**2+y[i]**2+z[i]**2 for i in range(nverts)]
MS.reset(x=x,y=y,z=z,scalars=colorval)
time.sleep(1.)
print t,dt
if t>4:
Bool=False
I don't think the plot is hanging. It's just that dt is so small and the time.sleep is so large that it tries your patience. If you set dt equal to, say, 0.1, and remove the time.sleep call, then the plot becomes more animated.
Also, use MS.reset when the size of the arrays change. When the size of the arrays stays the same, you'll get better performance using MS.set:
import numpy as np
import mayavi.mlab as ML
import math
import time
def produce_verts(A, t):
def delta(A, t):
return A * math.sin(t)
def verts(d):
return [(1 + d, 0, 0), (0, 1 + d, 0), (-1 - d, 0, 0), (0, -1 - d, 0),
(0, 0, 1 + d), (0, 0, -1 - d)]
return zip(*verts(delta(A, t)))
t = 0.
dt = 0.1
A = 0.5
ML.clf()
nverts = 6
x, y, z = produce_verts(A, t)
# Each triangle is a 3-tuple of indices. The indices are indices of `verts`.
triangles = [(i, (i + 1) % 4, j) for i in range(4) for j in (4, 5)]
colorval = [xi ** 2 + yi ** 2 + zi ** 2 for xi, yi, zi in zip(x, y, z)]
mesh = ML.triangular_mesh(
x, y, z, triangles, scalars=colorval, opacity=1, representation='mesh')
ms = mesh.mlab_source
while True:
t = (t + dt) % (2 * math.pi)
x, y, z = produce_verts(A, t)
colorval = [xi ** 2 + yi ** 2 + zi ** 2 for xi, yi, zi in zip(x, y, z)]
ms.set(x=x, y=y, z=z, scalars=colorval)
# time.sleep(0.1)
print t, dt
if t > 4:
break
ML.show()
I am currently working with astronomical data among which I have comet images. I would like to remove the background sky gradient in these images due to the time of capture (twilight). The first program I developed to do so took user selected points from Matplotlib's "ginput" (x,y) pulled the data for each coordinate (z) and then gridded the data in a new array with SciPy's "griddata."
Since the background is assumed to vary only slightly, I would like to fit a 3d low order polynomial to this set of (x,y,z) points. However, the "griddata" does not allow for an input order:
griddata(points,values, (dimension_x,dimension_y), method='nearest/linear/cubic')
Any ideas on another function that may be used or a method for developing a leas-squares fit that will allow me to control the order?
Griddata uses a spline fitting. A 3rd order spline is not the same thing as a 3rd order polynomial (instead, it's a different 3rd order polynomial at every point).
If you just want to fit a 2D, 3rd order polynomial to your data, then do something like the following to estimate the 16 coefficients using all of your data points.
import itertools
import numpy as np
import matplotlib.pyplot as plt
def main():
# Generate Data...
numdata = 100
x = np.random.random(numdata)
y = np.random.random(numdata)
z = x**2 + y**2 + 3*x**3 + y + np.random.random(numdata)
# Fit a 3rd order, 2d polynomial
m = polyfit2d(x,y,z)
# Evaluate it on a grid...
nx, ny = 20, 20
xx, yy = np.meshgrid(np.linspace(x.min(), x.max(), nx),
np.linspace(y.min(), y.max(), ny))
zz = polyval2d(xx, yy, m)
# Plot
plt.imshow(zz, extent=(x.min(), y.max(), x.max(), y.min()))
plt.scatter(x, y, c=z)
plt.show()
def polyfit2d(x, y, z, order=3):
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
return m
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z += a * x**i * y**j
return z
main()
The following implementation of polyfit2d uses the available numpy methods numpy.polynomial.polynomial.polyvander2d and numpy.polynomial.polynomial.polyval2d
#!/usr/bin/env python3
import unittest
def polyfit2d(x, y, f, deg):
from numpy.polynomial import polynomial
import numpy as np
x = np.asarray(x)
y = np.asarray(y)
f = np.asarray(f)
deg = np.asarray(deg)
vander = polynomial.polyvander2d(x, y, deg)
vander = vander.reshape((-1,vander.shape[-1]))
f = f.reshape((vander.shape[0],))
c = np.linalg.lstsq(vander, f)[0]
return c.reshape(deg+1)
class MyTest(unittest.TestCase):
def setUp(self):
return self
def test_1(self):
self._test_fit(
[-1,2,3],
[ 4,5,6],
[[1,2,3],[4,5,6],[7,8,9]],
[2,2])
def test_2(self):
self._test_fit(
[-1,2],
[ 4,5],
[[1,2],[4,5]],
[1,1])
def test_3(self):
self._test_fit(
[-1,2,3],
[ 4,5],
[[1,2],[4,5],[7,8]],
[2,1])
def test_4(self):
self._test_fit(
[-1,2,3],
[ 4,5],
[[1,2],[4,5],[0,0]],
[2,1])
def test_5(self):
self._test_fit(
[-1,2,3],
[ 4,5],
[[1,2],[4,5],[0,0]],
[1,1])
def _test_fit(self, x, y, c, deg):
from numpy.polynomial import polynomial
import numpy as np
X = np.array(np.meshgrid(x,y))
f = polynomial.polyval2d(X[0], X[1], c)
c1 = polyfit2d(X[0], X[1], f, deg)
np.testing.assert_allclose(c1,
np.asarray(c)[:deg[0]+1,:deg[1]+1],
atol=1e-12)
unittest.main()
According to the principle of Least squares, and imitate Kington's style,
while move argument m to argument m_1 and argument m_2.
import numpy as np
import matplotlib.pyplot as plt
import itertools
# w = (Phi^T Phi)^{-1} Phi^T t
# where Phi_{k, j + i (m_2 + 1)} = x_k^i y_k^j,
# t_k = z_k,
# i = 0, 1, ..., m_1,
# j = 0, 1, ..., m_2,
# k = 0, 1, ..., n - 1
def polyfit2d(x, y, z, m_1, m_2):
# Generate Phi by setting Phi as x^i y^j
nrows = x.size
ncols = (m_1 + 1) * (m_2 + 1)
Phi = np.zeros((nrows, ncols))
ij = itertools.product(range(m_1 + 1), range(m_2 + 1))
for h, (i, j) in enumerate(ij):
Phi[:, h] = x ** i * y ** j
# Generate t by setting t as Z
t = z
# Generate w by solving (Phi^T Phi) w = Phi^T t
w = np.linalg.solve(Phi.T.dot(Phi), (Phi.T.dot(t)))
return w
# t' = Phi' w
# where Phi'_{k, j + i (m_2 + 1)} = x'_k^i y'_k^j
# t'_k = z'_k,
# i = 0, 1, ..., m_1,
# j = 0, 1, ..., m_2,
# k = 0, 1, ..., n' - 1
def polyval2d(x_, y_, w, m_1, m_2):
# Generate Phi' by setting Phi' as x'^i y'^j
nrows = x_.size
ncols = (m_1 + 1) * (m_2 + 1)
Phi_ = np.zeros((nrows, ncols))
ij = itertools.product(range(m_1 + 1), range(m_2 + 1))
for h, (i, j) in enumerate(ij):
Phi_[:, h] = x_ ** i * y_ ** j
# Generate t' by setting t' as Phi' w
t_ = Phi_.dot(w)
# Generate z_ by setting z_ as t_
z_ = t_
return z_
if __name__ == "__main__":
# Generate x, y, z
n = 100
x = np.random.random(n)
y = np.random.random(n)
z = x ** 2 + y ** 2 + 3 * x ** 3 + y + np.random.random(n)
# Generate w
w = polyfit2d(x, y, z, m_1=3, m_2=2)
# Generate x', y', z'
n_ = 1000
x_, y_ = np.meshgrid(np.linspace(x.min(), x.max(), n_),
np.linspace(y.min(), y.max(), n_))
z_ = np.zeros((n_, n_))
for i in range(n_):
z_[i, :] = polyval2d(x_[i, :], y_[i, :], w, m_1=3, m_2=2)
# Plot
plt.imshow(z_, extent=(x_.min(), y_.max(), x_.max(), y_.min()))
plt.scatter(x, y, c=z)
plt.show()
If anyone is looking for fitting a polynomial of a specific order (rather than polynomials where the highest power is equal to order, you can make this adjustment to the accepted answer's polyfit and polyval:
instead of:
ij = itertools.product(range(order+1), range(order+1))
which, for order=2 gives [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] (aka up to a 4th degree polynomial), you can use
def xy_powers(order):
powers = itertools.product(range(order + 1), range(order + 1))
return [tup for tup in powers if sum(tup) <= order]
This returns [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (2, 0)] for order=2