0

I want to plot the unit sphere x^2 + y^2 + z^2 = 1 & I am trying to use sympy , numpy , and matplotlib for the same. Below is a code snippet:

x,y = sp.symbols('x y')

def g(x,y):
    return sqrt(1-x**2 - y**2)
xrange2 = np.linspace(-1, 1, 100)
yrange2 = np.linspace(-1, 1, 100)
X2, Y2 = np.meshgrid(xrange2, yrange2)
Z2 = g(X2, Y2)
Z2[(1- X2**2 - Y2**2 < 0)] = np.nan
Z2[(1- X2**2 - Y2**2 > 0)] = np.nan
ax.plot_surface(X2, Y2, Z2,cmap='Blues', antialiased=True, edgecolor='black')

I don't wish to use parametric equations for the sphere, but rather plot it using x , y and z. Currently getting below error: Z contains NaN values. This may result in rendering artifacts.

Kedar_dg
  • 41
  • 1
  • 6
  • I am not sure how this works yet. But two things from your code: 1.) Z2 = g(X2, Y2) is actually not valid for a sphere. Mathematically, both +g(X2,Y2) and -g(X2,Y2) are points on sphere at (X2, Y2). I think that's why people introduce parametric equations. Because a sphere/circle is not really a function in terms of y vs x or z vs (x,y) 2.) you are setting everything except for 0 in your Z2 to nan, that's why you have the NaN value error. Z2[(1- X2**2 - Y2**2 < 0)] = np.nan Z2[(1- X2**2 - Y2**2 > 0)] = np.nan – Yayuchen Apr 27 '20 at 05:09

1 Answers1

1

From the question it is very unclear which version of sqrt is used. Sympy's sqrt certainly won't work. math.sqrt doesn't work on arrays. Only np.sqrt can work. But then, function g needs to be numpy vectorized.

np.sqrt works on arrays, and gives NaN when operated on negative numbers.

ax.plot_surface doesn't want to draw colormapped faces when some of the Z values are NaN, it only draws plain colors in that case. Note that antialiasing doesn't work for plotting faces, only for edges.

To draw a complete sphere, both Z2 and -Z2 need to be drawn.

Due to the NaNs and an equation that doesn't define evenly distributed points, some artifacts will be present. Also, the surfaces will not completely fill up. See this post to draw a sphere via an angular representation.

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

@np.vectorize
def g(x,y):
    return np.sqrt(1-x**2 - y**2)

fig = plt.figure()
ax = fig.gca(projection='3d')

xrange2 = np.linspace(-1, 1, 100)
yrange2 = np.linspace(-1, 1, 100)
X2, Y2 = np.meshgrid(xrange2, yrange2)
Z2 = g(X2, Y2)
ax.plot_surface(X2, Y2, -Z2, color='lightblue', antialiased=True, edgecolor='black')
ax.plot_surface(X2, Y2, Z2, color='lightblue', antialiased=True, edgecolor='black')

plt.show()

resulting plot

PS: Note that you are not really using sympy in the code (def g(x,y) uses its own version of standard Python variables x and y). Also, mixing numpy and sympy doesn't work. This related post handles plotting a surface as parametric surface via sympy. Note that these parametric surfaces only work for 2 variables, in this case x, y and z are defined in function of phi and theta. As far as I am aware, plotting a general 3D equation doesn't work with sympy at the moment.

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Thanks JohanC , I think matplotlib has limitations when drawing implicit surfaces. Even when I draw the parametric form , it looks like an ellipse. I tried to update to latest version and also tried to use the command on equal spacing , but that didn't work – Kedar_dg May 03 '20 at 23:43
  • Well, yes, for 3D there are a lot of limitations. There is only approximate z-ordering and a difficult to control perspective transformation. – JohanC May 04 '20 at 00:02