利用Python实现数据可视化(一):绘制常见空间曲面(Numpy库、Matplotlib库)
本文介绍了使用Python的Matplotlib和NumPy库绘制9种二次曲面的方法。通过定义不同函数,分别实现了马鞍面(双曲抛物面)、椭圆抛物面、双叶双曲面、二次锥面、单叶双曲面、双曲柱面、椭圆柱面、抛物柱面和椭球面的3D可视化。每个函数都包含参数调节功能,可以调整曲面形状和颜色映射。重点说明了各曲面的数学方程、绘制时的注意事项(如双叶曲面需要分上下两部分绘制)以及无效区域的过滤方法。文中还详细
一、绘制马鞍面(双曲抛物面)
定义函数saddle_surface(),用来绘制马鞍面,为方便代码的编写和调试,给定了函数参数的初始值,后续可根据不同的需要来调整函数中的参数。
首先,使用matplotlib库来定义绘图窗口的大小和格式,然后使用numpy库下的linspace获取相对应的数值,对于获取到的数值,需要进一步使用numpy.meshgrid()函数来进行处理,将其转化为相对应的二维矩阵网格,然后利用马鞍面(双曲抛物面)方程: 计算z的相关数值并使用ax.plot_surface()函数将其绘制成相对应的曲面,运行结果请见图1-1。
在plot_surface()函数中,可以使用matplotlib.cm.模块来为曲面添加颜色映射,具体有
matplotlib.cm.viridis:从深蓝色到黄色
matplotlib.cm.plasma:从暗紫色到亮黄色
matplotlib.cm.coolwarm:从红褐色到蓝色
matplotlib.cm.magma:从黑色到浅棕色
matplotlib.cm.cividis:从深蓝色到浅黄色
matplotlib.cm.jet:从深蓝色到深红色
matplotlib.cm.rainbow:从浅蓝色到浅红色
matplotlib.cm.Greys:从白色到黑色
matplotlib.cm.Blues:从白色到蓝色
matplotlib.cm.Greens:从白色到绿色
matplotlib.cm.Oranges:从白色到橙色
matplotlib.cm.Reds:从白色到红色
matplotlib.cm.inferno:从黑色到亮橙色
def saddle_surface(a=2, b=1, left_x=-15, right_x=15, left_y=-10, right_y=10):
"""绘制双曲抛物面(马鞍面)
参数含义:
① a,b为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点"""
# 设定画布的尺寸与格式
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111,projection='3d')
# 获取数值
x = numpy.linspace(left_x,right_x,100)
y = numpy.linspace(left_y,right_y,100)
# 将x与y的值转换为二维网格矩阵,用以计算z的值
X, Y = numpy.meshgrid(x,y)
# 利用马鞍面(双曲抛物面)的公式计算z的值
z = ((X**2)/(a**2)) - ((Y**2)/(b**2))
# 绘制马鞍面(双曲抛物面),同时为曲面添加颜色映射
ax.plot_surface(X, Y, z, cmap=matplotlib.cm.coolwarm)
# 为图片设置标题
ax.set_title(' (x²/{}²) - (y²/{}²) = z'.format(a,b))
# 设置x轴名称
ax.set_xlabel('values of x')
# 设置y轴名称
ax.set_ylabel('values of y')
# 设置z轴名称
ax.set_zlabel('values of z')
matplotlib.pyplot.show()

图1-1
二、绘制椭圆抛物面
绘制原理与马鞍面(双曲抛物面)一样,只是需要将马鞍面方程改写为椭圆抛物面方程: ,运行结果请见图2-1。
def ellipsoidal_paraboloid(a=10, b=10, left_x=-2, right_x=2, left_y=-2, right_y=2):
"""绘制椭圆抛物面
参数含义:
① a,b为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点"""
# 设定画布的尺寸与格式
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111,projection='3d')
# 获取数值
x = numpy.linspace(left_x,right_x,100)
y = numpy.linspace(left_y,right_y,100)
# 将x与y的值转换为二维网格矩阵,用以计算z的值
X,Y = numpy.meshgrid(x,y)
# 利用椭圆抛物面的公式计算z的值
z = ((X**2)/(a**2)) + ((Y**2)/(b**2))
# 绘制椭圆抛物面
ax.plot_surface(X, Y, z, cmap = matplotlib.cm.coolwarm)
# 为图片设置标题
ax.set_title(' (x²/{}²) + (y²/{}²) = z'.format(a,b))
# 设置x轴名称
ax.set_xlabel('values of x')
# 设置y轴名称
ax.set_ylabel('values of y')
# 设置z轴名称
ax.set_zlabel('values of z')
matplotlib.pyplot.show()

图2-1
三、绘制双叶双曲面
双叶双曲面方程:
特别注意:由于双叶双曲面分上下两部分,所以在代码中,应该绘制两次,绘制一次上半部分,再绘制一次下半部分,运行结果请见图3-1。
def hyperboloid_of_two_sheets(a=1,b=1,c=1,left_x=-2, right_x=2, left_y=-2, right_y=2):
"""绘制双叶双曲面
参数含义:
① a,b,c为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点 """
# 设定画布的尺寸与格式
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
# 获取数值
x = numpy.linspace(left_x, right_x, 100)
y = numpy.linspace(left_y, right_y, 100)
# 将x与y的值转换为二维网格矩阵,用以计算z的值
X, Y = numpy.meshgrid(x, y)
# 利用双叶双曲面公式来计算z的数值
z = numpy.sqrt((X ** 2 / a ** 2 + Y ** 2 / b ** 2 + 1) * (c ** 2))
# 双叶双曲面分正半叶和负半叶,所以要绘制两次
ax.plot_surface(X, Y, z, cmap = matplotlib.cm.coolwarm)
ax.plot_surface(X, Y, -z, cmap = matplotlib.cm.coolwarm)
# 为图片设置标题
ax.set_title(' (x²/{}²) + (y²/{}²) - (z²/{}²) = -1'.format(a,b,c))
# 设置x轴名称
ax.set_xlabel('values of x')
# 设置y轴名称
ax.set_ylabel('values of y')
# 设置z轴名称
ax.set_zlabel('values of z')
matplotlib.pyplot.show()

图3-1
四、绘制二次锥面
二次锥面方程:
二次锥面也分为上下两部分,所以也应该绘制两次,运行结果请见图4-1.
def secondary_cone_surface(a=1,b=1,c=2,left_x=-3, right_x=3, left_y=-3, right_y=3):
"""绘制二次锥面
参数含义:
① a,b,c为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点 """
# 设定画布的尺寸与格式
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
# 获取数值
x = numpy.linspace(left_x, right_x, 100)
y = numpy.linspace(left_y, right_y, 100)
# 将x与y的值转换为二维网格矩阵,用以计算z的值
X, Y = numpy.meshgrid(x, y)
# 利用二次锥面公式来计算z的数值
z = c ** 2 * ((X ** 2 / a ** 2) + (Y ** 2 / b ** 2))
# 二次锥面分正半轴锥面与负半轴锥面,所以应当分别进行绘制
z_upper = numpy.sqrt(z)
z_lower = -numpy.sqrt(z)
ax.plot_surface(X, Y, z_upper, cmap=matplotlib.cm.plasma)
ax.plot_surface(X, Y, z_lower, cmap=matplotlib.cm.plasma)
# 设置图片标题为二次锥面的方程
ax.set_title(' (x²/{}²) + (y²/{}²) - (z²/{}²) = 0'.format(a,b,c))
# 设置x轴名称
ax.set_xlabel('values of x')
# 设置y轴名称
ax.set_ylabel('values of y')
# 设置z轴名称
ax.set_zlabel('values of z')
# 调整坐标轴比例,防止变形
ax.set_box_aspect([a, b, c])
matplotlib.pyplot.show()

图4-1
五、绘制单叶双曲面
单叶双曲面方程:
特别注意,单叶双曲面在某些区间处没有实数解,所以在绘制之前,应当先排除没有实数解的区域,再进行绘制,运行结果请见图5-1.
def hyperboloid_of_one_sheet(a=2,b=2,c=1,left_x=-4, right_x=4, left_y=-4, right_y=4):
"""绘制单叶双曲面
参数含义:
① a,b,c为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点 """
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111,projection='3d')
x = numpy.linspace(left_x, right_x, 100)
y = numpy.linspace(left_y, right_y, 100)
X,Y = numpy.meshgrid(x,y)
# 利用单叶双曲面公式计算z的数值
z = c ** 2 * ((X ** 2 / a ** 2) + (Y ** 2 / b ** 2) - 1)
# 过滤没有实数解的区域
z = numpy.where(z>=0,z,numpy.nan)
z_upper = numpy.sqrt(z)
z_lower = -numpy.sqrt(z)
ax.plot_surface(X,Y,z_upper,cmap=matplotlib.cm.plasma)
ax.plot_surface(X,Y,z_lower,cmap=matplotlib.cm.plasma)
ax.set_title(' (x²/{}²) + (y²/{}²) - (z²/{}²) = 1'.format(a,b,c))
ax.set_xlabel('values of x')
ax.set_ylabel('values of y')
ax.set_zlabel('values of z')
ax.set_box_aspect([a, b, c])
matplotlib.pyplot.show()

图5-1
六、绘制双曲柱面
双曲柱面方程:
运行结果请见图6-1,(注意,本运行结果绘制的是平行于z轴的双曲柱面,如需绘制平行于其他轴的双曲柱面,请更改方程)
def hyperbolic_cylinder(a=2,b=1,left_x=-5, right_x=5, left_z=-3, right_z=3):
"""绘制双曲柱面
参数含义:
① a,b为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_z表示高坐标区间的左端点
⑤ right_z表示高坐标区间的右端点 """
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
x = numpy.linspace(left_x, right_x, 100)
z = numpy.linspace(left_z, right_z, 100)
X, Z = numpy.meshgrid(x, z)
y = b**2 * (X**2 / a**2 - 1)
# 过滤没有实数解的区域
y = numpy.where(y >= 0, y, numpy.nan)
y_right = numpy.sqrt(y)
y_left = -numpy.sqrt(y)
ax.plot_surface(X, y_right, Z, cmap=matplotlib.cm.turbo)
ax.plot_surface(X, y_left, Z, cmap=matplotlib.cm.turbo)
ax.set_title(' (x²/{}²) - (y²/{}²) = 1'.format(a,b))
ax.set_xlabel('values of x')
ax.set_ylabel('values of y')
ax.set_zlabel('values of z')
# 调整视角,参数elev表示天顶角(球坐标系中的fai),参数azim表示方位角(球坐标系中的cita)
ax.view_init(elev=35, azim=45)
ax.set_box_aspect([a, b, (left_z - right_z)/2])
matplotlib.pyplot.show()

图6-1
七、绘制椭圆柱面
椭圆柱面方程:
运行结果请见图7-1,(注意,本运行结果绘制的是平行于z轴的椭圆柱面,如需绘制平行于其他轴的椭圆柱面,请更改方程)
def elliptic_cylinder(a=2,b=1,left_x=-5, right_x=5, left_z=-3, right_z=3):
"""绘制椭圆柱面
参数含义:
① a,b为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_z表示高坐标区间的左端点
⑤ right_z表示高坐标区间的右端点 """
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
x = numpy.linspace(left_x, right_x, 100)
z = numpy.linspace(left_z, right_z, 100)
X, Z = numpy.meshgrid(x, z)
y = b ** 2 * (1 - (X ** 2 / a ** 2))
# 过滤没有实数解的区域
y = numpy.where(y >= 0, y, numpy.nan)
y_right = numpy.sqrt(y)
y_left = -numpy.sqrt(y)
ax.plot_surface(X, y_right, Z, cmap=matplotlib.cm.turbo)
ax.plot_surface(X, y_left, Z, cmap=matplotlib.cm.turbo)
ax.set_title(' (x²/{}²) + (y²/{}²) = 1'.format(a,b))
ax.set_xlabel('values of x')
ax.set_ylabel('values of y')
ax.set_zlabel('values of z')
# 调整视角,参数elev表示天顶角(球坐标系中的fai),参数azim表示方位角(球坐标系中的cita)
ax.view_init(elev=35, azim=45)
ax.set_box_aspect([a, b, (left_z - right_z)/2])
matplotlib.pyplot.show()

图7-1
八、绘制抛物柱面
双曲柱面方程:
运行结果请见图8-1,(注意,本运行结果绘制的是平行于z轴的抛物柱面,如需绘制平行于其他轴的抛物柱面,请更改方程)
def parabolic_cylinder(a=1, left_y=-5, right_y=5, left_z=-3, right_z=3):
"""绘制抛物柱面
参数含义:
① a为常数,大于0
② left_y表示纵坐标区间的左端点
③ right_y表示纵坐标区间的右端点
④ left_z表示高坐标区间的左端点
⑤ right_z表示高坐标区间的右端点 """
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d')
y = numpy.linspace(left_y, right_y, 100)
z = numpy.linspace(left_z, right_z, 100)
Y, Z = numpy.meshgrid(y, z)
# 抛物柱面公式
x = Y**2 / (2*a)
ax.plot_surface(x, Y, Z, cmap=matplotlib.cm.turbo)
ax.set_title('y²={}x'.format(2*a))
ax.set_xlabel('values of x')
ax.set_ylabel('values of y')
ax.set_zlabel('values of z')
# 调整视角,参数elev表示天顶角(球坐标系中的fai),参数azim表示方位角(球坐标系中的cita)
ax.view_init(elev=30, azim=45)
matplotlib.pyplot.show()

图8-1
九、绘制椭球
椭球方程:
运行结果请见图9-1。
def ellipsoid(a=2, b=3, c=1, left_x=-2, right_x=2, left_y=-3, right_y=3):
"""绘制椭球面
参数含义:
① a,b,c为常数,且均大于0
② left_x表示横坐标区间的左端点
③ right_x表示横坐标区间的右端点
④ left_y表示纵坐标区间的左端点
⑤ right_y表示纵坐标区间的右端点 """
fig = matplotlib.pyplot.figure(figsize=(10,10))
ax = fig.add_subplot(111,projection='3d')
x = numpy.linspace(left_x, right_x, 100)
y = numpy.linspace(left_y, right_y, 100)
X,Y = numpy.meshgrid(x,y)
# 椭球面公式
z = c ** 2 * (1 - X ** 2 / a ** 2 - Y ** 2 / b ** 2)
# 过滤没有实数解的区域
z = numpy.where(z>=0,z,numpy.nan)
z_upper = numpy.sqrt(z)
z_lower = -numpy.sqrt(z)
ax.plot_surface(X,Y,z_upper,cmap=matplotlib.cm.plasma)
ax.plot_surface(X,Y,z_lower,cmap=matplotlib.cm.plasma)
ax.set_title(' (x²/{}²) + (y²/{}²) + (z²/{}²) = 1'.format(a,b,c))
ax.set_xlabel('values of x')
ax.set_ylabel('values of y')
ax.set_zlabel('values of z')
# 保持坐标轴比例一致
ax.set_box_aspect([a, b, c])
matplotlib.pyplot.show()

图9-1
更多推荐
所有评论(0)