0

I have plotted a 'tear drop' shaped cylinder in matplotlib. To obtain the tear drop shape I plotted a normal cylinder from theta = 0 to theta = pi and an ellipse from theta = pi to theta = 2pi. However I am now trying to 'spin' the cylinder around it's axis which here is given conveniently by the z-axis.

I tried using the rotation matrix for rotating around the z-axis which Wikipedia gives as: enter image description here

However when I try to rotate through -pi/3 radians, the cylinder becomes very disfigured. enter image description here

Is there anyway to prevent this from happening? Here is my code:

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from math import sin, cos, pi
import math


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')


theta = np.linspace(0,2*pi, 1200)
Z = np.linspace(0,5,1000+600)

Z,theta = np.meshgrid(Z, theta)

X = []
Y = []
R = 0.003


#calculate the x and y values
for i in theta:
    cnt = 0
    tempX = []
    tempY = []
    for j in i:
         #circle
        if(i[0]<=pi):
            tempX.append(R*cos(j))
            tempY.append(R*sin(j))
            cnt+=1
         #ellipse
        else:
            tempX.append(R*cos(j))
            tempY.append(0.006*sin(j))
    X.append(tempX)
    Y.append(tempY)



X1 = np.array(X)
Y1 = np.array(Y)

#rotate around the Z axis
a = -pi/3
for i in range(len(X)):
    X1[i] = cos(a)*X1[i]-sin(a)*Y1[i]
    Y1[i] = sin(a)*X1[i]+cos(a)*Y1[i]



#plot
ax.plot_surface(X1,Y1,Z,linewidth = 0, shade = True, alpha = 0.3)


ax.set_xlim(-0.01,0.01)
ax.set_ylim(-0.01, 0.01)

azimuth = 173
elevation = 52
ax.view_init(elevation, azimuth)
plt.show()
fosho
  • 1,666
  • 6
  • 20
  • 28
  • 2
    Your rotating is flawed: To calculate `Y1[i]` you need the *old* value of `X1[i]`, but you already updated it. You can try something like `X1[i], Y1[i] = cos(a)*X1[i]-sin(a)*Y1[i], sin(a)*X1[i]+cos(a)*Y1[i]` – syntonym Jul 19 '16 at 14:52
  • @syntonym thanks a lot, this worked. If you type that up as an answer I will accept it! Thanks again :) – fosho Jul 19 '16 at 14:57

1 Answers1

2

Your rotating is flawed: To calculate Y1[i] you need the old value of X1[i], but you already updated it. You can try something like

X1[i], Y1[i] = cos(a)*X1[i]-sin(a)*Y1[i], sin(a)*X1[i]+cos(a)*Y1[i]

if you want to make the matrix multiplication a bit more obvious (and fix the bug) you could also do the following (please doublecheck that the matrix is correct and that the multiplication is in the right order, I did not test this):

rotation_matrix = np.array([[cos(a), -sin(a)], [sin(a), cos(a)]])
x, y = zip(*[(x,y) @ rotation_matrix for x,y in zip(x,y)])

the @ is new in 3.5 and for numpy array it's defined to be the matrix multiplication. If you are on a version below 3.5 you can use np.dot.

The zip(*...) is necessary to get a pair of lists instead of a list of pairs. See also this answer

Community
  • 1
  • 1
syntonym
  • 7,134
  • 2
  • 32
  • 45