Plotting a rectangular area on the surface of a sphere - python

I am trying to trace out a rectangular area on the surface of a sphere.
This is the code I have for the sphere:
import numpy as np
import random as rand
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("equal")
theta, phi = np.mgrid[0:2*np.pi : 20j ,0:np.pi : 20j]
r = 6.3
x = r * np.cos(phi)*np.sin(theta)
y = r * np.sin(phi)*np.sin(theta)
z = r * np.cos(theta)
ax.plot_wireframe(x,y,z, color = "k")
plt.show()
The points will be converted from lat/long to cart coords.
lat1x = 46.49913179 * (2*np.pi/360)
lat2x = 46.4423682 * (2*np.pi/360)
long1y = -119.4049072 * (2*np.pi/360)
long2y = -119.5048141 * (2*np.pi/360)
lat3x = 46.3973998 * (2*np.pi/360)
lat4x = 46.4532495 * (2*np.pi/360)
long3y = -119.4495392 * (2*np.pi/360)
long4y = -119.3492884 * (2*np.pi/360)
xw1 = r * np.cos(lat1x)*np.cos(long1y)
yw1 = r * np.cos(lat1x)*np.sin(long1y)
zw1 = r * np.sin(lat1x)
xw2 = r * np.cos(lat2x)*np.cos(long2y)
yw2 = r * np.cos(lat2x)*np.sin(long2y)
zw2 = r * np.sin(lat2x)
xw3 = r * np.cos(lat3x)*np.cos(long3y)
yw3 = r * np.cos(lat3x)*np.sin(long3y)
zw3 = r * np.sin(lat3x)
xw4 = r * np.cos(lat4x)*np.cos(long4y)
yw4 = r * np.cos(lat4x)*np.sin(long4y)
zw4 = r * np.sin(lat4x)
p1 = [xw1,yw1,zw1]
p2 = [xw2,yw2,zw2]
p3 = [xw3,yw3,zw3]
p4 = [xw4,yw4,zw4]
ax.scatter(p1,p2,p3,p4, color = "r")
These are the points and there conversion to cartesian coordinates I am having trouble getting them to appear on the surface of the sphere. They should also form a rough rectangular shape. I would like to be able to connect the points to draw a rectangle on the surface of the sphere. As an aside the rectangle is meant to be very small

Your conversion to cartesian coordinates may be wrong. Just like when creating the sphere, you might want to use the usual
But it will of course depend on how "lat" and "lon" are defined on the sphere.
More importantly, the scatter plot is incorrect. It's always scatter(x,y,z), first argument x coordinates, second argument y coordinates, third argument z coordinates.
import numpy as np
import random as rand
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("equal")
theta, phi = np.mgrid[0:2*np.pi : 20j ,0:np.pi : 20j]
r = 6.3
x = r * np.cos(phi)*np.sin(theta)
y = r * np.sin(phi)*np.sin(theta)
z = r * np.cos(theta)
ax.plot_wireframe(x,y,z, color = "k")
lat1x = 46.49913179 * (2*np.pi/360)
lat2x = 46.4423682 * (2*np.pi/360)
long1y = -119.4049072 * (2*np.pi/360)
long2y = -119.5048141 * (2*np.pi/360)
lat3x = 46.3973998 * (2*np.pi/360)
lat4x = 46.4532495 * (2*np.pi/360)
long3y = -119.4495392 * (2*np.pi/360)
long4y = -119.3492884 * (2*np.pi/360)
def to_cartesian(lat,lon):
x = r * np.cos(lon)*np.sin(lat)
y = r * np.sin(lon)*np.sin(lat)
z = r * np.cos(lat)
return [x,y,z]
p1 = to_cartesian(lat1x,long1y)
p2 = to_cartesian(lat2x,long2y)
p3 = to_cartesian(lat3x,long3y)
p4 = to_cartesian(lat4x,long4y)
X = np.array([p1,p2,p3,p4])
ax.scatter(X[:,0],X[:,1],X[:,2], color = "r")
plt.show()
Because the rectangle is pretty small you need to zoom in quite a bit in order to see it.

Related

How do I make a plot that changes through time?

Now, here is the code I'm working with:
import numpy
from matplotlib import pyplot as plt
import time, sys
nx = 41
dx = 2 / (nx-1)
nt = 25
dt = 0.025
c = 1
fig = plt.figure()
u = numpy.ones(nx)
u[int(.5 / dx):int(1 / dx + 1)] = 2
print(u)
un = numpy.ones(nx)
for n in range(nt):
un = u.copy()
plt.plot(numpy.linspace(0, 2, nx), u)
for i in range(1, nx):
u[i] = un[i] - c*dt/dx * (un[i] - un[i - 1])
plt.show()
It should animate the solution to the equation ∂u/∂t + c * ∂u/∂x = 0; but I don't know how to animate it - because at the current state, it shows at once the function at all time steps; and if instead I put plt.show() inside the loop (the outer one), it shows the graphs one at a time, and I have to close the graph window to see the next, which is not very convenient.
FuncAnimation can be used to create animations.
The code of the post can be rendered as an animation as follows:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
nx = 41
dx = 2 / (nx-1)
nt = 25
dt = 0.025
c = 1
fig = plt.figure()
u = np.ones(nx)
u[int(.5 / dx):int(1 / dx + 1)] = 2
x = np.linspace(0, 2, nx)
plot1, = plt.plot(x, u)
def update(t):
un = u.copy()
for i in range(1, nx):
u[i] = un[i] - c*dt/dx * (un[i] - un[i - 1])
plot1.set_ydata(u)
return plot1,
FuncAnimation(fig, update, frames=nt, blit=True)
plt.show()
PS: Note the comma after plot1 in plot1, = plt.plot(.... This grabs the first element in the list returned by plt.plot.
You could save it as a gif using the following:
import numpy
from matplotlib import pyplot as plt
import time, sys
from celluloid import Camera
from IPython.display import Image
nx = 41
dx = 2 / (nx-1)
nt = 25
dt = 0.025
c = 1
fig = plt.figure()
u = numpy.ones(nx)
u[int(.5 / dx):int(1 / dx + 1)] = 2
print(u)
un = numpy.ones(nx)
fig = plt.figure()
camera = Camera(fig)
for n in range(nt):
un = u.copy()
plt.plot(numpy.linspace(0, 2, nx), u, color= "blue")
for i in range(1, nx):
u[i] = un[i] - c*dt/dx * (un[i] - un[i - 1])
camera.snap()
animation = camera.animate()
animation.save('solution.gif', writer = 'imagemagick')
In essence it recursively takes a camera "snap" for each dt and collates them into a gif saved as "solution.gif" in the current working directory.

Why does my circle on my sphere becoming a figure eight?

here is the code in question to the title of this issue I have. I have hand-derived the formulas behind my code so it doesnt seem to be wrong...
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import random as rdm
resol = 30
resolcirc = 15
r=1
########## THE SPHERE ##########
phi = np.linspace(0, np.pi*((resol-1)/resol), resol)
theta = np.linspace(0, 2*np.pi*((resol*2-1)/resol*2), resol*2)
phi, theta = np.meshgrid(phi, theta)
x = r * np.sin(phi) * np.cos(theta)
y = r * np.sin(phi) * np.sin(theta)
z = r * np.cos(phi)
########## THE RANDOM POINT ##########
r1=1
randphi = rdm.random()*np.pi
randtheta = rdm.random()*2*np.pi
x1 = r1 * np.sin(randphi) * np.cos(randtheta)
y2 = r1 * np.sin(randphi) * np.sin(randtheta)
z3 = r1 * np.cos(randphi)
radpoint = 0.5
########## THE RANDOM CIRCLE ##########
rcirc=0.2
gamma = np.linspace(0, 2*np.pi*((resol-1)/resol), resol)
rotanglephi = -1 * rcirc * np.cos(gamma)
rotangletheta = rcirc * np.sin(gamma)
psitheta=2*np.sin(-1*rcirc*np.cos(gamma)/r)
psiphi=2*np.sin(rcirc*np.sin(gamma)/r)
x1 = r1 * np.sin(randphi+psiphi) * np.cos(randtheta+psitheta)
y2 = r1 * np.sin(randphi+psiphi) * np.sin(randtheta+psitheta)
z3 = r1 * np.cos(randphi+psiphi)
########## THE PLOT ###########
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, z, c='y', marker='.')
ax.scatter(x1,y2,z3, c='r', marker = 'x',s=50)
plt.tight_layout()
#plt.axis('off')
plt.show()
Normally it works totally fine as intended, as such:
enter image description here
However, I cannot for the life of me troubleshoot why it is giving me this funky behavior at the top and bottom of the sphere:
enter image description here
This the the absolute first step of this code, where I will need to create a point, and make a ring around it which will move in an orbit on this spherical surface. Help is massively appreciated!
Your solution does not define a circle it seems depending upon your theta/phi
look at the graph with values, for
randphi = np.pi / 8
randtheta = -np.pi / 4
I would suggest defining your circle as an intersection of a plane with a sphere here

python surface plot gradually varied color

I need to make a figure for the project. Now I get 90% of it. However, I want my figure to have some gradually varied color, some mix of red and balck. Is there anyway in python where I can achieve it?
Here's the figure I got:
Here's the figure I want:
Here's my code
import numpy as np
from matplotlib import cm, colors
import matplotlib.pyplot as plt
import scipy.special as sp
from mpl_toolkits.mplot3d import Axes3D
phi, theta = np.mgrid[0:2*np.pi:300j, 0:np.pi:150j]
Y30 = sp.sph_harm(0, 3, phi, theta).real
Y20 = sp.sph_harm(0, 2, phi, theta).real
R0 = 1
alpha30 = 0.1
alpha20 = 0.02
prefactor = alpha30*Y30 + alpha20 * Y20 +1
X = R0 * prefactor * np.sin(theta) * np.cos(phi)
Y = R0 * prefactor * np.sin(theta) * np.sin(phi)
Z = R0 * prefactor * np.cos(theta)
norm = colors.Normalize()
fig, ax = plt.subplots(subplot_kw=dict(projection='3d'), figsize=(10.5,10))
m = cm.ScalarMappable(cmap=cm.jet)
# hide the background axes
plt.axis('off')
# change the view
ax.view_init(1, )
ax.plot_surface(X, Y, Z, rstride=10, cstride=10, color = 'orangered', edgecolors='k',shade = True)
m.set_array(R0)
I don't need my figure to be exactly the same. I just want it to have some mixture of red and black, varying gradually. I would be very appreciate for the help.

Using python, I am looking to plot a 3D spherical cap with a given radius r

I am looking to make a small program that will produce a 3D plot of a spherical cap given parameters h and a.
Any help would be greatly appreciated!
I've started with a matplotlib example to plot a sphere...
I want to enter a value for a and h, get the corresponding radius of the sphere, then plot a spherical cap of height h and base radius a. Ideally the z axis and x y axis on the 3d plot will correspond to my initial a and h entered (as long as it makes geometric sense i presume?)
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
def capRatio(r, a, h):
'''cap to sphere ratio'''
surface_cap = np.pi * (a**2 + h**2)
surface_sphere = 4.0 * np.pi * r**2
return surface_cap/surface_sphere
def findRadius(a, h):
"find radius if you have cap base radius a and height"
r = (a**2 + h**2) / (2*h)
return r
#choose a and h
a = 4
h = 3
r = findRadius(a,h)
p = capRatio(r, a, h) # Ratio of sphere to be plotted, could also be a function of a.
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, p*np.pi, 100)
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))
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, rstride=4, cstride=4, alpha=0.3 , cmap= cm.winter)
plt.show()
The next part comes in limiting the range of coordinates you will accept and this could be done in a few ways. Here is one way that appears to work:
p = 0.8 # Ratio of sphere to be plotted, could also be a function of a.
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, p*np.pi, p*100)

Matplotlib plot pulse propagation in 3d

I'd like to plot pulse propagation in such a way at each step, it plots the pulse shape. In other words, I want a serie of x-z plots, for each values of y. Something like this (without color):
How can I do this using matplotlib (or Mayavi)? Here is what I did so far:
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
surf = ax.plot_wireframe(T, z, abs(U))
Change to:
ax.plot_wireframe(T, z, abs(U), cstride=1000)
and call:
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
will create the following graph:
If you need the curve been filled with white color:
import numpy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
U = numpy.abs(U)
verts = []
for i in xrange(T.shape[0]):
verts.append(zip(T[i, :], U[i, :]))
poly = PolyCollection(verts, facecolors=(1,1,1,1), edgecolors=(0,0,1,1))
ax.add_collection3d(poly, zs=z[:, 0], zdir='y')
ax.set_xlim3d(numpy.min(T), numpy.max(T))
ax.set_ylim3d(numpy.min(z), numpy.max(z))
ax.set_zlim3d(numpy.min(U), numpy.max(U))
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
pyplot.show()

Categories