使用 matplotlib 在 Python 中进行 3D 绘图

2023-10-23

数据可视化就是这样一个领域,大量的库都是用 Python 开发的。
在这些当中,Matplotlib是数据可视化最流行的选择。
虽然最初是为了绘制二维图表而开发的,例如直方图、条形图、散点图、线图等,Matplotlib 还扩展了其功能以提供 3D 绘图模块。

在本教程中,我们将介绍 Python 中 3D 绘图的各个方面。

我们首先在 3D 坐标空间中绘制一个点。然后我们将学习如何自定义绘图,然后我们将继续学习更复杂的绘图,例如 3D 高斯曲面、3D 多边形等。具体来说,我们将讨论以下主题:

 

 

在 3D 空间中绘制单个点

让我们首先完成在 Python 中创建 3D 绘图所需的每个步骤,并以在 3D 空间中绘制点为例。

第 1 步:导入库


import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D
  

第一个是使用 matplotlib 进行绘图的标准导入语句,您也会在 2D 绘图中看到该语句。
第二次导入Axes3D启用 3D 投影需要类。否则,它不会在其他地方使用。

Note3.2.0 之前的 Matplotlib 版本需要第二次导入。对于 3.2.0 及更高版本,您可以绘制 3D 绘图而无需导入mpl_toolkits.mplot3d.Axes3D.

第 2 步:创建图形和轴


fig = plt.figure(figsize=(4,4))

ax = fig.add_subplot(111, projection='3d')
  

Output:

Here we are first creating a figure of size 4 inches X 4 inches.
We then create a 3-D axis object by calling the add_subplot method and specifying the value ‘3d’ to the projection parameter.
We will use this axis object ‘ax’ to add any plot to the figure.

 

请注意,这两个步骤在您使用 Matplotlib 在 Python 中执行的大多数 3D 绘图中很常见。

第 3 步:绘制点

创建坐标区对象后,我们可以使用它在 3D 空间中创建我们想要的任何类型的绘图。
为了绘制单个点,我们将使用scatter()方法,并传递该点的三个坐标。


fig = plt.figure(figsize=(4,4))

ax = fig.add_subplot(111, projection='3d')

ax.scatter(2,3,4) # plot the point (2,3,4) on the figure

plt.show()
  

Output:

As you can see, a single point has been plotted (in blue) at (2,3,4).

 

绘制 3D 连续线

现在我们知道如何在 3D 中绘制单个点,我们可以类似地绘制穿过 3D 坐标列表的连续线。

我们将使用plot()方法并传递 3 个数组,每个数组代表线上点的 x、y 和 z 坐标。


import numpy as np

x = np.linspace(−4*np.pi,4*np.pi,50)

y = np.linspace(−4*np.pi,4*np.pi,50)

z = x**2 + y**2

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.plot(x,y,z)

plt.show()
  

Output:

We are generating x, y, and z coordinates for 50 points.
The x and y coordinates are generated usingnp.linspace to generate 50 uniformly distributed points between -4π and +4π. The z coordinate is simply the sum of the squares of the corresponding x and y coordinates.

 

自定义 3D 绘图

让我们在 3D 空间中绘制散点图,并看看如何根据我们的喜好以不同的方式自定义其外观。我们将使用NumPy 随机种子这样你就可以生成与教程相同的随机数。


np.random.seed(42)

xs = np.random.random(100)*10+20

ys = np.random.random(100)*5+7

zs = np.random.random(100)*15+50

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.scatter(xs,ys,zs)

plt.show()
  

Output:

Let us now add a title to this plot

添加标题

我们将调用set_title轴对象的方法向绘图添加标题。


ax.set_title("Atom velocity distribution")

plt.show()
  

Output:

NOTE that I have not added the preceding code (to create the figure and add scatter plot) here, but you should do it.

现在让我们为绘图上的每个轴添加标签。

添加轴标签

我们可以通过调用方法为 3D 图中的每个轴设置标签set_xlabelset_ylabel and set_zlabel在轴对象上。


ax.set_xlabel("Atomic mass (dalton)")

ax.set_ylabel("Atomic radius (pm)")

ax.set_zlabel("Atomic velocity (x10⁶ m/s)")

plt.show()
  

Output:

修改标记

正如我们在前面的示例中所看到的,默认情况下,每个点的标记是一个恒定大小的实心蓝色圆圈。
我们可以改变标记的外观,使它们更具表现力。

让我们从更改标记的颜色和样式开始


ax.scatter(xs,ys,zs, marker="x", c="red")

plt.show()
  

Output:

We have used the parameters marker and c to change the style and color of the individual points

修改轴限制和刻度

默认情况下,根据输入值设置轴上值的范围和间隔。
然而,我们可以将它们更改为我们想要的值。

让我们创建另一个代表一组新数据点的散点图,然后修改其轴范围和间隔。


np.random.seed(42)

ages = np.random.randint(low = 8, high = 30, size=35)

heights = np.random.randint(130, 195, 35)

weights = np.random.randint(30, 160, 35)

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.scatter(xs = heights, ys = weights, zs = ages)

ax.set_title("Age-wise body weight-height distribution")

ax.set_xlabel("Height (cm)")

ax.set_ylabel("Weight (kg)")

ax.set_zlabel("Age (years)")

plt.show()
  

Output:

We have plotted data of 3 variables, namely, height, weight and age on the 3 axes.
As you can see, the limits on the X, Y, and Z axes have been assigned automatically based on the input data.

让我们通过调用来修改每个轴上的最小和最大限制set_xlimset_ylim, and set_zlim方法。


ax.set_xlim(100,200)

ax.set_ylim(20,160)

ax.set_zlim(5,35)

plt.show()
  

Output:

The limits for the three axes have been modified based on the min and max values we passed to the respective methods.
We can also modify the individual ticks for each axis. Currently, the X-axis ticks are [100,120,140,160,180,200].
Let us update this to [100,125,150,175,200]


ax.set_xticks([100,125,150,175,200])

plt.show()
  

Output:

Similarly, we can update the Y and Z ticks using the set_yticks and set_zticks methods.


ax.set_yticks([20,55,90,125,160])

ax.set_zticks([5,15,25,35])

plt.show()
  

Output:

更改绘图的大小

如果我们希望绘图比默认大小更大或更小,我们可以在初始化图形时轻松设置绘图的大小 - 使用figsize的参数plt.figure method,
或者我们可以通过调用更新现有图的大小set_size_inches图形对象上的方法。
在这两种方法中,我们都必须以英寸为单位指定绘图的宽度和高度。

既然我们已经看到了第一种指定绘图大小的方法早些时候,让我们现在看看第二种方法,即修改现有图的大小。
我们将散点图的大小更改为 6×6 英寸。


fig.set_size_inches(6, 6)

plt.show()
  

Output:

The size of our scatter plot has been increased compared to its previous default size.

关闭/打开网格线

到目前为止,我们绘制的所有绘图默认都有网格线。
我们可以通过调用来改变这一点grid轴对象的方法,并传递值“False”。
如果我们想要再次恢复网格线,我们可以使用参数“True”调用相同的方法。


ax.grid(False)

plt.show()
  

Output:

根据类别设置 3D 绘图颜色

让我们假设散点图所代表的个体被进一步分为两个或更多类别。
我们可以通过用不同颜色绘制每个类别的个体来表示此信息。
例如,让我们将数据分为“男性”和“女性”类别。
我们将创建一个与数据点数量相同大小的新数组,并为“男性”类别分配值 0,为“女性”类别分配值 1。
然后我们将此数组传递给颜色参数c创建散点图时。


np.random.seed(42)

ages = np.random.randint(low = 8, high = 30, size=35)

heights = np.random.randint(130, 195, 35)

weights = np.random.randint(30, 160, 35)

gender_labels = np.random.choice([0, 1], 35) #0 for male, 1 for female

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.scatter(xs = heights, ys = weights, zs = ages, c=gender_labels)

ax.set_title("Age-wise body weight-height distribution")

ax.set_xlabel("Height (cm)")

ax.set_ylabel("Weight (kg)")

ax.set_zlabel("Age (years)")

plt.show()
  

Output:

The plot now shows each of the two categories with a different color.
But how would we know which color corresponds to which category?

我们可以添加一个“颜色条”来解决这个问题。


scat_plot = ax.scatter(xs = heights, ys = weights, zs = ages, c=gender_labels)

cb = plt.colorbar(scat_plot, pad=0.2)

cb.set_ticks([0,1])

cb.set_ticklabels(["Male", "Female"])

plt.show()
  

Output:

放置传奇

通常,我们想要在同一个图形上绘制多于一组的数据。
在这种情况下,我们必须为每个图分配标签,并在图中添加图例以区分不同的图。

例如,假设我们的年龄-身高-体重数据是从美国三个州收集的,即佛罗里达州、佐治亚州和加利福尼亚州。
我们想要绘制 3 个状态的散点图,并添加图例来区分它们。

让我们在 for 循环中创建 3 个图,并每次为它们分配不同的标签。


labels = ["Florida", "Georgia", "California"]

for l in labels:

    ages = np.random.randint(low = 8, high = 20, size=20)

    heights = np.random.randint(130, 195, 20)

    weights = np.random.randint(30, 160, 20)

    ax.scatter(xs = heights, ys = weights, zs = ages, label=l)

ax.set_title("Age-wise body weight-height distribution")

ax.set_xlabel("Height (cm)")

ax.set_ylabel("Weight (kg)")

ax.set_zlabel("Age (years)")

ax.legend(loc="best")

plt.show()
  

Output:

绘制不同大小的标记

在我们到目前为止看到的散点图中,所有点标记的大小都是恒定的。

我们可以通过将自定义值传递给参数来改变标记的大小s的散点图。
我们可以传递一个数字来将所有标记设置为新的固定大小,也可以提供一组值,其中每个值代表一个标记的大小。

在我们的示例中,我们将根据个体的身高和体重计算一个名为“bmi”的新变量,并使个体标记的大小与其 BMI 值成比例。


np.random.seed(42)

ages = np.random.randint(low = 8, high = 30, size=35)

heights = np.random.randint(130, 195, 35)

weights = np.random.randint(30, 160, 35)

bmi = weights/((heights*0.01)**2)

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.scatter(xs = heights, ys = weights, zs = ages, s=bmi*5 )

ax.set_title("Age-wise body weight-height distribution")

ax.set_xlabel("Height (cm)")

ax.set_ylabel("Weight (kg)")

ax.set_zlabel("Age (years)")

plt.show()
  

Output:

The greater the sizes of markers in this plot, the higher are the BMI’s of those individuals, and vice-versa.

绘制高斯分布

You may be aware of a univariate Gaussian distribution plotted on a 2D plane, popularly known as the ‘bell-shaped curve.’

source: https://en.wikipedia.org/wiki/File:Normal_Distribution_PDF.svg

我们还可以使用多元正态分布在 3D 空间中绘制高斯分布。
我们必须定义变量 X 和 Y 并一起绘制它们的概率分布。


from scipy.stats import multivariate_normal

X = np.linspace(-5,5,50)

Y = np.linspace(-5,5,50)

X, Y = np.meshgrid(X,Y)

X_mean = 0; Y_mean = 0

X_var = 5; Y_var = 8

pos = np.empty(X.shape+(2,))

pos[:,:,0]=X

pos[:,:,1]=Y

rv = multivariate_normal([X_mean, Y_mean],[[X_var, 0], [0, Y_var]])

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.plot_surface(X, Y, rv.pdf(pos), cmap="plasma")

plt.show()
  

Output:

Using the plot_surface method, we can create similar surfaces in a 3D space.

绘制 3D 多边形

我们还可以在 Python 中绘制具有 3 维顶点的多边形。


from mpl_toolkits.mplot3d.art3d import Poly3DCollection

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

x = [1, 0, 3, 4]

y = [0, 5, 5, 1]

z = [1, 3, 4, 0]

vertices = [list(zip(x,y,z))]

poly = Poly3DCollection(vertices, alpha=0.8)

ax.add_collection3d(poly)

ax.set_xlim(0,5)

ax.set_ylim(0,5)

ax.set_zlim(0,5)    
  

Output:

使用鼠标旋转 3D 绘图

要在Jupyter笔记本,你应该运行
魔法命令%matplotlib notebook在笔记本的开头。

这使我们能够通过放大和缩小绘图以及沿任意方向旋转它们来与 3D 绘图进行交互。


%matplotlib notebook
import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

import numpy as np

from scipy.stats import multivariate_normal

X = np.linspace(-5,5,50)

Y = np.linspace(-5,5,50)

X, Y = np.meshgrid(X,Y)

X_mean = 0; Y_mean = 0

X_var = 5; Y_var = 8

pos = np.empty(X.shape+(2,))

pos[:,:,0]=X

pos[:,:,1]=Y

rv = multivariate_normal([X_mean, Y_mean],[[X_var, 0], [0, Y_var]])

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.plot_surface(X, Y, rv.pdf(pos), cmap="plasma")

plt.show()
  

Output:

绘制两个不同的 3D 分布

我们可以在同一个图形中添加两个不同的 3D 绘图fig.add_subplot method.
我们提供给该方法的 3 位数字表示网格中的行数和列数以及当前绘图在网格中的位置。
前两位数字表示我们需要划分图形的总行数和总列数。
最后一位数字表示子图在网格中的位置。

例如,如果我们将值 223 传递给add_subplot方法中,我们指的是 2×2 网格中的第三个图(考虑行优先排序)。

现在让我们看一个示例,在单个图上绘制两个不同的分布。


#data generation for 1st plot
np.random.seed(42)

xs = np.random.random(100)*10+20

ys = np.random.random(100)*5+7

zs = np.random.random(100)*15+50

#data generation for 2nd plot
np.random.seed(42)

ages = np.random.randint(low = 8, high = 30, size=35)

heights = np.random.randint(130, 195, 35)

weights = np.random.randint(30, 160, 35)

fig = plt.figure(figsize=(8,4))

#First plot
ax = fig.add_subplot(121, projection='3d')

ax.scatter(xs,ys,zs, marker="x", c="red")

ax.set_title("Atom velocity distribution")

ax.set_xlabel("Atomic mass (dalton)")

ax.set_ylabel("Atomic radius (pm)")

ax.set_zlabel("Atomic velocity (x10⁶ m/s)")

#Second plot
ax = fig.add_subplot(122, projection='3d')

ax.scatter(xs = heights, ys = weights, zs = ages)

ax.set_title("Age-wise body weight-height distribution")

ax.set_xlabel("Height (cm)")

ax.set_ylabel("Weight (kg)")

ax.set_zlabel("Age (years)")

plt.show()    
  

Output:

We can plot as many subplots as we want in this way, as long as we fit them right in the grid.

将 Python 3D 绘图输出为 HTML

如果我们想将 3D 绘图嵌入到 HTML 页面中,而不先将其保存为图像文件,
我们可以通过将图形编码为“base64”,然后将其插入 HTML 中的正确位置来实现img tag


import base64

from io import BytesIO

np.random.seed(42)

xs = np.random.random(100)*10+20

ys = np.random.random(100)*5+7

zs = np.random.random(100)*15+50

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

ax.scatter(xs,ys,zs)

#encode the figure
temp = BytesIO()

fig.savefig(temp, format="png")

fig_encode_bs64 = base64.b64encode(temp.getvalue()).decode('utf-8')

html_string = """
<h2>This is a test html</h2>
<img src = 'data:image/png;base64,{}'/>
""".format(fig_encode_bs64)
  

现在,我们可以将此 HTML 代码字符串写入 HTML 文件,然后可以在浏览器中查看该文件


with open("test.html", "w") as f:

    f.write(html_string)
  

Output:

结论

在本教程中,我们学习了如何使用 matplotlib 库在 Python 中绘制 3D 绘图。
我们首先在 3D 坐标空间中绘制一个点,然后绘制 3D 曲线和散点图。

然后我们学习了在 Python 中自定义 3D 绘图的各种方法,例如向绘图添加标题、图例、轴标签、调整绘图大小、打开/关闭绘图上的网格线、修改轴刻度等。
我们还学习了如何根据数据点类别改变标记的大小和颜色。

之后,我们学习了如何在 3D 空间中绘制曲面。我们在 Python 中绘制了高斯分布和 3D 多边形。

然后我们了解了如何与 Jupyter Notebook 中的 Python 3D 绘图进行交互。

最后,我们学习了如何在同一个图形上绘制多个子图,以及如何将图形输出到 HTML 代码中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 matplotlib 在 Python 中进行 3D 绘图 的相关文章

随机推荐

  • 如何在 phpMyAdmin 中添加多个主机

    phpMyAdmin 默认配置仅允许连接到本地 MySQL 服务器 但是如果我们运行多个数据库服务器 那么如果我们可以从单个 phpMyAdmin 安装中选择需要连接的服务器 那就太好了 本操作指南将帮助您在 phpMyAdmin 中添加多
  • Bash 选择(制作菜单)

    在本教程中 我们将介绍以下基础知识select在 Bash 中构建 The select构造允许您生成菜单 Bash select构造 The select构造从项目列表生成菜单 它的语法几乎与for loop select ITEM in
  • 如何在 CentOS 7 上安装和配置 Redmine

    Redmine 是最流行的开源项目管理和问题跟踪软件工具之一 它是跨平台和跨数据库的 构建在 Ruby on Rails 框架之上 Redmine包括对多个项目 wiki 问题跟踪系统 论坛 日历 电子邮件通知等的支持 在本教程中 我们将介
  • 如何在 Ubuntu 18.04 上部署 Rocket.Chat

    Rocket Chat 是一个开源团队交流平台 是自托管的 Slack 替代品 它使用 Meteor 框架开发 提供各种功能 包括帮助台聊天 文件共享 视频会议 语音消息 API 等 对于想要托管自己的聊天系统的公司和社区来说 Rocket
  • .bashrc 与 .bash_profile

    如果您在命令行上花费大量时间 您很可能想要自定义您的 shell 环境 这可能意味着创建别名 将新目录添加到 PATH 或更改 shell 提示符的外观 您可能遇到过一些教程 其中他们说将您的配置放在 bashrc bash profile
  • 如何在 CentOS 7 上安装和使用 PHP Composer

    Composer是 PHP 的依赖管理器 类似于Node js 的 npm or Python 的点子 Composer 将提取您的项目所依赖的所有必需的 PHP 包并为您管理它们 它用于所有现代 PHP 框架和平台 例如 Laravel
  • 如何在 CentOS 8 上安装 Apache

    Apache HTTP 服务器是世界上使用最广泛的 Web 服务器 它是一个免费 开源 跨平台的HTTP服务器 具有强大的功能 并且可以通过多种模块进行扩展 在本文中 我们将解释如何在 CentOS 8 上安装和管理 Apache Web
  • 如何在 Debian 9 上安装 CouchDB

    CouchDB 是一个开源的容错且无模式的 NoSQL 数据库 由 Apache 软件基金会维护 CouchDB 服务器将其数据存储在命名数据库中 其中包含以下文档JSON结构 每个文档由许多字段和附件组成 字段可以包括文本 数字 列表 布
  • 如何在 CentOS 7 上安装 Visual Studio Code

    视觉工作室代码是微软开发的开源跨平台代码编辑器 它有一个内置的调试支持 嵌入式Git控制 语法突出显示 代码完成 集成终端 代码重构和片段 在 CentOS 计算机上安装 Visual Studio Code 最简单且推荐的方法是启用 VS
  • 如何在 Ubuntu 18.04 上安装 Mono

    Mono 是一个用于开发和运行基于 ECMA ISO 标准的跨平台应用程序的平台 它是 Microsoft NET 框架的免费开源实现 本教程介绍如何在 Ubuntu 18 04 上安装 Mono 先决条件 这些说明假定您以 root 身份
  • Linux中的su命令(切换用户)

    The su 替代或切换用户的缩写 实用程序允许您使用其他用户 默认为 root 用户 的权限运行命令 Using su是在当前登录会话中切换到管理帐户的最简单方法 当不允许 root 用户通过以下方式登录系统时 这尤其方便ssh或使用 G
  • Linux 中的Whereis命令

    whereis是一个命令行实用程序 允许您查找给定命令的二进制文件 源文件和手册页文件的位置 在这篇文章中 我们将向您展示如何使用Linuxwhereis命令 如何使用whereis命令 语法为whereis命令如下 whereis OPT
  • 在 CentOS 8 上使用 Let's Encrypt 保护 Nginx

    Let s Encrypt 是由互联网安全研究小组 ISRG 开发的免费 自动化 开放的证书颁发机构 提供免费的 SSL 证书 Let s Encrypt 颁发的证书受到所有主要浏览器的信任 并且自颁发之日起 90 天内有效 在本教程中 我
  • Expect 命令以及如何像魔术一样自动化 shell 脚本

    在上一篇文章中 我们讨论了写作实用的shell脚本 我们看到了编写 shell 脚本是多么容易 今天我们要讨论一个对 shell 脚本有神奇作用的工具 该工具是期待命令 or 期待脚本语言 Expect 命令或 Expect 脚本语言是一种
  • SSH 连接被拒绝(原因和解决方案)

    本教程将介绍您在使用 SSH 时可能遇到的最常见错误 连接被拒绝 请继续阅读 详细了解这个问题及其各种解决方案 Secure Shell SSH 是系统管理员最常用的工具之一 它对于管理所有服务器和执行日常任务至关重要 目录 hide 1
  • Linux env 命令:深入了解 Linux 环境管理

    The envLinux中的命令用于显示或设置环境变量 它可用于在修改后的环境中运行程序或显示当前环境 在本教程中 我们将深入研究其各种论点 并揭示其与脚本的集成 目录 hide 1 参数概览 2 执行不带参数的 env 命令 3 使用 e
  • 揭示 Linux 虚拟文件系统的强大功能

    Linux 虚拟文件系统或虚拟文件系统通常是位于实际文件系统之上的一层 它允许用户访问不同类型的文件系统 可以将虚拟文件系统视为内核与实际文件系统之间的接口 这意味着您将在 etc fstab 文件中找不到这些 Linux 虚拟文件系统的任
  • NumPy 随机种子(生成可预测的随机数)

    在计算科学中 随机种子是生成的伪随机数序列的起点 这些数字看似随机 但它们遵循确定性序列 种子决定了该序列的初始状态 在 Python 中NumPy 库 您可以使用设置随机种子numpy random seed 功能 这将使随机数生成的输出
  • Python map() 函数(转换可迭代对象)

    The map Python 中的 function 是一个内置函数 用于将函数应用于可迭代对象 数组 列表 元组 字典 集合 中的每个项目并返回一个迭代器 这使得它对于转换可迭代数据非常有用 目录 hide 1 Python map 函数
  • 使用 matplotlib 在 Python 中进行 3D 绘图

    数据可视化就是这样一个领域 大量的库都是用 Python 开发的 在这些当中 Matplotlib是数据可视化最流行的选择 虽然最初是为了绘制二维图表而开发的 例如直方图 条形图 散点图 线图等 Matplotlib 还扩展了其功能以提供