Matplotlib parametric surface plot unexpected results, why? - python

I am trying to plot an ellipsoid so, I thought I would amend the example code for a sphere from the matplotlib 3D plotting page.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Ellipsoid
u = np.linspace(-np.pi/2.0,np.pi/2.0,100)
v = np.linspace(-np.pi,np.pi,100)
x = 10 * np.outer(np.cos(u), np.cos(v))
y = 10 * np.outer(np.cos(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.sin(v))
# Sphere
#u = np.linspace(0, 2 * np.pi, 100)
#v = np.linspace(0, np.pi, 100)
#x = 10 * np.outer(np.cos(u), np.sin(v))
#y = 10 * np.outer(np.sin(u), np.sin(v))
#z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, cmap = cm.copper)
ax.set_xlabel('x-axis')
ax.set_ylabel('y-axis')
ax.set_zlabel('z-axis')
plt.show()
If you run the code you will see that the plot returns an aesthetically pleasing half inside out boat like surface but sadly not an ellipsoid.
Have included the sphere code (commented out) for comparison.
Is there something obvious here that I'm missing?

Why did you change the parametrization? Starting with the sphere as an example, you only have to change the semi-axis lengths:
# Ellipsoid
u = np.linspace(0, 2.*np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 60 * np.outer(np.cos(u), np.sin(v))
y = 20 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))

Related

How to draw sphere with cylinder by formula with matplotlib

I have two formulas:
x^2 + y^2+z^2 = 6
(x-3)^2+y^2=4
So I have to draw this shapes by matplotlib on python.
My solution:
`
import math
import matplotlib.pyplot as plt
from pylab import *
import numpy as np
import matplotlib.patches as patches
from mpl_toolkits.mplot3d import Axes3D
from itertools import product, combinations
import mpl_toolkits.mplot3d.art3d as art3d
def task3():
fig = plt.figure()
ax = plt.axes(projection='3d')
coefs = (1, 1, 1) # Coefficients in a0/c x**2 + a1/c y**2 + a2/c z**2 = 1
# Radii corresponding to the coefficients:
rx, ry, rz = 1 / np.sqrt(coefs)
# Set of all spherical angles:
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
# Cartesian coordinates that correspond to the spherical angles:
# (this is the equation of an ellipsoid):
x = rx * np.outer(np.cos(u), np.sin(v))
y = ry * np.outer(np.sin(u), np.sin(v))
z = rz * np.outer(np.ones_like(u), np.cos(v))
ax.plot_surface(x, y, z, rstride=6, cstride=6,
cmap='viridis', edgecolor='none')
# ax.scatter(X, Y, Z, c=Z, cmap='viridis', label="xy")
radius = 0.3
height = 2.4
elevation = -1
resolution = 720
color = 'r'
x_center = 0.7
y_center = -0
a = np.linspace(x_center - radius, x_center + radius, resolution)
b = np.linspace(elevation, elevation + height, resolution)
X, Z = np.meshgrid(a, b)
Y = np.sqrt(radius ** 2 - (X - x_center) ** 2) + y_center # Pythagorean theorem
ax.plot_surface(X, Y, Z, rstride=6, cstride=6,
cmap='viridis', edgecolor='none')
ax.plot_surface(X, (2 * y_center - Y), Z, rstride=6, cstride=6,
cmap='viridis', edgecolor='none')
plt.show()
[![Result. I cant post images, but you can compile result and then you will see that my solution too approximate)
I want to do it correctly

Setting coordinates for sphere

I have a code that produces a sphere. I want to change the coordinates in which the sphere spawns
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib import cm
from matplotlib import animation
import pandas as pd
fig = plt.figure(facecolor='black')
ax = plt.axes(projection = "3d")
u = np.linspace(0, 2*np.pi, 100)
v = np.linspace(0, np.pi, 100)
r = 10
ax.set_xlim(0, 60)
ax.set_ylim(0, 60)
ax.set_zlim(0, 60)
x = r * np.outer(np.cos(u), np.sin(v))
y = r * np.outer(np.sin(u), np.sin(v))
z = r * np.outer(np.ones(np.size(u)), np.cos(v))
def init():
ax.plot_surface(x,y,z)
return fig,
def animate(i):
ax.view_init(elev = 20, azim = i*4)
ani = animation. FuncAnimation(fig, animate, init_func = init, frames = 90, interval = 299)
plt.show()
So for instance, I want the sphere to be drawn in the coordinates (10,10,10)
Easy, just an offset to x, y, z, like this:
x = r * np.outer(np.cos(u), np.sin(v)) + 10
y = r * np.outer(np.sin(u), np.sin(v)) + 10
z = r * np.outer(np.ones(np.size(u)), np.cos(v)) + 10

How to plot Saturn and its rings using matplotlib 3D?

I have managed to create a code that outputs a sphere and a ring around it but the ring doesn't look like its rounding the sphere...
Can anyone save me here?
Code:
import numpy as np
from matplotlib import pyplot as plt
import mpl_toolkits.mplot3d.axes3d
theta = np.linspace(0, 2.*np.pi, 100)
phi = np.linspace(0, 2*np.pi, 100)
theta, phi = np.meshgrid(theta, phi)
c, a = 10, 0.2
x = (c + a*np.cos(theta)) * np.cos(phi)
y = (c + a*np.cos(theta)) * np.sin(phi)
z = a * np.sin(theta)
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
ax1.set_zlim(-10,10)
ax1.plot_surface(x, y, z, rstride=5, cstride=5, color='b', edgecolors='b')
ax1.view_init(36, 26)
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x2 = 4 * np.outer(np.cos(u), np.sin(v))
y2 = 4 * np.outer(np.sin(u), np.sin(v))
z2 = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax1.plot_surface(x2, y2, z2, rstride=5, cstride=5, color='r')
plt.show()

python matplotlib: drawing 3D sphere with circumferences

I'm trying to draw a sphere like this one using matplotlib:
but I can't find a way of having a dashed lines on the back and the vertical circumference looks a bit strange
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12,12), dpi=300)
ax = fig.add_subplot(111, projection='3d')
ax.set_aspect('equal')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 1 * np.outer(np.cos(u), np.sin(v))
y = 1 * np.outer(np.sin(u), np.sin(v))
z = 1 * np.outer(np.ones(np.size(u)), np.cos(v))
#for i in range(2):
# ax.plot_surface(x+random.randint(-5,5), y+random.randint(-5,5), z+random.randint(-5,5), rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
ax.plot(np.sin(theta),np.cos(u),0,color='k')
ax.plot([0]*100,np.sin(theta),np.cos(u),color='k')
In the example you show, I don't think that the circles can be perpendicular to one another (i.e. one is the equator and one runs through the north pole and south pole). If the horizontal circle is the equator, then the north pole must be somewhere on a vertical line drawn through the center of the yellow circle that represents the sphere. Otherwise, the right side of the equator would look higher or lower than the left. However, the ellipse that represents the polar circle only crosses through that center line at the top and bottom of the yellow circle. Therefore, the north pole is at the top of the sphere, which means that we must be looking straight on the equator, which means it should look like a line, not an ellipse.
Here's some code to reproduce something similar to the figure you posted:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_aspect('equal')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 1 * np.outer(np.cos(u), np.sin(v))
y = 1 * np.outer(np.sin(u), np.sin(v))
z = 1 * np.outer(np.ones(np.size(u)), np.cos(v))
#for i in range(2):
# ax.plot_surface(x+random.randint(-5,5), y+random.randint(-5,5), z+random.randint(-5,5), rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
elev = 10.0
rot = 80.0 / 180 * np.pi
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b', linewidth=0, alpha=0.5)
#calculate vectors for "vertical" circle
a = np.array([-np.sin(elev / 180 * np.pi), 0, np.cos(elev / 180 * np.pi)])
b = np.array([0, 1, 0])
b = b * np.cos(rot) + np.cross(a, b) * np.sin(rot) + a * np.dot(a, b) * (1 - np.cos(rot))
ax.plot(np.sin(u),np.cos(u),0,color='k', linestyle = 'dashed')
horiz_front = np.linspace(0, np.pi, 100)
ax.plot(np.sin(horiz_front),np.cos(horiz_front),0,color='k')
vert_front = np.linspace(np.pi / 2, 3 * np.pi / 2, 100)
ax.plot(a[0] * np.sin(u) + b[0] * np.cos(u), b[1] * np.cos(u), a[2] * np.sin(u) + b[2] * np.cos(u),color='k', linestyle = 'dashed')
ax.plot(a[0] * np.sin(vert_front) + b[0] * np.cos(vert_front), b[1] * np.cos(vert_front), a[2] * np.sin(vert_front) + b[2] * np.cos(vert_front),color='k')
ax.view_init(elev = elev, azim = 0)
plt.show()

Making Random 3-D Shapes in Python

How can I use Python to generate a bunch of spheres and ellipses in one plot? Ideally it would just entail setting the endpoints (or radii/axes) of each object and a color, like how you can easily generate rectangles/circles using endpoints.
I was imagining using something like matplotlib's 3-D module, where you can rotate & play with the plot once it's outputted. I'm open to using other libraries though!
I could possibly plot the equations as surfaces by manipulating & graphing a bunch of ellipsoid equations, but is there an easier solution?
VPython might be the quickest path to getting some spheres and ellipsoids on the screen. Also, VPython is much more interactive than matplotlib (in the sense that you can rotate, zoom, etc), and it's very easy to get started. In the end, it depends on what you're looking for. There are lots of ways to get spheres and ellipsoids on the screen.
from visual import *
myell = ellipsoid(pos=(x0,y0,z0), length=L, height=H, width=W)
ball = sphere(pos=(1,2,1), radius=0.5)
Were you looking for functionality that isn't included in matplotlib's mpl_toolkits.mplot3d module? From the 3D Surface demo:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.show()
I don't see any reason why you couldn't define another shape in the same field:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
x1 = 7 + 10 * np.outer(np.cos(u), np.sin(v))
y1 = 7 + 10 * np.outer(np.sin(u), np.sin(v))
z1 = 7 + 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
ax.plot_surface(x1, y1, z1, rstride=4, cstride=4, cmap=cm.coolwarm)
plt.show()

Categories

Resources