Making Random 3-D Shapes in Python - 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()

Related

How can I create a graph from an equation with two unknowns with python?

I want to create a probably plot with a equation and two unknowns but I didn't success...
Here is my script
from numpy import exp, sqrt, linspace
from matplotlib import pyplot as plt
from pylab import meshgrid, cm, imshow, contour, clabel, colorbar, axis, title, show
plt.rcParams["figure.figsize"] = [10, 5]
plt.rcParams["figure.autolayout"] = True
def f(x, y):
return (1 / sqrt(x)) * exp(-y / 50) * (1 - exp(-x / 1097) * (2 * exp(-y / (2 * 50)) - 1))
x = linspace(10, 1000, 990)
y = linspace(10, 50, 40)
X, Y = meshgrid(x, y)
Z = f(X, Y)
Thank you so much !!
I would like to have a x value between 10 and 1000 and y value between 10 and 50 for example. And obtain this kind of plot.
As explained in This Link You can use matplotlibs 3d plotting api. Here's an example:
fig = plt.figure()
ax = plt.axes(projection='3d')
plt.xlim(10, 1000)
plt.ylim(10, 50)
# Some Different Types of Plots That You can Use:
ax.scatter3D(X, Y, Z, c=Z, cmap='Greens')
# ax.plot_wireframe(X, Y, Z, color='black')
# ax.plot3D(X.flatten(), Y.flatten(), Z.flatten())
# ax.contour3D(X, Y, Z, 990, cmap='binary')
plt.savefig('test.png')

I have a problem with plotting sphere and a curve on it

I am trying to plot a curve on a sphere but I can not plot them at the same time. I identified some points with Euclidean norm 10 for my curve, and some other points to plot the sphere of radius 10, respectively as following.
Points for curve:
random_numbers=[]
basevalues=np.linspace(-0.9,0.9,100)
for i in range(len(basevalues)):
t=random.random()
random_numbers.append(t*10)
xvalues=[random_numbers[i]*np.cos(basevalues[i]) for i in range(len(basevalues))]
yvalues=[random_numbers[i]*np.sin(basevalues[i]) for i in range(len(basevalues))]
zvalues=[np.sqrt(100-xvalues[i]**2-yvalues[i]**2)for i in range(len(basevalues))]
Where xvalues, yvalues and zvalues are our points Euclidean components.
Points for 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))
Where x,y and z are Euclidean components of sphere points.
My problem:
When I try to plot the curve, without plotting sphere, it works. But when I plot them together, then it just return the sphere.
The whole code is the following:
import matplotlib.pyplot as plt
import numpy as np
import random
#Curve points
random_numbers=[]
basevalues=np.linspace(-0.9,0.9,100)
for i in range(len(basevalues)):
t=random.random()
random_numbers.append(t*10)
xvalues=[random_numbers[i]*np.cos(basevalues[i]) for i in range(len(basevalues))]
yvalues=[random_numbers[i]*np.sin(basevalues[i]) for i in range(len(basevalues))]
zvalues=[np.sqrt(100-xvalues[i]**2-yvalues[i]**2)for i in range(len(basevalues))]
# Sphere points
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))
# Plot the surface and curve
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
circ = ax.plot(xvalues,yvalues,zvalues, color='green',linewidth=1)
sphere=ax.plot_surface(x, y, z, color='r')
ax.set_zlim(-10, 10)
plt.xlabel("X axes")
plt.ylabel("Y axes")
plt.show()
What I want to occur:
I would like to plot the curve on the sphere, but it dose not happen in my code. I appreciate any hint.
If you use a "." option for plotting the points, like
circ = ax.plot(xvalues, yvalues,zvalues, '.', color='green', linewidth=1)
you will see the points on top of the sphere for certain viewing angles, but disappear sometimes even if they are in front of the sphere. This is a known bug explained in the matplotlib documentation:
My 3D plot doesn’t look right at certain viewing angles:
This is probably the most commonly reported issue with mplot3d. The problem is that – from some viewing angles – a 3D object would appear in front of another object, even though it is physically behind it. This can result in plots that do not look “physically correct.”
In the same doc, the developers recommend to use Mayavi for more advanced use of 3D plots in Python.
Using spherical coordinates, you can easily do that:
## plot a circle on the sphere using spherical coordinate.
import numpy as np
import matplotlib.pyplot as plt
# a complete sphere
R = 10
theta = np.linspace(0, 2 * np.pi, 1000)
phi = np.linspace(0, np.pi, 1000)
x_sphere = R * np.outer(np.cos(theta), np.sin(phi))
y_sphere = R * np.outer(np.sin(theta), np.sin(phi))
z_sphere = R * np.outer(np.ones(np.size(theta)), np.cos(phi))
# a complete circle on the sphere
x_circle = R * np.sin(theta)
y_circle = R * np.cos(theta)
# 3d plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x_sphere, y_sphere, z_sphere, color='blue', alpha=0.2)
ax.plot(x_circle, y_circle, 0, color='green')
plt.show()

matplotlib: apply marker only to start point or end point?

I am using matplotlib and I am struggling with style attributes.
How to add a marker only to the start point or end point of a 3D line and not on both sides?
Use the markevery parameter when plotting.
Example from the Parametric Curve example in the Gallery (version 2.2.5).
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['legend.fontsize'] = 10
fig = plt.figure()
ax = fig.gca(projection='3d')
# Prepare arrays x, y, z
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
l = ax.plot(x, y, z, marker='o', label='parametric curve both ends', markevery=[0,-1])
l = ax.plot(x+1, y+1, z, 'r', marker='o', label='parametric curve one end', markevery=[0])
ax.legend()
plt.show()
plt.close()
I used the example from version 2.2.5 because I don't have 3.2 installed. Making a 3d axis changed in 3.something - 3.2 example link.
Axes.plot markevery parameter

Shrinking ellipsoid in matplotlib

I am new to animations with matplotlib, and I am trying to animate a shrinking ellipsoid.
Specifically, I want to animate an ellipsoid that shrinks its axes proportionally. (Mathematically, I'm looking for a shrinking factor of e^(-t) multiplied to each axis, where t is time.)
I have made a function of time t that outputs a static ellipsoid with the code below:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
def param_surface(t):
fig = plt.figure(figsize = (10, 10))
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = axis_a(4 * t / 50) * np.outer(np.cos(u), np.sin(v))
y = axis_a(4 * t / 50) * np.outer(np.sin(u), np.sin(v))
z = axis_b(4 * t / 50) * np.outer(np.ones(np.size(u)), np.cos(v))
return(ax.plot_surface(x, y, z, rstride = 4, cstride = 4))
I have seen animations (such as the one here: https://pythonmatplotlibtips.blogspot.com/2018/11/animation-3d-surface-plot-funcanimation-matplotlib.html) that allow you to animate 3D plots in which z is defined as a function of x, y. However, in the case of the shrinking ellipsoid, I need to use spherical coordinates, which complicates things.
Can someone explain what to add to my code to go from static to the desired shrinking animation?

Matplotlib parametric surface plot unexpected results, why?

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))

Categories

Resources