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.
Related
I would like to plot the function x^3 - 3xy + y^3 = 0 (Folium of Descartes) but with different colors in quadrant 2 and 4, and at the peak of the leaf I want the colors to change. I was thinking about converting to a piecewise parametric equation to make the plotting in different colors easier, but I don't know how to convert into a parametric form.
I was originally using a contour to plot the function only in one color, but I have no idea how to get the color changes.
Below is what I have for the single color, but I would like to have separate colors for each of the segments listed above.
import matplotlib.pyplot as plt
import numpy as np
xrange = np.arange(-5, 5, .025)
yrange = np.arange(-5, 5, .025)
X, Y = np.meshgrid(xrange, yrange)
plt.contour(X, Y, X**3 - 3*X*Y + Y**3, levels=[0], colors=['#000000'])
plt.show()
This website gives parametric Cartesian and polar equations of the curve.
The parametric equation isn't symmetric in x and y, which is annoying for drawing nice curves.
The polar equation gives a radius rho for a given angle theta. Some experimenting shows that the tails are formed by theta negative, or larger than pi/2. The cusp is at pi/4.
To visualize the polar curve, x=rho*cos(theta) and y=rho*sin(theta) can be used. Coloring can happen depending on theta.
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
import numpy as np
a = 1
tail = 0.5
theta = np.linspace(-tail, np.pi / 2 + tail, 500)
rho = 3 * a * np.sin(theta) * np.cos(theta) / (np.cos(theta) ** 3 + np.sin(theta) ** 3)
x = rho * np.cos(theta)
y = rho * np.sin(theta)
cmap = LinearSegmentedColormap.from_list('', ['red', 'gold', 'blue'])
# cmap = ListedColormap(['red', 'blue'])
# cmap = 'Spectral'
plt.scatter(x, y, c=theta, cmap=cmap, s=1)
plt.axis('equal')
plt.axis('off')
plt.show()
Copying the leave 4 times, and filling them in decreasing order creates the following plot.
import matplotlib.pyplot as plt
import numpy as np
for a in np.linspace(1, 0.001, 50):
theta = np.linspace(0, np.pi / 2, 500)
rho = 3 * a * np.sin(theta) * np.cos(theta) / (np.cos(theta) ** 3 + np.sin(theta) ** 3)
x = rho * np.cos(theta)
y = rho * np.sin(theta)
for i in [-1, 1]:
for j in [-1, 1]:
plt.fill(i * x, j * y, c=plt.cm.summer(1 - a))
plt.axis('equal')
plt.axis('off')
plt.show()
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
I want to draw a line inside a torus which I have drawn with a surface plot. The line should not be visible inside the torus - like the inner side of the torus, which can only be seen at the "ends" of the torus (I cut-off one half of the torus). The line I have drawn is however visible everywhere (as you can see in the plot).
I have used the following code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# theta: poloidal angle | phi: toroidal angle
# note: only plot half a torus, thus phi=0...pi
theta = np.linspace(0, 2.*np.pi, 200)
phi = np.linspace(0, 1.*np.pi, 200)
theta, phi = np.meshgrid(theta, phi)
# major and minor radius
R0, a = 3., 1.
# torus parametrization
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)
# parametrization for a circular line at theta=0
x_circle = (R0-a/2. + a*np.cos(.0)) * np.cos(phi)
y_circle = (R0-a/2. + a*np.cos(.0)) * np.sin(phi)
z_circle = a * np.sin(.0)
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
# plot half of a circular line
ax1.plot3D( x_circle, y_circle, z_circle )
# plot half of torus
ax1.plot_surface( x_torus, y_torus, z_torus )
ax1.view_init(elev=15, azim=270)
ax1.set_xlim( -3, 3)
ax1.set_ylim( -3, 3)
ax1.set_zlim( -3, 3)
ax1.set_axis_off()
plt.show()
I thought simply plotting the line first should solve my problem, but it doesn't. Any suggestion or help how to change the behaviour of the line is greatly appreciated.
numpy.__version__ : 1.12.1
matplotlib.__version__: 2.0.0
Option one - use Mayavi
The easier way to do this would be with the Mayavi library. This is pretty similar to matplotlib, the only meaningful differences for this script are that the x, y, and z arrays passed to plot3d to plot the line should be 1d and the view is set a bit differently (depending on whether it is set before or after plotting, and the alt/az are measured from different reference).
import numpy as np
import mayavi.mlab as mlab
from mayavi.api import OffScreenEngine
mlab.options.offscreen = True
# theta: poloidal angle | phi: toroidal angle
# note: only plot half a torus, thus phi=0...pi
theta = np.linspace(0, 2.*np.pi, 200)
phi = np.linspace(0, 1.*np.pi, 200)
# major and minor radius
R0, a = 3., 1.
x_circle = R0 * np.cos(phi)
y_circle = R0 * np.sin(phi)
z_circle = np.zeros_like(x_circle)
# Delay meshgrid until after circle construction
theta, phi = np.meshgrid(theta, phi)
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)
mlab.figure(bgcolor=(1.0, 1.0, 1.0), size=(1000,1000))
mlab.view(azimuth=90, elevation=105)
mlab.plot3d(x_circle, y_circle, z_circle)
mlab.mesh(x_torus, y_torus, z_torus, color=(0.0, 0.5, 1.0))
mlab.savefig("./example.png")
# mlab.show() has issues with rendering for some setups
Option two - use matplotlib (with some added unpleasantness)
If you can't use mayavi it is possible to accomplish this with matplotlib, it's just... unpleasant. The approach is based on the idea of creating transparent 'bridges' between surfaces and then plotting them together as one surface. This is not trivial for more complex combinations, but here is an example for the toroid with a line which is fairly straightforward
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
theta = np.linspace(0, 2.*np.pi, 200)
phi = np.linspace(0, 1.*np.pi, 200)
theta, phi = np.meshgrid(theta, phi)
# major and minor radius
R0, a = 3., 1.
lw = 0.05 # Width of line
# Cue the unpleasantness - the circle must also be drawn as a toroid
x_circle = (R0 + lw*np.cos(theta)) * np.cos(phi)
y_circle = (R0 + lw*np.cos(theta)) * np.sin(phi)
z_circle = lw * np.sin(theta)
c_circle = np.full_like(x_circle, (1.0, 1.0, 1.0, 1.0), dtype=(float,4))
# Delay meshgrid until after circle construction
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)
c_torus = np.full_like(x_torus, (0.0, 0.5, 1.0, 1.0), dtype=(float, 4))
# Create the bridge, filled with transparency
x_bridge = np.vstack([x_circle[-1,:],x_torus[0,:]])
y_bridge = np.vstack([y_circle[-1,:],y_torus[0,:]])
z_bridge = np.vstack([z_circle[-1,:],z_torus[0,:]])
c_bridge = np.full_like(z_bridge, (0.0, 0.0, 0.0, 0.0), dtype=(float, 4))
# Join the circle and torus with the transparent bridge
X = np.vstack([x_circle, x_bridge, x_torus])
Y = np.vstack([y_circle, y_bridge, y_torus])
Z = np.vstack([z_circle, z_bridge, z_torus])
C = np.vstack([c_circle, c_bridge, c_torus])
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C, linewidth=0)
ax.view_init(elev=15, azim=270)
ax.set_xlim( -3, 3)
ax.set_ylim( -3, 3)
ax.set_zlim( -3, 3)
ax.set_axis_off()
plt.show()
Note in both cases I changed the circle to match the major radius of the toroid for demonstration simplicity, it can easily be altered as needed.
I would like to draw a sphere with points on its surface using Matplotlib. These points shall be connected by a spiral that spirals from one side of the sphere to the other.
To clarify this a little bit the plot should more or less look like this:
Has anyone a tip about how to do this?
Need to know parameters of spiral, formula or set of points.
However I post a code to plot a line with markers on a sphere for your start:
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))
elev = 10.
rot = 80. / 180. * np.pi
ax.plot_surface(x, y, z, rstride=1, cstride=1, color='y', linewidth=0, alpha=0.5)
# plot lines in spherical coordinates system
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='r', linestyle = '-', marker='o', linewidth=2.5)
ax.view_init(elev = elev, azim = 0)
plt.show()
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)