How to plot a parametric curve without using `plot3d_parametric_line` - python

The idea is to plot the curve: C(t) = (1 + cos(t))i + (1 + sin(t))j + (1 -sin(t)-cos(t))k. Following the instructions on the Plot Module at https://docs.sympy.org/latest/modules/plotting.html one can get it using plot3d_parametric_line:
Method 1:
%matplotlib notebook
from sympy import cos, sin
from sympy.plotting import plot3d_parametric_line
t = sp.symbols('t',real=True)
plot3d_parametric_line(1 + cos(t), 1 + sin(t), 1-sin(t)-cos(t), (t, 0, 2*sp.pi))
Though this is a valid method there is another way to plot it without using plot3d_parametric_line but ax.plot. What I have tried:
Method 2:
fig = plt.figure(figsize=(8, 6))
ax = fig.gca(projection='3d')
ax.set_xlim([-0.15, 2.25])
ax.set_ylim([-0.15, 2.25])
ax.set_zlim([-0.75, 2.50])
ax.plot(1+sp.cos(t),1+sp.sin(t),1-sp.sin(t)-sp.cos(t))
plt.show()
But TypeError: object of type 'Add' has no len() comes up...
How can I fix it so that I get the same curve than with method 1?
Thanks

You can use the 3d plotting from matplotlib after defining a linear NumPy mesh and computing your x, y, z variables
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.gca(projection='3d')
t = np.linspace(0, 2*np.pi, 100)
x = 1 + np.cos(t)
y = 1 + np.sin(t)
z = 1 - np.sin(t) - np.cos(t)
ax.plot(x, y, z)
plt.show()

Related

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

Given general 3D plane equation, how can I plot this in python matplotlib?

Let's say I have a 3D plane equation:
ax+by+cz=d
How can I plot this in python matplotlib?
I saw some examples using plot_surface, but it accepts x,y,z values as 2D array. I don't understand how can I convert my equation into the parameter inputs to plot_surface or any other functions in matplotlib that can be used for this.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
a,b,c,d = 1,2,3,4
x = np.linspace(-1,1,10)
y = np.linspace(-1,1,10)
X,Y = np.meshgrid(x,y)
Z = (d - a*X - b*Y) / c
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)

Plotting a function of three variables in python

I would like to plot the contour lines for this function, however I cannot find any useful way to do it.
The potential function is :
V(x,y,z) = cos(10x) + cos(10y) + cos(10z) + 2*(x^2 + y^2 + z^2)
I unsuccessfully attempted something like:
import numpy
import matplotlib.pyplot.contour
def V(x,y,z):
return numpy.cos(10*x) + numpy.cos(10*y) + numpy.cos(10*z) + 2*(x**2 + y**2 + z**2)
X, Y, Z = numpy.mgrid[-1:1:100j, -1:1:100j, -1:1:100j]
But then, I don't know how to do the next step to plot it?
matplotlib.pyplot.contour(X,Y,Z,V)
An error will arise when you try to pass contour three-dimensional arrays, as it expects two-dimensional arrays.
With this in mind, try:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
def V(x,y,z):
return np.cos(10*x) + np.cos(10*y) + np.cos(10*z) + 2*(x**2 + y**2 + z**2)
X,Y = np.mgrid[-1:1:100j, -1:1:100j]
Z_vals = [ -0.5, 0, 0.9 ]
num_subplots = len( Z_vals)
fig = plt.figure(figsize=(10, 4))
for i,z in enumerate( Z_vals):
ax = fig.add_subplot(1 , num_subplots , i+1, projection='3d')
ax.contour(X, Y, V(X,Y,z), cmap=cm.gnuplot)
ax.set_title('z = %.2f'%z, fontsize=30)
fig.savefig('contours.png', facecolor='grey', edgecolor='none')
Instead, use ax.contourf(...) to show the surfaces, which looks nicer in my opinion.
There is no direct way to visualize a function of 3 variables, as it is an object (surface) which lives in 4 dimensions. One must play with slices of the function to see what's going on. By a slice, I mean a projection of the function onto a lower dimensional space. A slice is achieved by setting one or more of the function variables as a constant.
I'm not sure this is what the OP needed, but I think a possible solution might be this one:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
def compute_torus(precision, c, a):
U = np.linspace(0, 2*np.pi, precision)
V = np.linspace(0, 2*np.pi, precision)
U, V = np.meshgrid(U, V)
X = (c+a*np.cos(V))*np.cos(U)
Y = (c+a*np.cos(V))*np.sin(U)
Z = a*np.sin(V)
return X, Y, Z
x, y, z = compute_torus(100, 2, 1)
fig = plt.figure()
color_dimension = z # Here goes the potential
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
m = plt.cm.ScalarMappable(norm=norm, cmap='jet')
m.set_array([])
fcolors = m.to_rgba(color_dimension)
# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(x,y,z, rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
Setting color_dimension to the values of the potential function, using this code can be plotted over a torus. In general, it can be plotted over any 3D shape of (x,y,z), but of course if the 3D space is fully filled with points everywhere, it's unlikely the image will be clear.

Plotting function of 3 dimensions over given domain with matplotlib

I am trying to visualize a function of 3 parameters over a cube in R^3 to get an idea of the smoothness of the function. An example of this problem is shown in the sample code below
%pylab
from mpl_toolkits.mplot3d import Axes3D
import itertools
x = np.linspace(0,10,50)
y = np.linspace(0,15,50)
z = np.linspace(0,8,50)
points = []
for element in itertools.product(x, y, z):
points.append(element)
def f(vals):
return np.cos(vals[0]) + np.sin(vals[1]) + vals[2]**0.5
fxyz = map(f, points)
xi, yi, zi = zip(*points)
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(xi, yi, zi, c=fxyz, alpha=0.5)
plt.show()
The problem with this approach is that the inside of the cube cannot be visualized. Is there a better way to graph a function over some dense subset of R^3?
As #HYRY and #nicoguaro suggested in the comments above, Mayavi is much better suited for this type of work. There is a good set of examples here that I used for reference. Here is what I came up with
import numpy as np
from mayavi import mlab
x = np.linspace(0,10,50)
y = np.linspace(0,15,50)
z = np.linspace(0,8,50)
X, Y, Z = np.meshgrid(x, y, z)
s = np.cos(X) + np.sin(Y) + Z**0.5
b1 = np.percentile(s, 20)
b2 = np.percentile(s, 80)
mlab.pipeline.volume(mlab.pipeline.scalar_field(s), vmin=b1, vmax=b2)
mlab.axes()
mlab.show()
After which I rotated the figure to desired angles with the GUI and saved desired views

Basemap on the face of a matplotlib.mplot3d cube

As the title suggests, I'm trying to plot a Basemap map on the z=0 surface of a matplotlib.mplot3d lineplot. I know the Axes3D object is capable of plotting on the z=0 surface (via Axes3D.plot, Axes3D.scatter, etc.), but I can't figure out how to do so with a Basemap object. Hopefully the code below shows what I need clearly enough. Any ideas would be much appreciated!
import matplotlib.pyplot as pp
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap
# make sample data for 3D lineplot
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
# make the 3D line plot
FIG = ct.pp.figure()
AX = Axes3D(FIG)
AX.plot(x, y, z, '-b')
# make the 2D basemap
### NEEDS TO SOMEHOW BE AT z=0 IN FIG
M = ct.Basemap(projection='stere', width=3700e3, height=2440e3,
lon_0=-5.0, lat_0=71.0, lat_ts=71.0,
area_thresh=100, resolution='c')
PATCHES = M.fillcontinents(lake_color='#888888', color='#282828')
Just add your map as a 3d collection to the Axes3D instance:
import numpy as np
import matplotlib.pyplot as pp
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-500, 500, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
FIG = pp.figure()
AX = Axes3D(FIG)
AX.plot(x, y, z, '-b')
M = Basemap(projection='stere', width=3700e3, height=2440e3,
lon_0=-5.0, lat_0=71.0, lat_ts=71.0,
area_thresh=100, resolution='c')
AX.add_collection3d(M.drawcoastlines())
AX.grid(True)
pp.draw()
pp.show()
AX.add_collection3d(M.drawcoastlines())
works but
PATCHES = M.fillcontinents(lake_color='#888888', color='#282828')
does not work.
As soon as you add color fill you get an error similar to: "AttributeError: 'Polygon' object has no attribute 'do_3d_projection'"
M.fillcontinents(lake_color='#888888', color='#282828')`
returns an array of Polygons, not one of the inputs required by add_collection(). collect.PatchCollection() does not seem to work either.
So what do you use to add `M.fillcontinents(lake_color='#888888', color='#282828') to a 3D plot?

Categories

Resources