Matplotlib-3-0-秘籍-全-
Matplotlib 3.0 秘籍(全)
零、前言
在大数据时代,寻找有价值的业务见解类似于在大海捞针。 可视化在不断增加的数据量和各种数据中找到这些块时起着至关重要的作用。 Matplotlib 凭借其丰富的可视化功能,使探索性数据分析过程变得用户友好且更加高效。
Matplotlib 的核心功能非常强大,许多内部和第三方辅助工具包进一步增强了。 市场上的任何书籍都仅覆盖其全部功能的一小部分。 在本书中,我们介绍了 Matplotlib 的完整核心功能及其许多流行的工具包。
Matplotlib 在使用 Python 生态系统的机器学习从业人员和研究人员中很受欢迎。 凭借其丰富的功能,它可以用于商业智能和运营报告应用。 在本书中,我们尝试介绍这些应用中的示例。
尽管基于秘籍的秘籍方法使本书成为快速解决方案的参考指南,但我们已经涵盖了足够的理论背景,对于初学者来说也很容易。
这本书是给谁的
本书适用于数据分析师,业务分析师,数据科学家和 Python 开发人员,他们正在为各种可视化应用寻求快速解决方案,例如临时报告,专业仪表板,探索性数据分析,交互分析,选定中的嵌入式可视化文件 GUI 工具箱和 Web 应用,三维图和地理地图。
那些对开发商业智能,机器学习,科学或工程应用感兴趣的人也会从与这些学科相关的秘籍中受益。
充分利用这本书
除了第 9 章,“开发交互式绘图”和第 10 章,“嵌入图形用户界面”外,Python 的基本知识足以理解本书的内容。 。 这两章介绍需要中级 Python 编程经验的交互式绘图和嵌入式应用。
许多 Python 发行版自动包含 Matplotlib 及其所有依赖项。 如果尚未安装任何标准的 Python 发行版,则可以在这个页面上按照的安装过程来安装 Matplotlib 及其相关的依赖项。
使用约定
本书中使用了许多文本约定。
CodeInText
:表示文本中的词,数据库表名称,文件夹名称,文件名,文件扩展名,路径名,伪 URL,用户输入和 Twitter 句柄。 例如:“我们将按照.txt
,.csv
和.xlsx
文件,分为三个部分。”
代码块设置如下:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import cm
粗体:表示您在屏幕上看到的新术语,重要单词或顺序。 例如,菜单或对话框中的单词会出现在这样的文本中。 这是一个示例:“当您运行程序并单击下一步时,您将看到以下三个图,代表每个群集,如每个标题中所示。”
Warnings or important notes appear like this.Tips and tricks appear like this.
标题
在本书中,您会发现几个经常出现的标题(“准备”,“操作步骤”,“工作原理”,和“另见”)。
要给出有关如何完成秘籍的明确说明,请按以下说明使用这些部分:
准备
本节告诉您在秘籍中会有什么期望,并介绍如何设置秘籍所需的任何软件或任何初步设置。
操作步骤
本节包含遵循秘籍所需的步骤。
工作原理
本节通常包括对上一节中发生的情况的详细说明。
更多
本节包含有关秘籍的其他信息,以使您对秘籍有更多的了解。
另见
本节提供了指向该秘籍其他有用信息的有用链接。
一、Matplotlib 的剖析
本章从 Matplotlib 的介绍开始,包括 Matplotlib 的架构和图形元素,然后是秘籍。 以下是本章将介绍的秘籍:
- 在交互模式下工作
- 在非交互模式下工作
- 从外部文件读取并绘图
- 如何更改和重置默认环境变量
介绍
Matplotlib 是一个跨平台的 Python 库,用于绘制二维图形(也称为图)。 它可以在各种用户界面中使用,例如 Python 脚本,IPython Shell,Jupyter 笔记本,Web 应用和 GUI 工具包。 它可以用于开发专业的报表应用,交互式分析应用,复杂的仪表板应用或嵌入到 Web/GUI 应用中。 它还支持将图形保存为各种硬拷贝格式。 它还对三维图形的支持有限。 它还支持许多第三方工具包以扩展其功能。
请注意,本书中的所有示例均已通过 Matplotlib 3.0 和 Jupyter Notebook 5.1.0 进行了测试。
Matplotlib 的架构
Matplotlib 具有三层架构:后端,艺术家和脚本,它们在逻辑上组织为栈。 脚本是开发人员用来创建图形的 API。 美工完成了内部创建图形的实际工作。 后端是显示图形的位置。
后端层
这是图形显示在输出设备上的最底层。 这可以是 Matplotlib 支持的任何用户界面。 后端有两种类型:用户界面后端(用于pygtk
,wxpython
,tkinter
,qt4
或macosx
等,也称为交互式后端)和硬拷贝后端,以制作图像文件(.png
,.svg
,.pdf
和.ps
,也称为非交互式后端)。 我们将在稍后的第 9 章,“开发交互式绘图”和第 10 章,“将图形嵌入图形用户界面”中学习如何配置这些后端。
艺术家层
这是栈的中间层。 Matplotlib 使用artist
对象绘制图形的各种元素。 因此,我们在图形中看到的每个元素(请参见图中的元素)都是一个艺术家。 该层提供了面向对象的 API ,以最大的灵活性来绘制图形。 该接口适用于经验丰富的 Python 程序员,他们可以创建复杂的仪表板应用。
脚本层
这是栈的最顶层。 该层提供了用于创建图形的简单接口。 这供没有太多编程专业知识的最终用户使用。 这称为pyplot
API。
图元素
包含输出图的所有元素的高级 Matplotlib 对象称为figure
。 可以以不同方式排列多个图形以形成图形。 图的每个元素都是可自定义的。
图形
下图是figure
的剖析图,其中包含其所有元素:
Anatomy of a figure (Source : http://diagramss.us/plotting-a-graph-in-matlab.html)
轴域
axes
是该图的子部分,其中绘制了图形。axes
具有标题,x 标签和 y 标签。figure
可以具有许多这样的axes
,每个figure
代表一个或多个图形。 在上图中,只有一个axes
,两个是蓝色和红色的折线图。
轴
这些是数字线,代表要绘制的图形的比例。 二维图具有 x 轴和 y 轴,而三维图具有 x 轴, y 轴 ,以及 z 轴。
Don't get confused between axes and axis. Axis is an element of axes. Grammatically, axes is also the plural for axis, so interpret the meaning of axes depending on the context, whether multiple axis elements are being referred to or an axes object is being referred to.
标签
这是图中各个元素的名称,例如 x 轴标签, y 轴标签,图形标签(上图中的蓝色信号/红色信号图形剖析等等。
图例
当axes
中有多个图形时(如上图,图形剖析图),每个图形都有其自己的标签,所有这些标签均表示为图例。 在上图中,图例位于图的右上角。
标题
它是每个axes
的名称。 当图形具有多个带有各自标题的轴域时,figure
也可以具有自己的标题。 上图只有一个轴域,因此轴域和该图都只有一个标题。
刻度标签
每个轴(x,y 或 z)都有一个范围的值,该值分为许多相等的桶。 桶分为两个级别。 在上一个图(剖析图), x 轴刻度范围从 0 到 4,分为四个主要区域(0-1、1-2、2-3 和 3-4),每个主要桶又分为四个次要桶(0-0.25、0.25-0.5 和 0.5-0.75)。 主桶两侧的刻度称为主刻度,次桶称为次刻度,它们的名称为主刻度标签和次刻度标签。
轴线
该图的边界称为轴线。 每个轴域有四个轴线(上,下,左和右)。
网格
为了更容易读取图形上各个点的坐标,将图形区域划分为网格。 通常,此网格沿着 x 和 y 轴的主要刻度线绘制。 在上图中,以虚线显示了网格。
在交互模式下工作
Matplotlib 可以在交互式或非交互式模式下使用。 在交互模式下,每条语句后图形显示都会更新。 在非交互模式下,只有明确要求这样做,图形才会显示。
准备
您需要 Python,NumPy 和 Matplotlib 包的有效安装。
使用以下命令,可以打开或关闭交互模式,还可以在任何时间点检查当前模式:
matplotlib.pyplot.ion()
设置交互模式ON
matplotlib.pyplot.ioff()
切换OFF
交互模式matplotlib.is_interactive()
检查交互模式是ON
(True
)还是OFF
(False
)
操作步骤
让我们看看在交互模式下工作有多么简单:
- 将屏幕输出设置为后端:
%matplotlib inline
- 导入
matplotlib
和pyplot
库。 在 Python 中,通常的做法是导入带有清晰同义词的库。 注意plt
是matplotlib.pyplot
包的同义词:
import matplotlib as mpl import matplotlib.pyplot as plt
- 将交互模式设置为开:
plt.ion()
- 检查交互模式的状态:
mpl.is_interactive()
- 您应该得到的输出为
True
。 - 绘制折线图:
plt.plot([1.5, 3.0])
您应该看到以下图形作为输出:
- 现在,借助以下代码,将轴标签和标题添加到图形中:
## Add labels and title
plt.title("Interactive Plot") #Prints the title on top of graph
plt.xlabel("X-axis") # Prints X axis label as "X-axis"
plt.ylabel("Y-axis") # Prints Y axis label as "Y-axis"
执行上述三个语句后,图形应如下所示:
工作原理
因此,这就是解释的方式:
plt.plot([1.5, 3.0])
绘制连接两个点(0, 1.5)
和(1.0, 3.0)
的折线图。plot
命令需要两个参数(分别为x
和y
轴,使用 Python 列表,NumPy 数组或 pandas 数据帧)。 。- 如果仅传递一个参数,则将其作为 y 轴坐标,而对于 x 轴坐标,它将采用所提供参数的长度。
- 在此示例中,我们仅传递两个点的一个列表,这些列表将作为 y 轴坐标。
- 对于 x 轴,由于列表
[1.5, 3.0]
的长度为 2,因此它采用的默认值为 0 到 1。 - 如果我们在 y 的列表中有三个坐标,那么对于 x,它将取 0 到 2 的范围。
- 您应该看到类似于步骤 6 中显示的图形。
plt.title("Interactive Plot")
,将标题作为"Interactive Plot"
打印在图形顶部**。plt.xlabel("X-axis")
,将 x 轴标签打印为"X-axis"
。plt.ylabel("Y-axis")
,将 y 轴标签打印为"Y-axis"
。- 执行完前面的三个语句后,您应该看到如图步骤 7 中所示的图形。
如果您使用的是 Python Shell,则在执行每个代码语句后,您应该首先看到图形标题已更新,然后是 x 轴标签,最后是 y 轴标签 。
如果您使用的是 Jupyter 笔记本,则只有在执行给定单元格中的所有语句后才能看到输出,因此您必须将这三个语句中的每一个放在单独的单元格中,然后一个接一个地执行,以查看绘图在每个代码语句之后被更新。
In older versions of Matplotlib or certain backends (such as macosx
), the graph may not be updated immediately. In such cases, you need to call plt.draw()
explicitly at the end, so that the graph gets displayed.
更多
您可以在同一图上再添加一个折线图,然后继续进行直到完成交互式会话:
- 绘制折线图:
plt.plot([1.5, 3.0])
- 添加标签和标题:
plt.title("Interactive Plot")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
- 再添加一个折线图:
plt.plot([3.5, 2.5])
下图是执行代码后获得的输出:
因此,我们现在在交互模式下工作。
在非交互模式下工作
在交互模式下,我们看到了随着每条指令逐步构建的图形。 在非交互模式下,您将提供所有说明来构建图形,然后使用命令显式显示图形。
操作步骤
在非交互模式下工作也不困难:
- 重新启动内核,并导入
matplotlib
和pyplot
库:
import matplotlib
import matplotlib.pyplot as plt
- 将交互模式设置为关闭:
plt.ioff()
- 检查交互模式的状态:
matplotlib.is_interactive()
- 您应该获得输出
False
。 - 执行以下代码; 您不会在屏幕上看到该图:
## Plot a line graph
plt.plot([1.5, 3.0])
## Plot the title, X and Y axis labels
plt.title("Non Interactive Mode")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
- 执行以下语句,然后您将在屏幕上看到该图:
## Display the graph on the screen
plt.show()
工作原理
前面的每个代码语句都是不言自明的。 要注意的重要事项是在非交互模式下,为要显示的图形编写完整的代码,然后显式调用plt.show()
以在屏幕上显示图形。
以下是获得的输出:
The latest versions of Jupyter Notebook seem to display the figure without calling
plt.show()
command explicitly. However, in Python shell or embedded applications, plt.show()
or plt.draw()
is required to display the figure on the screen.
从外部文件读取并绘图
默认情况下,Matplotlib 接受输入数据作为 Python 列表,NumPy 数组或 pandas 数据帧。 因此,需要先读取所有外部数据并将其转换为这些格式之一,然后再将其提供给 Matplotlib 进行图形绘制。 从性能的角度来看,NumPy 格式更有效,但对于默认标签,pandas 格式比较方便。
如果数据是.txt
文件,则可以使用 NumPy 函数读取数据并将其放入 NumPy 数组中。 如果数据为.csv
或.xlsx
格式,则可以使用 Pandas 读取数据。 在这里,我们将演示如何读取.txt
,.csv
和.xlsx
格式,然后绘制图表。
准备
导入读取输入文件所需的matplotlib.pyplot
,numpy
和pandas
包:
- 导入具有
plt
同义词的pyplot
库:
import matplotlib.pyplot as plt
- 导入具有
np
同义词的numpy
库。numpy
库可以管理 n 维数组,支持这些数组上的所有数学运算:
import numpy as np
- 以
pd
作为同义词导入pandas
包:
import pandas as pd
操作步骤
我们将在三个单独的部分中遵循.txt
,.csv
和.xlsx
文件的顺序。
从.txt
文件读取
以下是一些步骤:
- 将文本文件读入
txt
变量:
txt = np.loadtxt('test.txt', delimiter = ',')
txt
这是前面代码块的说明:
test.txt
文本文件有 10 个数字,用逗号隔开,代表二维空间中的 x 和 y 五个点的坐标(1, 1)
,(2, 4)
,(3, 9)
,(4, 16)
和(5, 25)
。- 函数
loadtxt()
和将文本数据加载到 NumPy 数组中。
您应该获得以下输出:
array([ 1., 1., 2., 4., 3., 9., 4., 16., 5., 25.])
- 将平面数组转换为 2D 空间中的五个点:
txt = txt.reshape(5,2)
txt
执行前面的代码后,您应该看到以下输出:
array([[ 1., 1.], [ 2., 4.], [ 3., 9.], [ 4., 16.], [ 5., 25.]])
- 将
.txt
变量拆分为x
和y
轴坐标:
x = txt[:,0]
y = txt[:,1]
print(x, y)
这是前面代码块的解释:
- 将
x
和y
轴点与txt
变量分开。 x
是txt
中的第一列,y
是第二列。- Python 索引从 0 开始。
执行上述代码后,您应该看到以下输出:
[ 1\. 2\. 3\. 4\. 5.] [ 1\. 4\. 9\. 16\. 25.]
从.csv
文件读取
.csv
文件具有行和列的关系数据库结构,test.csv
文件在 2D 空间中具有五个点的 x,y 坐标。 每个点是文件中的一行,分为两列:x
和y
。 相同的 NumPy loadtxt()
函数用于加载数据:
x, y = np.loadtxt ('test.csv', unpack = True, usecols = (0,1), delimiter = ',')
print(x)
print(y)
执行上述代码后,应该看到以下输出:
[ 1\. 2\. 3\. 4\. 5.] [ 1\. 4\. 9\. 16\. 25.]
从.xlsx
文件读取
现在,让我们从.xlsx
文件中读取相同的数据,并创建x
和y
NumPy 数组。 NumPy loadtxt()
函数不支持.xlsx
文件格式。 可以使用 Python 数据处理包pandas
:
- 将
.xlsx
文件读入 pandas 数据帧中。 该文件在 2D 空间中具有相同的五个点,每个点在具有x
和y
列的单独行中:
df = pd.read_excel('test.xlsx', 'sheet', header=None)
- 将 pandas 数据帧转换为 NumPy 数组:
data_array = np.array(df)
print(data_array)
您应该看到以下输出:
[[ 1 1] [ 2 4] [ 3 9] [ 4 16] [ 5 25]]
- 现在从 NumPy 数组中提取
x
和y
坐标:
x , y = data_array[:,0], data_array[:,1]
print(x,y)
您应该看到以下输出:
[1 2 3 4 5] [ 1 4 9 16 25]
绘制图形
从三种格式(.txt
,.csv
和.xlsx
)中的任何一种读取数据并将其格式化为x
和y
变量后,我们使用以下变量绘制图形:
plt.plot(x, y)
在屏幕上显示图形:
plt.show()
以下是获得的输出:
工作原理
根据数据的格式和结构,我们将不得不使用 Python,NumPy 或 pandas 函数来读取数据并将其重新格式化为可以馈入matplotlib.pyplot
函数的适当结构。 之后,按照通常的绘制说明绘制所需的图形。
更改和重置默认环境变量
Matplotlib 使用matplotlibrc
文件存储跨 matplotlib 功能使用的各种环境和图形参数的默认值。 注意,该文件很长。 这些默认值可自定义以应用于会话中的所有绘图。
可以使用print(matplotlib.rcParams)
命令从该文件获取所有默认参数设置。
matplotlib.rcParams
命令用于将这些默认值更改为任何其他支持的值,一次更改一个参数。matplotlib.rc
命令用于为特定组中的多个参数设置默认值,例如,行,字体,文本等。 最后,matplotlib.rcdefaults()
命令用于恢复默认参数。
Matplotlib 在内部使用matplotlib.rcsetup()
命令来验证所更改的参数是可接受的值。
准备
以下代码块提供了包含所有配置参数的文件路径:
## Get the location of matplotlibrc file
import matplotlib
matplotlib.matplotlib_fname()
您应该看到类似下面的目录路径。 确切的目录路径取决于您的安装:
'C:\\Anaconda3\\envs\\keras35\\lib\\site-packages\\matplotlib\\mpl-
data\\matplotlibrc'
操作步骤
以下代码块以及注释可帮助您了解更改和重置默认环境变量的过程:
- 导入具有
plt
同义词:的matplotlib.pyplot
包
import matplotlib.pyplot as plt
- 从我们在前面的秘籍中使用的同一
test.csv
文件中加载x
和y
变量:
x, y = np.loadtxt ('test.csv', unpack = True, usecols = (0,1),
delimiter = ',')
- 更改组
'lines'
中多个参数的默认值:
matplotlib.rc('lines', linewidth=4, linestyle='-', marker='*')
- 分别更改参数的默认值:
matplotlib.rcParams['lines.markersize'] = 20
matplotlib.rcParams['font.size'] = '15.0'
- 绘制图形:
plt.plot(x,y)
- 显示图形:
plt.show()
以下是将获得的输出:
工作原理
matplotlib.rc
和matplotlib.rcParams
命令覆盖指定参数的默认值作为这些命令中的参数。 在绘制图形时,pyplot
工具将使用这些新值。
It should be noted that these values will be active for all plots in the session. If you want different settings for each plot in the same session, then you should use the attributes available with the plot
command.
更多
您可以使用rsdefaults()
命令将所有参数重置为其默认值,如下框所示:
## To restore all default parameters
matplotlib.rcdefaults()
plt.plot(x,y)
plt.show()
该图如下所示:
.
十、使用mplot3d
工具包绘制 3D 图形
在本章中,我们将介绍绘制以下图形的方法:
- 线形图
- 散点图
- 条形图
- 多边形图
- 等高线图
- 曲面图
- 线框图
- 三角曲面图
- 在 3D 模式下绘制 2D 数据
- 在 3D 中可视化 2D 中的线性不可分离数据
- 绘制单词嵌入
介绍
Matplotlib 的早期版本仅限于 2D 绘图,后来又将 3D 功能添加为附加工具箱:mplot3d
。 尽管它具有有限的 3D 功能,但它涵盖了 3D 绘图的大多数常见业务需求。
绘图命令与 2D 命令相似。 只是我们向 Matplotlib 注册,我们将通过从工具包中导入Axes3D
来使用 3D 图,并在轴域定义中指定projection='3d'
。
如果您正在使用任何交互式后端,还可以通过将图形拖向所需的任何方向来旋转 3D 图片以获取不同的视图。 您还可以通过在帧之间稍稍停顿的情况下旋转图形来创建动画。 我们将学习如何在某些图中使用这些功能,尽管它们可以应用于所有图中。
线形图
在本秘籍中,我们将学习如何创建 3D 线形图。 它类似于 2D 等效折线图,并且 2D 折线图的和属性中的许多属性都将结转到 3D。
我们将在相同的轴域上绘制凹凸曲线,并从不同角度查看它们,例如平行视图,俯视图以及绕, z 轴旋转。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
以下是绘制 3D 折线图的步骤:
- 准备 x,y 和 z 轴坐标的数据:
x = np.linspace(-5, 5, 25)
y = np.linspace(-5, 5, 25)
z = x**2 + y**2
z1 = 1 - (x**2 + y**2)
- 定义一个函数来绘制图形并设置其属性:
def plot_graph(axes, xlabel, ylabel, zlabel, title, elevation, rotation):
axes.plot3D(x, y, z, label='concave')
axes.plot(x, y, z1, label='convex')
axes.view_init(elev=elevation, azim=rotation)
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)
axes.set_zlabel(zlabel)
axes.set_title(title)
axes.legend(loc='best')
- 定义用于 3D 绘图的图形和轴域
ax1
:
fig = plt.figure(figsize=(15,9))
ax1 = fig.add_subplot(231, projection='3d')
- 用默认高度和旋转度在
ax1
上绘制曲线:
plot_graph(ax1, 'X', 'Y', 'Z', 'default view', None, None)
- 定义第二个轴域
ax2
并以 0 度的仰角绘制它,并以默认的azimuth
角进行绘制:
ax2 = fig.add_subplot(232, projection='3d')
plot_graph(ax2, 'X', 'Y', 'Z', 'elevation angle = 0,\n azimuth angle=None', 0, None)
- 定义第三个轴域
ax3
并以 90 度仰角绘制它,并以默认azimuth
缺省角度进行绘制:
ax3 = fig.add_subplot(233, projection='3d')
plot_graph(ax3, 'X', 'Y', ' ', 'elevation angle = 90,\n azimuth angle=None', 90, None)
ax3.set_zticks([])
- 定义第四个轴域
ax4
,并使用默认仰角和-30
度的方位角进行绘制:
ax4 = fig.add_subplot(234, projection='3d')
plot_graph(ax4, 'X', 'Y', 'Z', 'elevation angle = None,\n azimuth angle=-30', None, -30)
- 定义第五个轴域
ax5
,并使用默认仰角和30
度的方位角进行绘制:
ax5 = fig.add_subplot(235, projection='3d')
plot_graph(ax5, 'X', 'Y', 'Z', 'elevation angle = None,\n azimuth
angle=30', None, 30)
- 调整绘图之间的空间,并将其显示在屏幕上:
plt.tight_layout(w_pad=5)
plt.show()
工作原理
这是前面的代码块的说明:
x = np.linspace(−5, 5, 25)
创建一个数组,该数组的 25 个点在 -5 和 +5 之间等距分布,并且z
和z1
被定义为x
和y
def plot_graph(axes, xlabel, ylabel, zlabel, title, elevation, rotation):
是用于绘制具有给定属性的图形的函数:axes
指定要在其上绘制图形的轴域。xlabel
,ylabel
和zlabel
分别为 x,y 和 z 轴指定标签。title
指定图的标题。elevation
指定相对于 xy 平面的视角:0 表示平行于 xy 平面的视角,90 表示俯视图。rotation
指定在 z 轴上旋转的绘图的视图。elevation
和rotation
均以度为单位。axes.plot3D(x, y, z, label='concave')
与 2D 线形图语法相似,不同之处在于,我们还包括 z 轴。 您也可以使用axes.plot()
代替axes.plot3D()
,就像我们对凸曲线所做的那样。 大多数其他绘图也是如此,但并非所有情况都如此。axes.view_init(elev=elevation, azim=rotation)
指定绘图出现时的视图。- 函数中的其余语句已经为我们所熟悉。
ax1 = fig.add_subplot(231, projection='3d')
在图形上添加了一个轴域,其布局指定为2 x 3
网格:projection='3d'
指定它为 3D 轴域,并在其上绘制三维图。 这是 2D 和 3D 绘图语法之间的主要区别。
- 在
ax1
上,我们使用默认仰角和旋转角度绘制图表 - 在
ax2
至ax4
上,我们绘制了具有不同仰角和旋转角度的相同图形,以查看其视图的差异。
在执行前面的代码时,您应该在屏幕上看到以下图形和绘图:
散点图
在本秘籍中,我们将学习如何在 3D 中绘制散点图。 在此示例中,我们将使用Iris
数据集,该数据集具有三个不同的群集。 在前面的章节中,我们已经多次在 2D 中看到它,所以让我们看看它在 3D 中的外观。
我们还将学习如何使用在前面的秘籍中学习的init_view
方法创建动画 3D 绘图。 为此,我们需要使用任何后端,因为动画无法与嵌入式显示器%matplotlib inline
一起使用。
准备
设置所需的后端:
import matplotlib
matplotlib.use('tkAgg')
导入所需的库:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
以下是实现逻辑的步骤:
- 加载并准备 3D 图的数据:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" : 1, "virginica" : 2})
x, y, z = iris['petal_length'], iris['petal_width'], iris['species']
- 定义并实例化图形和轴域以进行 3D 绘图:
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111, projection='3d')
- 使用
for
循环绘制散点图,以绘制具有不同颜色和标记的每个聚类:
for name, c, marker in zip((0, 1, 2), ('r', 'b', 'g'), ('o', '^', '*')):
index = iris['species'] == name
ax.scatter(x[index], y[index], z[index], s=25*x[index]*y[index],
c=c, marker=marker)
- 设置图形的标签:
ax.set_xlabel('petal length')
ax.set_ylabel('petal width')
ax.set_zlabel('species')
ax.set_zticks([0, 1, 2])
- 定义一个循环以创建 3D 图动画:
for angle in range(0, 360):
ax.view_init(30, angle)
plt.pause(.001)
- 在 Tkinter 后端上显示动画图形:
plt.show();
工作原理
这是前面代码的解释:
matplotlib.use('tkAgg')
将后端设置为 Tkinter。x, y, z = iris['petal_length'], iris['petal_width'], iris['species']
为 x,y 和 z 坐标准备数据。 我们在 x 和 y 轴域上绘制*petal_length*
和petal_width
,然后在 z 轴域上绘制species
(簇号)。ax.scatter(x[index], y[index], z[index], s=25*x[index]*y[index], c=c, marker=marker)
与 2D 散点图语法相似,不同之处在于,我们还包括 z 轴。- 要创建动画,我们使用
for
循环,并将视图旋转角度从 0 更改为 360 度:ax.view_init(30, angle)
使仰角固定为 30 度,并在每次迭代中将旋转角改变 1 度plt.pause(.001)
在两次迭代之间暂停 0.001 秒
执行上述代码后,您应该会在一个新窗口中看到一个动画图,该窗口以 Tkinter 后端打开。 该图的静态版本应类似于此处所示:
条形图
在本秘籍中,我们将学习如何在 3D 模式下绘制条形图。 我们将使用电池销售数据,该数据已在第 2 章和“基本绘图”入门中用于表格绘制。 在这里,我们只会在条形图下方绘制条形图,而不是表格图。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
以下是实现逻辑的步骤:
- 定义用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(10,6))
ax = fig.add_subplot(111, projection='3d')
- 准备 x,y 和 z 轴的数据:
## Years for which we have battery sales data
x = [2011, 2012, 2013, 2014, 2015]
## Repeat X, 5 times to represent each of the 5 battery ratings
X = x * 5
## List of Battery ratings
battery_ratings = ['7Ah', '35Ah', '40Ah', '135Ah', '150Ah']
## Number of units sold each year, each rating. e.g. 75 units of 7Ah(0) batteries, 144 units of 35Ah(1) #batteries sold in 2011
Y = np.array([[75, 144, 114, 102, 108],
[90, 126, 102, 84, 126],
[96, 114, 75, 105, 135],
[105, 90, 175, 90, 75],
[90, 75, 135, 75, 90]])
## Represent battery rating in numeric codes
yticks = [0, 1, 2, 3, 4]
## Use different color for each of the battery ratings
colors = ['r', 'g', 'b', 'y', 'm']
- 绘制条形图:
i=0
for c, k in zip(colors, yticks):
cs = [c] * len(X)
ax.bar(X[i:i+5], Y[:,int(i/5)], zs=k, zdir='y', color=cs,
alpha=0.8)
i += 5
- 设置图表的标签:
ax.set_yticks(yticks)
ax.set_yticklabels(battery_ratings)
ax.set_xlabel('Year')
ax.set_ylabel('Battery Type')
ax.set_zlabel('Units Sold')
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
-
x 和 y 是长度为 25 的列表,分别代表年份和所售单位的数量。
-
yticks
以数字格式表示电池额定值,将在 y 轴上标出。 -
colors
是连续用于和电池额定值中每种颜色的五种颜色的列表。 -
for
循环在每次迭代中连续绘制一项电池额定数据。 -
cs = [c] * len(X)
创建一个长度为X
的相同颜色c
的列表。 -
ax.bar(X[i:i+5], Y[:,int(i/5)], zs=k, zdir='y', color=cs, alpha=0.8)
绘制,条形图:- 从
X
和Y
数组中提取每种电池类型的五个元素(代表五年),以绘制一行横条。 zs=k
指定将数字电池额定值映射到 z 轴。zdir='y'
指定交换 z 和 y 轴,以便在 y 轴绘制Z
数据。 在 z 轴域上绘制y
数据。alpha=0.8
指定图形所需的透明度级别
- 从
-
步骤 4 和步骤 5 对您来说非常熟悉。
执行代码后,您应该看到此处显示的图形:
多边形图
在本秘籍中,我们将学习如何绘制多边形图。 它类似于折线图,但在折线下填充。 在此示例中,我们还将使用相同的电池销售数据。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.collections import PolyCollection
from matplotlib.ticker import MultipleLocator
操作步骤
以下是编码逻辑的步骤:
- 定义用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(10,6))
ax = fig.add_subplot(111, projection='3d')
- 准备 x,y 和 z 轴的数据:
## Years for which we have battery sales data
x = [2011, 2012, 2013, 2014, 2015]
## Repeat X, 5 times to represent each of the 5 battery ratings
X = x * 5
## List of Battery ratings
battery_ratings = ['7Ah', '35Ah', '40Ah', '135Ah', '150Ah']
## Number of units sold each year, each rating. e.g. 75 units of 7Ah(0) batteries,
## 144 units of 35Ah(1) batteries sold in 2011
Y = np.array([[75, 144, 114, 102, 108],
[90, 126, 102, 84, 126],
[96, 114, 75, 105, 135],
[105, 90, 175, 90, 75],
[90, 75, 135, 75, 90]])
## Represent battery rating in numeric codes
yticks = [0, 1, 2, 3, 4]
## Use different color for each of the battery ratings
colors = ['r', 'g', 'b', 'y', 'm']
- 准备要绘制的多边形的顶点:
vertices = []
for i in np.arange(0, 25, 5):
vertices.append([(xs[i], 0.)] + list(zip(xs[i:i+5], Y[:,int(i/5)])) + [(xs[i+4], 0.)])
- 绘制条形图:
poly = PolyCollection(vertices, facecolors=['r', 'g', 'b', 'y', 'm'], alpha=0.6)
ax.add_collection3d(poly, zs=yticks, zdir='y')
- 将 x 轴的主要刻度设置为
1
的增量:
majorLocator = MultipleLocator(1)
ax.xaxis.set_major_locator(majorLocator)
- 设置 x,y 和 z 轴的限制:
ax.set_xlim(2011, 2015)
ax.set_ylim(-1,4)
ax.set_zlim(0,175)
- 设置 y 轴的刻度,并为 x,y 和 z 轴设置标签:
ax.set_yticks(yticks)
ax.set_yticklabels(battery_ratings)
ax.set_xlabel('Year')
ax.set_ylabel('Battery Type')
ax.set_zlabel('Units Sold')
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
- 前两个步骤与前面的秘籍完全相同
vertices.append([(xs[i], 0.)] + list(zip(xs[i:i+5], Y[:,int(i/5)])) + [(xs[i+4], 0.)])
创建给定电池额定值的顶点。for
循环会为所有电池额定值创建此类顶点。(xs[i], 0)
和(xs[i+4],0.)
是在 x 轴上终止的端点,其中 y 坐标为零, x 坐标是序列中的第一个和最后一个点。 将这两个点相加即可完成围绕 x 轴的循环,以便可以绘制出填充的多边形。poly = PolyCollection(vertices, facecolors=['r', 'g', 'b', 'y', 'm'], alpha=0.6)
定义了一个多边形的集合,它等于给定的顶点:facecolors=['r', 'g', 'b', 'y', 'm']
定义用于填充每个电池额定值的多边形的颜色。alpha=0.6
定义每个填充多边形的透明度级别。
ax.add_collection3d(poly, zs=yticks, zdir='y')
将集合添加到轴域,这实际上是绘制集合图的图:zs=yticks
将yticks
设置为 z 轴zdir='y'
交换 z 和 y 轴数据,以便y
数据用于 z 轴,而Z
数据用于 y 轴,就像我们在前面的秘籍中所做的一样。
majorLocator = MultipleLocator(1)
以 1 为步长定义majorLocator
,ax.xaxis.set_major_locator(majorLocator)
将其应用于 x 轴,以便不绘制和浮点数的年份。ax.set_xlim(2011, 2015)
,ax.set_ylim(-1,4)
和ax.set_zlim(0,175)
应用 x,y 和 z 轴的上限和下限。 这里需要这些来显示图形,因为此处的多边形和补丁是浮动对象,pyplot
不知道使用的默认限制,这与所有其他情况不同,其中它会根据源数据中的数据点来确定限制。- 您已经熟悉了最后两个步骤。
在运行前面的代码时,您应该在屏幕上看到以下图形:
更多
对于前面的示例,我们使用了PolyCollection
。 Matplotlib 中还有两个其他选项,LineCollection
和PatchCollection
。
等高线图
我们在第 2 章和“基本绘图入门”中学习了如何绘制 2D 等高线图。 在这里,我们将学习如何在 3D 模式下绘制它。 我们将使用与之前相同的数据,以便我们可以看到 2D 和 3D 可视化之间的差异。
准备
导入所需的库:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import cm
操作步骤
以下是创建所需图的步骤:
- 定义用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(10,8))
ax = fig.gca(projection='3d')
- 加载
Loss
,theta1
和theta2
变量的数据:
## Read Loss, theta0 and theta1 values
Loss = pd.read_excel('Loss.xlsx')
theta0_vals = pd.read_excel('theta0.xlsx')
theta1_vals = pd.read_excel('theta1.xlsx')
- 使用
np.meshgrid
准备X
和Y
坐标:
X, Y = np.meshgrid(theta0_vals, theta1_vals)
- 绘制
contour
图:
## Plot contour curves
cset = ax.contour(X, Y, Loss, np.logspace(-2,3,100), cmap=cm.coolwarm)
- 绘制颜色条:
fig.colorbar(cset, shrink=0.5, aspect=5)
- 设置标签:
ax.set_xlabel('theta0')
ax.set_ylabel('theta1')
ax.set_zlabel('Loss')
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
- 前两个步骤是不言自明的。
X, Y = np.meshgrid(theta0_vals, theta1_vals)
为theta0
和theta1
变量创建 x 和 y 坐标。 请参见第 2 章,“基本绘图入门”,以获得有关meshgrid
的详细说明。cset = ax.contour(X, Y, Loss, np.logspace(-2,3,100), cmap=cm.coolwarm)
绘制等高线图。 它为X
和Y
的各种值绘制,Loss
变量的轮廓。 每个轮廓具有Loss
(z 轴)的固定值,因此轮廓沿 z 轴垂直放置,而值最低的轮廓位于底部:np.logspace(-2,3,100)
指定要绘制轮廓的损耗值范围。 它们的对数空间范围为 -2(线性范围为 0.01)至 +3(线性范围为 1000),并在此范围内均等间隔地采集 100 个样本。cmap=cm.coolwarm
指定将coolwarm
颜色表用于轮廓的可视化。
- 我们还绘制了 2D 中每个轮廓的损耗实际值,但 3D 并没有实现。
fig.colorbar(cset, shrink=0.5, aspect=5)
设置颜色条,以显示与 , 指定的颜色表不同的颜色的轮廓:shrink=0.5
指定颜色条大小从默认大小开始的缩小量。aspect=5
在颜色条上指定数据的较大大小与较小大小的比率。
- 最后两个步骤是不言自明的。
运行前面的代码后,您应该在屏幕上看到下图:
更多
填充轮廓图还有另一种选择,其中整个轮廓填充有和指定的颜色。 您只需要在plot
语句中用contourf
替换轮廓。
曲面图
在本秘籍中,我们将学习如何绘制曲面图。 通常用于在机器学习问题中可视化损失(误差)表面。 当误差面具有多个最小值时,有助于查看算法是否卡在任何局部最小值中。 我们将使用与,之前的轮廓图相同的数据。
准备
导入所需的库:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
操作步骤
以下是绘制曲面图的步骤:
- 定义图形和 3D 绘图轴域:
fig = plt.figure(figsize=(10,8))
ax = fig.gca(projection='3d')
- 读取曲面图的数据:
## Read Loss, theta0 and theta1 values
Loss = pd.read_excel('Loss.xlsx')
theta0_vals = pd.read_excel('theta0.xlsx')
theta1_vals = pd.read_excel('theta1.xlsx')
- 为
X
和Y
坐标使用theta0
和theta1
的值范围创建meshgrid
:
X, Y = np.meshgrid(theta0_vals, theta1_vals)
- 绘制曲面图:
## Plot surface graph
surf = ax.plot_surface(X, Y, Loss, cmap='plasma')
- 在图中添加颜色条:
fig.colorbar(surf, shrink=0.5, aspect=5)
- 为图形设置标签:
ax.set_xlabel('theta0')
ax.set_ylabel('theta1')
ax.set_zlabel('Loss')
- 在屏幕上显示该图:
plt.show()
工作原理
除了步骤 4,其中所有步骤均与之前的轮廓图完全相同,在该步骤中,我们将ax.contour()
替换为ax.plot_surface()
。 我们还用plasma
颜色表替换了coolwarm
颜色表。 其他所有内容都与等高线图相同。
执行代码后,您应该在屏幕上看到下图:
线框图
在本秘籍中,我们将学习如何绘制线框图。 它类似于曲面图,其中和选项在每个方向上采样多个点以连接到曲面。 在这里,我们将实现一个动画的线框图。
准备
将交互式输出的设置为所需的后端:
import matplotlib
matplotlib.use('Qt5Agg')
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
以下是绘制线框图所涉及的步骤:
- 定义用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(111, projection='3d')
- 准备 x 和 y 坐标的数据:
x = np.linspace(-2, 2, 25)
y = np.linspace(-5, 5, 25)
X, Y = np.meshgrid(x, y)
- 设置, x,y 和 z 轴的标签:
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
- 为 z 轴设置限制,以使动画激活时,轴刻度不会保持变化:
ax.set_zlim(-4, 4)
- 通过将 z 轴数据设为
X
,Y
的函数,并使用变量phi
从0
至90
度来绘制动画线框图:
wframe = None
for phi in np.linspace(0, 90, 100):
if wframe:
ax.collections.remove(wframe)
Z = np.cos(2 * np.pi * X + phi) * (1 - np.sqrt(X**2 + Y**2))
wframe = ax.plot_wireframe(X, Y, Z, rstride=2, cstride=2)
plt.pause(0.1)
- 在 Qt5 后端上显示图形:
plt.show()
工作原理
这是代码的说明:
- x 是从 -2 到 +2 的 25 个数字的列表,它们之间的间距相等; 同样,y 是从 -5 到 +5 的 25 个数字的列表, x 和 y 是 x 和 y 之间的网格。
ax.set_zlim(-4, 4)
将的 z 轴限制设置为 -4 至 +4。 由于 z 是变量phi
的函数,因此这些数据限制在 z 轴上保持变化。 为避免更改图上的限制,请将限制的最大边界设置为 -4 到 +4。wframe = None
初始化wframe
变量。for phi in np.linspace(0, 90, 100):
是for
循环,从 0 开始,然后以 100 个相等的步长一直到 90 度。if wframe:
检查线框是否已经存在。 第一次不会出现 。 不会出现,因为我们没有初始化它。 随后,它将始终为真,因此在绘制新的线框之前,将使用ax.collections.remove(wframe)
将其删除。Z = np.cos(2 * np.pi * X + phi) * (1 - np.sqrt(X**2 + Y**2))
根据 x,y 和phi
的函数计算Z
值。wframe = ax.plot_wireframe(X, Y, Z, rstride=2, cstride=2)
绘制线框图:rstride
是连接点之前沿行跳过的点数。cstride
是连接这些点之前沿列跳过的点数。
plt.pause(0.1)
暂停 0.1 秒,然后绘制下一个线框。 这就是创建动画效果的原因。- 在这里,我们不需要使用
plt.draw()
或任何其他等效函数来刷新图形。plot_wireframe
会照顾好它。
运行代码后,在动画完成后,您应该看到下图:
三角曲面图
在本秘籍中,我们将学习如何绘制三角形曲面图。 它类似于曲面图,但是曲面将具有三角形连接。 我们将使用不同的数据绘制三个这样的图,并显示轴和不显示轴。
准备
导入所需的库:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下是绘制三角形曲面图的步骤:
- 准备三个不同图的数据:
## Make radii and angles arrays.
radii = np.linspace(0., 1.0, 16)
angles = np.linspace(0, 2*np.pi, 32)
## Repeat all angles for each radius.
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
## Convert polar (radii, angles) coords to cartesian (x, y) coords.
x = (radii*np.cos(angles)).flatten()
y = (radii*np.sin(angles)).flatten()
## Compute z to make the triangle surface.
z = np.tan(x**2 + y**2)
z1 = np.cos(x**2 + y**2)
z2 = np.cos(x**3 + y**3)
- 定义图:
fig = plt.figure(figsize=(12,6))
- 绘制第一个三角形曲面图:
ax1 = fig.add_subplot(131, projection='3d')
ax1.plot_trisurf(x, y, z, linewidth=0.5, cmap='viridis')
- 绘制第二个三角形曲面图:
ax2 = fig.add_subplot(132, projection='3d')
ax2.plot_trisurf(x, y, z1, linewidth=0.5, cmap='cool')
plt.axis('off')
- 绘制第三个三角形曲面图:
ax3 = fig.add_subplot(133, projection='3d')
ax3.plot_trisurf(x, y, z2, linewidth=0.5, color='c')
plt.axis('off')
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
np.linspace(0., 1.0, 16)
将的 0 到 1 范围划分为 16 个相等的部分,因为半径定义了在 0 和 1 之间平均分布的半径数,类似地,角度定义了在 0 和2 * pi
之间平均分布的角度数(360 度)。np.repeat(angles[..., np.newaxis], n_radii, axis=1)
,为每个半径重复角度数组,创建一个32 x 16
的矩阵:np.newaxis
为每个半径创建一个附加大小。axis=1
指定应将每个新维度添加为一列。
x = (radii*np.cos(angles)).flatten()
使用极坐标在笛卡尔坐标系中创建 x 坐标。y = (radii*np.sin(angles)).flatten()
使用极坐标在笛卡尔坐标系中创建 x 坐标。z = np.tan(x**2 + y**2)
计算plot1
的 z 坐标。z1 = np.cos(x**2 + y**2)
计算plot2
的 z 坐标。z2 = np.cos(x**3 + y**3)
计算plot3
的 z 坐标。fig = plt.figure(figsize=(12,6))
定义并实例化该图形。ax1 = fig.add_subplot(131, projection='3d')
定义了第一个轴域,ax1.plot_trisurf(x, y, z, linewidth=0.5, cmap='viridis')
绘制了第一张图。 指定的色表是'viridis'
。ax2 = fig.add_subplot(132, projection='3d')
定义第二个轴域,ax2.plot_trisurf(x, y, z1, linewidth=0.5, cmap='cool')
绘制第二个图。 指定的色表是cool
。plt.axis('off')
指定不显示绘图上的轴。ax3 = fig.add_subplot(133, projection='3d')
定义了第三个轴域。ax3.plot_trisurf(x, y, z2, linewidth=0.5, color='c')
绘制了第三个图。 我们使用单色代替该颜色表,并再次关闭轴。
执行代码后,您应该在屏幕上看到三个图形的图形:
在 3D 模式下绘制 2D 数据
在本秘籍中,我们将学习如何在 3D 模式下绘制 2D 数据。 我们将根据原因码将产品缺陷绘制为条形图,将累积缺陷绘制为线形图。 我们将在 x 轴,z 轴和 y 轴上的累积缺陷百分比。 在 2D 空间中,有两个 y 轴,其中一个具有条形图的比例,另一个具有折线图的比例。
准备
导入所需的库:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
以下是绘制和所需 3D 图的步骤:
- 定义用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(10,6))
ax = fig.add_subplot(111, projection='3d')
- 定义条形图的数据并绘制:
x = [0, 1, 2, 3, 4, 5]
y = [19, 12, 6, 4, 3, 2]
ax.bar(x, y, zs=0, zdir='y', label='Number of Defects in (X,Z)')
- 为累积缺陷图定义的数据并绘制:
x = [0, 1, 2, 3, 4, 5]
y = [41, 67, 80, 89, 96, 100]
ax.plot(x, y, zs=0, zdir='z', color='g', lw=5, label='Cumulative Defects in (X,Y)')
- 设置 y 和 z 轴的限制:
ax.set_ylim(0,100)
ax.set_zlim(0,20)
- 为 x,y 和 z 轴设置标签,并设置图例:
ax.set_xlabel('Defect Reason Code')
ax.set_ylabel('Cumulative %of defects')
ax.set_zlabel('Number of Defects')
ax.legend(loc='best')
- 在屏幕上显示图:
plt.show()
工作原理
这是代码的说明:
x = [0, 1, 2, 3, 4, 5]
是产品缺陷原因代码的列表。y = [19, 12, 6, 4, 3, 2]
是按原因代码列出的缺陷计数。ax.bar(x, y, zs=0, zdir='y', label='Number of Defects in (X,Z)')
绘制条形图:- 缺陷原因代码在 x 轴上,缺陷数量在 z 轴上。
zdir='y'
交换 y 和 z 轴,以便在 z 轴域上绘制y
数据。 在 y 轴域上绘制z
数据,在这种情况下为零。- 指定的标签将显示在图例中。
y = [41, 67, 80, 89, 96, 100]
是累积缺陷占总数百分比的列表。ax.plot(x, y, zs=0, zdir='z', color='g', lw=5, label='Cumulative Defects in (X,Y)')
绘制线形图:- 缺陷原因代码在 x 轴上,累积缺陷在 y 轴上。
zdir='z'
指定在上将z
数据绘制在 z 轴上,在此情况下,轴由zs=0
指定为零。color='g'
指定和线形图应为绿色。lw=5
指定图的线宽应为五个单位。- 标签将显示在图例上。
ax.set_ylim(0,100)
设置 y 轴的上限和下限,ax.set_zlim(0,20)
设置 z 轴的下限和上限。ax.set_xlabel('Defect Reason Code')
设置 x 轴的标签。ax.set_ylabel('Cumulative %of defects')
设置 y 轴的标签。ax.set_zlabel('Number of Defects')
设置 z 轴的标签。ax.legend(loc='best')
指定自动为图例选择最佳位置。
运行代码后,您应该在屏幕上看到下图:
在 3D 中可视化 2D 中的线性不可分离数据
在本秘籍中,我们将学习如何可视化在 3D 中线性不可分离的 2D 数据。 这通常用于解释支持向量机算法的内部工作原理,该算法将较低维的数据带到较高维的空间,以便可以找到一个平面。将数据整齐地分离为各种群集。
我们将使用相同的数据绘制 2D 和 3D 图,以使其可视化效果更好。
准备
导入所需的库:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
操作步骤
这是绘制和所需图形的步骤:
- 将数据从 Excel 文件读取到列表中:
## Read the Data, two product test scores, and result 1 means accepted and 0 means rejected
scores_data = pd.read_csv('test_scores_results.txt',header=None)
- 创建一个 Pandas 数据帧可以轻松地将数据分为不同的类别:
## Add columns labels to the data
columns = ['Test1_Score', 'Test2_Score', 'Accepted']
scores_data = np.array(scores_data)
df = pd.DataFrame(data=scores_data, columns=columns)
- 将数据分为
accepted
和rejected
类别:
df_accepted = df[(df['Accepted'] == 1.0)]
df_rejected = df[(df['Accepted'] == 0.0)]
- 将数据分为
accepted
和rejected
类别的 x 和 y 坐标:
accepted_score1 = np.array(df_accepted)[:,0]
accepted_score2 = np.array(df_accepted)[:,1]
rejected_score1 = np.array(df_rejected)[:,0]
rejected_score2 = np.array(df_rejected)[:,1]
- 定义并实例化图形:
fig = plt.figure(figsize=(12,8))
- 定义 2D 绘图的轴域并绘制
accepted
和rejected
数据点:
ax = fig.add_subplot(121)
ax.plot(accepted_score1, accepted_score2, 'gD', label='Accepted')
ax.plot(rejected_score1, rejected_score2, 'ro', label='rejected')
- 绘制 2D 图的标签和图例:
plt.xlabel('Test1 Score')
plt.ylabel('Test2 Score')
plt.legend(loc='best')
- 定义 3D 绘图的轴域:
ax = fig.add_subplot(122, projection='3d')
- 将接受和拒绝的数据点绘制为散点图:
ax.scatter(accepted_score1, accepted_score2, zs=-0.75, zdir='z', s=50, color='g',
marker='D', label='Accepted')
ax.scatter(rejected_score1, rejected_score2, zs=0.75, zdir='y', s=50, color='r',
marker='o', label='rejected')
- 为 3D 图设置标签,限制和图例:
ax.set_xlabel('Test1 Score')
ax.set_ylabel('Test2 Score')
ax.set_zlabel('Test2 Score')
ax.set_zlim(-1, 1)
ax.legend(loc='best')
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
scores_data = pd.read_csv('test_scores_results.txt',header=None)
从 Excel 文件的中读取数据,该文件没有标题。 它具有测试 1 和测试 2 得分,rejected
状态为0
,accepted
状态为1
。scores_data = np.array(scores_data)
将scores_data
转换为 NumPy 数组。df = pd.DataFrame(data=scores_data, columns=columns)
使用scores_data
数组和列名列表创建pandas
数据帧df
。df_accepted = df[(df['Accepted'] == 1.0)]
使用test1
和test2
得分为accepted
数据创建df_accepted
数据帧。df_rejected = df[(df['Accepted'] == 0.0)]
使用test1
和test2
得分为rejected
数据创建df_rejected
数据帧。accepted_score1 = np.array(df_accepted)[:,0]
和accepted_score2 = np.array(df_accepted)[:,1]
是accepted
类别的 x 和 y 坐标。rejected_score1 = np.array(df_rejected)[:,0]
和rejected_score2 = np.array(df_rejected)[:,1]
是rejected
类别的 x 和 y 坐标。ax.plot(accepted_score1, accepted_score2, 'gD', label='Accepted')
绘制二维图,其中accepted
类别点为绿色散点图,并带有菱形标记。 由于未提供线型参数,因此将其视为散点图。ax.plot(rejected_score1, rejected_score2, 'ro', label='rejected')
将,rejected
类别点绘制为红色的散点图,并带有一个圆形标记。 由于未提供线型参数,因此将其视为散点图。ax.scatter(accepted_score1, accepted_score2, zs=-0.75, zdir='z', s=50, color='g', marker='D', label='Accepted')
在 xy 平面上绘制 3D 散点图,其中accepted
类的z = -0.75
。ax.scatter(rejected_score1, rejected_score2, zs=0.75, zdir='y', s=50, color='r', marker='o', label='rejected')
在 xy 平面上绘制 3D 散点图,其中rejected
类别的z = 0.75
。- 其余的语句是不言自明的。
运行代码后,您应该在屏幕上看到下图:
词嵌入
在第 7 章,“嵌入文本和表达式”中,我们学习了如何在 2D 空间中绘制单词嵌入。 在这里,我们将学习如何在 3D 空间中绘制相同的单词嵌入。 要创建所需数据,我们将必须运行具有三个分量的t-SNE
算法以生成 x,y 和 z 坐标。 我们将使用此输出来绘制图形。
准备
导入所需的库:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pickle
操作步骤
以下是绘制单词嵌入图所涉及的步骤:
- 使用
pickle
加载所需的数据:
threed_embeddings = pickle.load(open('threed_embeddings','rb'))
reverse_dictionary = pickle.load(open('word_reverse_dictionary',
'rb'))
- 创建用于 3D 绘图的图形和轴域:
fig = plt.figure(figsize=(20,20))
ax = fig.gca(projection='3d')
- 为每个
400
最高字词绘制带有文本标注的散点图:
num_points = 400
words = [reverse_dictionary[i] for i in range(1, num_points+1)]
for i, label in enumerate(words):
x, y, z = threed_embeddings[i,:]
ax.scatter(x, y, z)
ax.text(x, y, z, label, ha='right', va='bottom')
- 设置 x,y 和 z 轴的限制和标签:
ax.set_xlim(-800,400)
ax.set_ylim(-200,800)
ax.set_zlim(-800,400)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
- 在屏幕上显示该图:
plt.show()
工作原理
它的工作原理与第 7 章“嵌入文本和表达式”中解释的 2D 等价物类似,不同之处在于输入文件具有三个组成部分,它们映射到三个维度 x,y 和 z。
运行代码后,您应该在屏幕上看到下图:
在这里,与 2D 等价物相比,相似的词看起来很少。 例如,数字 1、2、3、4、5 等看起来更远,而在 2D 中它们看起来像是一个不错的簇。 但是,它们仍然相对在一起。
十一、使用axisartist
工具包
在本章中,我们将通过以下秘籍学习如何使用axisartist
工具包的各种功能:
- 了解
AxisArtist
中的属性 - 在矩形框中定义曲线网格
- 在矩形框中定义极坐标轴域
- 将浮动轴用于矩形图
- 使用浮动轴创建极坐标轴域
- 在浮动极坐标轴域上绘制行星系统数据
介绍
开发axisartist
工具包的主要动机是支持曲线网格,例如用于在天文学中绘制行星系统的网格。 它有助于绘制在直角轴域和极坐标轴域上均具有弯曲轴域的图形,还可以帮助绘制具有浮动轴的图形。
axisartist
是使用自 Matplotlib 主Axes
类派生的自定义Axes
类,其中每个轴(左,下,上和右)由单独的艺术家管理。 由于ax.axis
的作用类似于字典,因此ax.axis["left"]
,ax.axis["bottom"]
,ax.axis["top"]
和ax.axis["right"]
可以访问它们。 我们还可以根据需要定义其他轴。
了解axisartist
中的属性
在本秘籍中,我们将学习如何使用AxisArtist
的基本属性和属性,例如固定轴,浮动轴,标签和刻度。 在本秘籍中,我们将不会使用这些属性绘制任何图形。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import mpl_toolkits.axisartist as AxisArtist
操作步骤
以下是绘制所需图形的步骤:
- 定义图形和
AxisArtist
参数,然后将其添加到图形中,如下所示:
fig = plt.figure()
ax = AxisArtist.Axes(fig, [0.1, 0.1, 0.8, 0.8])
fig.add_axes(ax)
- 使用以下命令将上轴和右轴设置为不可见,然后设置轴的标签:
ax.axis["right", "top"].set_visible(False)
ax.set_xlabel("X Axis")
ax.axis["bottom"].label.set_rotation(30)
ax.set_ylabel("Y Axis")
- 在
y=1
处创建一个浮动轴,如下所示:
ax.axis["y=1"] = ax.new_floating_axis(nth_coord=0, value=1.0)
ax.axis["y=1"].label.set_text("floating X axis on top")
- 在
x=0.5
处创建另一个浮动轴,如下所示:
ax.axis["x=0.5"] = ax.new_floating_axis(nth_coord=1, value=0.5)
ax.axis["x=0.5"].set_axis_direction("top")
ax.axis["x=0.5"].label.set_text("floating Y axis in the middle")
- 使用以下命令在右侧创建一个固定轴:
ax.axis["right"] = ax.new_fixed_axis(loc="right", offset=(20, 20))
ax.axis["right"].set_axis_direction("bottom")
ax.axis["right"].label.set_text("fixed Y axis on right")
- 将颜色属性分配给所有轴的刻度线,刻度线标签和标签属性,如下所示:
ax.axis["left", "bottom"].major_ticks.set_color("darkblue")
ax.axis["left", "bottom"].major_ticklabels.set_color("darkblue")
ax.axis["left", "bottom"].label.set_color("darkblue")
ax.axis["right", "y=1"].major_ticks.set_color("green")
ax.axis["right", "y=1"].major_ticklabels.set_color("green")
ax.axis["right", "y=1"].label.set_color("green")
- 如下设置刻度线对齐,填充和 x 和 y 轴限制:
ax.axis[:].major_ticks.set_tick_out(True)
ax.axis[:].label.set_pad(10)
ax.set_xlim(0,2)
ax.set_ylim(-1,2)
- 通过以下命令设置轴
y=1
的属性:
ax.axis["x=0.5"].toggle(all=False, label=True)
ax.axis["x=0.5"].label.set_color("red")
- 设置图形的标题(在这里,我们使用了
AxisArtist Demo
),最后,在屏幕上显示图形,如下所示:
ax.set_title('AxisArtist Demo', pad=50, loc='right')
plt.show()
工作原理
这是前面代码的解释:
fig = plt.figure()
定义图形对象。ax = AxisArtist.Axes(fig, [0.1, 0.1, 0.8, 0.8])
定义AxisArtist
类在给定坐标处的轴,分别从左侧开始,一直到底部,宽度和高度。fig.add_axes(ax)
将轴域对象添加到图形中。ax.axis["right", "top"].set_visible(False)
将上轴和右轴(脊)设置为不可见。 您也可以分别为每个轴设置此设置。ax.set_xlabel("X Axis")
将 x 轴的标签设置为"X Axis"
。ax.axis["bottom"].label.set_rotation(30)
将 x 轴标签逆时针旋转 30 度。ax.set_ylabel("Y Axis")
将 y 轴标签的标签设置为"Y Axis"
。ax.axis["y=1"] = ax.new_floating_axis(nth_coord=0, value=1.0)
定义了一个新轴,如下所示:- 浮动轴的位置会随着在 x 或 y 轴上设置的限制而变化,因为它是在数据坐标系中以轴的固定值创建的。
nth_coord
指定新轴是与 x 还是 y 轴对齐。 设置为 0 时,它平行于 x 轴; 如果为 1,则新轴将平行于 y 轴。value
参数指定轴上的值; 该新轴将被创建。 在这种情况下,由于value=1.0
参数在y=1
中创建了它。"y=1"
是为此新轴指定的名称,并用它保存在ax.axis
字典中。
ax.axis["y=1"].label.set_text("floating X axis on top")
设置新浮动轴的标签。ax.axis["x=0.5"] = ax.new_floating_axis(nth_coord=1, value=0.5)
会再创建一个浮动轴,如下所示:nth_coord=1
指定此新轴应平行于 Y 轴。value=0.5
指定应在x=0.5
处创建新的浮动轴。"x=0.5"
是为此新轴指定的名称。
ax.axis["x=0.5"].set_axis_direction("top")
指定应在轴的哪一侧显示刻度线,刻度标签和轴标签。top
表示它们都应位于轴的顶部或左侧,这取决于它是否平行于 x 或 y 轴。ax.axis["x=0.5"].label.set_text("floating Y axis in the middle")
设置新轴的标签。ax.axis["right"] = ax.new_fixed_axis(loc="right", offset=(20, 20))
创建如下固定轴:- 固定轴是位置固定的轴,因为它是相对于给定的轴/轴线以指定的偏移量创建的。
loc="right"
指定应在绘图的右侧创建新轴。offset=(20, 20)
指定距默认右轴的磅数偏移(1 点 = 1/72 英寸),在这种情况下,该偏移量将变为不可见。 它在 x 轴(底部)上方 20 个点,在默认右轴的右侧 20 个点。
ax.axis["right"].set_axis_direction("bottom")
指定刻度,刻度标签和轴标签应绘制在新轴的右侧(或当轴平行于 x 轴时显示在底部)。ax.axis["right"].label.set_text("fixed Y axis on right")
设置新轴的标签。ax.axis["left", "bottom"].major_ticks.set_color("darkblue")
为左侧(y)和底部(x)轴的主要刻度设置深蓝色。ax.axis["left", "bottom"].major_ticklabels.set_color("darkblue")
将深蓝色设置为刻度标签的颜色。ax.axis["left", "bottom"].label.set_color("darkblue")
将深蓝色设置为轴标签的颜色。ax.axis["right", "y=1"].major_ticks.set_color("green")
为"right"
和"y=1"
轴的主要刻度线设置绿色。ax.axis["right", "y=1"].major_ticklabels.set_color("green")
为刻度标签设置绿色。ax.axis["right", "y=1"].label.set_color("green")
为轴标签设置绿色。ax.axis[:].major_ticks.set_tick_out(True)
在刻度标签的同一侧设置刻度。 默认情况下,在axisartist
类中,刻度和刻度标签位于轴的相对侧。 应当注意,默认情况下,在 Matplotlib 主轴域中,类,刻度和刻度标签被绘制在该轴的同一侧。axis[:]
包含字典中的所有元素,这意味着所有轴-默认情况下为四个轴和三个新添加的轴。 当然,"top"
和"right"
默认轴设置为"invisible"
状态,因此您看不到它们的刻度和刻度标签! 因此,此函数仅适用于所有可见轴。ax.axis[:].label.set_pad(10)
再次针对所有可见轴在轴及其标签之间添加填充(以便没有重叠)。ax.set_xlim(0,2)
设置 x 轴的最小和最大限制。ax.set_ylim(-1,2)
设置 y 轴的最小和最大限制。ax.axis["x=0.5"].toggle(all=False, label=True)
使刻度和刻度标签不可见,而轴x=0.5
的轴标签可见:all=False
使刻度,刻度标签和轴标签均不可见。 您也可以一次更改刻度,刻度标签和标签的设置,而不是一次全部更改。label=True
使轴标签可见。- 我们为
set_axis_direction
参数使用默认选项,即底部(与 y 轴平行的轴的右侧)。
ax.axis["x=0.5"].label.set_color("red")
为轴x=0.5
的轴标签设置红色。plt.show()
在屏幕上显示图形。
执行上述代码后,您应该在屏幕上看到以下示意图:
新的浮动轴和固定轴的刻度与相应的主轴域的 x或 y 轴刻度相同。 Matplotlib 当前不为这些新轴中的每一个支持不同的比例。 Matplotlib 3.0 版有望消除此限制。
在矩形框中定义曲线网格
在本秘籍中,我们将学习如何在使用笛卡尔坐标系的矩形轴域内创建具有自己的坐标系的曲线网格。 我们将在曲线坐标表示的两个点之间绘制一条简单的线形图。
这本质上是一个自定义开发的曲线坐标系,为此,我们必须定义从曲线坐标到笛卡尔坐标并以相反方向映射的函数。 在后续秘籍中,我们将学习axistartist
类提供的预定义转换。
准备
您需要使用以下或命令导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axisartist import Subplot
from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear
操作步骤
以下是绘制所需图形的步骤:
- 首先,将图形定义如下:
fig = plt.figure(1, figsize=(7, 4))
- 接下来,定义转换函数以将曲线坐标转换为直线坐标:
## Transformation Function to convert curvilinear coordinates to rectilinear coordinates
def curv2rect_tr(x, y):
x, y = np.asarray(x), np.asarray(y)
return x, y - x
- 定义转换函数以将直线坐标转换为曲线坐标:
## Transformation Function to convert rectilinear coordinates to curvilinear coordinates
def rect2curv_tr(x, y):
x, y = np.asarray(x), np.asarray(y)
return x, y + x
- 定义
grid_helper
函数,该函数负责在具有直线坐标的矩形轴域上绘制具有曲线坐标的网格线。 它以变换函数为输入,并使用它们绘制网格线:
grid_helper = GridHelperCurveLinear((curv2rect_tr, rect2curv_tr))
- 使用上一步中定义的网格助手函数来定义轴域:
ax = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
- 将刚刚定义的轴域添加到图中:
fig.add_subplot(ax)
- 在曲线坐标中定义两个点,并将它们转换为等效的直线坐标:
x, y = curv2rect_tr([2.0, 8.0], [4.0, 16.0])
- 使用直线坐标绘制线形图,如下所示:
ax.plot(x, y, linewidth=2.0, color='g')
- 设置长宽比和 x 和 y 轴限制的值:
ax.set_aspect(1.)
ax.set_xlim(0, 15.)
ax.set_ylim(0, 15.)
- 使用浮动轴方法在曲线坐标中创建 x 和 y 轴,如下所示:
ax.axis["y"] = ax.new_floating_axis(nth_coord=0, value=4.0)
ax.axis["y"].set_ticklabel_direction('+')
ax.axis["x"] = ax.new_floating_axis(1, 9.0)
ax.axis["x"].set_ticklabel_direction('-')
- 打开背景网格:
ax.grid(True, zorder=0)
- 打印点
A
,B
,C
和D
代表 x 和 y 轴,曲线坐标中的点绘制为折线图:
ax.text(-1.5, 8.5, 'A', size=25, weight=50, color='b')
ax.text(8.5, -1.5, 'B', size=25, weight=50, color='b')
ax.text(3.5, -1.5, 'C', size=25, weight=50, color='b')
ax.text(3.5, 15, 'D', size=25, weight=50, color='b')
ax.text(2.0, 1.5, '(2.0, 4.0)', weight='bold', color='b')
ax.text(7.5, 8.5, '(8.0, 16.0)', weight='bold', color='b')
- 最后,使用以下命令在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
def curv2rect_tr(x, y)
定义了将曲线坐标转换为直线坐标的函数。 它在新坐标中保留 x,但直线坐标中的 y 定义为y-x
:x, y = np.asarray(x), np.asarray(y)
将输入参数x
和y
重新定义为 NumPy 数组。- 将曲线坐标映射到直线坐标,直线系统的
x = x
(两个系统中的值相同),直线系统中的y
等于曲线系统中的y-x
。
def rect2curv_tr(x, y)
定义将直线坐标转换为曲线坐标的函数。 它是curv2rect
函数的反函数。grid_helper = GridHelperCurveLinear((curv2rect_tr, rect2curv_tr))
定义了一个辅助函数,它使用作为参数提供的转换函数在两个方向上绘制网格线。 因此,将使用新的浮动轴沿这些网格线设置其轴域。ax = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
将轴域定义为子图,如下所示:fig
是开头定义的图形对象。1,1,1
与plt.subplot()
表示法相似,并指定它是1 x 1
网格内的第一个轴域。- 将先前定义的
grid_helper
作为参数。
fig.add_subplot(ax)
将轴域添加到图形中。x, y = curv2rect_tr([2.0, 8.0], [4.0, 16.0])
在曲线坐标中获取(2.0, 4.0)
和(8.0, 16,0)
点,并将其转换为等效的直线坐标,分别为(2.0, 2.0)
和(8.0, 8.0)
。ax.plot(x, y, linewidth=2.0, color='g')
绘制线宽为 2.0 点的绿色线形图。ax.set_aspect(1.)
将长宽比设置为 1,这意味着 x 和 y 轴数据标尺都相等。ax.set_xlim(0, 15.)
设置 x 轴的最小和最大限制,ax.set_ylim(0, 15.)
设置 y 轴的限制。ax.axis["0"] = ax.new_floating_axis(nth_coord=0, value=4.0)
在曲线坐标中为第一个坐标定义浮动轴,该坐标以 4.0 的值切割网格线。 在轴字典中将其命名为"0"
轴。 该线由图中以蓝色突出显示的点 C 和 D 表示。ax.axis["0"].set_ticklabel_direction('+')
指定刻度线标签应沿该轴的值递增方向放置在该轴的右侧。 如果为'-'
,则它们将放置在轴的左侧。 但是,默认情况下,刻度线的位置与刻度线标签的方向相反。ax.axis["1"] = ax.new_floating_axis(1, 9.0)
定义第二条浮动轴,该第二条浮动轴在 X 轴上的值为 9.0。 在轴字典中将其命名为"1"
。 该线在图中由以蓝色突出显示的点 A 和 B 表示。ax.axis["1"].set_ticklabel_direction('-')
指定刻度标签应按递增顺序放置在轴的左侧。 在这种情况下,轴向下(从 0 到 8)增加,因此该方向的左侧在直线上方! 因此,刻度线标签位于行上方,而刻度线则位于行下方。ax.grid(True)
显示网格线。ax.text(-1.5, 8.5, 'A', size=25, weight=50, color='b')
绘制蓝色的点“ A”,大小为 25,权重为 50。类似地,B,C 和 D 点以及(2.0, 4.0)
和(8.0, 16)
坐标,用这些指定的属性绘制。plt.show()
在屏幕上显示图形。
执行上述代码后,您应该在屏幕上看到以下示意图:
在矩形框中定义极坐标轴域
在前面的秘籍中,我们学习了定义自定义变换,并使用它来绘制曲线坐标中的曲线网格线。 但是,它们都使用 x,y 坐标的笛卡尔坐标系。 在本秘籍中,我们将学习如何在矩形框中使用极坐标(角度和半径坐标)。 在本秘籍以及所有后续秘籍中,我们将使用 Matplotlib 提供的预构建转换。
准备
您需要使用以下或命令导入必需的库:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear
import mpl_toolkits.axisartist.angle_helper as angle_helper
from matplotlib.projections import PolarAxes
from matplotlib.transforms import Affine2D
from mpl_toolkits.axisartist import SubplotHost, ParasiteAxesAuxTrans
import matplotlib.cbook as cbook
操作步骤
以下是绘制图形所需的步骤:
- 如下定义图:
fig = plt.figure(1, figsize=(7, 4))
- 定义转换函数,如下所示:
## PolarAxes.PolarTransform needs angle units as radian. However, we # plot the coordinate system in degrees for easier visualization
curv2rect_tr = Affine2D().scale(np.pi/180., 1.) +
PolarAxes.PolarTransform()
- 计算角度和半径的边界值,以绘制网格线:
##(25, 25) is the number of steps it takes from minimum limit to
maximum limit for x and y
## number of grid lines(circular for radius, diagonal for angle) will
be influenced by these steps
extreme_finder = angle_helper.ExtremeFinderCycle(25, 25,
lon_cycle=360,
lat_cycle=None,
lon_minmax=None,
lat_minmax=(0, 50))
- 定义角度的网格定位器:
## Determine grid values appropriate for the coordinate (degree,
minute, second).
grid_locator1 = angle_helper.LocatorDMS(18)
- 定义角度的刻度格式器:
## Use an appropriate formatter to show angle values in degree,
minute and second format.
tick_formatter1 = angle_helper.FormatterDMS()
- 定义半径的网格定位器:
grid_locator2 = MaxNLocator(12)
- 定义绘制网格的网格助手:
grid_helper = GridHelperCurveLinear(curv2rect_tr,
extreme_finder=extreme_finder,
grid_locator1=grid_locator1,
tick_formatter1=tick_formatter1,
grid_locator2=grid_locator2)
- 使用前面定义的图形和网格帮助器定义主轴域:
ax = SubplotHost(fig, 1, 1, 1, grid_helper=grid_helper)
- 使用以下命令使右轴和上轴的刻度标签可见:
ax.axis["right", "top"].major_ticklabels.set_visible(True)
- 将角度刻度线映射到右轴,将半径刻度线映射到底轴,如下所示:
ax.axis["right"].get_helper().nth_coord_ticks = 0
ax.axis["bottom"].get_helper().nth_coord_ticks = 1
- 使用以下命令将主轴域添加到图中:
fig.add_subplot(ax)
- 定义一个从属轴域并将其附加到主轴域上:
axp = ParasiteAxesAuxTrans(ax, curv2rect_tr, "equal")
ax.parasites.append(axp)
- 在从属轴域上绘制折线图:
intp = cbook.simple_linear_interpolation
axp.plot(intp(np.array([0, 75, 180, 300]), 100), intp(np.array([9.,
12., 16, 21]), 100),
linewidth=2.0, color='g')
- 在折线图上标注起点和终点:
axp.text(0,7.5, '.', color='r', size=50)
axp.text(3,9.5, 'A(0,9)', color='b', weight='bold')
axp.text(295, 20.5, '.', color='r', size=50)
axp.text(300,21, 'B(300,21)', color='b', weight='bold')
- 设置主轴域的长宽比和 x 和 y 限制:
ax.set_aspect(1.0)
ax.set_xlim(-20, 22)
ax.set_ylim(-25, 20)
- 将网格选项设置为
True
以显示网格:
ax.grid(True)
- 最后,使用以下命令在屏幕上显示图形:
plt.show()
工作原理
以下是上述代码的说明:
curv2rect_tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()
定义主轴域和从属轴域之间的转换:PolarAxes.PolarTransform()
需要以弧度为单位的角度; 因此,我们添加scale(np.pi/180., 1.)
以方便度数和弧度之间的转换。Affine2D
是两个轴域之间的线性变换。
extreme_finder = angle_helper.ExtremeFinderCycle()
计算给定 X,Y 限制和此函数中设置的其他参数的角度和半径的边界值:(25, 25)
是从为 x 和 y 设置的最小和最大限制开始执行的步数。- 网格线的数量(半径为圆形,角度为对角线)将受这些步骤的影响。
lon_cycle=360
为角度设置一个周期限制。 由于我们需要极坐标轴域,因此我们将其设置为 360 度。lat_minmax=(0, 50)
设置半径的最小值和最大值。
grid_locator1 = angle_helper.LocatorDMS(30)
确定适合于角度坐标的网格值(度,分,秒):- 参数中的数字 30 指定应绘制 30 条网格线作为角度坐标,每条网格线将转换为 12 度(
360/30
)。 但是,您看到的网格线每 10 度绘制一次。 - 网格线取决于三组参数,并将决定平衡所有三组参数的网格线的最佳位置:
- 给定 x 和 y 限制。
- 赋予
extreme_finder
函数的各种参数。 - 在
grid_locator
中指定的参数。
- 参数中的数字 30 指定应绘制 30 条网格线作为角度坐标,每条网格线将转换为 12 度(
tick_formatter1 = angle_helper.FormatterDMS()
格式化角度刻度标签以显示度数。grid_locator2 = MaxNLocator(12)
确定半径的网格值。 数字 12 指定要在绘图上绘制的圆形网格的数量。 在这种情况下,我们在绘图上看到了 12 条网格线。 但是,根据其他参数集,这也可能略有不同。grid_helper = GridHelperCurveLinear()
绘制给定转换函数,网格定位器和格式器的网格线。ax = SubplotHost(fig, 1, 1, 1, grid_helper=grid_helper)
使用先前创建的图形和网格帮助器对象定义主轴域。ax.axis["right", "top"].major_ticklabels.set_visible(True)
使右和上轴刻度标签可见,默认情况下不可见。ax.axis["right"].get_helper().nth_coord_ticks = 0
将右轴映射到角度坐标。 在极坐标中,第一个(0)坐标是一个角度,第二个(1)坐标是半径。fig.add_subplot(ax)
将主轴域添加到图形中。axp = ParasiteAxesAuxTrans(ax, curv2rect_tr)
使用定义的转换函数在主轴域上定义极坐标的从属轴域。ax.parasites.append(axp)
将从属轴域添加到主轴域。intp = cbook.simple_linear_interpolation
表示将线性插值应用于要在从属轴域上绘制的数据。axp.plot()
将寄生轴域的四个点绘制为绿色的线形图,线宽为 2.0。 参数100
指定从起点到终点移动时要采取的增量数,以便沿轨迹平滑过渡。axp.text()
绘制红点并用折线起点和终点的坐标对其进行标注。ax.set_aspect(1.0)
设置 x 和 y 坐标之间的长宽比。ax.set_xlim(-20, 22)
和ax.set_ylim(-25, 20)
指定绘制图形和图表的 x 和 y 坐标的下限和上限。ax.grid(True, zorder=0)
设置网格线,zorder=0
指定在绘制任何其他艺术家之前应绘制网格线。 如果我们不设置此项,您将看到网格线与绿色线形图重叠,因为先绘制线形图,然后再绘制网格线! 为了避免这种重叠,我们为网格线的绘制函数设置了zorder=0
。
执行上述代码后,您应该在屏幕上看到以下示意图:
将浮动轴用于矩形图
在本秘籍中,我们将学习如何绘制浮动轴。 当我们必须设计一个复杂的仪表板应用时,这些功能很有用,在该应用中,我们可能必须以不同于标准水平或垂直方向的其他方向放置单个图形或绘图。
我们将绘制三个不同的图以演示浮动轴的各种功能。
准备
您需要使用以下或命令导入必需的库:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
操作步骤
以下是绘制所有三个图形所需的步骤:
- 如下定义图:
fig = plt.figure(1, figsize=(14, 6))
- 如下准备数据:
month_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
units_sold = [500, 600, 750, 900, 1100, 1050, 1000, 950, 800, 700,
550, 450]
- 定义转换函数,如下所示:
curv2rect_tr1 = Affine2D().scale(200, 1).rotate_deg(30)
- 如下定义网格助手函数:
grid_helper1 = floating_axes.GridHelperCurveLinear(curv2rect_tr1,
extremes=(0, 13, 0, 1400))
- 使用以下命令定义主轴域和从属轴域:
ax1 = floating_axes.FloatingSubplot(fig, 131,
grid_helper=grid_helper1)
fig.add_subplot(ax1)
axp1 = ax1.get_aux_axes(curv2rect_tr1)
- 使用以下参数绘制条形图:
bars = axp1.bar(month_num, units_sold)
for bar in bars:
height = bar.get_height()
axp1.text(bar.get_x() + bar.get_width()/2., 1.002*height,'%d' %
int(height),
ha='center', va='bottom', rotation=30)
- 将刻度线设置为与网格线正确对齐,并指定标题,如下所示:
grid_helper1.grid_finder.grid_locator1._nbins = 14 # X axis ticks
grid_helper1.grid_finder.grid_locator2._nbins = 5 # Y axis ticks
axp1.text(5, 1800, 'bar plot', rotation=30, size=15, weight='bold',
color='b')
- 对箱形图重复上述所有步骤,如下所示:
## Read data
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
data = [wine_quality['alcohol'], wine_quality['fixed acidity'], wine_quality['quality']]
## Define transformation function
curv2rect_tr2 = Affine2D().scale(4, 1).rotate_deg(-30)
## Define grid helper function
grid_helper2 = floating_axes.GridHelperCurveLinear(curv2rect_tr2, extremes=(0, 4, 0, 20))
## Define main axes
ax2 = floating_axes.FloatingSubplot(fig, 132, grid_helper=grid_helper2)
fig.add_subplot(ax2)
## Define parasite axes
axp2 = ax2.get_aux_axes(curv2rect_tr2)
## Plot boxplot
axp2.boxplot(data)
## Set the tick and grid lines
grid_helper2.grid_finder.grid_locator1._nbins = 4
grid_helper2.grid_finder.grid_locator2._nbins = 5
## Set title and labels
axp2.text(1, 21, 'box plot', rotation=-30, size=15, weight='bold', color='b')
ax2.axis["bottom"].label.set_text('X axis')
ax2.axis["bottom"].label.set_color('blue')
ax2.axis["left"].label.set_text('Y axis')
ax2.axis["left"].label.set_color('red')
- 同样,对正弦/余弦函数作图重复相同的步骤,如以下代码块所示:
## Prepare data, define transformation and grid helper functions,
main axes
x = np.linspace(0, 10, 100)
curv2rect_tr3 = Affine2D().scale(1, 1).rotate_deg(10)
grid_helper3 = floating_axes.GridHelperCurveLinear(curv2rect_tr3, extremes=(0, 10, -5, 5))
ax3 = floating_axes.FloatingSubplot(fig, 133, grid_helper=grid_helper3)
fig.add_subplot(ax3)
## Define parasite axes, plot sine and cosine graphs, set title,
legend and grid
axp3 = ax3.get_aux_axes(curv2rect_tr3)
axp3.plot(x, 5*np.sin(x), label='sine')
axp3.plot(x, 5*np.cos(x), label='cosine')
ax3.legend(bbox_to_anchor=(0.35, 0., 1.05, 1.0), borderaxespad=0)
ax3.set_title('Sine/Cosine waves')
ax3.grid()
grid_helper3.grid_finder.grid_locator1._nbins = 5
grid_helper3.grid_finder.grid_locator2._nbins = 5
## Set labels, ticks and ticklabel attributes
ax3.axis["bottom"].label.set_text('X axis')
ax3.axis["bottom"].label.set_color('green')
ax3.axis["bottom"].major_ticks.set_color("green")
ax3.axis["bottom"].major_ticklabels.set_color("green")
ax3.axis["left"].label.set_text('Y axis')
ax3.axis["left"].label.set_color('red')
ax3.axis["left"].major_ticks.set_color("red")
ax3.axis["left"].major_ticklabels.set_color("red")
ax3.axis["bottom", "left"].major_ticks.set_tick_out(True)
ax3.axis["top", "right"].major_ticks.set_visible(False)
- 使用以下命令设置图形的标题,并调整图形之间的间距:
plt.suptitle('Floating Axes Demo',size=20, weight='bold', color='g')
plt.tight_layout()
plt.show()
工作原理
这是前面代码的解释:
curv2rect_tr1 = Affine2D().scale(200, 1).rotate_deg(30)
是转换函数,其工作原理如下:Affine2D
是线性变换。scale(200,1)
指定 x 和 y 轴之间的数据刻度。 这需要根据要在 x 和 y 轴域上绘制的数据范围进行设置。rotate_deg(30)
指定将绘图逆时针旋转 30 度。
grid_helper1 = floating_axes.GridHelperCurveLinear(curv2rect_tr1, extremes=(0, 13, 0, 1400))
定义网格线如下:curv2rect_tr1
是之前定义的转换函数。extremes=(0,13,0,1400)
定义 x 和 y 轴的上下限。 在此, x 轴的范围是 0 到 13, y 轴的范围是 0 到 1,400。 注意两个范围之间的差距! 这就是为什么我们在转换函数中为比例设置(200, 1)
的原因。
ax1 = floating_axes.FloatingSubplot(fig, 131, grid_helper=grid_helper1)
定义主轴域如下:131
表示它是三个图的1 x 3
网格中的第一个图。
fig.add_subplot(ax1)
将主轴域添加到图形中。axp1 = ax1.get_aux_axes(curv2rect_tr1)
定义条形图的从属轴域。bars = axp1.bar(month_num, units_sold)
在从属轴域上绘制条形图。for bar in bars
在每个小节上打印带有单位数量的文本。 这与我们先前学到的相同,增加了rotation=30
,以使文本沿与浮动轴相同的角度定向。grid_helper1.grid_finder.grid_locator1._nbins = 14
定义 x 轴的刻度数。grid_helper1.grid_finder.grid_locator2._nbins = 5
定义 y 轴的刻度数。axp1.text(5, 1800, 'bar plot', rotation=30, size=15, weight='bold', color='b')
绘制条形图的标题。 通常的set_title()
方法在这里不起作用,因此我们使用text
选项!curv2rect_tr2 = Affine2D().scale(4, 1).rotate_deg(-30)
定义要在不同轴域上绘制的箱形图的变换函数,如下所示:- 在此,我们基于此图的 x 和 y 轴的数据使用
scale(4,1)
。 - 我们使用
rotate_deg(-30)
规定绘图的顺时针旋转 30 度。
- 在此,我们基于此图的 x 和 y 轴的数据使用
grid_helper2 = floating_axes.GridHelperCurveLinear(curv2rect_tr2, extremes=(0, 4, 0, 20))
定义了箱形图的网格助手函数:extremes=(0, 4, 0, 20)
指定 x 和 y 轴的上下限。
ax2 = floating_axes.FloatingSubplot(fig, 132, grid_helper=grid_helper2)
定义用于绘制箱形图的第二个轴域:132
指定它是1 x 3
绘图网格上的第二个绘图。grid_helper=grid_helper2
指定用于该绘图的网格助手函数。
axp2 = ax2.get_aux_axes(curv2rect_tr2)
定义用于箱形图的从属轴域。axp2.boxplot(data)
在从属轴域上绘制箱形图。grid_helper2.grid_finder.grid_locator1._nbins = 4
设置 x 轴的刻度数。grid_helper2.grid_finder.grid_locator2._nbins = 5
设置 y 轴的刻度数。axp2.text(1, 21, 'box plot', rotation=-30, size=15, weight='bold', color='b')
打印与轴的 30 度方向对齐的箱形图的标题。x = np.linspace(0, 10, 100)
是绘制正弦波和余弦波的数据,作为该图中的第三幅图。curv2rect_tr3 = Affine2D().scale(1, 1).rotate_deg(10)
为第三个图定义了比例为 1:1 且方向为 10 度的变换函数。grid_helper3 = floating_axes.GridHelperCurveLinear(curv2rect_tr3, extremes=(0, 10, -5, 5))
定义了第三幅图的网格函数, x 限制为 0 到 10, y 限制为 -5 到 +5。ax3 = floating_axes.FloatingSubplot(fig, 133, grid_helper=grid_helper3)
定义了第三幅图的第三主轴域,其中133
指定它是图中1 x 3
幅图网格上的第三幅图。axp3 = ax3.get_aux_axes(curv2rect_tr3)
定义了第三幅图的从属轴域。axp3.plot(x, 5*np.sin(x), label='sine')
在从属轴域上绘制正弦波。axp3.plot(x, 5*np.cos(x), label='cosine')
在相同的从属轴域上绘制余弦波。ax3.legend(bbox_to_anchor=(0.35, 0., 1.05, 1.0), borderaxespad=0)
设置图例,但未与轴的方向对齐。ax3.set_title('Sine/Cosine waves')
会再次打印标题,但不会正确对齐,因此最好使用text
方法,就像我们对前两个图所做的那样。ax3.grid()
绘制网格线。 这些将与轴的方向正确对齐,因为它们由网格辅助函数参数控制并指定了nbins
参数。grid_helper3.grid_finder.grid_locator1._nbins = 5
指定 x 轴上刻度线/网格线的数量。grid_helper3.grid_finder.grid_locator2._nbins = 5
指定 y 轴上刻度线/网格线的数量。plt.suptitle('Floating Axes Demo',size=20, weight='bold', color='g')
打印整个图形的标题。
执行上述代码后,您应该在屏幕上看到以下示意图:
使用浮动轴创建极坐标轴域
在第 2 章(基本绘图入门)中,我们学习了如何在定义轴域的同时使用pyplot
的projection='polar'
选项绘制极坐标图。 在本秘籍中,我们将学习如何使用浮动轴绘制极坐标图。
准备
您需要使用以下或命令导入必需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist.grid_finder import (FixedLocator, MaxNLocator, DictFormatter)
操作步骤
以下是绘制绘图所需的步骤:
- 如下定义图:
fig = plt.figure(1, figsize=(8, 4))
- 定义转换函数,如下所示:
curv2rect_tr = PolarAxes.PolarTransform()
- 如下定义角度坐标的自定义刻度字典:
pi = np.pi
angle_ticks = [(0, r"$0$"), (.25*pi, r"$\frac{1}{4}\pi$"),
(.5*pi, r"$\frac{1}{2}\pi$"), (.75*pi, r"$\frac{3}
{4}\pi$"),
( pi, r"$\pi$"), (1.25*pi, r"$1.25\pi$"),
(1.5*pi, r"$1.5\pi$"), (1.75*pi, r"$1.75\pi$")]
- 根据角度和半径坐标为定义网格定位器和格式器:
grid_locator1 = FixedLocator([value for value, string in
angle_ticks])
tick_formatter1 = DictFormatter(dict(angle_ticks))
grid_locator2 = MaxNLocator(5)
- 定义网格助手函数,如下所示:
grid_helper = floating_axes.GridHelperCurveLinear(curv2rect_tr,
extremes=(2*pi, 0, 5, 0),
grid_locator1=grid_locator1,
grid_locator2=grid_locator2,
tick_formatter1=tick_formatter1,
tick_formatter2=None)
- 定义主轴域和从属轴域:
main_axes = floating_axes.FloatingSubplot(fig, 111,
grid_helper=grid_helper)
fig.add_subplot(main_axes)
parasite_ax = main_axes.get_aux_axes(curv2rect_tr)
- 接下来,在从属轴域上绘制极坐标图:
theta = np.arange(0., 2., 1./180.)*np.pi
parasite_ax.fill(theta, 5*np.cos(8*theta), color=(0.8,0.0,0.9), hatch='//', alpha=0.5)
- 将网格设置为绘图的标题,标题,并在屏幕上显示图形:
main_axes.grid(True, zorder=0)
main_axes.set_title('Polar Plot using Floating Axes', weight='bold', color='b', pad=50)
plt.show()
工作原理
以下是上述代码的说明:
curv2rect_tr = PolarAxes.PolarTransform()
定义极坐标变换函数。angle_ticks
是用于角度坐标的刻度的字典,其中包含角度的值及其相应的文本表示形式。grid_locator1 = FixedLocator([value for value, string in angle_ticks])
为角度坐标定义了网格定位器。FixedLocator()
定义了字典指定的固定位置的刻度/网格位置。tick_formatter1 = DictFormatter(dict(angle_ticks))
格式化要显示的角度坐标值。grid_locator2 = MaxNLocator(5)
指定半径坐标的网格定位器。 数字5
表示在半径图上应该有 5 条网格线。grid_helper = floating_axes.GridHelperCurveLinear()
定义网格助手函数。 对于两个坐标,它以相反的顺序使用限制,即上限,然后是下限。 我们使用了(2*pi, 0, 5, 0)
,这意味着角度的上限为2 * pi
,下限为零。 同样,半径的上限为 5,下限为零。main_axes = floating_axes.FloatingSubplot(fig, 111, grid_helper=grid_helper)
定义主轴域。parasite_ax = main_axes.get_aux_axes(curv2rect_tr)
定义了从属轴域。parasite_ax.fill(theta, 5*np.cos(8*theta), color=(0.8,0.0,0.9), hatch='//', alpha=0.5)
使用填充方法和阴影线绘制极坐标图。color=(0.8,0.0,0.9)
是使用 RGB 通道组合的自定义颜色。main_axes.grid(True, zorder=0)
将网格线设置为可见。 网格线将在主图之前绘制,因此它们位于主图的背景中。
执行上述代码后,您应该在屏幕上看到以下示意图:
在浮动极坐标轴域上绘制行星系统数据
在本秘籍中,我们将学习有关使用浮动轴在极坐标中绘制行星系统数据的信息。 我们将绘制两个具有不同限制和属性的图表,以展示多种可能性。 我们没有学习任何新功能或代码,只是在实际应用中应用,我们在前面的秘籍中学习的功能。
准备
您需要使用以下或命令导入必需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import PolarAxes
import mpl_toolkits.axisartist.angle_helper as angle_helper
from mpl_toolkits.axisartist.grid_finder import MaxNLocator
操作步骤
以下是绘制两个图所需的步骤:
- 固定种子以确保数据的可重复性:
np.random.seed(19681211)
- 如下定义图:
fig = plt.figure(1, figsize=(12, 6))
- 定义转换函数,网格定位器和格式器,如下所示:
curv2rect_tr1 = Affine2D().translate(-85, 5).scale(np.pi/180., 1.) + PolarAxes.PolarTransform()
grid_locator1 = angle_helper.LocatorDMS(10)
tick_formatter1 = angle_helper.FormatterDMS()
grid_locator2 = MaxNLocator(4)
- 如下设置角度和半径坐标的限制:
## Specify angle coordinate limits in degrees
langle, uangle = 120., 225.
## Specify radial coordinate limits in '1000 km
lradius, uradius = 8, 16
- 定义网格助手函数:
grid_helper1 = floating_axes.GridHelperCurveLinear(curv2rect_tr1,
extremes=(langle, uangle, lradius, uradius),
grid_locator1=grid_locator1,
grid_locator2=grid_locator2,
tick_formatter1=tick_formatter1,
tick_formatter2=None)
- 定义主轴域并将其添加到图中,如下所示:
main_axes1 = floating_axes.FloatingSubplot(fig, 121, grid_helper=grid_helper1)
fig.add_subplot(main_axes1)
- 定义一个函数来设置轴的各种属性,如下所示:
def set_axis_attr(axes, leftlabel, toplabel):
axes.axis["bottom"].toggle(all=False) # by default all are visible, this makes them all invisible
axes.axis["right"].toggle(all=False) # by default ticks are visible, so this will make them invisible
axes.axis["left"].set_axis_direction("bottom")
axes.axis["left"].label.set(text=leftlabel, color='blue')
# by default label and ticklabels are invisible, this will make them visible
axes.axis["top"].toggle(all=True)
axes.axis["top"].set_axis_direction("bottom")
axes.axis["top"].major_ticklabels.set_axis_direction("top")
axes.axis["top"].label.set_axis_direction("top")
axes.axis["top"].label.set(text=toplabel, color='blue')
axes.axis[:].major_ticks.set_tick_out(True)
- 调用上一步中定义的函数:
set_axis_attr(main_axes1, "left axis", "top axis")
- 接下来,如下定义从属轴域:
parasite_axes1 = main_axes1.get_aux_axes(curv2rect_tr1)
- 在从属轴域上绘制散点图和折线图:
theta = np.random.randint(langle, uangle, 25) # in degrees
radius = np.random.randint(lradius, uradius, 25)
parasite_axes1.scatter(theta, radius)
parasite_axes1.plot([135, 165, 195, 225], [8, 10, 12, 16],
color='r')
- 使用以下命令设置显示的网格线:
main_axes1.grid(True, zorder=0)
- 对第二个图重复步骤 2 到 10,为您提供以下内容:
curv2rect_tr2 = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()
grid_locator3 = angle_helper.LocatorHMS(10)
tick_formatter3 = angle_helper.FormatterHMS()
grid_locator4 = MaxNLocator(5)
langle, uangle = 0., 135.
lradius, uradius = 0, 25
grid_helper2 = floating_axes.GridHelperCurveLinear(curv2rect_tr2,
extremes=(langle, uangle, lradius, uradius),
grid_locator1=grid_locator3,
grid_locator2=grid_locator4,
tick_formatter1=tick_formatter3,
tick_formatter2=None)
main_axes2 = floating_axes.FloatingSubplot(fig, 122, grid_helper=grid_helper2)
fig.add_subplot(main_axes2)
set_axis_attr(main_axes2, "Radius('1000KM)", "Angle(HMS)")
parasite_axes2 = main_axes2.get_aux_axes(curv2rect_tr2)
theta = np.random.randint(langle, uangle, 25) # in degrees
radius = np.random.randint(lradius, uradius, 25)
parasite_axes2.scatter(theta, radius)
parasite_axes2.plot([0, 45, 90, 135], [5, 15, 20, 25], color='r')
main_axes2.grid(True, zorder=0)
- 最后,设置图形的标题,并使用以下命令在屏幕上显示图形:
plt.suptitle('Planetary System Plots',size=20, weight='bold',
color='g')
plt.show()
工作原理
由于本秘籍中未引入任何新功能或语法,因此在此不再重复代码说明。 所有这些语句和功能已经在本章的早期秘籍中进行了说明。
唯一的区别是,与第一幅图相比,我们为第二幅图使用了不同的网格定位器和格式化程序。 第一个遵循度,分钟和秒(DMS)格式,而第二个遵循小时,分钟和秒(HMS)格式。 在两个图的上轴刻度标签中都可以看到相同的内容。
运行上述代码后,您应该在屏幕上看到以下图表:
十二、使用axes_grid1
工具包
在本章中,我们将学习axes_grid1
工具包的功能。 我们将介绍以下秘籍:
- 使用
axisartst
和axesgrid1
工具包绘制双生轴域 - 使用
AxesDivider
绘制散点图和相关的直方图 - 使用
AxesDivider
绘制颜色条 - 使用
ImageGrid
在网格中用颜色条绘制图像 - 使用
inset_locator
放大图像 - 使用
inset_locator
绘制插入轴域
介绍
axes_grid1
工具包旨在提供一组帮助器类,以在网格中绘制带有颜色条的图像,并根据图像大小正确对齐颜色条。 它可用于放大图像的一部分,绘制插入轴域(类似于图片中的图片),绘制二维图和两个变量,从属轴域和锚定艺术家中每个变量的关联直方图。
使用axisartist
和axesgrid1
工具箱绘制双生轴域
在第 4 章和“开发可视化来提高发布质量”中,我们学习了如何使用双生轴域方法在图的左右轴域上绘制两个不同的比例尺。 在第 9 章和“开发交互式绘图”中,我们学习了如何在 y 轴域上绘制不同的测量单位,并再次使用twinx
方法进行交互式分析 。 在本秘籍中,我们将学习如何使用 Matplotlib twinx
主方法以及axisartist
和axes_grid1
工具包在 y 轴域上绘制多个比例尺。
准备
我们将首先使用 Matplotlib twinx()
方法绘制图形。 然后,在“更多”部分中,我们将使用axisartist
和axes_grid1
工具包再次绘制图形。
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
操作步骤
以下是绘制双生轴域图所需的步骤:
- 定义图形和主轴域(左侧为
ax1
, y 轴),如下所示:
fig, ax1 = plt.subplots(1,1)
- 定义双生轴域(右侧为
ax2
, y 轴,右侧为ax3
,另一 y 轴):
ax2 = ax1.twinx()
ax3 = ax1.twinx()
- 放置
ax3
使其不与ax2
右侧轴域重叠:
ax3.spines["right"].set_position(("axes", 1.15))
- 准备数据并在主轴域
ax1
上绘制产品缺陷条形图:
x = [0, 1, 2, 3, 4, 5]
y = [19, 12, 6, 4, 3, 2]
b = ax1.bar(x, y, label='Number of Defects')
- 在右轴域
ax2
上的折线图中准备数据并按百分比绘制累积缺陷:
y = [41, 67, 80, 89, 96, 100]
l, = ax2.plot(x, y, color='g', lw=5, label='Cumulative Defects as %')
- 准备数据并在第二个右轴域
ax3
上绘制累积的缺陷计数折线图:
y = [19, 31, 37, 41, 44, 46]
l1, = ax3.plot(x, y, color='m', lw=5, label='Cumulative Defects
Count')
- 定义步长为
2
的主定位器,并将其应用于主轴域ax1
的 y 轴:
majorLocator = MultipleLocator(2)
ax1.yaxis.set_major_locator(majorLocator)
- 使用以下代码设置 x 和 y 标签以及所有轴域的限制:
ax1.set(xlabel='Defect Reason Codes', ylabel='Number of Defects')
ax2.set(ylabel='Cumulative Defects as %')
ax3.set_ylim(15,50)
ax3.set_ylabel('Cumulative Defects Count', labelpad=10)
- 如下设置主轴域的图例和标题:
graphs = [b, l, l1]
ax1.legend(graphs, [g.get_label() for g in graphs], loc=5)
ax1.set_title('Product Defects - August 2018')
- 设置标签的颜色:
ax1.yaxis.label.set_color(b.patches[0].get_facecolor())
ax2.yaxis.label.set_color(l.get_color())
ax3.yaxis.label.set_color(l1.get_color())
- 设置两个右轴的颜色,如下所示:
ax2.spines["right"].set_edgecolor(l.get_color())
ax3.spines["right"].set_edgecolor(l1.get_color())
- 设置刻度和刻度标签的颜色,如下所示:
ax1.tick_params(axis='y', colors=b.patches[0].get_facecolor())
ax2.tick_params(axis='y', colors=l.get_color())
ax3.tick_params(axis='y', colors=l1.get_color())
- 最后,使用以下命令在屏幕上显示图形:
plt.show()
工作原理
这是前面代码的解释:
-
ax2 = ax1.twinx()
和ax3 = ax1.twinx()
创建名为ax2
和ax3
的逻辑轴域,它们共享主轴域(ax1
)的 x 轴。 y 轴在右侧。 -
ax3.spines["right"].set_position(("axes", 1.15))
将第二个 y 轴向右移动主轴域宽度的 15%。 如果我们不这样做,则ax2
和ax3
的 y 轴将相互重叠,并在同一轴域上同时显示它们的刻度和刻度标签。 -
x = [0, 1, 2, 3, 4, 5]
是产品缺陷代码的列表,y = [19, 12, 6, 4, 3, 2]
是缺陷原因代码的列表。 -
b = ax1.bar(x, y, label='Number of Defects')
绘制了产品缺陷数量的条形图。 -
y1 = [41, 67, 80, 89, 96, 100]
是累积缺陷占总数百分比的列表。 -
l, = ax2.plot(x, y1, color='g', lw=5, label='Cumulative Defects as %')
将其绘制为线形图。 -
y2 = [19, 31, 37, 41, 44, 46]
是累积缺陷计数的列表。 -
l1, = ax3.plot(x, y2, color='m', lw=5, label='Cumulative Defects Count')
将其绘制为线形图。 -
majorLocator = MultipleLocator(2)
以2
的步长定义定位器,ax1.yaxis.set_major_locator(majorLocator)
将定位器应用于主轴域ax1
的 y 轴。 -
ax3.set_ylabel('Cumulative Defects Count', labelpad=10)
为最右边的轴设置 y 轴标签,而labelpad=10
指定该轴与其标签之间的间隙,以使标签不与该轴的刻度标签重叠。 -
ax1.legend(graphs, [g.get_label() for g in graphs], loc=5)
绘制图例如下:[g.get_label() for g in graphs]
获取在绘制图形时设置的每个图形的标签列表。loc=5
指定将图例绘制在轴的右侧。 有关放置图例的更多选项,请参考第 4 章和“开发可视化来提高发布质量”。
-
ax1.yaxis.label.set_color(b.patches[0].get_facecolor())
设置主轴域的 y 轴标签的颜色,如下所示:b.patches[0].get_facecolor()
获取条形图中第一个条的facecolor
值,b.patches[]
是另存为色块的条形容器。- 使用此命令,而不是显式设置颜色,我们将使用用于绘制图形的颜色并将其用于 y 轴标签。 始终使用相同的颜色。
-
ax2.yaxis.label.set_color(l.get_color())
和ax3.yaxis.label.set_color(l1.get_color())
获得线形图l
和l1
的颜色,并将它们应用于各自的标签。 -
ax2.spines["right"].set_edgecolor(l.get_color())
设置右轴的颜色,用于绘制线形图l
。 -
ax3.spines["right"].set_edgecolor(l1.get_color())
设置第二个右轴的颜色,用于绘制折线图l1
。 -
ax1.tick_params(axis='y', colors=b.patches[0].get_facecolor())
设置刻度和刻度标签的颜色。
执行上述代码后,您应该在屏幕上看到以下图形:
更多
现在,我们将使用axisartist
和axes_grid1
工具包绘制相同的图形。 遵循的步骤是相同的,因此在此我们将不描述每个步骤,而是将整个代码列出在一个块中。 此后,我们将解释这两种方法之间的主要区别。
这是使用axisartist
和axes_grid1
工具包绘制图形的完整代码块:
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import matplotlib.pyplot as plt
plt.figure()
ax1 = host_subplot(111, axes_class=AA.Axes)
ax1.axis["top"].toggle(all=False) # switch off ticks and ticklabels for
the top axis
ax2 = ax1.twinx()
ax3 = ax1.twinx()
new_fixed_axis = ax3.get_grid_helper().new_fixed_axis
ax3.axis["right"] = new_fixed_axis(loc="right", axes=ax3, offset=(60,
0))
ax2.axis["right"].toggle(all=True)
ax3.axis["right"].toggle(all=True)
ax1.set_xlabel('Defect Reason Codes')
ax1.set_ylabel('Number of Defects')
ax2.set_ylabel('Cumulative Defects as %')
ax3.set_ylabel('Cumulative Defects Count')
x = [0, 1, 2, 3, 4, 5]
y = [19, 12, 6, 4, 3, 2]
y1 = [41, 67, 80, 89, 96, 100]
y2 = [19, 31, 37, 41, 44, 46]
b = ax1.bar(x, y, label='Number of Defects')
l, = ax2.plot(x, y1, lw=5, label='Cumulative Defects as %', color='b')
l1, = ax3.plot(x, y2, lw=5, label='Cumulative Defects Count',
color='g')
ax3.set_ylim(15, 50)
ax1.legend(loc=5)
ax1.set_title('Product Defects - August 2018')
ax1.axis["left"].label.set_color(b.patches[0].get_facecolor())
ax2.axis["right"].label.set_color(l.get_color())
ax3.axis["right"].label.set_color(l1.get_color())
ax1.axis["left"].major_ticks.set_color(b.patches[0].get_facecolor())
ax2.axis["right"].major_ticks.set_color(l.get_color())
ax3.axis["right"].major_ticks.set_color(l1.get_color())
ax1.axis["left"].major_ticklabels.set_color(b.patches[0].get_facecolor())
ax2.axis["right"].major_ticklabels.set_color(l.get_color())
ax3.axis["right"].major_ticklabels.set_color(l1.get_color())
## setting the color for axis itself is not working in AA
ax2.spines["right"].set_color(l.get_color())
ax3.spines["right"].set_color(l1.get_color())
ax1.axis[:].major_ticks.set_tick_out(True)
ax2.axis[:].major_ticks.set_tick_out(True)
ax3.axis[:].major_ticks.set_tick_out(True)
plt.show()
这是两种方法之间主要区别的解释:
- 而不是使用
plt.subplots()
,这里我们使用ax1 = host_subplot(111, axes_class=AA.Axes)
,它是axes_grid1
工具包的辅助函数,它以axisartist
作为参数。 这意味着ax1
轴域获得host_subplot()
和axisartist
的属性。 ax2=ax1.twinx()
自动为其 y 轴映射ax1
的右脊。- 但是,对于
ax3
,我们将必须使用以下命令手动创建另一个右轴:new_fixed_axis = ax3.get_grid_helper().new_fixed_axis
。ax3.axis["right"] = new_fixed_axis(loc="right", axes=ax3, offset=(60, 0))
。offset=(60,0)
将轴向右推动60
点,0
指向顶部。
ax2.axis["right"].toggle(all=True)
将ax1
右脊的轴标签,刻度和刻度标签设置为可见。ax3.axis["right"].toggle(all=True)
将新创建的右轴的轴标签,刻度和刻度标签设置为可见。- 我们为标签,刻度和刻度标签设置各种属性的方式,与我们在第 12 章“使用
axisartist
工具包”中了解的方法相同。 - 但是,某些属性无法与原始轴类一起正常工作,因为
axisartist
不能继承原始轴类的所有属性。 - 当您使用交互式后端打开该图并放大图形的某些部分时,只有主轴域的 y 限制发生变化,而其他 y 轴的数据则发生变化。 右(从属轴域)与初始设置相同。 如果不使用
axes_grid1
和axisartist
来绘制先前的图形,情况并非如此,其中所有 y 轴限制都会更改以反映图形的当前部分。
执行前面的代码块后,您应该看到以下图形:
使用AxesDivider
绘制散点图和相关的直方图
在本秘籍中,我们将学习如何使用axes_grdi1
的AxesDivider
类在主轴域上绘制双变量图,并在主轴域的任意两侧绘制两个单变量图。 这有助于可视化两个变量之间的关系,以及同一图中两个变量的分布情况(尽管三个不同的轴域/曲线)。
从技术上讲,在主轴域上绘制的变量和在主轴域两侧上的单变量图可以不同。 您可以从主轴域的四个侧面中选择任意两个侧面以进行单变量图绘制。 但是,通常的做法是绘制在主轴域的顶部和右侧。
在此秘籍中,我们将在带有两个变量的主轴域上绘制散点图,并且在主轴域的顶部和右侧,将为散点图所使用的两个变量分别绘制直方图。
准备
让我们导入所需的库。 应当指出,我们不是直接导入AxesDiveder
; 相反,我们正在使用此类的帮助函数make_axes_locatable
。 您需要使用以下命令导入库:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import pandas as pd
操作步骤
以下是绘制图形所涉及的步骤:
- 使用以下命令加载我们先前已经使用的
Iris
数据集:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
x, y = iris['sepal_length'], iris['sepal_width']
- 如下定义图形和主轴域:
fig, axmain = plt.subplots(figsize=(8, 6))
- 使用 1 的长宽比在主轴域上绘制散点图
axmain.scatter(x, y)
axmain.set_aspect(1.)
- 定义轴域分割器,以使一个轴域位于主轴域的顶部,另一个轴域位于主轴域的右侧,如下所示:
divider = make_axes_locatable(axmain)
axtop = divider.append_axes("top", size=1.5, pad="15%",
sharex=axmain)
axright = divider.append_axes("right", "100%", 0.1, sharey=axmain)
- 使刻度标签对顶部轴域的 x 轴以及右轴域的 y 轴不可见,以使它们不与主轴域重叠:
axtop.xaxis.set_tick_params(labelbottom=False)
axright.yaxis.set_tick_params(labelleft=False)
- 在上下轴域上绘制直方图:
axtop.hist(x, bins=15)
axright.hist(y, bins=10, orientation='horizontal')
- 设置顶部轴域的
yticks
,和右侧轴域的xticks
:
axtop.set_yticks([0, 5, 10, 15, 20])
axright.set_xticks([0, 10, 20, 30, 40])
- 如下设置所有轴域的标签和标题:
axmain.set(xlabel='sepal length', ylabel='sepal width', title='iris
scatter plot')
axtop.set_title('sepal length', size=10)
axright.set_title('sepal width', size=10)
- 最后,使用以下命令在屏幕上显示图形:
plt.show()
工作原理
这是前面代码的解释:
- 您已经熟悉了前面的示例的前三个步骤。
divider = make_axes_locatable(axmain)
定义轴域分离器。 它实质上是定位给定轴域的边界。axtop = divider.append_axes("top", size=1.5, pad="15%", sharex=axmain)
在主轴域上方定义一个新轴域,如下所示:"top"
指定要在当前轴域之上绘制的新轴域。size=1.5
指定此新轴域的高度为 1.5 英寸,其宽度与主访问宽度相同。pad=15%
指定主轴域与顶部新轴域之间的间隙为主轴域高度的 15%。sharex=axmain
指定此新轴域应与主轴域共享 x 轴属性,例如轴标签,刻度和刻度标签
axright = divider.append_axes("right", "100%", 0.1, sharey=axmain)
在主轴域右侧定义了一个新轴域,如下所示:"right"
指定新轴域应绘制在主轴域的右侧。100%
指定新轴域的宽度与主轴域的宽度相同。 新轴域的高度也与主轴域的高度相同,因为它们都共享 y 轴。0.1
是主轴域和该新轴域之间的填充(以磅为单位)。sharey=axmain
指定此新轴域应与主轴域共享 y 轴属性,例如轴标签,刻度和刻度标签。
axtop.xaxis.set_tick_params(labelbottom=False)
使 x 轴标签对于上轴域不可见。axright.yaxis.set_tick_params(labelleft=False)
使 y 轴标签对于右轴域不可见。axtop.hist(x, bins=15)
在具有 15 个桶的顶轴域上绘制直方图。axright.hist(y, bins=10, orientation='horizontal')
使用水平条形图而不是默认垂直条形图在带有 10 个桶的右轴域上绘制直方图。- 其余的语句设置所有三个轴域的刻度,标签和标题。
运行代码后,您应该在屏幕上看到以下图形:
使用AxesDivider
绘制颜色条
在本秘籍中,我们将学习如何使用AxesDivider
绘制图像的颜色条,以确保其与图像正确对齐。 我们已经使用了pyplot.colorbar()
很多次,但有时颜色条超出了图像边界。 使用AxesDivider
和ImageGrid
,我们将不会看到此问题,如本秘籍所示。
我们将在三个轴域上绘制图像–一个使用不带AxesDivider
的常规pyplot.colorbar()
; 第二个使用AxesDivider
和右侧的垂直颜色条; 第三个再次使用AxesDivider
,但这一次在图像顶部带有水平色条。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd
操作步骤
以下是使用颜色条绘制图像所涉及的步骤:
- 将数据集加载到
winequality.csv
上,如下所示:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
corr_wine = wine_quality.corr()
- 使用以下命令定义该图:
fig = plt.figure(1, (16., 6.))
- 定义第一个子图,绘制图像和颜色条,并使用以下代码设置 x 和 y 刻度。
plt.subplot(131)
plt.imshow(corr_wine, cmap='plasma')
plt.colorbar()
plt.xticks(range(len(corr_wine)),corr_wine.columns, rotation=75)
plt.yticks(range(len(corr_wine)),corr_wine.columns)
- 使用以下代码,定义第二个子图,绘制图像,定义
AxesDivider
,在右侧绘制颜色条,然后设置 x 和 y 刻度。
ax2 = plt.subplot(132)
im1 = ax2.imshow(corr_wine, cmap='Blues')
ax2_divider = make_axes_locatable(ax2)
cax1 = ax2_divider.append_axes("right", size="7%", pad=0.03)
plt.colorbar(im1, cax=cax1)
ax2.set_xticks(range(len(corr_wine)))
ax2.set_xticklabels(corr_wine.columns, rotation=75)
ax2.set(yticks=range(len(corr_wine)), yticklabels=corr_wine.columns)
- 定义第三个子图,绘制图像,定义
AxesDivider
,在顶部绘制水平色条,然后按如下所示设置 x 和 y 刻度。
ax3 = plt.subplot(133)
im2 = ax3.imshow(corr_wine)
ax3_divider = make_axes_locatable(ax3)
cax2 = ax3_divider.append_axes("top", size="7%", pad="2%")
cb2 = plt.colorbar(im2, cax=cax2, orientation="horizontal")
cax2.xaxis.set_ticks_position("top")
ax3.set_xticks(range(len(corr_wine)))
ax3.set_xticklabels(corr_wine.columns, rotation=75)
ax3.set(yticks=range(len(corr_wine)), yticklabels=corr_wine.columns)
- 使用以下命令调整绘图之间的间隔:
plt.tight_layout(w_pad=-1)
7.最后,使用以下命令在屏幕上显示图形:
plt.show()
工作原理
这是前面代码的解释:
fig = plt.figure(1, (16., 6.))
将图 1 定义为16 x 6
英寸。plt.subplot(131)
定义1 x 3
网格上的第一个轴域。plt.imshow(corr_wine, cmap='plasma')
使用'plasma'
颜色表绘制相关图。plt.colorbar()
在其右侧绘制图像的颜色条。plt.xticks(range(len(corr_wine)),corr_wine.columns, rotation=75)
在75
度的倾斜度上绘制 x 轴刻度和带有属性名称的刻度标签。plt.yticks(range(len(corr_wine)),corr_wine.columns)
绘制 y 轴刻度和刻度标签,没有任何旋转。ax2 = plt.subplot(132)
在1 x 3
的网格上定义第二个轴域。im1 = ax2.imshow(corr_wine, cmap='Blues')
使用'Blues'
颜色表绘制相关图。ax2_divider = make_axes_locatable(ax2)
为第二个轴域定义AxesDivider
函数。cax1 = ax2_divider.append_axes("right", size="7%", pad=0.03)
使用AxesDivider
定义了颜色条的新轴域。"right"
指定将新轴域放置在ax2
的右侧。size="7"
指定新轴域的宽度应为ax2
宽度的 7%。pad=0.03
指定ax2
轴域和颜色条轴域之间的间隙应为ax2
宽度的 3%。plt.colorbar(im1, cax=cax1)
绘制ax2
右侧的颜色条,并带有给定的图像和颜色条轴域。ax2.set_xticks(range(len(corr_wine)))
将 x 轴刻度设置为输入数据中我们具有的属性数。ax2.set_xticklabels(corr_wine.columns, rotation=75)
设置带有属性名称和75
倾斜度的刻度标签。ax2.set(yticks=range(len(corr_wine)), yticklabels=corr_wine.columns)
设置 y 轴刻度和刻度标签,不旋转。ax3 = plt.subplot(133)
在1 x 3
的网格上定义第三个轴域。- 其余步骤与前面介绍的第二个图完全相同,除了颜色条以水平方向而不是默认垂直方向绘制在图像顶部。
plt.tight_layout(w_pad=-1)
调整绘图之间的间隔,以确保没有重叠。 负w_pad
值用于减小tight_layout()
使用的默认间隙。
运行上述代码后,您应该在屏幕上看到以下图形。 应该注意的是,在第一个图中,颜色条超出了图像的高度,而在第二个和第三个图中,它与图像的高度或宽度完全匹配,这是使用AxesDivider
的优点:
使用ImageGrid
在网格中使用颜色条绘制图像
在第 3 章,“绘制多个图形,子图形和图形”和第 6 章,“绘制高级功能”的过程中,我们学习了如何在网格上绘制具有多个网格选项的多个图。 当您尝试使用带有这些选项的网格上的颜色条来绘制图像时,颜色条对齐可能不是我们想要的方式。axes_grid1
工具包的ImageGrid
辅助函数可在网格中以正确对齐方式绘制带有颜色条的图像。 我们将在本秘籍中学习如何使用这些功能。
我们将在三个不同的图中连续绘制相同的相关图,但是使用网格的不同特征来演示大多数(如果不是全部)可用特征。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.pyplot import imread, imshow
from mpl_toolkits.axes_grid1 import ImageGrid
import pandas as pd
操作步骤
以下是绘制所需图形所涉及的步骤:
- 加载数据并创建具有相同相关矩阵的四个图像的列表,如下所示:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
corr_wine = wine_quality.corr()
images = []
images.append(corr_wine)
images.append(corr_wine)
images.append(corr_wine)
images.append(corr_wine)
- 定义大小为
12 x 8
英寸的图形:
fig = plt.figure(1, (12, 8.))
- 定义要在第一个轴域上绘制的
2 x 2
网格:
grid1 = ImageGrid(fig, 131, nrows_ncols=(2, 2), axes_pad=0.0,
label_mode="1")
- 如下设置 x 和 y 刻度和刻度标签:
grid1.axes_llc.set_xticks(range(len(corr_wine)))
grid1.axes_llc.set_xticklabels(corr_wine.columns, rotation=90)
grid1.axes_llc.set(yticks=range(len(corr_wine)),
yticklabels=corr_wine.columns)
- 在先前定义的
2 x 2
网格上绘制具有相同相关矩阵的四张图像,没有颜色条,:
for i in range(4):
gd = grid1[i].imshow(images[i], cmap='coolwarm')
- 定义另一个要在第二个轴域上绘制的
2 x 2
网格:
grid2 = ImageGrid(fig, 132, nrows_ncols=(2, 2), axes_pad=0.1, label_mode="L", cbar_location="top",
cbar_mode="single")
- 在先前定义的
2 x 2
网格上,用相同的相关矩阵在上绘制四个图像:
for i in range(4):
im = grid2[i].imshow(images[i])
grid2.cbar_axes[0].colorbar(im)
- 定义要在第三个轴域上绘制的第三个
2 x 2
网格:
grid3 = ImageGrid(fig, 133, nrows_ncols=(2, 2), axes_pad=(0.5, 0.3),
abel_mode="0",
cbar_location="right", cbar_mode="each",
cbar_size="10%", cbar_pad="3%")
- 在先前定义的
2 x 2
网格上绘制具有相同或相关矩阵的四个图像:
limits = ((-1, 1), (-1, 0), (0, 1.), (-0.5, 0.5))
for i in range(4):
im = grid3[i].imshow(images[i], interpolation="nearest",
vmin=limits[i][0], vmax=limits[i][1])
grid3.cbar_axes[i].colorbar(im)
grid3.cbar_axes[i].set_yticks((limits[i][0], limits[i][1]))
- 最后,使用以下命令在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
images = []
用空白初始化图像列表。images.append(corr_wine)
将corr_wine
相关矩阵附加到图像列表。 我们重复四次以创建要在2 x 2
网格上绘制的四个图像的列表。grid1 = ImageGrid(fig, 131, nrows_ncols=(2, 2), axes_pad=0.0, label_mode="1")
如下定义图像网格:fig
指定要在其上绘制网格的图形。131
指定它是一个1 x 3
的网格,并且这是第一个网格。nrows_ncols=(2,2)
将网格格式指定为2 x 2
。axes_pad=0.0
指定图像之间的间隔为零。label_mode="1"
指定应仅为网格的左下角图像打印刻度标签和轴标签。
grid1.axes_llc.set_xticks(range(len(corr_wine)))
设置 x 轴上的刻度线,其数量与相关矩阵中的变量数量一样多。grid1.axes_llc.set_xticklabels(corr_wine.columns, rotation=90)
在 x 轴上以90
度倾斜度打印带有变量名的刻度标签。grid1.axes_llc.set(yticks=range(len(corr_wine)), yticklabels=corr_wine.columns)
使用相同的变量名称为 y 轴打印刻度和刻度标签,无需旋转。for i in range(4):
是for
循环,可在四个网格中一张一张地绘制图像:gd = grid1[i].imshow(images[i], cmap='coolwarm')
使用coolwarm
色彩图绘制图像。
grid2 = ImageGrid()
使用以下参数定义第二个图像网格:fig
指定要绘制此网格的图形。132
指定它是另一个1 x 3
网格中的第二个网格。nrows_ncols=(2,2)
将网格格式指定为2 x 2
。axes_pad=0.1
将图像之间的间隙指定为 0.1 英寸。label_mode="L"
指定是要为左右图像绘制的标签,形成"L"
形状。cbar_location="top"
指定颜色条应绘制在图像顶部。cbar_mode="single"
指定只能在网格顶部绘制一个颜色条。
for i in range(4):
是用于在四个网格上一一绘制图像的for
循环:im = grid2[i].imshow(images[i], cmap='ocean')
使用'ocean'
颜色表绘制图像。
grid2.cbar_axes[0].colorbar(im)
打印颜色条。grid3 = ImageGrid()
定义第三个图像网格,其参数如下:fig
指定要绘制此网格的图形。133
指定它是另一个1 x 3
网格中的第三个网格。nrows_ncols=(2,2)
将网格格式指定为2 x 2
。axes_pad=(0.5,0.3)
将图像之间的间距指定为水平0.5
英寸和垂直0.3
英寸。label_mode="0"
,指定要为所有图像绘制标签。cbar_location="right"
指定应在图像的右侧绘制颜色条。cbar_mode="each"
指定应在网格中每个图像的右侧绘制颜色条。cbar_size="10%"
指定彩条宽度应为图像轴域宽度的10%
。cbar_pad="3%"
指定彩条和图像之间的距离为图像轴域宽度的 3%。limits = ((-1, 1), (-1, 0), (0, 1.), (-0.5, 0.5))
指定要应用于四个图像的每个颜色条的下限和上限,而不是绘制 -1 至 +1 的整个范围。
for i in range(4):
是用于在四个网格中一一绘制图像的for
循环:im = grid3[i].imshow(images[i], interpolation="nearest", vmin=limits[i][0], vmax=limits[i][1], cmap='ocean')
使用'ocean'
色彩图绘制图像。interpolation="nearest"
指定值超出指定限制的单元格将填充这些限制内的最近单元格值。vmin=limits[i][0]
指定给定i
图像(元组的第一项)的下限。vmax=limits[i][1]
指定给定i
图像(元组的第二个条目)的上限。grid3.cbar_axes[i].colorbar(im)
打印颜色条。grid3.cbar_axes[i].set_yticks((limits[i][0], limits[i][1]))
使用给定的限制设置 y 轴的刻度和刻度标签。
执行上述代码后,您应该在屏幕上看到以下图形:
使用inset_locator
放大图像
在第 6 章“带有高级功能的绘图”中,我们学习了如何使用 Matplotlib 的面向对象接口在主轴域内绘制插入轴域。 在本秘籍和下一篇秘籍中,我们将学习如何使用axes_grid1
工具包的inset_locator
助手函数创建插入轴域并绘制图像和其他图形。
在本秘籍中,我们将学习如何放大图像的一部分并将其显示在相同主轴域的插入轴域上。
我们将在两个轴域上绘制图像,并在每个图中放大图像的不同部分。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
操作步骤
这是绘制图形的必要步骤:
- 如下定义图形和两个轴域:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=[8, 4])
- 使用以下命令加载
winequality
数据并计算相关矩阵:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
corr_wine = wine_quality.corr()
- 创建一个带有零的扩展图像,并将相关矩阵插入其中:
extended_image = np.zeros([100, 100], dtype="d")
ny, nx = corr_wine.shape
extended_image[25:25 + ny, 25:25 + nx] = corr_wine
- 绘制具有给定范围的扩展图像,即 x 和 y 限制,如下所示:
extent = [-2, 2, -3, 1]
ax1.imshow(extended_image, extent=extent, interpolation="nearest",
origin="lower")
- 定义插入轴域,如下所示:
axins1 = zoomed_inset_axes(ax1, 3, loc=1)
- 在插入轴域上绘制扩展图像:
axins1.imshow(extended_image, extent=extent,
interpolation="nearest", origin="lower")
- 设置 x 和 y 轴的插入轴域数据限制,并指定要放大的相关矩阵部分:
axins1.set_xlim(-1.0, -0.5)
axins1.set_ylim(-2.0, -1.5)
- 使用以下给定值设置刻度线:
axins1.xaxis.get_major_locator().set_params(nbins=8)
axins1.yaxis.get_major_locator().set_params(nbins=8)
- 将插入轴域的刻度标签设置为在 x 和 y 轴上均不可见:
plt.xticks(visible=False)
plt.yticks(visible=False)
- 在选定要缩放的部分周围标记一个边界框,并使用线条将其与缩放的插入轴域连接:
mark_inset(ax1, axins1, loc1=2, loc2=4, fc="none", ec="b")
- 对第二个轴域重复执行步骤 4 至步骤 8 ,这将显示放大的图像较小的部分:
ax2.imshow(extended_image, extent=extent, interpolation="nearest",
origin="lower")
axins2 = zoomed_inset_axes(ax2, 3, loc=1) # zoom = 3
axins2.imshow(extended_image, extent=extent,
interpolation="nearest", origin="lower")
axins2.set_xlim(-1.0, -0.75)
axins2.set_ylim(-2.0, -1.75)
axins2.yaxis.get_major_locator().set_params(nbins=8)
axins2.xaxis.get_major_locator().set_params(nbins=8)
plt.xticks(visible=False)
plt.yticks(visible=False)
mark_inset(ax2, axins2, loc1=2, loc2=4, fc="none", ec="m")
- 最后,使用以下命令在屏幕上显示图:
plt.show()
工作原理
这是前面代码的解释:
extended_image = np.zeros([100, 100], dtype="d")
创建一个用零填充的100 x 100
NumPy 数组,并将数据类型指定为双精度浮点数。nx, ny = corr_wine.shape
将相关矩阵的形状分为nx
和ny
。extended_image[25:25 + nx, 25:25 + ny] = corr_wine
将相关矩阵嵌入在(25, 25)
位置的100 x 100
零矩阵内,用corr_wine
的值替换零。extent = [-2, 2, -3, 1]
指定主轴域的 x 坐标上的数据限制为(-2, 3)
和 y 为(-3, 1)
。 有关更多详细信息,请参考第 6 章,“带有高级功能的绘图”,“起源和范围”中的秘籍。ax1.imshow(extended_image, extent=extent, interpolation="nearest", origin="lower")
在主轴域ax1
上绘制扩展图像。axins1 = zoomed_inset_axes(ax1, 3, loc=1)
定义插入轴域如下:ax1
是要在其上创建插入轴域的轴域。3
指定插入轴域数据比例是主轴域的三倍,因此对于 x 和 y 轴,主轴域上的一个单位缩放到插入轴域上的三个单位。loc=1
指定将插入轴域放置在主轴域的右上角。
axins1.imshow(extended_image, extent=extent, interpolation="nearest", origin="lower")
在插入轴域上绘制相同的扩展图像,并使用与主轴域相同的参数。axins1.set_xlim(-1.0, -0.5)
和axins1.set_ylim(-2.0, -1.5)
指定主轴域上要放大的图像部分。axins1.xaxis.get_major_locator().set_params(nbins=8)
和axins1.yaxis.get_major_locator().set_params(nbins=8)
定义插入轴域的 x 和 y 轴上的刻度数。plt.xticks(visible=False)
和plt.yticks(visible=False)
使插入标签的 x 和 y 轴均不可见刻度标签。mark_inset(ax1, axins1, loc1=2, loc2=4, fc="none", ec="b")
围绕要缩放的图像以及缩放的图像本身绘制边界,然后将它们连接到线条,如下所示:ax1
是主轴域的引用。axins1
的插入轴域的引用。loc1
和loc2
指定要连接图像的哪些角;2
指左上角,4
指右下角。fc="none"
指定不填充连接两个图像的线之间的区域。ec="b"
指定连接图像的线应为蓝色。
- 我们的第二个图与第一个图完全相同,只是要放大的图像部分小于第一个图。
axins2.set_xlim(-1.0, -0.75)
和axins2.set_ylim(-2.0, -1.75)
指定第二幅图要放大的主图像区域。
执行上述代码后,您应该在屏幕上看到以下图形:
使用inset_locator
绘制插入轴域
在本秘籍中,我们将学习在主轴域上绘制散点图,并在两个插入轴域上创建两个变量中每个变量的直方图。 我们将使用熟悉的Iris
数据集来执行此操作。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
操作步骤
这是绘制图形的分步方法:
- 加载
Iris
数据集,并使用sepal_length
和sepal_width
变量映射 x 和 y 坐标:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
x, y = iris['sepal_length'], iris['sepal_width']
- 如下定义图形和主轴域:
plt.figure(1, (8., 6.))
ax = plt.subplot(111)
- 使用右侧的颜色条绘制散点图:
im = ax.scatter(x, y, c=iris.petal_length, s=100*iris.petal_width, cmap='viridis', alpha=0.7)
plt.colorbar(im)
- 如下定义插入轴域 1 的属性:
inset_ax1 = inset_axes(ax, width="40%", height=1., loc=4)
- 在插入轴域 1 上绘制
sepal_length
直方图:
inset_ax1.hist(iris.sepal_length)
- 设置插入轴域的标题和标签,如下所示:
inset_ax1.set_title('sepal length', size=10, pad=20)
inset_ax1.axis["bottom"].toggle(all=False)
inset_ax1.axis["top"].toggle(all=True)
inset_ax1.xaxis.get_major_locator().set_params(nbins=5)
inset_ax1.yaxis.get_major_locator().set_params(nbins=10)
- 如下定义插入轴域 2 的属性:
inset_ax2 = inset_axes(ax, width=1.5, height="25%", loc=2)
8.在插入轴域 2 上绘制sepal_width
直方图:
inset_ax2.hist(iris.sepal_width)
- 设置插入轴域的标题和标签,如下所示:
inset_ax2.set_title('sepal width', size=10)
inset_ax2.axis["left"].toggle(all=False)
inset_ax2.axis["right"].toggle(all=True)
inset_ax2.xaxis.get_major_locator().set_params(nbins=6)
inset_ax2.yaxis.get_major_locator().set_params(nbins=10)
- 设置主轴域的标题和标签,如下所示:
ax.set(xlabel='sepal length', ylabel='sepal width')
ax.set_title('iris plot', size=20, color='g')
- 最后,使用以下命令在屏幕上显示图:
plt.show()
工作原理
这是前面代码的解释:
im = ax.scatter(x, y, c=iris.petal_length, s=100*iris.petal_width, cmap='viridis', alpha=0.7)
在主轴域上绘制散点图,如下所示:x
和y
是要绘制的sepal_length
和sepal_width
变量。c=iris.petal_length
指定点的颜色应根据其petal_length
值。s=100*iris.petal_width
指定散点图上的点的大小应根据其petal_width
值乘以100
来确定。cmap='viridis'
指定要使用的颜色表。alpha=0.7
指定绘图上点的透明度级别。
plt.colorbar(im)
在主轴域的右侧绘制颜色条。inset_ax1 = inset_axes(ax, width="40%", height=1., loc=4)
定义插入轴域 1 的属性,如下所示:ax
是要放置插入轴域的主轴域。width="40%"
指定插入轴域的宽度应为主轴域宽度的40%
。height=1.
指定插入轴域的高度应为 1 英寸。loc=4
指定将插入轴域放置在主轴域的右下角。
inset_ax1.hist(iris.sepal_length)
绘制sepal_length
变量的直方图。inset_ax1.set_title('sepal legth', size=10, pad=20)
打印大小为10
点的插入轴域标题,并将其定位在顶部轴域上方20
点,以使刻度标签和标题不重叠。inset_ax1.axis["bottom"].toggle(all=False)
将底部轴的轴标签,刻度和刻度标签设置为不可见。inset_ax1.axis["top"].toggle(all=True)
将顶部轴的轴标签,刻度和刻度标签设置为可见。inset_ax1.xaxis.get_major_locator().set_params(nbins=5)
指定 x 轴上的刻度数。inset_ax1.yaxis.get_major_locator().set_params(nbins=10)
指定 y 轴上的刻度数。inset_ax2 = inset_axes(ax, width=1.5, height="25%", loc=2)
定义第二插入轴域如下:width=1.5
将插入轴域的宽度指定为1.5
英寸。height="25%"
指定插入轴域的高度为主轴域高度的25%
。loc=2
指定将插入轴域放置在主轴域的左上角。
ax.set(xlabel='sepal length', ylabel='sepal width')
设置主轴域的 x 和 y 轴标签。ax.set_title('iris plot', size=20, color='g')
用20
点的大小和绿色设置图形的标题。
执行上述代码后,您应该在屏幕上看到以下图形:
十三、使用 Cartopy 工具包绘制地理地图
在本章中,我们将介绍以下秘籍:
- 绘制基本地图特征
- 绘制投影
- 使用网格线和标签
- 在地图上绘制位置
- 绘制具有政治边界的国家地图
- 使用 GeoPandas 和 Cartopy 绘制国家地图
- 绘制世界人口稠密的地方
- 绘制人口前五名和后五名的国家
- 绘制全球温度
- 绘制时区
- 绘制动画地图
介绍
Cartopy 是用于在 Matplotlib 上绘制地理地图的第三方工具包。 预计到 2020 年,Cartopy 将取代 Basemap。Cartopy 具有多种功能,可满足许多不同的用户群体。 在这里,我们将尝试介绍企业中通常使用的大多数功能。
地理地图以经度和纬度绘制,均以度为单位。 经度绘制在 x 轴上,并且从西到 180 度(-180)到东到 180 度(180)变化。 纬度绘制在 y 轴上,并且从向南 90 度(-90)到向北 90 度(90)变化。 地图上的位置以其经度和纬度值标识。
绘制基本地图特征
在本秘籍中,我们将学习 Cartopy 提供的用于绘制地图的基本功能。 该秘籍将涵盖国家边界,沿海地区与陆地,陆地区域,海洋,河流和湖泊的边界等特征。 它还将介绍如何提供背景图像以实现更好的可视化效果。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
操作步骤
以下是绘制基本地图所涉及的步骤:
- 如下定义图形和轴域:
fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
- 使用以下命令设置范围和背景图像:
ax.set_global()
ax.stock_img()
- 添加如下所需的特征以在地图中绘制:
ax.add_feature(cfeature.LAND, color='wheat')
ax.add_feature(cfeature.OCEAN, color='skyblue')
ax.add_feature(cfeature.COASTLINE, linestyle='-',lw=3)
ax.add_feature(cfeature.BORDERS, linestyle=':')
ax.add_feature(cfeature.LAKES, alpha=0.5, color='y')
ax.add_feature(cfeature.RIVERS, color='blue')
ax.tissot(facecolor='orange', alpha=0.4) # Tissot's indicatrix in cartography
- 设置标题和标签,如下所示:
ax.set_title('Cartopy Map Features - Demo', size=20, weight='bold', color='g')
ax.text(0.5, -0.06, 'Longitude', va='bottom', ha='center', size=15, color='r',
rotation='horizontal', rotation_mode='anchor', transform=ax.transAxes)
ax.text(-0.02, 0.55, 'Latitude', va='bottom', ha='center', size=15, color='b',
rotation='vertical', rotation_mode='anchor', transform=ax.transAxes)
- 最后,使用以下命令在屏幕上显示地图:
plt.show()
工作原理
这是前面代码的解释:
-
import cartopy.crs as ccrs
导入负责设置参考坐标系的包。 -
import cartopy.feature as cfeature
导入用于绘制各种特征(如陆地,海洋,河流和湖泊)的包装。 -
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
定义要在其上绘制地图的轴域,如下所示:(1,1,1)
指定它是1 x 1
网格中的第一个轴域,这实际上意味着它是整个图形中的唯一图。projection=ccrs.PlateCarree()
指定用于绘制地图的坐标参考系统。 Cartopy 提供了许多这样的投影(参考坐标系)。 在下一秘籍中,我们将看到很多。- 投影仅提供地图的轮廓,因此根据我们要绘制的内容,我们可以添加各种预定义的特征,然后绘制我们感兴趣的数据。
-
ax.set_global()
指定坐标系的限制由整个地球形成,这恰好是默认设置。 通过覆盖此全局设置,我们可以设置较小的限制来绘制特定的关注区域。 我们将在后续秘籍中学习如何执行此操作。 -
ax.stock_img()
在背景上绘制默认图像,以提供更好的可视化效果。 也可以用我们自己的图像覆盖它。 -
ax.add_feature(cfeature.LAND, color='wheat')
绘制使用wheat
颜色设置标记为陆地的区域。 -
ax.add_feature(cfeature.OCEAN, color='skyblue')
使用skyblue
颜色设置绘制海洋。 -
ax.add_feature(cfeature.COASTLINE, linestyle='-',lw=3)
绘制了沿沿海地区将土地和水分离的线,线宽为3
点,虚线样式。 -
ax.add_feature(cfeature.BORDERS, linestyle=':')
使用冒号线型绘制国家边界。 -
ax.add_feature(cfeature.LAKES, alpha=0.5, color='y')
使用yellow
颜色设置绘制湖泊。 -
ax.add_feature(cfeature.RIVERS, color='blue')
使用颜色blue
绘制河流。 -
ax.tissot(facecolor='orange', alpha=0.4)
绘制天梭的底线。 -
ax.set_title('Cartopy Map Features - Demo', size=20, weight='bold', color='g')
打印带有各种文本相关属性的标题。 -
ax.text()
用于打印 x 和 y 标签。 常规的ax.set_xlabel
和ax.set_ylabel
命令在这里不起作用,因为ax.gridlines()
函数具有轴域控件,该函数也没有用于绘制 x 和 y 轴标签的预定义方法。
运行上述代码后,您应该在屏幕上看到以下地图:
绘制投影
如先前的秘籍中所述,投影是在其中绘制地图的坐标参考系统。 Cartopy 提供了许多不同的投影,在本秘籍中,我们将绘制九个带有默认参数的投影,以演示它们的外观。 可用投影的完整列表可以在这个页面中找到。
准备
您需要使用以下命令导入所需的库:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
操作步骤
以下是绘制九种不同投影所涉及的步骤:
- 定义图:
fig = plt.figure(figsize=(12,9))
- 将
3 x 3
网格中的轴域一一定义为子图,并为每个图使用不同的投影,如下所示:
ax1 = fig.add_subplot(331, projection=ccrs.PlateCarree())
- 为每个图设置默认的背景图像:
ax1.stock_img()
- 打印图的标题,如下所示:
ax1.set_title('PlateCarree', color='green')
- 然后,对我们的九种不同投影重复步骤 1 至步骤 4。 请参阅此处的示例:
ax2 = fig.add_subplot(332, projection=ccrs.Mercator())
ax2.stock_img()
ax2.set_title('Mercator', color='green')
ax3 = fig.add_subplot(333, projection=ccrs.LambertCylindrical())
ax3.stock_img()
ax3.set_title('LambertCylindrical', color='green')
ax4 = fig.add_subplot(334, projection=ccrs.Robinson())
ax4.stock_img()
ax4.set_title('Robinson', color='green')
ax5 = fig.add_subplot(335, projection=ccrs.Mollweide())
ax5.stock_img()
ax5.set_title('Mollweide', color='green')
ax6 = fig.add_subplot(336, projection=ccrs.Orthographic())
ax6.stock_img()
ax6.set_title('Orthographic', color='green')
ax7 = fig.add_subplot(337, projection=ccrs.Sinusoidal())
ax7.stock_img()
ax7.set_title('Sinusoidal', color='green')
ax8 = fig.add_subplot(338, projection=ccrs.RotatedPole())
ax8.stock_img()
ax8.set_title('RotatedPole', color='green')
ax9 = fig.add_subplot(339, projection=ccrs.InterruptedGoodeHomolosine())
ax9.stock_img()
ax9.set_title('InterruptedGoodeHomolosine', color='green')
- 为整个图形打印一个超级标题:
fig.suptitle("Cartopy Projections - Demo", size=20, weight='bold', color='blue')
- 最后,使用以下命令在屏幕上显示整个图形:
plt.show()
工作原理
这是前面代码的解释:
ax1 = fig.add_subplot(331, projection=ccrs.PlateCarree())
在9
个轴域(曲线)的3 x 3
网格上定义了第一个轴域,并对轴域使用PlateCarree
投影,如以下屏幕截图所示ax1.stock_img()
将默认图像绘制为地图的背景。- 对所有九个预测重复前两个步骤
- 由于这是可用的示例投影的演示,因此我们不会添加任何预定义功能或任何其他用户定义的地图
执行上述代码后,您应该在屏幕上看到以下图表:
使用网格线和标签
在本秘籍中,我们将学习如何绘制网格线以及如何管理刻度线和刻度线标签。 Cartopy 具有预定义的gridlines()
函数来管理这些功能,该功能具有许多助手函数,可根据需要格式化标签。
我们将绘制四个图表来演示默认选项,以及当我们要以特定的自定义方式绘制标签时可能的自定义程度。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
操作步骤
以下是使用各种选项设置刻度和标签格式来绘制四个图表的步骤:
- 在第一个图上用
PlateCarree
投影定义图形和轴域,如下所示:
fig = plt.figure(figsize=(12,8))
ax1 = fig.add_subplot(221, projection=ccrs.PlateCarree())
- 应用默认图像作为背景,并将海岸线特征添加到绘图中:
ax1.stock_img()
ax1.coastlines()
- 定义
gridlines()
函数,如下所示:
gl1 = ax1.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5,
linestyle='--')
- 关闭上轴和右轴标签:
gl1.xlabels_top = False
gl1.ylabels_right = False
- 定义 x 和 y 轴标签样式,如下所示:
gl1.xlabel_style = {'size': 10, 'color': 'indigo', 'weight': 'bold'}
gl1.ylabel_style = {'size': 10, 'color':'darkblue','weight': 'bold'}
- 打印标题和 x 和 y 标签,并为第一张图使用默认的刻度和刻度标签,如下所示:
ax1.set_title('PlateCarree - Default Ticks', color='green', size=15)
ax1.text(0.5, -0.15, 'Longitude', va='bottom', ha='center',
size=10, color='r', rotation='horizontal',
rotation_mode='anchor', transform=ax1.transAxes)
ax1.text(-0.08, 0.55, 'Latitude', va='bottom', ha='center',
size=10, color='b', rotation='vertical',
rotation_mode='anchor', transform=ax1.transAxes)
- 使用
Mercator
投影定义第二个绘图的轴域。 应用背景图像,并像以前一样添加海岸线特征:
ax2 = fig.add_subplot(222, projection=ccrs.Mercator())
ax2.stock_img()
ax2.coastlines()
- 定义
gridlines()
函数,如下所示:
gl2 = ax2.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5,
linestyle='--')
- 关闭下轴和左轴标签:
gl2.xlabels_bottom = False
gl2.ylabels_left = False
- 定义 x 和 y 轴标签的格式化器:
gl2.xformatter = LONGITUDE_FORMATTER
gl2.yformatter = LATITUDE_FORMATTER
- 定义标签样式,然后为第二个图表打印标题和标签:
gl2.xlabel_style = {'size': 10, 'color': 'indigo', 'weight': 'bold'}
gl2.ylabel_style = {'size': 10, 'color': 'darkblue', 'weight':
'bold'}
ax2.set_title('Mercator - Formatted Ticks', color='green', size=15,
pad=30)
ax2.text(0.5, -0.1, 'Longitude', va='bottom', ha='center',
size=10, color='r', rotation='horizontal',
rotation_mode='anchor', transform=ax2.transAxes)
ax2.text(-0.05, 0.55, 'Latitude', va='bottom', ha='center',
size=10, color='b', rotation='vertical',
rotation_mode='anchor', transform=ax2.transAxes)
- 对于第三幅图,我们将执行以下操作:
* 对 x 轴使用固定的刻度位置
* 关闭 x 轴的网格线
* 关闭上轴和左轴的标签
其余功能与前两个图中的相同。 有关示例,请参见以下代码块:
ax3 = fig.add_subplot(223, projection=ccrs.Mercator())
ax3.stock_img()
ax3.coastlines()
gl3 = ax3.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5, linestyle='--')
gl3.xlabels_top = False
gl3.ylabels_left = False
gl3.xlines = False
gl3.xlocator = mticker.FixedLocator([-180, -45, 0, 45, 180])
gl3.xformatter = LONGITUDE_FORMATTER
gl3.yformatter = LATITUDE_FORMATTER
gl3.xlabel_style = {'size': 10, 'color': 'indigo', 'weight': 'bold'}
gl3.ylabel_style = {'size': 10, 'color': 'darkblue', 'weight': 'bold'}
ax3.set_title('Mercator - Xticks at fixed locations', color='green', size=15)
- 在第四幅图中,我们将完全使用完全自定义的标签和格式选项,而根本不使用
gridlines()
函数,如下所示:
ax4 = fig.add_subplot(2, 2, 4, projection=ccrs.PlateCarree(central_longitude=180))
ax4.set_global()
ax4.stock_img()
ax4.coastlines()
ax4.set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
ax4.set_yticks([-90, -60, -30, 0, 30, 60, 90], crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter(zero_direction_label=True,
number_format='.1f', degree_symbol='')
lat_formatter = LatitudeFormatter(number_format='.1f')
ax4.xaxis.set_major_formatter(lon_formatter)
ax4.yaxis.set_major_formatter(lat_formatter)
[i.set_color("indigo") for i in ax4.get_xticklabels()]
[i.set_weight("bold") for i in ax4.get_xticklabels()]
[i.set_color("darkblue") for i in ax4.get_yticklabels()]
[i.set_weight("bold") for i in ax4.get_yticklabels()]
ax4.set_title('PlateCarree - Xticks & Yticks at fixed locations',
color='green', size=15)
- 最后,使用以下命令在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
gl1 = ax1.gridlines(crs=ccrs.PlateCarree(), draw_labels=True, linewidth=2, color='gray', alpha=0.5, linestyle='--')
定义要绘制的网格线的格式:ccrs.PlateCarree()
指定要使用的参考坐标系(即投影)。 在这种情况下,我们将使用PlateCarree
投影。draw_labels=True
指定要绘制与网格线对齐的刻度和刻度标签。 通过将此参数设置为False
,可以将其关闭。linewidth=2
指定网格线的宽度。color='gray'
指定网格线的颜色。alpha=0.5
指定网格线的透明度。linestyle='--'
指定网格线的样式。
gl1.xlabels_top = False
关闭上轴标签。 默认情况下,gridlines()
函数为所有四个轴(左,下,上和右)绘制标签。 您可以通过更改此命令来打开或关闭其中的任何一个。gl1.ylabels_right = False
关闭右轴标签。gl1.xlabel_style = {'size': 10, 'color': 'indigo', 'weight': 'bold'}
定义要用于 x 轴标签的各种属性的字典。gl1.ylabel_style = {'size': 10, 'color': 'darkblue', 'weight': 'bold'}
定义要用于 y 轴标签的各种属性的字典。ax1.set_title('PlateCarree - Default Ticks', color='green', size=15)
打印具有各种属性的图表标题。ax1.text(0.5, -0.15, 'Longitude', va='bottom', ha='center', size=10, color='r', rotation='horizontal', rotation_mode='anchor', transform=ax1.transAxes)
绘制 x 轴标签:(0.5, -0.15)
是在坐标轴中从左至下的坐标,将在其中打印 x 轴标签。'Longitude'
是要打印的 x 轴标签。va='bottom'
指定标签应在底部垂直对齐。ha='center'
指定标签应在中心水平对齐。size=10
指定字体大小。color='r'
指定字体颜色。rotation='horizontal'
指定标签相对于轴的打印角度。 在这种情况下,角度设置为horizontal
。rotation_mode='anchor'
指定标签为锚对象。transform=ax1.transAxes
指定给定的坐标在轴域坐标系中。
ax2 = fig.add_subplot(222, projection=ccrs.Mercator())
定义第二张图表的轴域,该图表使用Mercator
投影。gl2.xformatter = LONGITUDE_FORMATTER
指定 x 刻度标签的格式选项。gl2.yformatter = LATITUDE_FORMATTER
指定 y 刻度标签的格式选项。LONGITUDE_FORMATTER
和LATITUDE_FORMATTER
是gridliner
函数内的预定义辅助函数。 它们都有自己的格式设置选项,但是在第二张图表中,我们都使用了所有默认参数。 他们基本上将东/西的方向设置为经度,将北/南的方向设置为纬度,并显示度数符号。 比较前两个图表的刻度标签以查看差异。gl3.xlines = False
关闭第三张图表在 x 轴上着陆的网格线。 您也可以使用gl.ylines
关闭 y 轴网格线。gl3.xlocator = mticker.FixedLocator([-180, -45, 0, 45, 180])
定义 x 轴的刻度位置。 我们没有在gridliner
的刻度位置中选择,而是在此处手动定义它们。ax4 = fig.add_subplot(2, 2, 4, projection=ccrs.PlateCarree(central_longitude=180))
定义第四个图表的轴域,如下所示:(2, 2, 4)
与(224)
相同,并指定这是2 x 2
图表网格中的第四张图表PlateCarree()
是要使用的投影central_longitude=180
指定纵轴的中心应为 180 度,而不是默认值 0
ax4.set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
定义 x 轴的刻度位置和标签。 在第四张图表中,我们没有使用gridlines()
函数; 因此,我们必须手动设置刻度位置:crs=ccrs.PlateCarree()
指定给定的刻度位置在PlateCarree
坐标系中。 这与投影不同,投影指定了在绘制地图时要使用的坐标系。- 如果投影使用一个参考坐标系,并且刻度标签由另一坐标系提供,则通过指定提供数据的坐标系,它将在绘制地图之前将数据转换为投影坐标系。
ax4.set_yticks([-90, -60, -30, 0, 30, 60, 90], crs=ccrs.PlateCarree())
定义 y 轴的刻度位置和标签。lon_formatter = LongitudeFormatter(zero_direction_label=True, number_format='.1f', degree_symbol='')
定义纵轴的格式化器:zero_direction_label=True
指定是否应使用E
符号(向东)打印 0 度number_format='.1f'
指定用于数字标签的小数点位数degree_symbol=''
指定将不打印度数符号-默认选项是将其打印
[i.set_color("indigo") for i in ax4.get_xticklabels()]
将'indigo'
颜色应用于 x 轴上的刻度标签,[i.set_weight("bold") for i in ax4.get_xticklabels()]
在其中打印刻度标签粗体:get_xticklabels()
获取当前的刻度标签set_color()
和set_weight()
语句将指定的颜色和粗体字体应用于每个刻度标签- 接下来的两个语句对 y 轴刻度标签执行相同的操作,但是使用
darkblue
颜色
执行上述代码后,您应该在屏幕上看到以下图:
应该注意的是,刻度标签和相关格式仅针对PlateCarree
和Mercator
投影定义。 对于其他投影,gridlines()
会在没有刻度标签的情况下进行绘图,因此我们无法在gridlines()
上使用draw_labels=True
参数进行投影。
在地图上绘制位置
在本秘籍中,我们将学习如何在地图上绘制具有给定经度和纬度参数的位置。 这样就可以根据位置之间的相对位置直观地表示位置。 我们还将学习如何在地球上沿直线和球形方向连接两个位置。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
操作步骤
这是绘制地图和全球各地的必要步骤。 您可以获取互联网上各个位置的经度和纬度信息。 在这里,我们将绘制主要城市,主要是国家的首都:
- 定义要在其上绘制地图的图形和轴域:
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson())
- 设置背景图像并添加海岸线特征:
ax.set_global()
ax.stock_img()
ax.coastlines()
- 使用给定的经度和纬度坐标绘制位置,如下所示:
ax.plot(-0.08, 51.53, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
- 使用文本函数标记位置:
plt.text(-0.08, 51.53, 'London', size=10, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
- 现在,对于我们要绘制的所有城市,重复执行步骤 1 至步骤 4 ,如以下代码块所示:
ax.plot(37.6173, 55.7558, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(37.6173, 55.7558, 'Moscow', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(77.1, 28.7, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(77.1, 28.7, 'New Delhi', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(-118.2437, 34.0522, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(-118.2437, 34.0522, 'Los Angeles', size=10, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(-74, 40.7128, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(-74, 40.7128, 'New York', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(149.13, -35.2809, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(149.13, -35.2809, 'Canberra', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(116.4074, 39.9042, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(116.4074, 39.9042, 'Beijing', size=10, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(18.4241, -33.9249, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(18.4241, -33.9249, 'Cape Town', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(55.2708, 25.2048, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(55.2708, 25.2048, 'Dubai', size=10, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(139.6917, 35.6895, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(139.6917, 35.6895, 'Tokyo', size=10, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
ax.plot(-79.3832, 43.6532, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(-79.3832, 43.6532, 'Toronto', size=10, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(7.3986, 9.0765, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(7.3986, 9.0765, 'Abuja', size=10, color='indigo', # Capital of Nigeria
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(-47.9218, -15.8267, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
plt.text(-47.9218, -15.8267, 'Brasilia', size=10, color='indigo', # Capital of Brazil
horizontalalignment='right', transform=ccrs.Geodetic())
ax.plot(-99.1332, 19.4326, 'o', transform=ccrs.PlateCarree(),
markersize=7, color='r')
plt.text(-99.1332, 19.4326, 'Mexico City', size=10, color='indigo', # Capital of Brazil
horizontalalignment='right', transform=ccrs.Geodetic())
- 现在,绘制伦敦和新德里之间的直线和球面线,如下所示:
ax.plot([-0.08, 77.1], [51.53, 28.7], color='g', transform=ccrs.PlateCarree())
ax.plot([-0.08, 77.1], [51.53, 28.7], color='m', transform=ccrs.Geodetic())
- 最后,使用以下命令在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson())
定义带有Robinson
投影的轴域。ax.plot(-0.08, 51.53, 'o', transform=ccrs.PlateCarree(), markersize=7, color='r')
将位置绘制为伦敦,如下所示:(-0.08, 51.53)
是伦敦的经度和纬度坐标。'o'
是要在地图上绘制位置的标记。transform=ccrs.PlateCarree()
指定提供经度和纬度参数的坐标系。 这些坐标将在内部转换为Robinson
坐标,因为我们正在绘制带有Robinson
投影的地图。markersize=7
指定要在地图上绘制的点的大小,即 7 个点(一个点是 1/72 英寸)。color='r'
将定位点被涂成红色。
plt.text(-0.08, 51.53, 'London', size=10, color='indigo', horizontalalignment='right', transform=ccrs.Geodetic())
打印该位置的标签,其中包含名称:(-0.08, 51.53)
代表打印标签的经度和纬度坐标。'London'
表示要在标签上打印的文本。size=10
是要打印的标签的大小。color='indigo'
是标签的颜色。horizontalalignment='right'
指定位置点应与标签的右侧对齐。transform=ccrs.Geodetic()
指定坐标为经度和纬度,以度为单位。 还有一个笛卡尔等效项,即ccrs.Geocentric
,其中坐标为常规 x,y 和 z 轴格式,以常规方式测量距离指标。
ax.plot([-0.08, 77.1], [51.53, 28.7], color='g', transform=ccrs.PlateCarree())
绘制了一条连接伦敦和新德里的折线图,并指定了它们各自的经度和纬度坐标:[-0.08, 77.1]
是伦敦和新德里的经度坐标[51.53, 28.7]
是伦敦和新德里的纬度坐标color='g'
表示两个城市之间绘制的线条的颜色将变为绿色transform=ccrs.PlateCarree()
指定要使用的坐标系,在这种情况下为笛卡尔坐标系,因此将绘制一条直线
- 由于我们正在使用
transform=ccrs.Geodetic()
,因此ax.plot([-0.08, 77.1], [51.53, 28.7], color='m', transform=ccrs.Geodetic())
沿实际地球仪以球形格式绘制了相同的折线图。 由于颜色参数的'm'
值,线条的颜色为洋红色。
执行代码后,您应该在屏幕上看到以下图:
绘制具有政治边界的国家地图
到目前为止,我们已经制作了覆盖全球的地图,这在您绘制例如全球公司办公室,跨大洲受到流行病影响的地区或跨许多国家的地震的地图时非常有用。
但是,如果要查看特定于某个地区的现象,该现象可能是一个国家,州,省甚至一个国家内的城市,则需要为地图设置较小的范围。 在本秘籍中,我们将学习如何做。
准备
通常,地图数据以形状文件的形式组织和分布。 为了能够读取这些文件并在地图上绘制数据,我们需要ShapeReader
包,通常由用于绘制地图的软件提供ShapeReader
包,在这种情况下,该程序为 cartopy。 源映射数据是由商业和开放源代码的几个不同实体准备,组织和分发的。 Cartopy 主要支持两种此类来源:一种可从这个页面获得。 另一个可以在这个页面中找到。 您可以参考这些站点,以获取有关每个包的更多信息。
在本章中,我们仅专注于自然地球数据提供的数据。
为了演示,我们将绘制三个国家/地区的地图:美国,英国和印度。 您只需更改经度和纬度范围内的范围,即可绘制任何其他国家,省或城市的地图。
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.io.shapereader as shpreader
操作步骤
这是绘制地图所需的步骤 :
- 定义图:
fig = plt.figure(figsize=(16,8))
- 用
PlateCarree
投影定义轴域:
ax1 = fig.add_subplot(131, projection=ccrs.PlateCarree())
- 如下定义美国的经度和纬度范围:
ax1.set_extent([-130, -66.5, 25, 47], ccrs.Geodetic())
- 使用
add_feature()
函数绘制美国地图。 为了方便起见,Cartopy 为美国提供了此功能,因此我们不必读取外部形状文件:
ax1.add_feature(cfeature.STATES, facecolor='wheat')
- 定义
gridlines()
函数如下:
gl1 = ax1.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5,
linestyle='--')
- 关闭上轴和右轴的标签,如下所示:
gl1.xlabels_top = False
gl1.ylabels_right = False
- 应用经度和纬度格式化程序以按适当的方向以度显示标签,如下所示:
gl1.xformatter = LONGITUDE_FORMATTER
gl1.yformatter = LATITUDE_FORMATTER
- 定义要在 x 和 y 标签上应用的属性的字典:
gl1.xlabel_style = {'size': 10, 'color': 'b'}
gl1.ylabel_style = {'size': 10, 'color': 'r', 'weight': 'bold'}
- 如下打印标题和 x 和 y 标签:
ax1.set_title('United States of America(lon/lat)\n[-130, -66.5, 25,
47]', color='g', size=15)
ax1.text(0.5, -0.2, 'Longitude', va='bottom', ha='center', size=10,
color='r', rotation='horizontal', rotation_mode='anchor',
weight='bold', transform=ax1.transAxes)
ax1.text(-0.1, 0.55, 'Latitude', va='bottom', ha='center', size=10,
color='b', rotation='vertical', rotation_mode='anchor',
weight='bold', transform=ax1.transAxes)
- 使用墨卡托投影定义轴域,以绘制印度地图:
ax2 = fig.add_subplot(132, projection=ccrs.Mercator())
- 设置印度的经度和纬度范围如下:
ax2.set_extent([68.12, 97.42, 8.07, 37.1], ccrs.Geodetic())
- 从自然地球数据中读取包含国家/地区特定数据的形状文件:
shapename = 'admin_1_states_provinces_lakes_shp'
states_shp = shpreader.natural_earth(resolution='10m',
category='cultural', name=shapename)
- 在地图上绘制国家的不同部分,如下所示:
for state in shpreader.Reader(states_shp).geometries():
ax2.add_geometries([state], ccrs.PlateCarree(),
facecolor='wheat', edgecolor='black')
- 定义网格线和轴标签,并以适当的格式将它们与标题一起打印,如在美国所做的那样,并在此处显示:
gl2 = ax2.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5,
linestyle='--')
gl2.xlabels_top = False
gl2.ylabels_right = False
gl2.xformatter = LONGITUDE_FORMATTER
gl2.yformatter = LATITUDE_FORMATTER
gl2.xlabel_style = {'size': 10, 'color': 'blue'}
gl2.ylabel_style = {'size': 10, 'color': 'red', 'weight': 'bold'}
ax2.set_title('India(lon/lat)\n[68.12, 97.42, 8.07, 37.1]',
color='g', size=15)
- 现在,对英国重复上述步骤:
ax3 = fig.add_subplot(133, projection=ccrs.Mercator())
ax3.set_extent([-8.62, 1.77, 49.9, 60.84], ccrs.Geodetic())
for state in shpreader.Reader(states_shp).geometries():
ax3.add_geometries([state], ccrs.PlateCarree(),
facecolor='wheat', edgecolor='black')
gl3 = ax3.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2,
color='gray', alpha=0.5, linestyle='--')
gl3.xlabels_top = False
gl3.ylabels_right = False
gl3.xformatter = LONGITUDE_FORMATTER
gl3.yformatter = LATITUDE_FORMATTER
gl3.xlabel_style = {'size': 10, 'color': 'blue'}
gl3.ylabel_style = {'size': 10, 'color': 'red', 'weight': 'bold'}
ax3.set_title('United Kingdom(lon/lat)\n[-8.62, 1.77, 49.9, 60.84]',
color='g', size=15)
16.最后,使用以下命令在屏幕上显示该图:
plt.tight_layout(w_pad=5)
plt.show()
工作原理
这是代码的说明:
-
ax1.set_extent([-130, -66.5, 25, 47], ccrs.Geodetic())
指定要绘制的区域范围,如下所示:(-130, -66.5)
是美国的最小和最大经度坐标(25, 47)
是美国的最小和最大纬度坐标ccrs.Geodetic()
指定所使用的数据坐标格式为经度和纬度,以度为单位
-
ax1.add_feature(cfeature.STATES, facecolor='wheat')
绘制了美国各州的内部边界。 Cartopy 将此作为一种特征,类似于我们先前了解的其他物理特征,例如陆地,海洋,河流和湖泊。 对于其他国家/地区,我们将不得不从形状文件中获取数据并将其单独绘制。 -
gridlines()
及其相关的标签格式与前面的秘籍相同。 -
ax1.set_title('United States of America(lon/lat)\n[-130, -66.5, 25, 47]', color='g', size=15)
打印图表的标题,包括第一行的名称,以及下一行的经度和纬度坐标(\n
,换行符,将文本分为两行)。 -
ax2.set_extent([68.12, 97.42, 8.07, 37.1], ccrs.Geodetic())
指定要在第二个轴域上绘制的区域的范围,如下所示:(68.12, 97.42)
是印度的最小和最大经度坐标。(8.07, 37.1)
是印度的最小和最大纬度坐标。crs.Geodetic()
指定数据坐标为经度和纬度,以度为单位。
-
shapename = 'admin_1_states_provinces_lakes_shp'
指定要从自然地球数据站点下载以绘制地图的形状文件的名称。 它不是确切的文件名,而是可用的各种类型中的文件类型。 类型很多,例如admin 0
,admin 1
,populated places
,railroads
,roads
,airports
和ports
。 有关详细信息,请参考自然地球数据站点,该站点可在这个页面上找到。 -
states_shp = shpreader.natural_earth(resolution='10m', category='cultural', name=shapename)
从自然地球下载数据,解压缩和读取形状文件:resolution='10m'
指定数据中的详细程度。 一共有三个级别,10m
,50m
和110m
,其中10m
最详细,110m
提供了更汇总的数据级别。category='cultural'
指定数据的类别。 同样,存在三类,cultural
,physical
和raster
。Cultural
涉及政治和行政边界,physical
涉及陆地,海洋,河流和湖泊,raster
涉及环境和气候相关条件的数据。name=shapename
指定要以形状文件格式下载的数据类型。
-
for state in shpreader.Reader(states_shp).geometries():
启动for
循环以读取在上一步中下载的形状文件的内容:shapereader
访问文件,解压缩并下载形状文件的内容Reader
访问形状文件的内容Reader
下有两种方法,即records
和geometries
:geometries
访问要绘制的形状,并且在我们知道形状文件的元数据时很有用。 在这种情况下,我们知道我们正在绘制国家内部的州边界,因此我们直接使用geometries
。- 当我们需要有关形状文件内容的元数据的其他信息时,将使用
records
方法。 一旦有了元数据,就可以使用records.geometries
访问要绘制的形状。
-
在
for
循环的每次迭代中,给定state
边界的ax2.add_geometries([state], ccrs.PlateCarree(), facecolor='wheat', edgecolor='black')
图。 它使用black
颜色作为边界边缘,使用wheat
颜色作为状态区域。 -
正如我们在前面的秘籍中所了解的,其余的代码处理网格线和相关的格式。
-
我们重复绘制英国的完全相同的过程。 我们只需要设置要绘制的区域的适当范围,如下所示:
ax3.set_extent([-8.62, 1.77, 49.9, 60.84], ccrs.Geodetic())
设置英国的范围(-8.62, 1.77)
是英国的最小和最大经度坐标(49.9, 60.84)
是英国的最小和最大纬度坐标
执行上述代码后,您应该在屏幕上看到以下地图:
使用 GeoPandas 和 Cartopy 绘制国家地图
在前面的秘籍中,我们使用shapereader
下载文件,并使用Reader
读取形状文件的内容并绘制它们。shapereader
和Reader
都是由 Cartopy 提供的。 在本秘籍中,我们将继续使用shapereader
下载所需的形状文件,但使用 GeoPandas 读取并绘制形状文件的内容。 我们在第 6 章和“带有高级功能的绘图”中更早地使用了 GeoPandas 来绘制本书那部分中的地图。
我们将绘制与前面秘籍相同的三个国家地图。 但是,我们将使用两种不同类型的文件,admin 0
和admin 1
,并为每种类型绘制三个国家/地区,总共有六个图表。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import geopandas
from cartopy.io import shapereader
import cartopy.crs as ccrs
操作步骤
以下是绘制国家地图的步骤:
- 如下定义图:
fig = plt.figure(figsize=(12, 6))
- 定义六个轴域以绘制六个不同的图形,所有图形均带有
PlateCarree
投影。 这次,我们不绘制背景图像,并且也没有添加coastlines()
:
ax1 = fig.add_subplot(231, projection=ccrs.PlateCarree())
ax2 = fig.add_subplot(232, projection=ccrs.PlateCarree())
ax3 = fig.add_subplot(233, projection=ccrs.PlateCarree())
ax4 = fig.add_subplot(234, projection=ccrs.PlateCarree())
ax5 = fig.add_subplot(235, projection=ccrs.PlateCarree())
ax6 = fig.add_subplot(236, projection=ccrs.PlateCarree())
- 使用
shapereader
下载admin_0
形状文件:
shpfilename = shapereader.natural_earth(resolution='10m',
category='cultural', name='admin_0_countries')
- 将形状文件的内容读取到 Pandas 数据帧中:
df0 = geopandas.read_file(shpfilename)
- 在地图投影上设置美国的范围:
ax1.set_extent([-130, -66.5, 25, 50], crs=ccrs.PlateCarree())
- 提取与美国有关的多边形(即构成国家的块):
poly = df0.loc[df0['ADMIN'] == 'United States of America']['geometry']
- 使用
geometries
方法在地图上绘制多边形,如下所示:
ax1.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none', edgecolor='0.5')
- 打印图的标题:
ax1.set_title('United States of America - Admin0')
- 对印度,然后对英国重复步骤 4 至步骤 8 。 请参见以下示例:
ax2.set_extent([-8.62, 1.77, 49.9, 60.84], crs=ccrs.PlateCarree()) # United Kingdom
poly = df0.loc[df0['ADMIN'] == 'United Kingdom']['geometry']
ax2.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none',
edgecolor='0.5')
ax2.set_title('United Kingdom - Admin0')
ax3.set_extent([68.12, 97.42, 8.07, 37.1], crs=ccrs.PlateCarree()) # India
poly = df0.loc[df0['ADMIN'] == 'India']['geometry']
ax3.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none', edgecolor='0.5')
ax3.set_title('India - Admin0')
- 使用
shapereader
下载admin_1
形状文件:
shpfilename = shapereader.natural_earth(resolution='10m',
category='cultural',
name='admin_1_states_provinces_lakes_shp')
df1 = geopandas.read_file(shpfilename)
- 对每个国家/地区重复步骤 4 至步骤 8 ,如下所示:
ax4.set_extent([-130, -66.5, 25, 50], crs=ccrs.PlateCarree()) # United States of America
poly = df1.loc[df1['admin'] == 'United States of America']
['geometry']
ax4.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none',
edgecolor='0.5')
ax4.set_title('United States of America - Admin1')
ax5.set_extent([-8.62, 1.77, 49.9, 60.84], crs=ccrs.PlateCarree()) # United Kingdom
poly = df1.loc[df1['admin'] == 'United Kingdom']['geometry']
ax5.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none',
edgecolor='0.5')
ax5.set_title('United Kingdom - Admin1')
ax6.set_extent([68.12, 97.42, 8.07, 37.1], crs=ccrs.PlateCarree()) # India
poly = df1.loc[df1['admin'] == 'India']['geometry']
ax6.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none',
edgecolor='0.5')
ax6.set_title('India - Admin1')
- 最后,在屏幕上显示图,如下所示:
plt.show()
工作原理
这是前面代码的解释:
shpfilename = shapereader.natural_earth(resolution='10m', category='cultural', name='admin_0_countries')
从自然地球数据网站下载所需的形状文件。df0 = geopandas.read_file(shpfilename)
将形状文件的内容读取到df0
, Pandas 数据帧对象中。ax1.set_extent([-130, -66.5, 25, 50], crs=ccrs.PlateCarree())
设置美国范围。poly = df0.loc[df0['ADMIN'] == 'United States of America']['geometry']
从 Pandas 数据帧读取要绘制为多边形的特定块:df0
数据帧有一个'ADMIN'
列,用于存储国家名称,用于提取与美国有关的特定内容。geometry
是df0
中的另一列,用于存储形成特定国家/地区的区块的信息。- 此形状文件中每个国家/地区只有一个对象。 因此,它仅将国家的轮廓绘制为一个多边形,而没有州或省的内部块。
ax1.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor='none', edgecolor='0.5')
使用geometries
方法在地图上绘制多边形:facecolor='none'
指定不使用任何颜色填充块。edgecolor = '0.5'
指定使用灰色绘制边缘。
ax1.set_title('United States of America - Admin0')
打印图的标题。shpfilename = shapereader.natural_earth(resolution='10m', category='cultural', name='admin_1_states_provinces_lakes_shp')
读取我们在先前秘籍中使用的admin_1
形状文件。 这不仅将具有admin0
中的国家边界,而且还将具有内部州和省边界。df1 = geopandas.read_file(shpfilename)
将形状文件内容读取到 Pandas 数据帧中。poly = df1.loc[df1['admin'] == 'United States of America']['geometry']
过滤形成美国的多边形。 在这种情况下,geometry
列将为每个国家/地区提供多个对象,并指定该国家/地区内的州和省。- 其余步骤与
admin 0
文件的步骤完全相同。
执行上述代码后,您应该在屏幕上看到以下地图。 应当注意,我们没有使用默认图像作为背景,因此,我们在这里看不到彩色图像。 第一行只是国家/地区的轮廓,而第二行中的图则描绘了每个国家/地区内的州和省,如Admin 0
和Admin 1
文件中所示:
绘制世界人口稠密的地方
在此秘籍中,我们将绘制全球人类居住的位置。 我们将使用自然地球数据网站上的相应形状文件。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
操作步骤
以下是绘制地图所涉及的步骤:
- 使用
PlateCarree
投影定义图形和轴域:
plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.PlateCarree())
- 如下设置背景图像和海岸线:
ax.stock_img()
ax.coastlines()
- 从自然地球数据网站下载所需的形状文件:
shp_fn = shpreader.natural_earth(resolution='10m',
category='cultural', name='populated_places')
- 获取每个位置的特定坐标,如下所示:
xy = [pt.coords[0] for pt in shpreader.Reader(shp_fn).geometries()]
- 使用以下命令解压缩坐标:
x, y = zip(*xy)
- 使用散点图绘制这些点:
ax.scatter(x,y, transform=ccrs.Geodetic())
- 绘制图的标题,如下所示:
ax.set_title('Populated places of the world.')
- 最后,使用以下命令在屏幕上显示地图:
plt.show()
工作原理
这是前面代码的解释:
shp_fl = shpreader.natural_earth(resolution='10m', category='cultural', name='populated_places')
下载形状文件,其中包含人类填充的位置信息xy = [pt.coords[0] for pt in shpreader.Reader(shp_fl).geometries()]
将位置的坐标提取到xy
变量中x, y = zip(*xy)
将坐标解压缩为 x 和 y 坐标ax.scatter(x,y, transform=ccrs.Geodetic())
绘制位置的散点图ax.set_title('Populated places of the world.')
设置绘图的标题
执行上述代码后,您应该在屏幕上看到以下地图。 蓝点代表存在人类的位置:
绘制人口前五名和后五名的国家
在本秘籍中,我们将学习如何提取每个国家的人口数据,按人口数量对它们进行排序,并在人口图上绘制按人口计算的前五名和后五名国家。 我们将下载并使用110m
分辨率的admin 0
形状文件。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
操作步骤
以下是绘制地图所需的步骤:
- 使用以下命令下载所需的形状文件:
shpfilename = shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries')
- 提取数据并对其进行排序,以按人口升序获得国家/地区,如下所示:
reader = shpreader.Reader(shpfilename)
countries = reader.records()
country = next(countries)
population = lambda country: country.attributes['POP_EST']
sort_by_pop = sorted(countries, key=population)
- 提取前五个和最后五个条目,分别代表人口不足的前五名和前五名的国家。 从网上离线获取相应的经度和纬度坐标:
## get the first 5 entries that represent lowest population
B5_countries_by_pop = sort_by_pop[:5]
B5_Country_Names = ', '.join([country.attributes['NAME_LONG'] for
country in B5_countries_by_pop])
## get the last 5 entries that represent highest population
T5_countries_by_pop = sort_by_pop[-5:]
T5_Country_Names = ', '.join([country.attributes['NAME_LONG'] for
country in T5_countries_by_pop])
##B5_Country_Names = ['French Southern and Antarctic Lands',
'Falkland Islands', 'Antarctica', 'Greenland', #'Northern Cyprus']
B5_lat = [49.28, 51.796, 82.862, 71.71, 35.32]
B5_lon = [69.35, 59.523, 135, 42.60, 33.31]
##T5_Country_Names = ['Brazil', 'Indonesia', 'United States',
'India', 'China']
T5_lat = [-14.2350, -0.7893, 37.0902, 20.5937, 40]
T5_lon = [-51.9253, 113.9213, -95.7129, 78.9629, 116.5]
- 定义图形,轴域并设置默认值:
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson())
ax.set_global()
ax.stock_img()
ax.coastlines()
- 将这些点绘制在全球地图上,如下所示:
ax.plot(B5_lon, B5_lat, 'o', transform=ccrs.PlateCarree(), markersize=10, color='r')
ax.plot(T5_lon, T5_lat, 'o', transform=ccrs.PlateCarree(), markersize=10, color='g')
- 使用
text
扩展嵌入函数来绘制与每个点相对应的标签:
plt.text(B5_lon[0], B5_lat[0], 'FSAL', size=12, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(B5_lon[1], B5_lat[1], 'FI', size=12, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(B5_lon[2], B5_lat[2], 'Antarctica', size=12,
color='indigo', horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(B5_lon[3], B5_lat[3], 'Greenland', size=12, color='indigo',
horizontalalignment='right', transform=ccrs.Geodetic())
plt.text(B5_lon[4], B5_lat[4], 'NC', size=12, color='indigo',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(T5_lon[0], T5_lat[0], 'Brazil', size=12, color='m',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(T5_lon[1], T5_lat[1], 'Indonesia', size=12, color='m',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(T5_lon[2], T5_lat[2], 'United States', size=12, color='m',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(T5_lon[3], T5_lat[3], 'India', size=12, color='m',
horizontalalignment='left', transform=ccrs.Geodetic())
plt.text(T5_lon[4], T5_lat[4], 'China', size=12, color='m',
horizontalalignment='right', transform=ccrs.Geodetic())
- 使用以下命令在屏幕上显示图:
plt.show()
工作原理
这是代码的说明:
shpfilename = shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries')
从自然地球数据网站下载所需的形状文件。reader = shpreader.Reader(shpfilename)
设置读取器以从形状文件提取数据。countries = reader.records()
设置生成器对象以开始读取文件。country = next(countries)
提取下一个国家/地区记录。population = lambda country: country.attributes['POP_EST']
定义了一个匿名函数,该函数返回给定国家记录的人口。'POP_EST'
是导入的国家/地区记录的属性之一。lambda
是用于定义临时的一次性使用匿名函数的 Python 构造。sort_by_pop = sorted(countries, key=population)
按填充顺序对导入的形状文件进行排序,映射到countries
。B5_countries_by_pop = sort_by_pop[:5]
从排序的文件中提取前五个记录。 这些记录代表了人口规模排名前五的国家。B5_Country_Names = ', '.join([country.attributes['NAME_LONG'] for country in B5_countries_by_pop])
选取国家/地区的长名称,如这五个国家/地区的NAME_LONG
属性中所给。T5_countries_by_pop = sort_by_pop[-5:]
从排序的文件中拾取最后五个条目。 这些条目代表了人口规模排名前五的国家。T5_Country_Names = ', '.join([country.attributes['NAME_LONG'] for country in T5_countries_by_pop])
为每个国家/地区选择了长名。B5_lat = [49.28, 51.796, 82.862, 71.71, 35.32]
和B5_lon = [69.35, 59.523, 135, 42.60, 33.31]
是排名靠后的五个国家/地区的经度和纬度坐标列表。T5_lat = [-14.2350, -0.7893, 37.0902, 20.5937, 40]
和T5_lon = [-51.9253, 113.9213, -95.7129, 78.9629, 116.5]
是前五个国家/地区的经度和纬度坐标。fig = plt.figure(figsize=(10, 5))
定义大小为(10, 5)
英寸的图形。ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson())
定义使用Robinson
投影绘制地图的轴域。ax.plot(B5_lon, B5_lat, 'o', transform=ccrs.PlateCarree(), markersize=10, color='r')
使用'0'
标记绘制底部的五个国家/地区,标记设置为 10 点,颜色为红色。ax.plot(T5_lon, T5_lat, 'o', transform=ccrs.PlateCarree(), markersize=10, color='g')
使用'0'
标记绘制前五个国家/地区的位置,将其设置为大小为 10 点,并用绿色标记。plt.text()
语句为这 10 个位置中的每个位置打印标签,并带有各自的长名称。 对于某些国家/地区,我们使用了缩写,因为它们的名称对于地图来说太长了。 您可以在本章的代码文件中看到它们的全名。
执行上述代码后,您应该在屏幕上看到以下图:
绘制全球温度
在本秘籍中,我们将学习如何绘制全球给定温度的图表,以可视化它们相对彼此的外观。 您需要从这里下载用于绘制地图所需的温度文件。
准备
您需要使用以下命令导入所需的库:
from netCDF4 import Dataset
import matplotlib.pylab as plt
import numpy as np
from matplotlib import cm
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point
操作步骤
以下是绘制地图所需的步骤:
- 如下加载用于绘制地图的温度文件:
netCDF_temp = Dataset('temperature_annual_1deg.nc')
- 对于要在地图上绘制的所有点,提取经度和纬度坐标以及相应的摄氏温度:
lat = netCDF_temp.variables['lat'][:]
lon = netCDF_temp.variables['lon'][:]
temp = netCDF_temp.variables['t_an'][0,0,:,:]
- 在温度和经度上添加循环点以删除白色垂直线,否则该垂直线将显示在图形上:
temp_cyc, lon_cyc = add_cyclic_point(temp, coord=lon)
- 使用
Robinson
投影定义图形和轴域:
plt.figure(figsize=(12,6))
ax = plt.subplot(111, projection=ccrs.Robinson())
- 使用以下命令将背景图像和海岸线添加到地图中:
ax.stock_img()
ax.coastlines()
- 使用
seismic
颜色表使用pcolormesh
函数绘制温度:
temp_map = ax.pcolormesh(lon_cyc, lat, temp_cyc, vmin=-10, vmax=40,
transform=ccrs.PlateCarree(),cmap=cm.seismic)
- 绘制带有
'horizontal'
方向的颜色条,如下所示:
plt.colorbar(temp_map, orientation='horizontal')
- 使用以下命令在屏幕上显示图:
plt.show()
工作原理
这是前面代码的解释:
netCDF_temp = Dataset('temperature_annual_1deg.nc')
加载温度数据。 这是一个netCDF-compliant
文件,因此将需要适当的工具来读取数据,我们已经在此秘籍的“准备”部分中导入了该数据集。lon = netCDF_temp.variables['lon'][:]
和lat = netCDF_temp.variables['lat'][:]
提取要绘制温度的位置的经度和纬度坐标。temp = netCDF_temp.variables['t_an'][0,0,:,:]
提取第一层的温度。temp_cyc, lon_cyc = add_cyclic_point(temp, coord=lon)
添加循环点以避免经度为零的垂直白线。temp_map = ax.pcolormesh(lon_cyc, lat, temp_cyc, vmin=-10, vmax=40, transform=ccrs.PlateCarree(),cmap=cm.seismic)
绘制所需的温度图,如下所示:lon_cyc
,lat
和temp_cyc
是要绘制的经度,纬度和温度数据vmin
和vmax
指定要在地图上绘制的最低和最高温度cmap=cm.seismic
指定将使用seismic
颜色表
plt.colorbar(temp_map, orientation='horizontal')
以水平方向绘制颜色条。
执行代码后,您应该在屏幕上看到以下地图:
绘制时区
在本秘籍中,我们将学习如何在地图上绘制时区。自然地球数据网站上提供了时区形状文件,因此我们可以像过去一样使用shapereader
下载它。 但是,我们已离线下载文件,并在此处使用它来演示 Cartopy 提供的另一个函数:ShapelyFeature
。
准备
您需要使用以下命令导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.feature import ShapelyFeature
import matplotlib.ticker as mticker
操作步骤
以下是在地图上绘制时区所需的步骤:
- 使用
PlateCarree
投影定义图形和轴域:
plt.figure(figsize=(12, 6))
ax = plt.axes(projection=ccrs.PlateCarree())
- 如下将背景图像和海岸线特征应用于地图:
ax.stock_img()
ax.coastlines(zorder=0)
- 使用
ShapelyFeature
函数读取时区形状文件的内容作为特征:
shape_feature = ShapelyFeature(Reader('ne_10m_time_zones.shp').geometries(),
ccrs.PlateCarree(), edgecolor='black')
- 在地图上绘制特征,如下所示:
ax.add_feature(shape_feature, alpha=0.4, zorder=5, lw=1)
- 应用
gridlines()
函数,如下所示:
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=2, color='gray', alpha=0.5, linestyle='--')
- 关闭左,上和右轴标签:
gl.xlabels_top = False
gl.ylabels_left = False
gl.ylabels_right = False
- 为 x 轴应用固定的刻度位置,覆盖默认刻度,如下所示:
gl.xlocator = mticker.FixedLocator(np.linspace(-180, 180, 25))
- 将 x 轴上的刻度标签的格式设置如下:
gl.xlabel_style = {'size': 10, 'color': 'blue'}
- 绘制地图标题:
ax.set_title('Global Time Zones', size=15, color='g')
- 最后,使用以下命令在屏幕上显示地图:
plt.show()
工作原理
这是前面代码的解释:
ax.coastlines(zorder=0)
如下在地图上绘制海岸线:zorder=0
指定应首先绘制海岸线,以免它们进入前景并遮盖时区线
shape_feature = ShapelyFeature(Reader('ne_10m_time_zones.shp').geometries(),ccrs.PlateCarree(), edgecolor='black')
创建一个可以添加到地图的特征对象:- 到目前为止,
Reader
从形状文件中提取内容 ShapelyFeature
将内容准备为可使用add_feature
方法添加到地图的特征
- 到目前为止,
ax.add_feature(shape_feature, alpha=0.4, zorder=5, lw=1)
将在上一步中创建的地图项添加到地图中:shape_feature
是要绘制的特征alpha=0.4
指定透明度级别zorder=5
指定时区线的打印时间比海岸线晚,因此它们出现在前景中,海岸线显示在背景中lw=1
指定时区线的宽度
- 地图上有 24 条时区线:经度 0 度的左侧 12 条,右侧 12 条。 经度零度本身表示格林威治标准时间(GMT),因此零度右侧的纵向坐标位于 GMT 之前,零度左侧的经向坐标在格林威治标准时间后面。
gridlines()
和相关的格式与本章到目前为止的操作相似。gl.xlocator = mticker.FixedLocator(np.linspace(-180, 180, 25))
在 x 轴上施加刻度,从 -180 度到 +180 度以 25 个相等的间隔(每 15 个间隔)开始。- 每 15 度经度代表时区 1 小时的时间。 因此,经度为零度右侧的第一个时区比格林尼治标准时间(经度 7.5 度)早 30 分钟。 同样,零度经度左侧的第一个时区比格林尼治标准时间晚 30 分钟。 印度比格林尼治标准时间早 5.5 小时。 这些时区表示不使用夏令时的标准时间。
执行上述代码后,您应该在屏幕上看到以下图:
绘制动画地图
在本秘籍中,我们将学习如何为三维可视化绘制动画地图。
准备
您需要使用以下命令导入所需的库:
import cartopy.crs as ccrs
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下是绘制动画地图并将其保存为 MP4 文件的步骤:
- 设置要在其上制作地图动画的后端,如下所示:
import matplotlib
matplotlib.use('tkagg')
- 定义图:
fig = plt.figure(figsize=(6, 6))
- 定义一个函数,以使用新的帧不断更新地图:
def animate(longitude):
ax = plt.gca()
ax.remove()
ax = plt.axes([0, 0, 1, 1], projection=ccrs.Geostationary(central_longitude=longitude))
ax.set_global()
ax.coastlines()
ax.stock_img()
ax.gridlines()
- 激活动画,如下所示:
ani = animation.FuncAnimation(fig, animate, frames=np.linspace(0, 360, 10),
interval=50, repeat=True, repeat_delay=500)
- 使用以下命令将动画地图另存为 MP4 文件:
ani.save("Geostationary.mp4")
- 使用以下命令在屏幕上显示动画:
plt.show()
工作原理
这是前面代码的解释:
matplotlib.use('tkagg')
设置 Tkinter 后端以显示动画fig = plt.figure(figsize=(6, 6))
定义图形def animate(longitude):
是用于使用新框架更新地图的函数:ax = plt.gca()
获取当前活动轴域的引用。ax.remove()
删除该轴域上的绘图(如果已经存在)。ax = plt.axes([0, 0, 1, 1], projection=ccrs.Geostationary(central_longitude=longitude))
使用Geostationary
投影刷新此函数接收到的当前经度轴域上的地图。ax.coastlines()
将海岸线特征添加到地图。ax.stock_img()
将背景图像添加到地图。ax.gridlines()
将网格线添加到图像。 我们此处无法使用draw_labels=True
参数,因为我们正在使用Geostationary
投影。
ani = animation.FuncAnimation(fig, animate, frames=np.linspace(0, 360, 10), interval=50, repeat=True, repeat_delay=500)
激活动画:fig
是要在其上绘制地图的图形对象。animate
是先前定义的动画的更新函数。frames
是 10 个条目的列表,其中条目平均间隔 36 度。 此数字将自动传递到动画函数,该函数会接收该数字并映射到当前经度。 因此,地球在每次迭代中旋转 36 度。interval=50
指定连续帧之间的时间间隔(以毫秒为单位)。repeat=True
指定在显示所有帧之后,应重复该循环,以便动画永远持续下去。repeat_delay=500
指定开始下一个周期之前的时间延迟(以毫秒为单位)。
ani.save("Geostationary.mp4")
将动画和文件名Geostationary.mp4
保存到当前工作目录中
运行前面的代码后,您应该在屏幕上看到类似以下的内容(这里是动画图的快照)。 您可以在代码目录中找到 MP4 文件,以查看实际的动画:
十四、使用 Seaborn 工具包的探索性数据分析
在本章中,我们将学习如何使用另一种第三方工具箱seaborn
和绘制以下类型图形的秘籍:
-
关系图(
sns.relplot
):- 线形图(
sns.lineplot
) - 散点图(
sns.scatterplot
)
- 线形图(
-
类别图(
sns.catplot
):- 条带图和群图(
sns.stripplot
,sns.swarmplot
) - 盒子图和 Boxn 图(
sns.boxplot
,sns.boxnplot
) - 条形图和计数图(
sns.barplot
,sns.countplot
) - 提琴图(
sns.violinplot
) - 点图(
sns.pointplot
)
- 条带图和群图(
-
分布图:
- 分布,核密度估计(KDE)和地毯图(
sns.distplot
,sns.kdeplot
和sns.rugplot
)
- 分布,核密度估计(KDE)和地毯图(
-
回归图:
- 回归图和残差图(
sns.regplot
,sns.residplot
) - LM 图(
sns.lmplot
)
- 回归图和残差图(
-
多图网格:
- 联合图和联合网格图(
sns.jointplot
,sns.JointGrid
) - 配对图和配对网格图(
sns.pairplot
,sns.PairGrid
) - 方面网格(
sns.FacetGrid
)
- 联合图和联合网格图(
-
矩阵图:
- 热图(
sns.heatmap
) - 群集图(
sns.clustermap
)
- 热图(
介绍
Seaborn 是基于 Matplotlib 构建的功能强大的可视化工具。 它使多变量探索性数据分析更加容易和直观,并且增加了一些新类型的图,并且其背景样式和颜色表更加令人愉悦。 它具有许多内置的统计函数,使其成为统计数据分析的首选工具。 它还具有非常详尽的在线文档,您可以在这个页面中找到它们。
我们将使用两个数据集来演示大多数海洋特征。 您已经熟悉了一个数据集Wine Quality
,我们将引入一个新数据集,其中包含来自虚拟小吃店的零食销售数据。 无需在每个秘籍中多次阅读这些文件,我们将在本节中对它们进行描述,随后我们将仅使用它们来绘制图形。 这与我们到目前为止在本书中采用的方法略有不同。 这两个数据文件都可以在本章的代码库中找到。
零食销售数据集
该数据集(在代码库中提供)包含有关给定日期,星期几,是否为周末以及当天是否促销的各种商品的销售信息。 我们拥有三年的数据:2015 年,2016 年和 2017 年。数据集的前五行如下所示:
然后,我们将添加两个有助于绘制所需图形的派生变量:Month
(1 至 12)和Quarter
(1 至 4)。 添加这些变量后,的前五行如下所示:
以下代码块读取 Excel 文件并添加其他变量:
import pandas as pd
import numpy as np
snacks_sales = pd.read_csv('Snacks_Data.csv')
snacks_sales['Month'] = pd.DatetimeIndex(snacks_sales['Date']).month
Quarter_Mapping = {1:1, 2:1, 3:1, 4:2, 5:2, 6:2, 7:3, 8:3, 9:3, 10:4,
11:4, 12:4}
snacks_sales['Quarter'] = snacks_sales['Month'].map(Quarter_Mapping)
葡萄酒品质
该数据集具有 11 个影响葡萄酒质量的属性。Quality
的等级从 3 到 8,然后我们将 3 和 4 映射到Low
,将 5 和 6 映射到Med
,将 7 和 8 映射到High
以创建一个新变量:Quality
。
数据集的前五行如下所示:
我们还将为Wine Quality
数据集计算相关矩阵,我们将在一些图中使用它们。
以下是用于读取其他变量并将其添加到Wine Quality
数据集的代码块:
import pandas as pd
## Read the data from a csv file into pandas data frame
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
## Map numeric Quality codes to "Low", "Med" and "High" qualitative
ratings
quality_map = {3:'Low', 4: 'Low', 5:'Med', 6:'Med', 7:'High', 8:'High'}
wine_quality['Quality'] = wine_quality['quality'].map(quality_map)
## compute correlation matrix
corr = wine_quality.corr()
## Display the first 5 records of wine_quality dataset, and unique
values of quality variable
wine_quality.head()
set(wine_quality.quality)
语义和方面变量
除了在二维图中绘制关系的两个变量之外,seaborn 还可以绘制三个附加变量对两个主要变量之间的关系的影响图。 这三个变量称为语义变量。 它们被称为hue
,size
和style
,它们充当给定绘图函数的参数。
对于hue
的每个唯一值,将有一个关系图; 同样,对于style
的每个唯一值,将有一个关系图。 如果中有两个唯一值hue
变量(例如Yes
和No
),并且中有两个唯一值,则style
变量(例如s
和D
标记),则将有2 * 2 = 4
关系图(Yes & s
,Yes & D
,No & s
,No & D
组合)。 各种hue
值以不同的颜色绘制,各种style
值以不同的线或标记样式绘制。
同样,size
变量会影响为两个主要变量绘制的点的大小。 与, Matplotlib 散点函数不同,此处,size
变量范围分为多个桶,并将点分配给这些桶。 在 Matplotlib 散点函数中,每个点分别映射到size
变量中的不同值。
除了这三个语义变量之外,seaborn 还允许在row
和col
中添加另外两个变量,其中对于的每个唯一值,行/列变量将有一个图(轴域),它将按行/列排列。 这些row
和col
变量称为方面变量,因为它们使我们能够了解其他方面对所绘制的两个主要变量的影响。
这些附加变量可以映射到要分析数据的各个维度,或者要分析两个变量之间的关系。 在典型的销售分析方案中,两个主要变量可以是销售额(单位或美元)或时间(天,月或季度),维度可以是业务部门,产品线,地区/ 国家/地区,销售代表,促销活动,货币等。
关系图
关系图描述了两个连续变量之间的关系。seaborn
和relplot()
中有一个通用的 API,用于两种类型的绘图:行和散点图绘图。 但是,这两种类型也分别具有单独的函数:lineplot()
和scatterplot()
。 我们可以使用带有参数的relplot()
绘制线形图或散点图,或者直接使用lineplot()
和scatterplot()
函数。
带有一对一和一对多关系的线形图
在线形图中,观测值连接到可以自定义样式的线。x
和y
变量之间的关系可以是一对一的,有时也可以是一对多的。 在我们的Snack Sales
数据集中,如果将每个项目的销售额与日期或期间作图,则这是一对一的关系,因为每个日期/期间和销售额对都只有一个观察值。 但是,如果我们按月销售,则每个月有 30 个观察值(销售记录),这是一对多的关系。
Seaborn 提供了多种选择来绘制这两种类型的关系。 在主要秘籍中,我们将学习一对一的关系,在“更多”部分,我们将学习一对多的关系。
准备
导入所需的包:
import matplotlib.pyplot as plt
import seaborn as sns
操作步骤
以下是绘制具有各种选项的四个折线图的步骤:
- 设置背景样式:
sns.set(style='darkgrid')
- 绘制带有标题的
Period
和Smoothies
销售之间的折线图:
sns.relplot(x='Period', y='Smoothies',
data=snacks_sales.query("Period < 300"), kind='line')
plt.title('line plot', size=20, color='g')
- 绘制
Period
和Smoothies
销售之间的折线图,并以以一周中的天作为色调:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.relplot(x='Period', y='Smoothies', hue='daywk',
hue_order=day_order,
data=snacks_sales.query("Period < 300"), kind='line')
plt.title('line plot with hue=daywk', size=20, color='g')
- 以
Promotion
作为hue
在Period
和Smoothies
销售之间绘制折线图:
sns.relplot(x='Period', y='Smoothies', hue='Promotion', hue_order=
["Yes", "No"],
data=snacks_sales.query("Period < 300"), kind='line')
plt.title('line plot with hue=Promotion', size=20, color='g')
- 以
Promotion
作为hue
,weekend
作为style
在Period
和Smoothies
销售之间绘制折线图:
sns.relplot(x='Period', y='Smoothies', hue='Promotion', hue_order=
["Yes", "No"], style='weekend',
style_order=["Y", "N"], kind='line',
data=snacks_sales.query("Period < 300"))
plt.title('line plot with hue and style', size=20, color='g')
工作原理
这是代码的说明:
sns.set(style='darkgrid')
设置绘图的背景样式。 Seaborn 提供了五种预定义样式:dark
,darkgrid
,white
,whitegrid
和ticks
sns.relplot(x='Period', y='Smoothies', data=snacks_sales.query("Period < 300"), kind='line')
绘制和两个主要变量之间的关系,它们由x
和y
指定:Period
和Smoothies
是Snacks Sales
数据集中两个变量的名称Snacks Sales
是输入数据集,query("Period < 300")
将过滤器应用于数据集以仅绘制前 300 个观测值(行),因为绘制整个数据集太拥挤kind='line'
表示绘制折线图
- 对于第二个图,我们将添加
hue='daywk'
和hue_order=day_order
plt.title('line plot', size=20, color='g')
绘制标题,大小为 20 点,绿色。day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
指定在图表上绘制星期几的顺序hue='daywk'
表示绘制一周中每一天Period
和Smoothies
销售之间的关系,hue_order=day_order
指定一周中的这一天应按[day_order
列表- 对于第三张图,我们将更改
hue="Promotion"
并将["Yes", "No"]
映射到hue_order
- 对于第四个图,我们将添加
style='weekend'
和style_order=["Y", "N"]
执行上述代码后,您应该在屏幕上看到以下图表:
线形图:
线形图,色相为daywk
:
以色相作为促销的线形图:
具有色相和样式的线形图:
更多
在上一节中,Period
和Smoothies
销售具有一对一映射。 现在让我们用替换Period
到Month
变量中,每个月我们有 30 个观测值(行)。 我们将再次使用Month
和Smoothies
销售变量绘制四幅图。 我们将使用hue
和style
语义变量,并将Promotion
和weekend
映射到它们。
以下是绘制和所需图表的代码块:
sns.relplot(x='Month', y='Smoothies', data=snacks_sales, kind='line')
plt.title('line plot', size=20, color='g')
sns.relplot(x='Month', y='Smoothies', hue='Promotion',
data=snacks_sales, kind='line',
err_style="bars", ci=68) # Standard Errors
plt.title('line plot with Error bar and hue', size=20, color='g')
sns.relplot(x='Month', y='Smoothies', hue='Promotion', style='weekend',
kind='line', ci='sd', data=snacks_sales)
plt.title('line plot with hue and style', size=20, color='g')
sns.relplot(x='Month', y='Smoothies', hue='Promotion', style='weekend',
dashes=False, markers=True,
data=snacks_sales, kind='line', ci=None)
plt.title('line plot with hue and custom style', size=20, color='g')
plt.show();
这是代码工作方式的说明:
- 在第一个图中,在之前的部分与该部分之间,唯一的区别是变量从
Period
更改为Month
。 由于它们与Smoothies
销售的关系不同,因此该图看起来非常不同,并提供了不同的信息。 - 它基本上计算给定月份所有 30 个观测值的平均销售额,并绘制所有此类平均值的折线图。 它使用默认参数
ci=95
,这意味着要计算每个平均点周围的 95% 置信区间,并绘制每个平均点周围的范围,将所有这些平均点连接为线形图,最后对这些平均点之间的范围区域进行着色 - 您还可以通过指定
estimator=None
作为参数来关闭平均值和置信区间。 由于变量具有一对多关系,因此该图采用锯齿形! - 在第二个图中,通过指定
err_style='bars'
和 68% 的置信区间ci=68
,我们将默认线形图更改为误差图。 我们还添加hue = 'Promotion'
。 - 在第三幅图中,我们使用
ci='sd'
将每个月的置信区间从固定值更改为 30 个值的标准差,并添加style='weekend'
。 - 在第四个图中,通过指定
dashes=False
和'markers=True
,我们将的默认实线和虚线的默认线型替换为默认markers
。 除了markers=True
之外,我们还可以指定特定的标记,例如markers=['D', 's']
,以覆盖默认标记。 我们还指定ci=None
以避免在平均线形图周围绘制置信区间。
执行前面的代码和之后,您应该在屏幕上看到和以下图形:
线形图:
带有误差线和色调的线形图:
具有色相和样式的线形图:
具有色相和自定义样式的线形图:
带有长格式数据集的折线图
在先前的秘籍中,我们将两个变量之间的关系绘制为单线形图,并使用其他语义变量对其进行了分析。 输入数据集具有各个项目的销售数据,例如Pies
,Cakes
,Cookies
,Coffee
和Smoothies
,这些项目中的每一个都是数据集中的一列。 但是,如果要在相同的轴域/图上为这些项目中的每个项目绘制折线图以进行相对销售分析,则需要将输入数据略有不同,然后再将其传递给relplot()
。
准备
当前格式的输入数据称为宽格式,因为每一项都以一列表示,从而增加了表的宽度。 我们需要创建另一种长格式的数据集,其中所有项目都合并为一列,从而增加行数或表的深度。
以下是实现此目的的代码:
## Create a long form DataFrame from wide form DF
long_sales = pd.melt(snacks_sales, var_name='Item', value_name='Sales',
id_vars=['daywk', 'weekend', 'Date', 'Promotion',
'Period', 'Month', 'Quarter'])
long_sales.shape # dimensions, number of rows and columns
long_sales.sample(n=5) # Display random 5 sample rows
这是数据集中的五个随机行的外观:
操作步骤
我们将在此秘籍中绘制两个数字。 第一个图形有四个图,第二个有一个图:
- 第一张图使用色相变量描述了每个图中所有五个项目的销售额,但每个图代表
weekend
和Promotion
变量的组合,它们分别指定为row
和col
变量:
g = sns.relplot(x='Period', y='Sales', data=long_sales, kind='line',
hue='Item', row='weekend', col='Promotion')
- 第二个图描述了每月所有项目的 30 天每日销售额,但仅包括
weekend
销售,并且Promotion
为ON
和OFF
时:
## one line for each of Items
long_sales['Day'] = pd.DatetimeIndex(long_sales['Date']).day
sns.relplot(x='Day', y='Sales', hue='Promotion',
data=long_sales.query("weekend =='Y'"), kind='line',
units="Item", estimator=None, lw=1, height=6, aspect=2);
工作原理
这是前面代码的解释:
x
,y
,data
,kind
和hue
参数与我们在前面的秘籍中看到的参数完全相同row='weekend'
指定对于weekend
的每个唯一值,沿图的行绘制单独的轴域col='Promotion'
指定对于Promotion
的每个唯一值,沿图的列绘制单独的轴域- 当同时指定了
row
和col
变量时,它将使用两者的组合来绘制网格
结果图如下所示:
对于第二个图,我们首先定义一个派生变量Day
,以存储每个观察值/行的当月值并将其添加到输入数据集中。 一年中的每一天都会代表一年中的每个月进行 12 次销售观察。 我们将在此图中绘制按日销售:
data=long_sales.query("weekend =='Y'")
限制仅在周末绘制数据。units="Item"
指定为Item
的每个唯一值绘制折线图。estimator=None
关闭每个折线图的计算和绘图平均值以及置信区间lw=1
指定要绘制的线的宽度height=6
和aspect=2
指定图形的大小,高度为 6 英寸,宽度为 12 英寸(高度的两倍)
结果图如下。 它的一个问题是不清楚哪个线形图属于哪个项目! 目前,在这种情况下,它不允许我们绘制标签:
散点图
散点图将两个变量之间的关系绘制为单个点,而不相互连接。 它有助于可视化这些点如何在 x 和 y 轴上分布,以发现数据中是否存在任何模式或簇。 我们将使用与上一节相同的Snack Sales
数据集,并在主要部分中使用相同的语义变量,并在中使用row
和col
变量“更多”部分。
准备
导入所需的库并将背景样式设置为dark
:
import matplotlib.pyplot as plt
import seaborn as sns
操作步骤
- 在
Smoothies
销售和Period
之间绘制散点图:
sns.relplot(x='Period', y='Smoothies', data=snacks_sales,
kind='scatter')
plt.title('scatter plot', size=20, color='g')
- 添加
hue = 'Promotion'
:
sns.relplot(x='Period', y='Smoothies', hue='Promotion',
data=snacks_sales)
plt.title('scatter plot with hue', size=20, color='g')
- 添加
style = 'weekend'
:
sns.relplot(x='Period', y='Smoothies', hue='Promotion',
style='weekend', markers=['^', 'D'],
data=snacks_sales)
plt.title('scatter plot with hue and style', size=20, color='g')
- 添加
size = 'Cookies'
:
sns.relplot(x='Period', y='Smoothies', hue='Promotion',
style='weekend', size='Cookies',
markers=['^', 'D'],data=snacks_sales)
plt.title('scatter plot with hue, size and style', size=20,
color='g');
工作原理
lineplot()
和scatterplot()
之间的唯一区别是将kind='line'
更改为kind='scatter'
。 在relplot()
中,默认为kind='scatter'
,因此您可以省略此参数,就像我们在此处绘制的一些图所示。
所有,其他参数与前面的秘籍中的,完全相同。
这是绘图的样子:
散点图:
带有色相的散点图:
具有色相和样式的散点图:
具有色相,大小和样式的散点图:
更多
在本节中,我们将使用row
和col
参数以及hue
绘制相同的数据。
这是此代码:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.relplot(x='Period', y='Smoothies', hue='Promotion', col='daywk',
col_wrap=3, col_order=day_order, data=snacks_sales,
height=3)
sns.relplot(x='Period', y='Smoothies', col='daywk',
col_order=day_order, row='Promotion', row_order=['Yes',
'No'], data=snacks_sales, height=3)
plt.show();
col_wrap=3
指定仅绘制三列,然后将其包装到下一行。 使用此选项时,不能使用row
参数。
您应该在屏幕上看到和下图:
与hue_order
和style_order
相似,我们也可以指定row_order
和col_order
。
结果图如下:
类别图
当要绘制的两个变量之一是分类的,而不是连续的时,则使用类别图。 Seaborn 增强了 Matplotlib 提供的和类别图中的一些,并且还添加了一些其他图。 在本节中,我们将介绍五组这样的绘图。
Seaborn 提供了一个通用 API catplot()
来涵盖所有此类图。 这使您更容易熟悉一组通用参数,可以传递这些参数来绘制所有类型的类别图。 但是,每个不同的函数都可以直接使用,有时其中一些函数可能提供并非所有类型的绘图都通用的独特功能。 请参考这个页面上每个特定图的文档。
条带和群体图
由于其中一个变量是分类变量,因此,给定分类变量值的和其他变量的所有值都落在一条直线上,该直线具有许多重叠点,这使其难以可视化。 条带图和群体图允许将这些点绘制成稍微偏离直线,避免基于给定参数的重叠。
准备
导入所需的库,将背景样式设置为ticks
,并在以 Matplotlib 格式指定时启用color_codes
映射为seaborn
颜色:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks", color_codes=True)
操作步骤
- 用
jitter=0.05
和hue='Promotion'
绘制星期几Cookies
的销售条形图:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.catplot(x='daywk',y='Cookies', data=snacks_sales,
hue='Promotion', order=day_order, jitter=0.05, height=4,
aspect=2, kind='strip')
plt.title('stripplot with jitter=0.05', size=20, color='g')
- 使用,默认
jitter
和指定的调色板,绘制星期四(星期四除外)Cookies
的销售条形图:
sns.catplot(x='daywk',y='Cookies', data=snacks_sales.query("daywk !=
'Thursday'"), order=['Monday', 'Tuesday', 'Wednesday',
'Friday', 'Saturday', 'Sunday'],palette='Set1',
height=4, aspect=2); # jitter=False plots all the points
on one line similar to plt
plt.title('stripplot with default jitter', size=20, color='g')
- 绘制
Cookies
和一周中hue = 'Promotion'
的群销售图:
sns.catplot(x='daywk',y='Cookies', data=snacks_sales,
order=day_order, hue='Promotion',
kind='swarm',height=4, aspect=2)
plt.title('swarmplot', size=20, color='g');
工作原理
这是前面代码的解释:
order=day_order
指定在轴域上绘制,分类变量的唯一值的顺序。jitter=0.05
指定要应用的抖动量; 的值越大,的值越长直线范围。kind='strip'
指定图的类型,在这种情况下为stripplot()
。 但是,这是catplot()
的默认类型,因此也可以省略。- 如果要并排绘制
hue
变量值,而不是在同一条带上同时显示两种颜色,则可以传递和dodge=True
参数。 对于stripplot()
,默认为dodge=False
,这是我们在此处使用的内容。 data=snacks_sales.query("daywk != 'Thursday'")
过滤输入数据以排除Thursday
的所有观测值,因此该图仅包括一周中的剩余天数。palette='Set1'
指定要应用的调色板。 它类似于 Matplotlib 的cmap
。 我们也可以在此处使用 Matplotlib 提供的cmap
选项。- 我们将默认
jitter
用于第二个绘图。 默认值不是jitter
的固定值,而是根据输入数据分布而变化。 - 我们还可以通过指定
jitter=False
来关闭抖动,在这种情况下,其输出将类似于 Matplotlib 的输出。 - 第三个图
kind='swarm'
指定要绘制的游泳图。 在这里,它使用不同的算法在线上分布点,以确保根本没有重叠的点:
箱形图和 Boxn 图
boxplot()
与我们在 Matplotlib 中看到的类似,boxnplot()
是 Seaborn 的扩展,旨在提供有关该关系的更多详细信息。
boxplot()
提供中值(框内的线),第一个(框的底部)和第三个四分位数(框的顶部),顶部和底部的 1.5 IQR(1.5 倍的框的大小(垂直图的高度,水平图的宽度))位置的胡须,以及胡须以外的异常值的详细信息。 几百个观察说,对于大多数情况来说和数据集的大小很小,这已经足够了。
但是,当数据集很大时,则无法对和尾端提供足够的见解。boxnplot()
通过提供多个四分位数覆盖两端的尾端来解决boxplot()
的这一局限性。 有关此的更多详细信息,请参阅此处的论文。
准备
导入所需的库,将背景样式设置为ticks
,并在以 Matplotlib 格式指定时,将color_codes
映射为深浅的颜色:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks", color_codes=True)
操作步骤
在这里,我们将使用长格式数据集并绘制所有商品的销售情况:
- 绘制
boxplot()
,其中包含以下各项的销售额:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='box',
height=4, aspect=2);
- 为第二个图添加
hue=Promotion
:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='box',
hue='Promotion', height=4, aspect=2);
- 将色调更改为
hue=weekend
:
sns.catplot(x='daywk', y='Sales', data=long_sales, kind='box',
hue='weekend', order=day_order, height=4, aspect=2);
- 用
boxnplot()
重复和最后三步:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='boxen',
height=4, aspect=2);
sns.catplot(x='Item', y='Sales', data=long_sales, kind='boxen',
hue='Promotion', height=4, aspect=2);
sns.catplot(x='Sales', y='daywk', data=long_sales, kind='boxen',
hue='weekend',
order=day_order, height=4, aspect=2);
工作原理
这是前面代码的解释:
kind='box'
指定它是boxplot()
。dodge=True
是boxplot()
和boxnplot()
的默认值,因此默认情况下,将为和色调变量的每个唯一值绘制一个单独的图。 如果要在同一个箱图上绘制两个图,则必须传递dodge=False
参数。kind='boxen'
指定绘制一个箱形图。
执行上述代码后,您应该在屏幕上看到以下图表:
条形图和计数图
barplot()
与我们在 Matplotlib 中看到的类似,但是countplot()
是 seaborn 的扩展。barplot()
中条形的高度代表给定类别的所有观测值的平均值,而countplot()
中,条形高度代表给定类别的观察数。
准备
导入所需的库,将背景样式设置为ticks
,并在以 Matplotlib 格式指定时,将color_codes
映射为深浅的颜色:
import matplotlib.pyplot as plt
import seaborn as sns
from numpy import median
sns.set(style="ticks", color_codes=True)
操作步骤
我们将使用各种不同的选项绘制四个条形图和三个计数图:
- 使用,长数据格式的输入数据绘制
barplot()
,并在顶部用实际值标注条:
plt.figure(figsize=(9,4))
b = sns.barplot(x='Item', y='Sales', data=long_sales, estimator=sum,
palette='husl')
b.set(yscale='log', ylim=[50000, 1000000])
sns.despine()
for bar in b.patches:
b.annotate("{:,}".format(bar.get_height()),
(bar.get_x()+bar.get_width()/2.,bar.get_height()),
ha='center',va='center',xytext=
(0,10),textcoords='offset points',
color='b', weight='bold')
plt.title('Bar Plot: Long Data Format,value annotation &
estimator=sum', size=15, color='g', weight='bold')
- 使用全数据格式的输入数据绘制
barplot()
,以绘制所有数字变量:
sns.catplot(data=snacks_sales, kind='bar', height=4, aspect=2, #
wide form
order=['Cakes', 'Pies', 'Cookies', 'Smoothies',
'Coffee', 'weekday', 'Period'],
palette="Set1");
plt.title('Bar Plot: Wide Data Format,Plots all numerical
variables', size=15, color='g', weight='bold')
- 使用长数据格式,估计量等于中位数和自定义调色板绘制
barplot()
:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='bar',
hue='Promotion', hue_order=['Yes','No'], palette={"Yes":
"r", "No": "indigo"},
estimator=median, capsize=0.25, height=4, aspect=2);
plt.title('Bar Plot: Long Data Format, estimator=median and custom
palette', size=15, color='g', weight='bold')
- 用
estimator=len/count
,自定义误差宽度和颜色绘制barplot()
:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.catplot(x='daywk', y='Sales', data=long_sales, kind='bar',
hue='Promotion', ci='sd',
estimator=len, capsize=0.25, errcolor='m', errwidth=5,
hue_order=['Yes','No'], palette="muted",
order=day_order, height=4, aspect=2);
plt.title('Bar Plot, estimator=len(count), errwidth=5, errcolor=m',
size=15, color='g', weight='bold')
- 绘制一个
countplot()
,其中包含所有项目的销售额:
sns.catplot(x='Item', data=long_sales, kind='count', height=4,
aspect=2); # long form data frame
plt.title('Count Plot: Sales by Item', size=15, color='g',
weight='bold')
- 使用
hue
和自定义调色板绘制countplot()
:
sns.catplot(x='Item', data=long_sales, kind='count',
hue='Promotion', hue_order=['Yes','No'], palette={"Yes":
"r", "No": "indigo"}, height=4, aspect=2);
plt.title('Count Plot, hue=Promotion, custom palette', size=15,
color='g', weight='bold')
- 绘制
countplot()
,按星期几销售:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.catplot(x='daywk', data=long_sales, kind='count',
hue='Promotion', hue_order=['Yes','No'], palette="Set2",
order=day_order, height=4, aspect=2);
plt.title('Count Plot: Sales by day of the week', size=15,
color='g', weight='bold');
工作原理
这是前面代码的解释。 这是第一个绘图:
catplot()
和kind='bar'
不能灵活地捕获单个条形图,因此无法在每个条形图的顶部绘制值。 因此,对于第一个图,我们使用barplot()
,它类似于的 Matplotlib 条形图b = sns.barplot(x='Item', y='Sales', data=long_sales, estimator=sum, palette='husl')
绘制条形图:estimator=sum
指定指定给定项目的所有观测值之和,而不是默认平均值palette='husl'
指定要使用的调色板
b.set(yscale='log', ylim=[50000, 1000000])
在 y 轴上设置对数刻度并将限制设置为给定限制。sns.despine()
使和的上轴线和右轴线不可见。 如果要使左轴和底轴也不可见,则可以传递参数left=True
和right=True
。for bar in b.patches:
是一个for
循环,可捕获每个条形并在其顶部绘制值。 和与我们在第 2 章和“基本绘图入门”中所做的相同,对于是 Matplotlib 条形图。plt.title('Bar Plot: Long Data Format,value annotation & estimator=sum', size=15, color='g', weight='bold')
绘制图表标题。
这是第二个绘图:
- 我们直接传递宽格式数据集,而没有像到目前为止一样提供
x
和y
变量。 在这种情况下,默认情况下会绘制输入数据集中每个数字变量的条形图。 - 但是,我们可以通过不在顺序列表中指定这些变量来防止某些数字列被绘制。
order=['Cakes', 'Pies', 'Cookies', 'Smoothies', 'Coffee', 'Period']
:除实际项目外,我们顺序列表中仅包含Period
。 因此,即使它们是数字变量,也不会绘制weekday
,Month
和Quarter
变量。palette="Set1"
设置为预定义的调色板Set1
。
这是第三个绘图:
- 我们返回长数据格式并指定
x
和y
数据变量。 hue='Promotion'
指定使用不同的颜色映射为Promotion
的每个唯一值绘制条形图。hue_order=['Yes','No']
指定绘制Promotion
条的顺序。palette={"Yes": "r", "No": "indigo"}
指定自定义调色板字典。estimator=median
指定用于汇总给定项目的观察值的统计信息。 默认统计信息是平均值; 在这里,我们用中位数覆盖它。 在此数据集中,所有项目的均值和中位数彼此非常接近,因此我们可能无法观察到条形图中的差异。 某些函数sum
和len
在核心 Python 中可用,因此不需要导入它们,而median
在 Python 中不可用,因此我们需要从 NumPy 导入。capsize=0.25
在误差栏的顶部和底部指定和误差栏帽的宽度。
这是第四个绘图:
estimator=len
指定将汇总统计信息的长度(观察数)用作。ci='sd'
指定对置信区间的使用标准差,而不是固定百分比值。errcolor='m'
将误差栏的颜色指定为洋红色。errwidth=5
指定彩条线的宽度。
这是第五个绘图:
kind='count'
指定应绘制一个计数图。- 在这里,条形的高度是-每个项目类别中观察值的计数。 在这种情况下,所有项目的计数均相同。
这是第六个图:
- 我们加上
hue="Promotion"
,因此Promotion
的两个值的计数不同。 - 我们像第三张图一样使用自定义调色板
这是偶数图:
- 将 x 轴的
Item
替换为daywk
。 palette="Set2"
设置另一个预定义的调色板。
执行上述代码后,您应该在屏幕上的以下七个图上看到和:
提琴图
Seaborn 扩展了 Matplotlib 提供的提琴图功能,以在, 提琴图中包含不同的图。 与仅显示摘要统计信息的boxplot
不同,提琴图甚至显示数据的分布。
准备
导入所需的库,将背景样式设置为ticks
,并启用color_codes
,以 Matplotlib 格式指定时将其映射为 Seaborn 颜色:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks", color_codes=True)
操作步骤
我们将在此处绘制四个带有不同选项的提琴图:
- 在 x 轴域上绘制销量,在 y 轴域上绘制物品:
sns.catplot(x='Sales', y='Item', data=long_sales, kind='violin',
height=6, aspect=1)
plt.title('1\. Horizontal Violin Plot', size=15, color='g',
weight='bold')
- 在 x 轴域上绘制物品并在 y 轴域上绘制销量,添加
hue='Promotion'
,然后在提琴图的两侧分别填充不同的颜色:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='violin',
hue='Promotion',
hue_order=["Yes", "No"], split=True, height=4, aspect=2)
plt.title('2\. Vertical Violin Plot, hue=Promotion, split=True',
size=15, color='g', weight='bold')
- 用
hue='Promotion'
绘制垂直提琴图,并用数据填充提琴的两侧:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
sns.catplot(x='daywk', y='Sales', data=long_sales, kind='violin',
order=day_order, hue='Promotion',
hue_order=["Yes", "No"], split=True, inner="stick",
palette="pastel",height=4, aspect=2)
plt.title('3\. Violin Plot, hue=Promotion, split=True, inner=stick',
size=15, color='g', weight='bold')
- 用
hue='Promotion'
绘制垂直提琴图,用不同的颜色填充侧面,然后覆盖群图:
g = sns.catplot(x='daywk', y='Sales', data=long_sales,
kind='violin', order=day_order, hue='Promotion',
hue_order=["Yes", "No"], split=True, inner=None,
palette="pastel", height=4, aspect=2)
sns.catplot(x='daywk',y='Sales',
data=long_sales[long_sales['Period'] < 50], order=day_order,
color="k", size=3, kind='swarm',height=4, aspect=2, ax=g.ax)
g.ax.set_title('4\. Violin Plot with overlay of swarm plot', size=15,
color='g', weight='bold');
plt.axis('off'); # remove unwanted empty axes
工作原理
这是前面代码的解释。
这是第一个绘图:
x='Sales' and y='Item'
指定类别变量在 y 轴上,连续变量在 x 轴上,生成水平图kind='violin'
指定它是提琴图height=6
将图的高度指定为6
英寸aspect=1
表示,图的宽度为,与相同,高度
这是第二个图:
x='Item', y='Sales'
指定规则的垂直图。hue='Promotion'
将变量指定为Promotion
。hue_order=["Yes", "No"]
指定绘制Promotion
值的顺序。split=True
仅在hue
变量为二进制时适用,并指定提琴的每一侧应填充不同的颜色,代表的值hue
变量。
这是第三个图:
- 将
Item
变量替换为 x 轴上的daywk
变量,并提供绘制日期的顺序。 inner="stick"
指定绘制棒状线,代表和Promotion
变量的两个不同值,代表提琴每侧的数据分布; 这仅在split=True
时适用,而在,hue
变量为二进制时才适用。palette="pastel"
指定要使用的预定义调色板。
这是我们的绘图:
kind='violin'
指定绘制提琴图。inner=None
指定除了基于hue
的颜色映射外,不在提琴的任何一侧绘制任何内容。data=long_sales[long_sales['Period'] < 50]
将绘图限制为仅 50 个观测值,以避免混乱。kind='swarm'
指定violinplot
顶部的覆盖图为swarmplot
。ax=g.ax
指定叠加图的轴域,与绘制violinplot
的轴域相同。
执行上述代码后,您应该在屏幕上看到以下四个图:
点图
条带图和群图以不重叠的方式绘制属于特定类别的所有点。box
,boxn
和violin
图描绘了各种类别的一组点的摘要统计量; 同样,bar
和count
使用某些统计指标绘制汇总,并相应绘制条形图。 最后,point
图将聚合度量描述为图形中的一个点,各个类别的所有此类点均用线连接。
准备
导入所需的库,将背景样式设置为ticks
,并以 Matplotlib 格式指定时,将color_codes
映射为seaborn
颜色。 :
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks", color_codes=True)
操作步骤
我们将用不同的选项绘制四个点图:
- 绘制一个
pointplot()
和宽表单数据集,以绘制所有在顺序列表中列出的数字变量:
sns.catplot(data=snacks_sales, kind='point', ci=99.99, capsize=0.25,
height=4, aspect=2, order=['Cakes', 'Pies', 'Cookies',
'Smoothies', 'Coffee', 'weekday', 'Period'])
plt.title('1\. Point Plot with wide form dataset', size=15,
color='g', weight='bold');
- 使用长数据集绘制此
pointplot()
,以s
指定标记并将置信区间为的标准差绘制i
变量。
sns.catplot(x='Item', y='Sales', data=long_sales, kind='point',
markers='D', ci='sd', height=4, aspect=2) # long form
data frame
plt.title('2\. Point Plot with diamond marker and std as ci',
size=15, color='g', weight='bold');
- 使用其他
hue
和col
变量以及自定义调色板来绘制此pointplot()
:
sns.catplot(x='Item', y='Sales', data=long_sales, kind='point',
hue='Promotion', hue_order=['Yes','No'], palette={"Yes":
"r", "No": "indigo"},
markers=["^", "o"], linestyles=["-", "--"], ci=None,
col='daywk', col_wrap=3,
height=4, aspect=2, scale=1.5)
plt.suptitle("3\. Point Plot, hue=Promotion, col='daywk'", size=15,
color='g', weight='bold')
plt.tight_layout(pad=5,w_pad=0.25, h_pad=0.25);
- 以
pointplot()
和色相来表示每日销售量,并确保和线形图对于两个Promotion
的不同值不重叠:
sns.catplot(x='daywk', y='Sales', data=long_sales, kind='point',
hue='Promotion', dodge=True,
hue_order=['Yes','No'], palette="Set2", order=day_order,
height=4, aspect=2)
plt.title('4\. Point Plot of day wise sales with hue and dodge',
size=15, color='g', weight='bold');
工作原理
这是前面代码的解释。
这是第一个绘图:
kind='point'
指定它是pointplot()
。ci=99.99
指定置信区间。capsize=0.25
指定误差条顶部的盖子宽度。order=['Cakes', 'Pies', 'Cookies', 'Smoothies', 'Coffee', 'weekday', 'Period'])
指定轴上项目的顺序。
这是第二个图:
markers='D'
指定使用菱形标记代替圆圈。ci='sd'
指定对使用标准差作为置信区间。
这是第三个图:
hue='Promotion'
使用变量Promotion
指定色调。hue_order=['Yes','No']
是绘制色调值的顺序。palette={"Yes": "r", "No": "indigo"}
是自定义调色板。markers=["^", "o"]
使用这些标记为的每个唯一值指定Promotion
变量。linestyles=["-", "--"]
是每个折线图的线条样式。ci=None
指定不绘制的置信区间范围。col='daywk'
使用变量指定daywk
绘制列。col_wrap=3
指定每行仅绘制三个图,然后将下一行包装到中。scale=1.5
在默认大小上指定绘图上对象大小的比例因子。plt.suptitle()
打印整个图形的标题。plt.tight_layout(pad=5,w_pad=0.25, h_pad=0.25);
调整绘图之间的空间,并在图形顶部留出足够的空间,以使和标题完全合适。
这是我们的图:
- 它类似于第三图的,但不使用
col
变量并应用dodge=True
,因此将Promotion
的两个唯一值的图分开设置,而不是像第三幅图一样。
执行上述代码后,您应该在屏幕上看到以下四个图:
分布图
分布图用于可视化数据的概率分布。 Seaborn 提供了三个函数:distplot()
,kdeplot()
和rugplot()
。
通过传递适当的参数,distplot()
可用于核密度估计(KDE)和地毯分布。 但是,distplot()
限于单变量分布,而kdeplot()
也允许双变量分布。 因此,当需要双变量分布时,可以使用kdeplot()
,对于单变量分布,可以使用distplot()
。
distplot()
我们将绘制三个具有不同选项的不同分布图,以展示其大多数功能。
准备
导入所需的库,将背景样式设置为white
,并在以 Matplotlib 格式指定时,将color_codes
映射为深浅的颜色:
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import norm, pareto, gamma
sns.set(style="whitegrid", color_codes=True)
scipy.stats
是一个包含各种统计函数的科学 Python 库,norm
,pareto
和gamma
是不同类型的概率分布函数。 我们将使用它们来拟合和给定的数据集,以查看哪种分布非常适合该数据。
操作步骤
以下是绘制和所需图的步骤:
- 用直方图,KDE 和
rugplot
绘制销售Coffee
的分布:
sns.distplot(snacks_sales.Coffee, color='g', rug=True, rug_kws=
{"color": 'm', "height": 0.1})
plt.title('1\. Distribution Plot of Coffee Sales with rug=True',
size=15, color='g', weight='bold')
plt.show();
- 使用步骤类型直方图,带阴影的 KDE 和图例绘制曲奇销售的水平分布:
sns.distplot(snacks_sales.Cookies, vertical=True,
hist_kws={"histtype": "step", "linewidth": 3, "alpha":
1, "color": "indigo", "label": "Histogram"},
kde_kws={"shade": True, "color": "orange", "lw": 3,
"label": "KDE"})
plt.title('2\. Horizontal Distribution Plot of Cookies Sales',
size=15, color='g', weight='bold')
plt.show();
- 绘制销售的分布,并拟合三种不同的分布,以检查哪种分布最适合此数据:
ax = sns.distplot(snacks_sales.Smoothies, fit=norm, kde=False,
rug=True, color='b',
fit_kws={"color": "b"}, label='normal')
sns.distplot(snacks_sales.Smoothies, hist=False, fit=pareto,
kde=False, rug=True, color='g', label='pareto',
fit_kws={"color": "g"}, ax=ax)
sns.distplot(snacks_sales.Smoothies, hist=False, fit=gamma,
kde=False, color='r', label='gamma',
fit_kws={"color": "r"}, ax=ax)
ax.legend()
plt.title('3\. Distribution Plot - 3 different distribution
functions', size=15, color='g', weight='bold')
plt.show();
工作原理
这是前面代码的解释:
这是第一个绘图:
sns.distplot(snacks_sales.Coffee, color='g', rug=True, rug_kws={"color": 'm', "height": 0.1})
图。 这是必需的分布图。snacks_sales.Coffee
是要绘制其分布的咖啡销售数据。color='g'
指定默认情况下绘制的直方图和 KDE 图的颜色为绿色。- 如果要关闭直方图或 KDE 图,请传递参数
hist=False
和kde=False
。 rug=True
指定是否应在该分布图上绘制地毯图。 默认选项是False
,因此未绘制。rug_kws={"color": 'm', "height": 0.1}
是用于格式化地毯图的关键字字典。 在这里,我们使用了洋红色,在地毯图中,木棒的高度为o.1
。plt.show()
在屏幕上显示绘图,因此后续绘图不会在第一个绘图的顶部重叠。
这是第二个图:
vertical=True
指定该图应在垂直轴域上绘制,这表示水平直方图。 默认选项为False
,在这种情况下,它会绘制垂直直方图,如在第一个图中所示。hist_kws={"histtype": "step", "linewidth": 3, "alpha": 0.7, "color": "indigo", "label": "Histogram"}
是用于绘制直方图的参数的直方图关键字字典:"histtype": "step"
指定楼梯直方图,而不是规则的平滑坡道。"linewidth": 3
表示直方图的线宽为三点。"alpha": 0.7
指定直方图行的透明度级别。"color": "indigo"
指定直方图的颜色为靛蓝色。"label": "Histogram"
是出现在图例上的标签。
kde_kws={"shade": True, "color": "orange", "lw": 3, "label": "KDE"})
是用于绘制 KDE 绘图的参数的关键字字典:"shade": True
指定在 KDE 图下的区域应加阴影。"color": "orange"
指定用于 KDE 图的颜色,并在 KDE 曲线下的区域上加阴影。 尽管我们指定了一种颜色,但它的 KDE 曲线和曲线下的阴影区域使用略有不同的阴影来区分这两种颜色。"lw": 3
指定要绘制的线的宽度。"label": "KDE"
是出现在图例上的标签。
这是第三个图:
- 在该图中,我们为同一数据拟合了三条不同的曲线,以检查哪一条最合适。 实际上,存在许多连续和离散的分布。 根据数据的性质,我们在选择最佳分布之前先尝试这些分布。 在
distplot()
中使用它们之前,我们需要导入适当的包(scipy.stats
是一个很好的来源)以加载这些分发函数。 fit=norm
指定适合正态分布; 同样,fit=pareto
和fit=gamma
指定pareto
和gamma
分布函数以适合我们拥有的数据。kde=False
指定不绘制 KDE 曲线,因为我们正在拟合其他分布。 如果我们想将 KDE 曲线与其他分布进行比较,我们也可以保留它。rug=True
指定我们也应该为此数据绘制rugplot()
。fit_kws={"color": "b"}
是用于拟合给定分布函数的关键字字典。 它仅指定要用于分布曲线的颜色。
执行上述代码后,您应该在以下三个图中看到:
kdeplot()
KDE 是一种将分布函数拟合到给定数据集的非参数方法。 因此,对于给定的单变量(单变量)或双变量(两个变量)数据,kdeplot()
拟合并绘制 KDE 分布曲线。
准备
导入所需的库,将背景样式设置为white
,并启用color_codes
,以 Matplotlib 格式指定时将其映射为 Seaborn 颜色:
import matplotlib.pyplot as plt
import seaborn as sns
操作步骤
我们将绘制两个二元 KDE 图。 在第二个图中,我们将在相同的轴域上绘制两个具有不同变量集的 KDE 图,以进行比较:
- 用等高线和颜色条绘制双变量 KDE 图:
sns.kdeplot(snacks_sales.Smoothies, snacks_sales.Pies, kernel='epa',
n_levels=25, cmap='Reds', cbar=True)
plt.title('1\. Bivariate KDE Plot', size=15, color='g',
weight='bold');
plt.show();
- 用阴影区域绘制两组变量的双变量 KDE 图:
Cookies_temp = snacks_sales.Cookies + 500
ax=sns.kdeplot(snacks_sales.Period, snacks_sales.Coffee,
kernel='gau',shade=True, shade_lowest=False,
cmap='Purples_d')
sns.kdeplot(snacks_sales.Period, Cookies_temp, kernel='cos',
shade=True, shade_lowest=False, cmap='Blues')
ax.set_ylabel('Sales')
ax.text(0, 1400, 'Cookies', color='b', weight='bold')
ax.text(0, 650, 'Coffee', color='purple', weight='bold')
plt.title('2\. Bivariate KDE Plot - 2 sets of variables', size=15,
color='g', weight='bold')
plt.show();
工作原理
这是代码的说明。
这是第一个绘图:
snacks_sales.Smoothies
和snacks_sales.Pies
是要绘制的变量。kernel='epa'
指定要用于适合 KDE 的内核方法(Epanechnikov)。 其他可用选项包括gau
(高斯/正态),cos
(余弦),biw
(双权),triw
(三权)和tri
(三角形)。 有关更多详细信息,请参阅这里。n_levels=25
指定要绘制的轮廓数量。cmap='Reds'
指定要使用的颜色表。cbar=True
指定绘制颜色条。
这是第二个图:
Cookies_temp = snacks_sales.Cookies + 500
将所有观测值增加 500,这样这些值就不会与我们将在同一轴域上绘制的其他变量值重叠。ax=sns.kdeplot(snacks_sales.Period, snacks_sales.Coffee, kernel='gau',shade=True, shade_lowest=False, cmap='Purples_d')
在ax
轴域上绘制第一个 KDE 图。kernel='gau'
,使用高斯核方法shade=True
填充轮廓内的区域。shade_lowest=False
仅适用于shade=True
,仅适用于二元 KDE 图。 它迫使它不填充最外轮廓,该轮廓覆盖轮廓外轴域的整个区域。 如果我们不将其设置为false
,则可能会看到整个轴域的区域都填充了最外面轮廓的颜色。ax.set_ylabel('Sales')
覆盖从数据变量名称中拾取的默认 y 轴标签。ax.text(0, 1400, 'Cookies', color='b', weight='bold')
和ax.text(0, 650, 'Coffee', color='purple', weight='bold')
插入 KDE 图的标签:kdeplot()
中提供的'label'
选项仅适用于单变量图。 因此,我们在此处使用了text
选项。
执行上述代码后,您应该在屏幕上看到以下两个图:
| |
|
回归图
回归图有助于将二维数据拟合为线性或多项式曲线。 这有助于可视化两个变量之间的关系,以了解它与 n 的线性或多项式拟合的紧密程度。 Seaborn 为此提供了三个函数:regplot()
,residplot()
和lmplot()
。regplot()
和lmplot()
都具有将二维数据拟合为 n 的线性或多项式的相同目的,但是regplot()
是轴域级函数,而lmplot()
是图形级函数,使它能够使用row
和col
语义变量在单个图形中绘制多个回归图。residplot()
帮助拟合曲线并绘制残差以了解拟合的质量。
regplot()
和residplot()
我们将绘制两个回归图和一个残差图以演示这些函数中可用的各种选项。
准备
导入所需的库,将背景样式设置为dark
,并在以 Matplotlib 格式指定时,将color_codes
映射为深浅的颜色:
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import pearsonr
sns.set(style="dark", color_codes=True)
操作步骤
以下是绘制和所需图的步骤:
- 绘制线性回归图,并以 R 方和 p 值标注:
R, p = pearsonr(wine_quality['fixed acidity'], wine_quality.pH)
g1 = sns.regplot(x='fixed acidity', y='pH', data=wine_quality,
truncate=True, ci=99,
marker='D', scatter_kws={'color': 'r'});
textstr =
'$\mathrm{pearson}\hspace{0.5}\mathrm{R}^2=%.2f$\n$\mathrm{pval}=%.
2e$' % (R**2, p)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
g1.text(0.55, 0.95, textstr, transform=ax.transAxes, fontsize=14,
va='top', bbox=props)
plt.title('1\. Linear Regression', size=15, color='g', weight='bold')
- 绘制
2
阶多项式回归曲线:
g2 = sns.regplot(x='fixed acidity', y='pH', data=wine_quality,
order=2, ci=None,
marker='s', scatter_kws={'color': 'skyblue'},
line_kws={'color': 'red'});
plt.title('2\. Non Linear Regression of order 2', size=15, color='g',
weight='bold')
- 绘制逻辑回归曲线:
wine_quality['Q'] = wine_quality['Quality'].map({'Low': 0, 'Med': 0,
'High':1})
g2 = sns.regplot(x='fixed acidity', y='Q', logistic=True,
n_boot=750, y_jitter=.03, data=wine_quality,
line_kws={'color': 'r'})
plt.show();
- 绘制残差图:
g3 = sns.residplot(x='fixed acidity', y='density', order=2,
data=wine_quality, scatter_kws={'color': 'b',
'alpha': 0.5});
plt.show();
工作原理
这是代码的说明。
这是第一个绘图:
R, p = pearsonr(wine_quality['fixed acidity'], wine_quality.pH)
计算给定数据分布的和的R
和p
值。 R 方和 p 值表示数据拟合的质量。g1=sns.regplot()
绘制了回归曲线以及和原始数据点的散布图:truncate=True
指定仅在可用数据点之前拟合曲线。 默认设置是将其扩展到轴域的两端。ci=99
指定在线性曲线的周围绘制 99% 的置信区间。marker='D'
以菱形绘制点,而不是默认圆。scatter_kws={'color': 'r'}
是散点图关键字字典,具有要使用的属性。 用红色绘制点。- 富文本格式的
textstr
指定要在曲线上绘制的文本。 props
指定要在曲线上绘制的文本字符串周围的框的属性。g1.text()
在指定位置的打印文本。
这是第二个图:
g2 = sns.regplot()
绘制散点图,具有二阶多项式。order=2
指定拟合二阶多项式。ci=None
不在绘制拟合曲线周围的置信区间。marker='s'
以正方形绘制点,而不是默认圆。scatter_kws={'color': 'skyblue'}
为散点指定的颜色。line_kws={'color': 'red'}
指定回归线的颜色。
这是第三个图:
wine_quality['Q'] = wine_quality['Quality'].map({'Low': 0, 'Med': 0, 'High':1})
通过将Low
和Med
映射到0
以及将High
映射到1
,得出仅具有二进制值'0'或'1'的新质量变量。 这是拟合逻辑回归曲线所必需的。g3 = sns.regplot()
绘制散点图并拟合逻辑回归曲线:logistic=True
指定拟合逻辑回归曲线。n_boot=750
指定用于估计和置信区间的重采样次数。y_jitter=.03
指定要添加的偏差量,以使点不会重叠太多。 这仅影响可视化,并在拟合曲线之后和绘制之前添加。line_kws={'color': 'r'}
,用红色绘制拟合曲线。
这是我们的绘图:
g4 = sns.residplot()
绘制残差的散点图,并在0
残差周围绘制一条虚线。scatter_kws={'color': 'b', 'alpha': 0.5}
绘制蓝色的残留点,透明度为0.5
。
执行和之前的代码后,您应该在屏幕上看到以下四个图:
lmplot()
我们将绘制三个具有不同选项的绘图。 对于第一个,我们将使用hue
变量,对于,将第二个使用col
变量以及参数回归模型, 对于第三个变量,我们将col
变量与非参数回归模型一起使用。
准备
导入所需的库,将背景样式设置为dark
,并在以 Matplotlib 格式指定时,将color_codes
映射为深浅的颜色:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="dark", color_codes=True)
操作步骤
以下是绘制和所需图的步骤:
- 使用
Quality
作为变量hue
绘制线性回归图:
g1 = sns.lmplot(x='fixed acidity', y='pH', hue='Quality', hue_order=
['Low', 'Med', 'High'], logx=True,
data=wine_quality, height=4, aspect=2, ci=None)
- 使用
Quality
作为变量col
绘制参数回归图,并自定义标签,刻度和轴限制:
g2 = sns.lmplot(x='fixed acidity', y='pH', data=wine_quality, ci=99,
col='Quality', col_order=['Low', 'Med', 'High'],
height=3, robust=True, scatter_kws={'color': 'g'})
g2 = g2.set_axis_labels("Fixed Acidity", "pH")
g2.set(xlim=(0, 20), ylim=(2.4, 4.0), xticks=[5, 10, 15, 20],
yticks=[2.5, 3.0, 3.5, 4.0])
- 使用
Quality
作为变量col
绘制非参数回归图:
g3 = sns.lmplot(x='fixed acidity', y='density',
data=wine_quality,lowess=True, markers='s',
col='Quality', col_order=['Low', 'Med', 'High'],
height=3, line_kws={'color': 'g'})
plt.show();
工作原理
这是代码的说明。
这是第一个绘图:
hue='Quality'
将Quality
指定为,hue
变量,因此对于的每个唯一值,Quality
变量将绘制具有不同颜色的回归图。hue_order=['Low', 'Med', 'High']
是要绘制的色调变量值的顺序。logx=True
指定拟合形式为y = log(x)
的曲线。ci=None
指定不围绕曲线绘制置信区间。
结果图如下所示:
这是第二个图:
ci=99
指定绘制 99% 的置信区间。col='Quality'
将Quality
指定为列列变量,以便对于Quality
的每个唯一值,它沿图的列绘制回归图。col_order=['Low', 'Med', 'High'
指定图形在图形上的放置顺序。robust=True
指定要减轻离群值对曲线拟合数据的影响。scatter_kws={'color': 'g'}
指定以绿色绘制点。g2 = g2.set_axis_labels("Fixed Acidity", "pH")
用用户定义的标签覆盖的默认轴标签。g2.set(xlim=(0, 20), ylim=(2.4, 4.0), xticks=[5, 10, 15, 20], yticks=[2.5, 3.0, 3.5, 4.0])
会覆盖的默认轴限制和刻度。
结果图如下所示:
这是第三个绘图:
lowess=True
指定拟合非参数回归模型markers='s'
使用默认颜色绘制正方形的点line_kws={'color': 'g'}
将拟合曲线绘制为绿色
生成的图看起来像这里显示的图:
多图网格
在本章前面的“具有长格式数据集的线形图和点图”秘籍中,当我们将row
和col
变量用于线形图中的各种可视化方面时,我们已经看到了某些类型的多图网格。 但是, seaborn 提供了三组用于不同用途的预定义网格。
jointplot()
和JointGrid()
启用,将创建三个轴域/图作为一个图形。 主轴域称为联合图,其他两个称为边缘轴域。 边缘轴域之一在联合图的顶部,第二边缘轴域在联合图的右侧。 在联合图上绘制了两个变量之间的关系,并且在每个边缘轴域上绘制了这两个变量中的每一个的单变量分布。 这些函数具有各种参数,可以灵活地在这三个轴域的每一个上选择和类型的图形。
pairplot()
和PairGrid()
可以成对出现,每个成对包含两个变量。 我们只需传递宽格式数据集,并使用一条语句,就可以得到以行和列的网格形式显示所有数值变量之间成对关系的图形。 同样,这里有许多选择不同类型图形的选项。
jointplot()
和JointGrid()
以及pairplot()
和PairGrid()
之间的区别在于,可以灵活地选择各种参数和每种参数提供的图形类型。jointplot()
和pairplot()
灵活性较差,但易于使用并可以快速绘制。JointGrid()
和PairGrid()
提供更多的灵活性,有许多参数可供选择。
FacetGrid()
是多图网格的第三类。 用于hue
,style
,size
,row
和col
变量的组合的多维分析。 我们已经在关系图和类别图的上下文中看到了这些。 他们在内部使用FacetGrid()
; 在这里,我们将直接访问它。
jointplot()
和JointGrid()
jointplot()
使用kind
参数启用了五种绘图。 我们将为五种图绘制五种具有不同参数的图。
我们将使用JointGrid()
绘制另一组五个图,并利用其提供的灵活性来控制可在网格的三个轴域上绘制的图的类型和样式。
准备
这部分对于jointplot()
和JointGrid()
都是通用的,而“操作步骤”和“工作原理”部分将分别对它们分别重复。
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from scipy.stats import norm
from itertools import chain # chain enables iteration of multiple lists
in loops such as for loop.
## The following parameters are set in rc configuration file, so they
will be applicable for the entire session
## font_scale factor is the multiplier of default font size(instead of
absolute size, it is relative size)
sns.set(rc={"axes.linewidth": 1, "xtick.major.width": 1,
"ytick.major.width": 1,
"xtick.major.size": 5, "ytick.major.size": 5},
style="ticks", context="paper", font_scale=1.25)
jointplot()
我们将为jointplot()
支持的五种不同类型的绘图绘制五幅绘图。
操作步骤
以下是绘制和所需图形的步骤:
- 绘制回归图:
g1 = sns.jointplot(x='Pies', y='Smoothies', data=snacks_sales,
kind='reg',
marginal_kws=dict(bins=15, fit=norm, rug=True,
color='darkblue'),
space=0.1, color='g')
g1.ax_marg_x.set_title('1\. Regression Plot - Histogram, KDE, Normal,
Rug', size=20, color='g')
- 绘制散点图:
g2 = sns.jointplot(x='Cookies', y='Smoothies', data=snacks_sales,
s=100, marginal_kws=dict(kde=True, rug=True,
hist=False, color='orange'), space=0.1,
color='g', edgecolor="blue", alpha=0.6)
g2.ax_marg_x.set_title('2\. Scatter Plot - KDE, Rug', size=20,
color='g')
- 绘制 KDE 图:
g3 = sns.jointplot(x='Period', y='Smoothies', data=snacks_sales,
kind='kde', space=0, color='indigo')
g3.ax_marg_x.set_title('3\. KDE Plots', size=20, color='g');
- 绘制六角箱图:
g4 = sns.jointplot(x='Quarter', y='Pies', data=snacks_sales,
kind='hex', space=0, color='violet');
g4.ax_marg_x.set_title('4\. Hexbin Plot - Histograms', size=20,
color='g');
- 绘制残差图:
g5 = sns.jointplot(x='Cakes', y='Smoothies', data=snacks_sales,
kind='resid', space=0, color='c')
g5.ax_marg_x.set_title('5\. Residual Plot - Histogram, Normal',
size=20, color='g');
工作原理
这是代码的说明。
这是第一个绘图:
g = sns.jointplot()
绘制了三个图的所需联合图。kind='reg'
指定绘制回归图。marginal_kws=dict(bins=15, fit=norm, rug=True, color='darkblue')
是要应用于,边缘轴域图的参数的字典。 它们适用于,上和右边缘轴域,但与联合绘图对象无关:bins=15
是要绘制的直方图的仓数; 默认情况下,将绘制直方图。fit=norm
指定为给定数据拟合normal
分布曲线。rug=True
绘制给定数据的地毯图。color='darkblue'
是用于两个边缘轴域的所有元素的颜色。space=0.1
指定,联合图和边缘轴域之间的间距。0
表示它们紧密连接,彼此之间没有任何缝隙。color='g'
指定联合绘图对象的颜色。- 默认情况下,KDE 曲线将适合数据。 如果我们不想绘制它,我们应该将其设置为
false
。 在这种情况下,我们将同时具有 KDE 曲线和normal
分布曲线。
g1.ax_marg_x.set_title('1\. Regression Plot - Histogram, KDE, Normal, Rug', size=20, color='g')
绘制图的标题:ax_marg_x
是顶部的边缘轴域。jointplot()
内部调用JointGrid()
,这使我们可以访问,联合图和两个边缘轴域。 我们将在接下来介绍的JointGrid()
秘籍中详细了解它。size=20
是标题的字体大小,color='g'
将标题的颜色设置为绿色。
这是第二个图:
- 由于
kind='scatter'
是默认设置,因此我们没有提供 kind 参数。 因此,它绘制了一个散点图。 s=100
指定要绘制的每个点的大小。kde=True
使 KDE 曲线适合给定数据。rug=True
绘制地毯。hist=False
不会绘制直方图。color='orange'
是边缘轴域对象的颜色。space=0.1
是,联合轴域和边缘轴域之间的间距。color='g'
将绿色应用于联合绘图对象。edgecolor="blue"
是,边缘,圆圈的颜色。alpha=0.6
是和分散点的透明度。
执行后,这两个图应如下所示:
这是第三个图:
kind='kde'
是二元 KDE 图space=0
指定,联合轴域和边缘轴域之间没有空格color='indigo'
是所有对象的颜色; 由于我们尚未提供marginal_kws
,因此它对使用了相同的内容,边沿对象也是如此
这是我们的绘图:
kind='hex'
表示六角箱图space=0
表示联合轴域和边缘轴域之间没有间隙color='violet'
是所有对象的颜色
执行代码后,第三和第四图应如下所示:
这是第五个绘图:
kind='resid'
绘制残差绘图space=0
表示,联合轴域和边缘轴域之间没有空间color='c'
对所有对象使用青色颜色
执行前面的代码后,您应该看到第五张图,如下所示:
JointGrid()
我们将使用JointGrid()
和各种参数绘制五幅图,以展示大多数可用功能。
操作步骤
以下是绘制和所需图的步骤:
- 使用默认参数和轴域级自定义创建一个简单的
JointGrid
:
g1 = sns.JointGrid(x='Coffee', y='Cookies', data=snacks_sales,
space=0.1, height=6, ratio=2)
g1 = g1.plot(sns.regplot, sns.kdeplot)
##g = g.plot(plt.scatter, sns.distplot);
g1.ax_joint.set_xlabel('Coffee', color='g', size=20, weight='bold')
g1.ax_joint.set_ylabel('Cookies', color='g', size=20, weight='bold')
plt.setp(g1.ax_marg_x.get_yticklabels(), visible=True)
plt.setp(g1.ax_marg_x.get_xticklabels(), visible=True)
plt.setp(g1.ax_marg_y.get_xticklabels(), visible=True)
plt.setp(g1.ax_marg_y.get_yticklabels(), visible=True)
g1.ax_marg_x.set_facecolor('wheat')
g1.ax_marg_y.set_facecolor('wheat')
for l in chain(g1.ax_marg_x.axes.lines, g1.ax_marg_y.axes.lines):
l.set_linestyle('--')
l.set_lw(3)
l.set_color('red')
g1.ax_marg_x.set_title('1\. Regression Plot - KDE on marginals',
size=20, color='g')
- 用它们各自的参数分开联合和边缘图:
g2 = sns.JointGrid(x='Pies', y='Smoothies', data=snacks_sales,
space=0, ratio=2)
g2 = g2.plot_joint(sns.regplot, color="g", order=3, ci=68 )
g2 = g2.plot_marginals(sns.distplot, kde=False, rug=True, fit=norm,
color="#1EAFCD23")
g2.ax_marg_x.set_title('2\. Regression Plot - Histogram, Normal,
Rug', size=20, color='g')
- 将联合图,边缘
x
和边缘y
图分开,每个图上都有独立的控件:
g3 = sns.JointGrid(x='Pies', y='Smoothies', data=snacks_sales,
space=0, ratio=2)
g3 = g3.plot_joint(sns.regplot, color="g", order=3, ci=68)
g3.ax_marg_x.hist(snacks_sales['Pies'], color="b", alpha=.6,
bins=np.arange(0, 100, 5))
g3.ax_marg_y.boxplot(snacks_sales['Smoothies'], 1, 'gD')
g3.ax_marg_x.set_title('3\. Regression Plot - Histogram, Boxplot',
size=20, color='g');
- 在
JointGrid
上实现hue
:
g4 = sns.JointGrid("Cookies", "Smoothies", snacks_sales, space=0,
ratio=2)
i=1
for quarter, sales in snacks_sales.groupby('Quarter'):
sns.kdeplot(sales["Cookies"], ax=g4.ax_marg_x, label='Q'+str(i));
sns.kdeplot(sales["Smoothies"], ax=g4.ax_marg_y, vertical=True,
label='Q'+str(i));
g4.ax_joint.plot(sales["Cookies"], sales["Smoothies"], "D", ms=5)
i +=1
g4.ax_marg_x.set_title('4\. Scatter Plot - Histogram with hue, KDE on
marginals', size=20, color='g')
- 使用用户定义的联合和边缘图:
g5 = sns.JointGrid("Cookies", "Coffee", snacks_sales, space=0.5,
ratio=6)
def marginal_boxplot(a, vertical=False, **kws):
g = sns.boxplot(x="Promotion", y="Coffee", orient="v", **kws) if
vertical \
else sns.boxplot(x="Cookies", y="Promotion",
orient="h", **kws)
g.set_ylabel("")
g.set_xlabel("")
g5.plot_marginals(marginal_boxplot, palette={"Yes": "#ff000088", "No": "#00aa007e" }, data=snacks_sales,
linewidth=1, fliersize=10,notch=True)
sns.regplot(x="Cookies", y="Coffee", data=snacks_sales.query("Promotion == 'Yes'"), color="#ff000088",
truncate=True, label='Promotion: Yes', marker='D',
ax=g5.ax_joint,
scatter_kws={"s": 100, "edgecolor": "k", "linewidth":
.5, "alpha": .8})
sns.regplot(x="Cookies", y="Coffee", data=snacks_sales.query("Promotion == 'No'"),
color="#00aa007e", marker='^', label='Promotion: No',
scatter_kws={"s": 50, "edgecolor": "k", "linewidth": .5,
"alpha": .4},
line_kws={"linewidth": 2}, ax=g5.ax_joint)
g5.ax_marg_x.set_title('5\. Regression Plot with hue - Boxplots on
marginals', size=20, color='g')
g5.ax_joint.legend(loc=4)
plt.show();
工作原理
这是代码的说明:
这是第一个图:
g1 = sns.JointGrid()
设置网格:space=0.1
是联合图和边缘图之间的差距量。height=6
是绘图的高度,以英寸为单位。ratio=2
是联合绘图高度与边缘绘图高度的比率。
g1 = g.plot(sns.regplot, sns.kdeplot)
指定联合图的图类型,和边缘图均指定。 也可以使用plt.scatter
和sns.distplot
等其他兼容图来代替sns.regplot
和sns.kdeplot
。g.plot()
不能灵活地提供各种参数,它仅使用提供的绘图类型的的所有默认参数。 但是,可以进行轴域级自定义,如下所示:g1.ax_joint.set_xlabel('Coffee', color='g', size=20, weight='bold')
会覆盖联合轴域的默认 x 轴标签。"ax_joint"
是联合图的轴域名称。g1.ax_joint.set_ylabel('Cookies', color='g', size=20, weight='bold')
或会覆盖联合轴域的默认 y 轴标签。- 使边缘轴域刻度标签可见:
plt.setp(g1.ax_marg_x.get_yticklabels(), visible=True)
plt.setp(g1.ax_marg_x.get_xticklabels(), visible=True)
plt.setp(g1.ax_marg_y.get_xticklabels(), visible=True)
plt.setp(g1.ax_marg_y.get_yticklabels(), visible=True)
ax_marg_x
和ax_marg_y
是的名称,上,右边缘轴域
g1.ax_marg_x.set_facecolor('wheat')
设置,边缘 x 轴的面色(上图)。g1.ax_marg_y.set_facecolor('wheat')
设置,边缘 y 轴的面色(右图)。for l in chain(g1.ax_marg_x.axes.lines, g1.ax_marg_y.axes.lines):
是用于自定义两个边缘轴域上的折线图的循环:l.set_linestyle('--')
是要使用的线条样式。l.set_lw(3)
是线宽。l.set_color('red')
是线条的颜色。
g1.ax_marg_x.set_title('1\. Regression Plot - KDE on marginals', size=20, color='g')
绘制图形标题。ax_marg_x
是顶部边缘轴域,并且标题被打印在其顶部。 这部分中的所有其他图都相同。
这是第二个图:
-
在这里,我们可以分别绘制,联合图和边缘图,并可以传递适当的属性以自定义它们。
-
如第一张图所示,
g2 = sns.JointGrid(x='Pies', y='Smoothies', data=snacks_sales, space=0, ratio=2)
使用所需的数据设置了网格。 -
g2 = g2.plot_joint(sns.regplot, color="g", order=3, ci=68 )
在联合轴域上绘制回归图:- 我们可以传递适用于
sns.regplot()
的所有参数。 color="g"
指定使用绿色。order=3
,指定为所提供的数据拟合三阶多项式曲线。ci=68
指定置信区间,将围绕拟合曲线绘制。
- 我们可以传递适用于
-
g2 = g2.plot_marginals(sns.distplot, kde=False, rug=True, fit=norm, color="#1EAFCD23")
绘制两个边缘轴域上的分布图,提供的参数适用于以下两个方面:kde=False
并未绘制 KDE 曲线。rug=True
绘制地毯。fit=norm
拟合法线。color="#1EAFCD23"
使用十六进制形式指定的颜色。
执行前面的代码后,您应该在屏幕上看到以下两个图:
这是第三张图:
- 在这里,我们可以灵活地在两个边缘轴域上绘制不同类型的图。
g3 = sns.JointGrid()
创建网格,如,的前两个图所示。g3 = g3.plot_joint(sns.regplot, color="g", order=3, ci=68)
与第二个图中的相同。g3.ax_marg_x.hist(snacks_sales['Pies'], color="b", alpha=.6, bins=np.arange(0, 100, 5))
在顶部边缘轴域上绘制直方图。- 从本质上讲,
g3.ax_marg_x
就像标准的 matplotlib 轴域一样,我们可以使用 Matplotlib 图中的任何绘制任何东西。 在这里,我们正在绘制直方图,传递的参数来自 Matplotlib 直方图。 g3.ax_marg_y.boxplot(snacks_sales['Smoothies'], 1, 'gD')
在,右边缘轴域上绘制箱形图。 同样,它是 Matplotlibboxplot
和,传递的参数来自和 Matplotlibboxplot
。1
指定使用该槽口,默认为0
的默认为没有槽口的矩形框。'gD'
指定异常值的颜色和标记,在这种情况下为绿色和菱形。
这是第四张图:
- 在该图中,我们在
JointGrid
上实现了hue
,并且还在边缘轴域上绘制了 Seaborn 图。 在第三张图中,我们使用了 Matplotlib 图。 g4 = sns.JointGrid("Cookies", "Smoothies", snacks_sales, space=0, ratio=2)
与所有JointGrid
图的通常相同。i=1
将索引初始化为 1。for quarter, sales in snacks_sales.groupby('Quarter'):
是用于按季度对销售数据进行分组的for
循环,因此它们可以在边缘轴域上绘制,而双变量数据可以在联合轴域上绘制:sns.kdeplot(sales["Cookies"], ax=g4.ax_marg_x, label='Q'+str(i))
在顶部边缘轴域上使用标签 Q1,Q2,Q3 和 Q4 绘制 KDE 图,在for
循环的每个迭代中使用一个。sns.kdeplot(sales["Smoothies"], ax=g4.ax_marg_y, vertical=True, label='Q'+str(i))
在右边缘轴域上绘制另一个 KDE 图,其标签与顶部轴域相似:vertical=True
指定以水平方向进行绘制。
g4.ax_joint.plot(sales["Cookies"], sales["Smoothies"], "D", ms=5)
在和联合图上绘制散点图:"D"
正在使用菱形标记ms=5
是标记大小
执行上述代码后,您应该在屏幕上看到以下两个图:
这是第五个图:
- 在此,我们使用用户定义的函数在上绘制联合轴域和两个边缘轴域。 我们将继续产生色调效果。
g5 = sns.JointGrid("Cookies", "Coffee", snacks_sales, space=0.5, ratio=6)
照常创建网格。def marginal_boxplot(a, vertical=False, **kws):
是在边缘轴域域上绘制箱形图的函数:g5 = sns.boxplot(x="Promotion", y="Coffee", orient="v", **kws) if vertical\else sns.boxplot(x="Cookies", y="Promotion", orient="h", **kws)
- 我们不是在调用此函数,而是将其传递给
sns.plot_marginals()
函数,该函数会将vertical
标志设置为True
或False
,取决于它要绘制的轴域,上一条语句检查此标志的状态,并适当映射数据和方向参数。 g5.set_ylabel("") and g5.set_xlabel("")
从轴上删除默认标签。
g5.plot_marginals(marginal_boxplot, palette={"Yes": "#ff000088", "No": "#00aa007e" }, data=snacks_sales,linewidth=1, fliersize=10,notch=True)
在边缘轴域上绘制箱形图:marginal_boxplot
是我们定义的用于在边缘轴域上绘制箱形图的函数。palette
为变量的不同值指定颜色代码,该变量被用作色相变量。linewidth=1
指定在箱形图中绘制的线宽。fliersize=10
指定超出胡须的异常值的大小。notch=True
指定绘制带有缺口的框,而不是矩形框。
sns.regplot()
对Promotion=Yes
数据在联合轴域上绘制一次回归图,对Promotion=No
进行第二次绘制。 所有参数均在回归图(lmplot()
和regplot()
)中进行了详细讨论。 因此,我们在这里不再重复。g5.ax_joint.legend(loc=4)
在联合轴域右下角的上绘制图例。
执行前面的代码块后,您应该在屏幕上看到第五个图,如下所示:
pairplot()
和PairGrid()
pairplot()
和PairGrid()
允许在一个语句中将数据集中的所有数值变量成对绘制为两个。 这是了解整个数据集中变量之间存在的高级关系和联合的快速方法。 这加快了机器学习项目的特征设计过程。pairplot()
对于双变量绘图只有两个选项:散点图和回归。PairGrid()
没有任何这样的限制。
准备
此部分对于pairplot()
和PairGrid()
都是通用的,而“操作步骤”和“工作原理”部分将分别对它们分别重复。
导入所需的库:
import matplotlib.pyplot as plt
import seaborn as sns
## The following parameters are set in rc configuration file, so they
will be applicable for the entire session
## font_scale factor is the multiplier of default font size(instead of
absolute size, it is relative size)
sns.set(rc={"axes.linewidth": 1, "xtick.major.width": 1,
"ytick.major.width": 1,
"xtick.major.size": 5, "ytick.major.size": 5},
style="ticks", context="paper",
font_scale=1.25)
pairplot()
我们将数据集的仅作为数据集的子集,以免因变量太多而无法绘制出混乱的图表。 我们将仅包含五个项目, 促销变量,将用作色相变量。 以下代码提取所需的子集:
snacks_sales_items = snacks_sales.loc[:,['Cakes', 'Cookies', 'Pies',
'Smoothies','Coffee','Promotion']]
操作步骤
有三种方法可以指定要使用pairplot()
绘制的网格类型。 让我们绘制所有三种格式并查看其中的区别:
- 在提供的数据集中绘制所有数字变量:
sns.pairplot(snacks_sales_items, hue='Promotion', kind='reg')
plt.show();
- 从提供的数据集中绘制所选变量:
sns.pairplot(snacks_sales, vars=['Coffee', 'Pies'], hue='Promotion',
kind='reg')
plt.show();
- 在行和列网格中绘制从提供的数据集中选择的变量,类似于我们先前使用的方面变量:
g = sns.pairplot(snacks_sales, x_vars=['Coffee', 'Pies', 'Cakes'],
y_vars=['Cookies', 'Smoothies'],
hue='Promotion', kind='scatter')
g.fig.subplots_adjust(wspace=.02, hspace=.02);
plt.show();
工作原理
这是前面代码的解释。
这是第一个绘图:
sns.pairplot(snacks_sales_items, hue='Promotion', kind='reg')
创建并绘制所需的网格:snacks_sales_items
是我们刚刚为此秘籍创建的数据集。hue='Promotion'
指定色调变量。kind='reg'
指定应为所有双变量图绘制回归图。- 在对角线上,默认情况下会绘制单变量
kdeplot()
。
执行后,您应该在屏幕上看到以下图:
这是第二个图:
sns.pairplot(snacks_sales_items, vars=['Coffee', 'Pies'],hue='Promotion', kind='reg')
仅绘制两个变量:Coffee
和Pies
。- 其他参数与第一个图相同。
执行后,您应该在屏幕上看到以下图:
这是第三个图:
g = sns.pairplot(snacks_sales_items, x_vars=['Coffee', 'Pies', 'Cakes'], y_vars=['Cookies', 'Smoothies', hue='Promotion', kind='scatter')
将创建一个3 x 2
的网格,并在行中绘制x_vars
,在列中绘制y_vars
。kind='scatter'
,绘制双变量散点图。g.fig.subplots_adjust(wspace=.02, hspace=.02)
,可以水平和垂直调整绘图之间的间隔。 这也可以应用于第一图和第二图。
执行代码后,您应该在屏幕上看到以下图表:
PairGrid()
PairGrid()
与pairplot()
的工作原理非常相似,但提供了更大的灵活性,可以将任何类型的图分别用于对角线,非对角线甚至更低和更高的对角线图。 但是,PairGrid()
不支持pairplot()
的行和列矩阵网格,因为它沿对角线使用单变量图,而行和列网格仅具有双变量绘图。
操作步骤
除了完整的数据集和选定的变量列表之外,它还有三种方法可以在网格中指定图的特定类型:
- 对网格中的所有图形单元/轴域使用相同类型的图:
g = sns.PairGrid(snacks_sales_items, hue='Promotion', hue_kws=
{"marker": ["^", "D"]},
palette={'Yes': 'blue', 'No': '#00a99f05'})
g.map(plt.scatter, edgecolor='k', s=50)
g.add_legend()
g.fig.subplots_adjust(wspace=.02, hspace=.02);
- 将一种类型的单变量图用于对角线,将另一种双变量类型用于非对角线图:
g = sns.PairGrid(snacks_sales_items, vars=['Coffee', 'Pies',
'Smoothies'], hue='Promotion', palette={'Yes':
'Orange', 'No': 'g'})
g.map_diag(plt.hist, histtype="step", linewidth=2)
g.map_offdiag(sns.kdeplot, n_levels=25, cmap="coolwarm")
g.add_legend()
g.fig.subplots_adjust(wspace=.02, hspace=.02);
- 对于对角线使用一种单变量,对于对角线使用一种双变量类型,对于下部对角线图使用另一种双变量类型:
g = sns.PairGrid(snacks_sales_items, vars=['Cakes', 'Pies',
'Cookies'], hue='Promotion',
palette={'Yes': 'darkblue', 'No': 'r'})
g.map_diag(sns.stripplot, jitter=True)
g.map_upper(sns.regplot, order=2, ci=90)
g.map_lower(sns.residplot, order=2, lowess=True)
g.add_legend();
工作原理
这是前面代码的解释:
这是第一个绘图:
g = sns.PairGrid(snacks_sales_items, hue='Promotion', hue_kws={"marker": ["^", "D"]},palette={'Yes': 'blue', 'No': '#00a99f05'})
为数据集中的所有变量创建网格:hue_kws={"marker": ["^", "D"]}
指定要用于hue
变量Promotion
的Yes
和No
值的标记palette={'Yes': 'blue', 'No': '#00a99f05'}
指定颜色代码,它是用于色调变量的唯一值
g.map(plt.scatter, edgecolor='k', s=50)
在网格上的每个图上绘制散点图:edgecolor='k'
将散点图的上的点的边缘指定为黑色。s=50
指定散点图上点/标记的大小。
g.add_legend()
将图例添加到图形的中。 由于某些原因,seaborn
不会像所有其他类型的绘图一样自动添加!g.fig.subplots_adjust(wspace=.02, hspace=.02)
,可水平和垂直调整绘图之间的间隔。
执行代码后,您应该在屏幕上看到以下图:
这是第二个绘图:
-
g = sns.PairGrid()
与以前一样创建网格,并使用和标准参数 -
g.map_diag(plt.hist, histtype="step", linewidth=2)
指定在所有对角线上绘制直方图:histtype="step"
是一个楼梯,而不是平滑的曲线。linewidth=2
是直方图的线的宽度。
-
g.map_offdiag(sns.kdeplot, n_levels=25, cmap="coolwarm")
在所有非对角线上绘制 kde 图:n_levels=25
指定要绘制的轮廓数量。cmap='coolwarm'
是用于绘制轮廓的颜色表。g.add_legend()
添加图例。g.fig.subplots_adjust(wspace=.02, hspace=.02)
调整绘图之间的间隔。
执行代码后,您应该在屏幕上看到以下图:
这是第三个绘图:
g = sns.PairGrid()
为数据集中的一组选定变量创建网格。g.map_diag(sns.stripplot, jitter=True)
在对角单元上绘制条形图,并设置了抖动,以使所有点都不落在一条直线上。g.map_upper(sns.regplot, order=2, ci=90)
回归图绘制在和上对角线单元中:order=2
指定将二阶多项式拟合到给定数据。ci=90
围绕拟合多项式绘制 90% 的置信区间。
执行代码后,您应该在屏幕上看到以下图:
FacetGrid()
如前所述,FacetGrid()
用于执行,语义变量hue
,style
和size
以及方面变量row
和col
进行多维分析。 当我们了解关系图和类别图时,我们已经间接使用了这些功能。
准备
导入所需的库:
import matplotlib.pyplot as plt
import seaborn as sns
## The following parameters are set in rc configuration file, so they
will be applicable for the entire session
## font_scale factor is the multiplier of default font size(instead of
absolute size, it is relative size)
sns.set(rc={"axes.linewidth": 1, "xtick.major.width": 1,
"ytick.major.width": 1,
"xtick.major.size": 5, "ytick.major.size": 5},
style="ticks", context="paper",
font_scale=1.25)
操作步骤
以下是绘制各种FacetGrid()
图以演示其功能的步骤:
- 绘制单变量直方图:
g = sns.FacetGrid(snacks_sales, col="Promotion", row="weekend",
height=3)
g = g.map(plt.hist, "Cookies", bins=10, color='m')
- 绘制双变量群图:
g = sns.FacetGrid(snacks_sales, col="Promotion", row="weekend",
height=3, margin_titles=True)
g = g.map(sns.swarmplot, "Quarter","Smoothies", order=[1, 2, 3, 4],
color='g')
- 绘制一个二元回归图:
g = sns.FacetGrid(snacks_sales, col="Quarter", row="weekend",
hue="Promotion",hue_order=['Yes', 'No'],
height=3, margin_titles=True, palette="Set2",
hue_kws=dict(marker=["^", "v"]))
g = g.map(sns.regplot, "Cookies","Coffee")
g.set(xlim=(200, 900), ylim=(100,800))
g.add_legend();
- 绘制双变量点图:
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
item_order = ['Coffee', 'Cakes', 'Pies', 'Cookies', 'Smoothies']
g = sns.FacetGrid(long_sales, col="daywk",col_wrap=3,
col_order=day_order, hue="Promotion",
hue_order=['Yes', 'No'], palette="Set1", height=3,
legend_out=False,
aspect=1.5, margin_titles=True)
g = g.map(sns.pointplot, "Item","Sales",
order=item_order).set_titles("{col_name}").add_legend()
g = g.fig.subplots_adjust(wspace=.05, hspace=.15);
工作原理
这是前面代码的解释:
这是第一个绘图:
g = sns.FacetGrid(snacks_sales, col="Promotion", row="weekend", height=3)
创建网格:snacks_sales
是输入数据帧。col="Promotion"
指定Promotion
作为列变量。row="weekend"
将weekend
指定为行变量。height=3
指定网格中每个图的高度。- 默认长宽比为 1,这意味着宽度与高度相同。
g = g.map(plt.hist, "Cookies", bins=10, color='m')
在网格的所有图上绘制直方图:bins=10
,指定直方图中桶的个数。color='m'
,指定使用洋红色作为颜色。
这是第二个图:
g = sns.FacetGrid(snacks_sales, col="Promotion", row="weekend", height=3, margin_titles=True)
创建网格:margin_titles=True
指定的标题,行变量绘制在最后一列的右侧。
g = g.map(sns.swarmplot, "Quarter","Smoothies", order=[1, 2, 3, 4], color='g')
绘制了Smoothies
季度销售量的群体图。order=[1, 2, 3, 4]
指定要在 x 轴域上绘制四分之一的顺序; 由于它是一个数字值,因此可以自动采用升序。color='g'
将绘图上的点涂成绿色。
执行这两个图的代码后,您应该在屏幕上看到以下图:
这是第三个图:
-
g = sns.FacetGrid()
创建所需的网格:col="Quarter"
将Quarter
映射到列变量。row="weekend"
将weekend
映射到行变量。hue="Promotion"
将Promotion
映射到色调变量。hue_order=['Yes', 'No']
是绘制它们的顺序。height=3
将每个绘图的高度设置为 3 英寸。margin_titles=True
设置行变量的标题,以绘制在最后一列的右侧。palette="Set2"
使用预定义的调色板。hue_kws=dict(marker=["^", "v"])
指定将这些标记用于Promotion
变量的的唯一值。
-
g = g.map(sns.regplot, "Cookies","Coffee")
绘制了Cookies
和Coffee
变量的回归图 -
g.set(xlim=(200, 900), ylim=(100,800))
,设置 x 和 y 轴限制 -
g.add_legend()
表示,由于现在添加了和色相变量,因此我们可以绘制图例。
执行上述代码后,您应该在屏幕上看到以下图:
这是我们的绘图:
day_order
是指定工作日绘制顺序的列表item_order
是指定绘制项目顺序的列表g = sns.FacetGrid()
使用和以下属性创建网格:long_sales
是的长格式数据帧,其中包含要绘制的数据。col="daywk"
将变量daywk
映射到列。col_wrap=3
,指定将每三列后的后续图包装成行。col_order=day_order
,指定要绘制星期几的顺序。hue="Promotion"
是映射到hue
的Promotion
变量。hue_order=['Yes', 'No']
是绘制Promotion
值的顺序。palette="Set1"
是要使用的调色板。height=3
是每个图的高度。aspect=1.5
是网格中每个图的宽度,应为1.5
乘以高度。legend_out=False
指定不将图例推到右侧的图外。 然后,选择作为要打印的绘图中的最佳位置。 默认设置是在中心右侧的绘图区域外进行绘图。margin_titles=True
表示行变量的标题绘制在最后一列的右侧。
g = g.map(sns.pointplot, "Item","Sales", order=item_order).set_titles("{col_name}").add_legend()
:- 绘制项目和销量的点图。
order=item_order
按此顺序绘制item
。set_titles("{col_name}")
使用相应绘图的col_name
设置标题,而不使用默认标题。add_legend()
将图例添加到图形中。
g = g.fig.subplots_adjust(wspace=.05, hspace=.15)
,调整绘图之间的间隔。
执行上述代码后,您应该在屏幕上看到以下图:
矩阵图
尽管pairplot()
和PariGrid()
可以绘制每个变量包含两个变量的网格中的多个变量之间的关系,但矩阵图可以通过使用与变量相关的聚合度量(例如相关性,协方差)以矩阵格式启用此格式,或者可以正常使用两个相关变量的财务,销售或运营等数据。
Seaborn 提供了两个矩阵图,heatmap()
和clustermap()
。
Heatmap()
提供数字的彩色表示,以了解数字的增加,减少,偏离或收敛的趋势,这可能不容易直接用数字捕捉,特别是当数字太小或太大时。
Clustermap()
使用分层聚类方法,并绘制和生成的树状图。
热图
热图通过使用色表表示颜色中的数字,因此我们的眼睛可以捕捉到和数据中各种变量的相对强度。
准备
导入和所需的库。 设置背景样式并准备绘制图形所需的数据。
我们将使用和相同的长格式数据帧作为输入,按Item
和Quarter
分组以按季度获得各种商品的销售额,并根据其中的数据表创建一个数据透视表,仍是数据帧格式,可以将其提供给 Seaborn 绘图:
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='white')
## Prepare the data in matrix format with Quartes on rows and Items in
columns
sales = pd.DataFrame(long_sales.groupby(["Item",
"Quarter"]).Sales.mean())
sales = sales.reset_index()
sales = sales.pivot('Quarter','Item', 'Sales')
sales.head()
操作步骤
这是绘制和所需图形的步骤。 我们将绘制三个数字,一个接一个。 第一个图将具有三个图,第二个图将有一个图,第三个图将有两个图:
- 定义第一个图形对象并定义轴域对象,我们将在其上绘制 Seaborn 图:
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(15,5))
2.用预定义的颜色表绘制热图:
sns.heatmap(sales, annot=True, fmt='.0f', linewidths=.5,
cmap="YlGnBu", ax=ax1)
ax1.set_title('Using pre-defined Colorbar')
- 绘制热图,带有以特定值为中心的色表:
sns.heatmap(sales, annot=True, fmt='.0f',linewidths=.5, robust=True,
cmap="YlGnBu", center=sales.loc[3, 'Cookies'],
yticklabels=False, ax=ax2)
ax2.set_title("Colorbar Centered at [3, 'Cookies']")
- 绘制设置了颜色表显示的热图:
sns.heatmap(sales, annot=True, fmt='.0f',linewidths=.5, robust=True,
vmin=200, vmax=600,
cmap="YlGnBu", yticklabels=False, ax=ax3)
ax3.set(title='Colorbar range(200, 600)', ylabel='')
- 调整绘图之间的间距,并在屏幕上显示图形:
plt.tight_layout()
plt.show();
- 在第二个图形对象上定义,并在单独的轴域上绘制热图和色条,并使用水平色条:
grid_kws = {"height_ratios": (.9, .05), "hspace": .4}
f, (plot_ax, cbar_ax) = plt.subplots(2, gridspec_kw=grid_kws)
ax = sns.heatmap(sales, ax=plot_ax, cmap="Set1", annot=True,
fmt='.0f',linewidths=.5,
cbar_ax=cbar_ax, cbar_kws={"orientation":
"horizontal"});
- 定义第三个图,并绘制
wine_quality
相关矩阵的热图:
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16,6))
sns.heatmap(corr, annot=True, fmt='.2f',linewidths=.5,
cmap="inferno", ax=ax1)
- 在上一步中定义的第三个图上绘制部分相关矩阵的热图:
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
sns.heatmap(corr, mask=mask, vmax=.3, annot=True, fmt='.2f',
cmap="inferno", ax=ax2)
- 在屏幕上显示该图:
plt.show();
工作原理
这是前面代码的解释。
这是第一个数字:
-
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(15,5))
连续定义图形和三个轴域。 -
sns.heatmap(sales, annot=True, fmt='.0f',linewidths=.5, cmap="YlGnBu", ax=ax1)
绘制热图:sales
是季度和项目销售数据帧。annot=True
指定在图上显示实际数字。fmt='.0f'
指定和数字应以整数格式显示,没有任何十进制值。linewidths=0.5
指定应使用此宽度的线来绘制所有行和列。cmap=" YlGnBu"
指定预定义的颜色表。ax=ax1
指定要在其上绘制该图的轴域。
-
ax1.set_title('Using pre-defined Colorbar')
绘制第一个图的标题。 -
sns.heatmap(sales, annot=True, fmt='.0f',linewidths=.5, robust=True, cmap="YlGnBu", center=sales.loc[3, 'Cookies'], yticklabels=False, ax=ax2)
绘制了和第二个热图,该色表的中心位于和指定值处:robust=True
:当未指定vmin
和vmax
范围时,色表范围是通过降低异常值的权重得出的。center=sales.loc[3, 'Cookies']
将此颜色表的中心颜色设置为该值,并将颜色条调整为要绘制的数据范围。 如果选择的值在数据范围的任意一个极端上,则仅将原始色表的一半用于新色条。yticklabels=False
关闭此图的 Y 轴的刻度标签。ax=ax2
是绘制此图的轴域。
-
sns.heatmap(sales, annot=True, fmt='.0f',linewidths=.5, robust=True, vmin=200, vmax=600, cmap="YlGnBu", yticklabels=False, ax=ax3)
绘制了另一个热图,并在色条上设置了限制:vmin=200
是的下限,vmax=600
是上限。 数据中低于下限的所有数字,都以颜色条的下端着色,高于上限的数字都以颜色条的上端着色。
-
ax3.set(title='Colorbar range(200, 600)', ylabel='')
打印标题并关闭 y 轴标签。 -
plt.tight_layout()
调整绘图之间的间隔,以确保没有重叠。
执行上述代码后,您应该在屏幕上看到以下图:
这是第二个数字:
f, (plot_ax, cbar_ax) = plt.subplots(2, gridspec_kw=grid_kws)
定义图形和一列中的两个轴域。grid_kws = {"height_ratios": (.9, .05), "hspace": .4}
是网格的参数字典。 和两个轴域的高度之比为0.9:0.05
,因此和色条轴域的高度与绘图高度相比非常短。 两个轴域之间的水平间距为 0.4。ax = sns.heatmap(sales, ax=plot_ax, cmap="Set1", annot=True, fmt='.0f',linewidths=.5, cbar_ax=cbar_ax, cbar_kws={"orientation": "horizontal"})
绘制热图:sales
是要绘制的数据。ax=plot_ax
指定要放置绘图的轴域。cmap= "Set1"
是另一个预定义的颜色表。annot=True
在绘图上显示数字。fmt='.0f'
数字显示时不带十进制值。linewidths=0.5
线以 0.5 的宽度绘制在矩阵中。cbar_ax=cbar_ax
指定颜色条轴域。cbar_kws={"orientation": "horizontal"})
绘制水平颜色条。
执行上述代码后,您应该在屏幕上看到以下图:
这是第三个数字:
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16,6))
定义第三个图形,带有一行中的两个轴域。sns.heatmap(corr, annot=True, fmt='.2f',linewidths=.5, cmap="inferno", ax=ax1)
绘制,相关矩阵,和wine_quality
数据的热图。 最后两个图中已经说明了所有参数。- 对于第二个绘图,
mask = np.zeros_like(corr)
使用corr
矩阵的相同大小创建遮罩,并用零填充。 mask[np.triu_indices_from(mask)] = True
将上对角线的所有元素设置为True
,其他元素(对角线和下对角线单元)将保留为False(0)
。sns.heatmap(corr, mask=mask, vmax=.3, annot=True, fmt='.2f', cmap="inferno", ax=ax2)
绘制热图:mask=mask
指定要应用于整个矩阵的遮罩。 它仅显示设置为Zero(False)
的条目,并隐藏设置为True(1).
的条目。它将mask
矩阵中的索引与corr
矩阵匹配。vmax = 0.3
,将颜色条的限制设置为 0.3。 所有高于 0.3 的值将用颜色条顶部的颜色进行着色。cmap="inferno"
设置要在此处使用的另一个预定义颜色表。
执行上述代码后,您应该在屏幕上看到以下图:
群集图
顾名思义,clustermap()
使用分层聚类方法对数据集中的各种变量进行聚类,并绘制和生成的树状图。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set(style='white')
操作步骤
以下是绘制两个聚类图的步骤,一个在Wine Quality
数据集中具有原始数据,另外一个在相关的相关矩阵中:
- 绘制
Wine Quality
数据集的聚类图:
row_colors =
wine_quality["Quality"].map(dict(zip(wine_quality["Quality"].unique
(), "rbg")))
g = sns.clustermap(wine_quality.drop('Quality',axis=1),
standard_scale=1, robust=True,
row_colors=row_colors, cmap='viridis')
- 绘制
Wine Quality
数据集的相关矩阵的聚类图:
g = sns.clustermap(corr, figsize=(10,8), z_score=1, cbar_kws={"label":
"color bar"})
工作原理
这是代码的说明:
Wine Quality
数据集中的Quality
变量具有Low
,Med
和High
值,分别具有63
,1319
和217
计数。 我们要突出显示群集中的哪些观测值属于哪个质量等级。 因此,我们提取这三个唯一值,并为其分配红色,绿色和蓝色三种颜色,以便和对应的观察结果相应地着色:
row_colors = wine_quality["Quality"].map(dict(zip(wine_quality["Quality"].unique(), "rbg")))
获取所有观测值的索引,并为分配适当的颜色代码,分别对应Low
(绿色),Med
(蓝色)和High
(红色)值。g = sns.clustermap(wine_quality.drop('Quality',axis=1), standard_scale=1, robust=True, row_colors=row_colors, cmap='viridis')
绘制群集图:wine_quality.drop('Quality',axis=1)
从群集映射中删除了Quality
变量,因为它已用作色调。standard_scale=1
,指定标准化数据集中的所有变量。 这可以按行或按列进行。 我们要按列进行操作,因为我们想标准化按列组织的变量。 本质上,它计算变量的最小值和最大值,然后从每个值中减去最小值,然后将结果除以最大值。 这有助于改善模型的表现。row_colors=row_colors
指定要在聚类地图上显示的观测值的颜色代码。cmap='viridis'
指定要使用的颜色表。- 我们可以尝试使用,
method
参数分配链接的不同方法,以及使用metric
参数分配距离的指标。 有关更多详细信息,请参考这里。 - 我们可以分别使用
g.dendrogram_row.reordered_ind
和g.dendrogram_col.reordered_ind
来获取,行和群集的col
索引的序列,其中g
是clustermap
对象。
执行上述代码后,您应该在屏幕上看到以下图:
进一步的解释如下:
g = sns.clustermap(corr, figsize=(10,8), z_score=1, cbar_kws={"label": "color bar"})
绘制了Wine Quality
数据集的相关矩阵的聚类图:figsize=(10,8)
指定要在其中绘制群集图的图形的大小。z_score=1
是另一种标准化方法,其中为每个变量计算均值和标准差,从每个元素中减去均值,然后将其除以标准差,以便结果变量分布的平均值为零,标准差/方差为 1。
执行上述代码后,您应该在屏幕上看到以下图:
二、基本绘图入门
在本章中,我们将介绍绘制以下图形的方法:
- 线形图
- 条形图
- 散点图
- 气泡图
- 堆叠图
- 饼图
- 表格图
- 极坐标图
- 直方图
- 箱形图
- 提琴图
- 热图
- Hinton 图
- 图像
- 等高线图
- 三角剖分
- 流图
- 路径
介绍
一幅图片价值一千个单词,数据的可视化在寻找数据中的隐藏图案方面起着至关重要的作用。 在一段时间内,已开发出各种图形来表示不同类型变量之间的不同关系。 在本章中,我们将看到如何在不同的上下文中使用这些不同的图以及如何使用 Matplotlib 绘制它们。
线形图
线形图用于表示两个连续变量之间的关系。 它通常用于表示随时间变化的趋势,例如季度和年度的 GDP 增长率,通货膨胀,利率和股票价格。 我们在第 1 章“Matplotlib 剖析”中看到的所有图形都是线形图的示例。
准备
我们将使用 Google 股票价格数据绘制时间序列线形图。 我们将数据(日期和每日收盘价,用逗号分隔)保存在没有标题的.csv
文件中,因此我们将使用 Pandas 库进行读取并将其传递给matplotlib.pyplot
函数以绘制图形。
现在,使用以下代码导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下代码绘制了 Google 股票价格的时间序列图:
- 将
Google Stock Price
文件(日期和价格)加载到 x,y 坐标中:
stock = pd.read_csv('GOOG.csv', header=None, delimiter=',')
- 添加列名:
stock.columns = ['date','price']
- 将 pandas 数据帧转换为时间序列:
stock['date'] = pd.to_datetime(stock['date'], format='%d-%m-%Y')
- 将日期设置为 Pandas 数据帧的索引:
indexed_stock = stock.set_index('date')
ts = indexed_stock['price']
- 绘制图形:
plt.plot(ts)
- 在屏幕上显示图形:
plt.show()
工作原理
以下是代码的说明:
pd.read_csv()
函数指定以下内容:header=None
,输入文件没有标题delimiter=','
,date
和price
用逗号(,)分隔- 将数据读入
stock
数据帧
stock.columns
命令为stock
数据帧中的每个属性date
和price
分配名称。pd.to_datetime()
函数将日期从字符格式转换为日期时间格式。 格式:%d-%m-%Y
参数指定输入文件中日期的格式。stock.set_index()
将date
列设置为索引,以便price
列可以表示时间序列数据,plot
命令可以理解。
下图是您应该从前面的代码块获得的输出:
更多
除了从.csv
或.xlsx
文件中读取 Google 股票价格数据之外,还有一些标准 API,例如fix_yahoo_finance
和pandas_datareader
可以直接从打开的数据库中读取数据。
Standard APIs undergo frequent changes and at times the database websites are not responsive. You need to install these APIs on your machine, as they don't come with standard Python distributions.
在这里,我们将展示一个使用fix_yahoo_finance
的示例:
- 导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
import fix_yahoo_finance as yf
- 下载从 2017 年 10 月 1 日至 2018 年 1 月 1 日的
AAPL
每日收盘价:
data = yf.download('AAPL','2017-10-01','2018-01-01')
- 按日期绘制收盘价(
Close
)。 请注意,此处date
是默认的 x 轴,因为yf.download
创建具有date
索引的数据。 因此,我们不需要为绘图提供 x 轴坐标。 请注意,这里我们使用的是plot()
Pandas 命令,而不是 Matplotlib:
data.Close.plot()
- 在屏幕上显示图形:
plt.show()
您应该看到一个图形,就像这里描述的那样:
您可以尝试使用pandas_datareader
API。 有关更多详细信息,请参考这个页面上的文档。
条形图
条形图是使用条形图比较不同类别数据的图形。 根据分类变量使用哪个轴,可以垂直或水平显示条形图。 假设我们有的数据,即在一年的时间内在冰淇淋店每月售出的冰淇淋数量。 我们可以使用条形图对此进行可视化。
准备
我们将使用 Python calendar
包将数字月份(1 到 12)映射到相应的描述月份(1 月到 12 月)。
在绘制图形之前,我们需要导入必要的包:
import matplotlib.pyplot as plt
import numpy as np
import calendar
操作步骤
以下代码绘制了条形图:
- 设置 x 和 y 轴的数据:
month_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
units_sold = [500, 600, 750, 900, 1100, 1050, 1000, 950, 800, 700,
550, 450]
- 分配空间并指定图形的布局:
fig, ax = plt.subplots()
- 将描述性月份名称设置为 x 轴刻度:
plt.xticks(month_num, calendar.month_name[1:13], rotation=20)
- 绘制条形图:
plot = ax.bar(month_num, units_sold)
- 将数据值添加到条形的顶部:
for rect in plot:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2., 1.002*height,'%d' %
int(height), ha='center', va='bottom')
- 在屏幕上显示图形:
plt.show()
工作原理
这是前面的代码块的说明:
- Matplotlib 的较旧版本仅接受浮点数据类型作为其数据参数。 因此,月份必须以数字格式表示。
month_num
和units_sold
是 Python 列表,表示一年中每个月的销售数量。plt.subplots()
允许我们根据图形的数量以及如何在图形中组织图形来定义图形的布局。 我们将在第 3 章“绘制多个图表,子图和图形”和第 6 章“带有高级功能的绘图”中了解更多信息。 在这种情况下,我们使用它来访问要绘制条形图的轴域,以便可以用代表条形图的实际数据对其进行标注。 如果您从第 1 章“Matplotlib 剖析”中回想起,我们已经看到轴域是图形中的单个图。- 将月份格式从数字格式更改为 x 轴上的相应月份名称。
calendar.month_name[1:13]
将返回 1 月至 12 月,而plt.xticks()
将 x 轴代号从数字 1 到 12,更改为 1 月到 12 月,以提高可读性。 for
循环中的ax.text()
用其相应的数据值标注每个条。 此函数的参数指定必须在条形图上精确放置数据文本的位置:首先,获取当前条形图的 x 和 y 坐标,然后再添加bar_width / 2
到 x 坐标,以及1.002
高度到 y 纵坐标;然后,使用va
和ha
自变量,将文本居中对齐在条形上方:
更多
前一节的条形图垂直绘制条形图。 我们还可以绘制水平条形图,如下所示。 除了plt.xticks()
和plt.bar()
分别被plt.yticks()
和plt.barh()
代替外,大多数代码与上一节中使用的代码相同:
## matplotlib accepts only floating point data types as its arguments
for data.
## So months have to be represented in numerical format
month_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
units_sold = [500, 600, 750, 900, 1100, 1050, 1000, 950, 800, 700, 550,
450]
fig, ax = plt.subplots()
## change the month number to month name on y axis
plt.yticks(month_num, calendar.month_name[1:13], rotation=20)
## plot horizontal bar graph
plot = plt.barh(month_num, units_sold)
## Display the graph on the screen
plt.show()
这是输出图的外观:
散点图
散点图用于比较两个变量的分布,并查看它们之间是否存在任何相关性。 如果数据中有不同的群集/段,则在散点图中将很清楚。
准备
导入以下库:
import matplotlib.pyplot as plt
import pandas as pd
我们将使用pandas
读取 Excel 文件。
操作步骤
以下代码块绘制了一个散点图,描述了年龄和体重之间的关系:
- 将图形大小(宽度和高度)设置为(
10, 6
)英寸:
plt.figure(figsize=(10,6))
- 从 Excel 文件中读取年龄和体重数据:
age_weight = pd.read_excel('scatter_ex.xlsx', 'age_weight')
x = age_weight['age']
y = age_weight['weight']
- 绘制散点图:
plt.scatter(x, y)
- 设置 x 和 y 轴标签:
plt.xlabel('Age')
plt.ylabel('Weight)
- 显示图形:
plt.show()
工作原理
该代码的说明如下:
plt.figure(figsize=(10,6))
用大小(10, 6)
覆盖默认图形大小。pd.read_excel()
读取数据,并将值分配给 x 和 y 轴坐标。plt.scatter(x,y)
绘制散点图。plt.xlabel()
和plt.ylabel()
设置 x 和 y 轴标签以提高可读性。
在终端上显示图形。 您应该看到以下图表:
很明显,年龄和体重之间没有关系,因为这些点是分散的。 如果所描绘的两个元素之间存在相关性,我们将观察到直线或曲线的图案。
The previous graphs could have been plotted with the plt.plot()
method also. The plt.scatter()
method has a lot more flexibility to customize each of the points with different sizes, colors, and so on, which we will observe in the bubble plot section. However, this flexibility comes at the cost of performance. For larger datasets, the plt.plot()
method is lot faster than the plt.scatter()
method.
更多
在这里,我们将看到另一个散点图示例,在这里我们可以清楚地看到不同的段。
The Iris
flower dataset is the oldest dataset, introduced in 1936 by Ronald Fisher. The dataset has 50 examples each of three species of Iris, named Setosa, Virginica, and Versicolor. Each example has four attributes, and the length and width in centimeters of both sepals and petals. This dataset is widely used in machine learning (ML) for classification and clustering. We will use this dataset to demonstrate how a scatter plot can show different clusters within a dataset.
以下代码块绘制了花瓣的长度和宽度的散点图:
- 使用 Pandas 从
.csv
文件加载Iris
数据集:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
- 在文件中,每类物种都用描述性名称定义,我们将其映射为
0
,1
或2
的数字代码:
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
- 以 x 轴上的花瓣长度和 y 轴上的花瓣宽度绘制散点图:
plt.scatter(iris.petal_length, iris.petal_width, c=iris.species)
- 标记 x 和 y 轴:
plt.xlabel('petal length')
plt.ylabel('petal width')
- 在屏幕上显示图形:
plt.show()
这是代码的说明:
pd.read_csv()
将数据读取到iris
数据帧中。- 数据帧中的
species
属性具有描述性的类名setosa
,versicolor
和virginica
。 但是,如果我们想用不同的颜色绘制每个类,则传递的参数应该是数字代码。 因此,我们将它们映射到数字代码。 iris['species'] = iris['species'].map()
将描述性名称替换为0
,1
和2
数字代码。c=iris.species
指定到不同类别的颜色映射。 这些参数类应该是数字的,这是我们之前所做的。plt.scatter()
绘制散点图。
您应该在屏幕上看到以下图形:
显然,我们可以在此处看到三个不同的群集。 但是,尚不清楚哪种颜色代表山,杂色和弗吉尼亚簇。 在随后的章节中,我们将看到如何使用标签来区分不同的聚类,在此我们将学习如何自定义图。
气泡图
使用相同的plt.scatter()
方法绘制气泡图。 它是散点图的体现,图中的每个点都显示为气泡。 这些气泡中的每一个都可以显示为不同的颜色,大小和外观。
准备
导入所需的库。 我们将使用 Pandas 来读取 Excel 文件:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下代码块绘制了一个气泡图,我们之前已经看到了一个散点图:
- 加载
Iris
数据集:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
- 在文件中,每类物种都定义为
0
,1
和2
,我们将其映射为它们的描述性名称:
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
- 绘制散点图:
plt.scatter(iris.petal_length, iris.petal_width,
s=50*iris.petal_length*iris.petal_width,
c=iris.species,
alpha=0.3)
- 标记 x 和 y 轴:
plt.xlabel('petal length')
plt.ylabel('petal width')
- 在屏幕上显示图形:
plt.show()
工作原理
以下是该代码的说明:
pd.read_csv()
读取数据并用数字代码替换描述性名称,如前所述。s = 50 * iris.petal_length * iris.petal_width
指定气泡的大小。 它实质上代表了该区域。s
公式中使用的常数50
是一个随机数,该常数将每个点的面积乘以该常数。 该常数越小,所有点的相对大小将越小。 尝试将此常数从 25 更改为 50,然后更改为 100,然后查看气泡大小如何变化。 如果没有此乘数,则某些点的大小太小而无法在图中观察到它们。c = iris.species
在数据中指定不同的类(群集)。pyplot
方法使用此方法以不同的颜色表示这些类别中的每一个。alpha=0.3
指定气泡的外观,并确定气泡的透明度。 范围是 0 到 1; 如果值接近零,则气泡高度透明;如果值接近 1,则气泡高度不透明:
堆叠图
堆叠图表示线形图下的区域,多条线形图彼此叠放。 它用于提供的可视化,即 y 轴域上绘制的多个变量的累积效果。
我们将通过缺陷原因代码绘制产品缺陷的数量,将三个月堆叠在一起,以给出该季度的累积情况。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下是绘制堆叠图的步骤:
- 定义图的数据:
x = np.array([1, 2, 3, 4, 5, 6], dtype=np.int32)
Apr = [5, 7, 6, 8, 7, 9]
May = [0, 4, 3, 7, 8, 9]
June = [6, 7, 4, 5, 6, 8]
- 定义要用于图例的
labels
列表:
labels = ["April ", "May", "June"]
- 定义图形和轴域:
fig, ax = plt.subplots()
- 绘制
stackplot
和legend
:
ax.stackplot(x, Apr, May, June, labels=labels)
ax.legend(loc=2)
- 设置标签和标题:
plt.xlabel('defect reason code')
plt.ylabel('number of defects')
plt.title('Product Defects - Q1 FY2019')
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
x = np.array([1, 2, 3, 4, 5, 6], dtype=np.int32)
是产品缺陷代码的列表,数据类型为整数。Apr = [5, 7, 6, 8, 7, 9]
是按缺陷代码分类的 4 月份产品缺陷计数的列表。May = [0, 4, 3, 7, 8, 9]
是按月份分类的缺陷代码的产品缺陷计数列表。June = [6, 7, 4, 5, 6, 8]
是按月份分类的缺陷代码的产品缺陷计数列表。labels = ["April ", "May", "June"]
是用作图例的标签列表。fig, ax = plt.subplots()
定义图形和要在其上绘制图形的轴域。ax.stackplot(x, Apr, May, June, labels=labels)
绘制具有给定数据和标签的堆叠图。ax.legend(loc=2)
指定要在图的左上方绘制的图例; 我们将在第 4 章“开发可视化以提高发布质量”中了解有关图例位置的更多信息。plt.xlabel('defect reason code')
绘制 x 轴的标签。plt.ylabel('number of defects')
绘制 y 轴标签。plt.title('Product Defects - Q1 FY2019')
绘制图形标题。plt.show()
在屏幕上显示图形。
在执行前面的代码时,您应该在屏幕上看到下图:
饼图
饼图用于表示各种类别/组对总数的贡献。 例如,每个州对国家 GDP 的贡献,一部电影对一年中发行的电影总数的贡献,学生等级(A,B,C,D 和 E)占总班级人数的百分比 ,或每月家庭支出在杂货,蔬菜,公用事业,服装,教育,医疗保健等方面的分配。
准备
导入所需的库:
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了一年中发行的电影类型的饼图:
- 设置饼图的数据:
labels = ['SciFi', 'Drama', 'Thriller', 'Comedy', 'Action', 'Romance']
sizes = [5, 15, 10, 20, 40, 10] # Add upto 100%
- 稍微在圆外显示一个切片:
explode = (0, 0, 0, 0, 0.1, 0) # only "explode" the 5th slice (i.e.'Action')
- 绘制饼图:
plt.pie(sizes, labels=labels, explode=explode, autopct='%1.1f%%',
shadow=True, startangle=90)
- 相等的长宽比可确保将饼图绘制为圆形。 默认值为椭圆:
plt.axis('equal')
- 在屏幕上显示图形:
plt.show()
工作原理
以下是代码的说明:
labels
和sizes
是 Python 列表,代表流派和一年中发行的电影总数的百分比。 输入列表中标签的顺序在饼图中按逆时针方向绘制。explode
参数指定要向外展开图表的哪个部分。autopct
自变量描述了要在百分比数据点中显示的小数点的数量。 如果省略此参数,则切片将不显示实际百分比(%
)数据。shadow
参数指定是否应在每个切片上显示阴影。startangle
参数指定第一个切片应开始的角度,并且它逆时针旋转以表示饼图中的所有其他切片。plt.pie()
绘制饼图。plt.axis(equal)
表示图表应显示为圆形(x 和 y 轴相等)。 默认形状是椭圆:
表格图
表格图是条形图和表格的组合,表示相同的数据。 因此,它是图形表示与表格中相应数据的组合。
准备
我们将以每年销售的电池数量为例,不同的安时(Ah)额定值。 有两个类别变量:年份和 Ah 等级,一个数字变量:售出的电池数量。
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了一张表格,列出了每年出售的电池类型:
- 准备数据:
rows = ['2011', '2012', '2013', '2014', '2015']
columns = ('7Ah', '35Ah', '40Ah', '135Ah', '150Ah')
data = [[75, 144, 114, 102, 108], [90, 126, 102, 84, 126],
[96, 114, 75, 105, 135], [105, 90, 150, 90, 75],
[90, 75, 135, 75, 90]]
- 定义 y 轴的范围和比例:
values = np.arange(0, 600, 100)
- 指定要使用的色谱。 每年将以不同的颜色表示:
colors = plt.cm.OrRd(np.linspace(0, 0.5, len(rows)))
- 定义要绘制条形的 x 轴刻度:
index = np.arange(len(columns)) + 0.3
bar_width = 0.5
- 初始化堆叠条形图的垂直偏移量:
y_offset = np.zeros(len(columns))
- 根据图形和轴域指定绘图区域:
fig, ax = plt.subplots()
- 绘制条并为表格创建文本标签。 初始化用于保存表数据的列表:
cell_text = []
for
循环的每次迭代都以一种颜色绘制所有电池额定值的一年数据:
n_rows = len(data)
for row in range(n_rows):
plot = plt.bar(index, data[row], bar_width, bottom=y_offset,
color=colors[row])
y_offset = y_offset + data[row]
cell_text.append(['%1.1f' % (x) for x in y_offset])
i=0
## Each iteration of this for loop, labels each bar with
corresponding value for the given year
for rect in plot:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2, y_offset[i],'%d'
% int(y_offset[i]),
ha='center', va='bottom')
i = i+1
- 在轴域的底部添加一个表格:
the_table = plt.table(cellText=cell_text, rowLabels=rows,
rowColours=colors, colLabels=columns, loc='bottom')
plt.ylabel("Units Sold")
- x 轴上有 n 个刻度,因为此表覆盖了标签:
plt.xticks([])
plt.title('Number of Batteries Sold/Year')
- 在屏幕上显示图:
plt.show()
工作原理
以下是代码的说明:
rows
是年份列表,columns
是电池额定值列表。 它们以图表中表格的行和列的形式绘制。data
是给定年份中每种额定电池的销售数量,例如,2011 年售出 75 单位 7Ah 电池。values
是指定 y 轴比例的列表,增量为 100,从零开始,最大为 600。 这是一个堆叠的条形图,它应该涵盖所有年份中给定电池额定值的总和(在这种情况下,最大值为 576)。plt.cm.OrRd()
指定强度变化的颜色范围; Matplotlib 中有预定义的颜色表。 我们将在第 4 章“开发可视化来提高发布质量”中介绍这些内容。 在这里,它用于以不同的颜色显示每年的数据。index
指定每个条形在 x 轴上的位置,bar_width
指定每个条形的宽度。y_offset
表示每年的数据应在 y 轴上的起始位置,因为每年的数据彼此堆叠。 从底部开始,从零开始,然后每年继续增加。- 当启动
for
循环时,每次迭代都会绘制给定年份所有电池额定值的条形,然后再进行另一个for
循环以用相应的数据标签标注每个条形。 - 第二个
for
循环中的参数指定将数据文本放置在小节上方的确切位置。 首先,获取当前条形 x 和 y 坐标,然后将bar_width/2
添加到 x 坐标,然后y_offset[i]
给我们 y 座标; 然后,使用va
和ha
,参数将文本在条上居中对齐。 - 然后添加
Y-label
,标题和掩码X-ticks
。
这是绘图的样子:
极坐标图
极坐标图是在极坐标轴域上绘制的图表,其坐标为角度(以度为单位)和半径,与 x 和 y 的笛卡尔系统相对。 我们将以组织中各个部门产生的计划支出与实际支出为例。 这也称为蜘蛛网图。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
Since it is a circular spider web, we need to connect the last point to the first point, so that there is a circular flow of the graph. To achieve this, we need to repeat the first department data point at the end of the list again. Hence, in the following example, 30 and 32 (the first entry in each of the lists) are repeated at the end again.
以下代码块绘制了一个极坐标图并将其显示在屏幕上:
- 设置极坐标图的数据:
Depts = ["COGS","IT","Payroll","R & D", "Sales & Marketing"]
rp = [30, 15, 25, 10, 20, 30]
ra = [32, 20, 23, 11, 14, 32]
theta = np.linspace(0, 2 * np.pi, len(rp))
- 通过设置图形大小和极坐标投影来初始化蜘蛛图:
plt.figure(figsize=(10,6))
plt.subplot(polar=True)
- 排列网格线以与每个部门名称对齐:
(lines,labels) = plt.thetagrids(range(0,360, int(360/len(Depts))),
(Depts))
- 绘制计划支出图,这是极坐标上的折线图,然后填充其下的区域:
plt.plot(theta, rp)
plt.fill(theta, rp, 'b', alpha=0.1)
- 绘制实际支出图,这是极坐标上的折线图:
plt.plot(theta, ra)
- 为图添加图例和标题:
plt.legend(labels=('Plan','Actual'),loc=1)
plt.title("Plan vs Actual spend by Department")
- 在屏幕上显示图:
plt.show()
工作原理
以下是代码的说明:
Depts
是组织中部门的列表。rp
和ra
是按部门列出的计划支出和实际支出的列表。plt.figure(figsize=(10,6))
设置图形大小。plt.subplot(polar=True)
设置极性投影。pyplot
方法仅接受弧度作为输入,因此我们需要将2 * np.pi
(相当于 360 度)弧度平均划分为多个部门,以获取每个部门的角度坐标。np.linspace(0, 2 * np.pi, len(rp))
执行此计算。
While the coordinates need to be given in radians, the degree equivalent is easy for visualization. To convert radians to degrees, you can use np.degrees
(theta
).
- 极角投影上的默认网格线为 45 度(360 度分为八个相等的部分,每个部分 45 度)。 由于我们的部门较少(只有五个),因此需要将网格数限制为部门数。
plt.thetagrids(range(0,360, int(360/len(Depts))), (Depts))
函数创建网格并用部门名称标记它们。 如果需要,此函数还返回可以随后使用的行和标签对象。plt.plot(theta, rp)
绘制计划费用,并使用plt.fill(theta, rp, 'b', alpha=0.1)
用蓝色填充区域。plt.plot(theta, ra)
,绘制实际费用而未填充其下的区域。
最后,在图上添加标题和图例。 您应该看到以下图表:
更多
在此示例中,我们使用了折线图。 极坐标投影也可以用于散点图,气泡图和条形图。 这只是另一个坐标系,每个点都需要转换为极坐标。
直方图
直方图用于绘制连续变量的分布。 连续变量值分为所需的仓数,并绘制在 x 轴上,落在每个仓中的值计数绘制在 y 轴上。 在 y 轴上,我们也可以绘制总数的百分比来代替计数,在这种情况下,它表示概率分布。 该图通常用于统计分析。
准备
我们将使用有关横向培训计划参与者先前工作经验的数据示例。 经验以年数衡量。
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码绘制了经验数据的直方图:
- 创建一个 NumPy 数组,其中包含横向培训班的参与者的工作经验(以年为单位):
grp_exp = np.array([12, 15, 13, 20, 19, 20, 11, 19, 11, 12, 19, 13, 12,
10, 6, 19, 3, 1, 1, 0, 4, 4, 6, 5, 3, 7, 12, 7, 9,
8, 12, 11, 11, 18, 19, 18, 19, 3, 6, 5, 6, 9, 11,
10, 14, 14, 16, 17, 17, 19, 0, 2, 0, 3, 1, 4, 6,
6, 8, 7, 7, 6, 7, 11, 11, 10, 11, 10, 13, 13, 15,
18, 20, 19, 1, 10, 8, 16, 19, 19, 17, 16, 11, 1,
10, 13, 15, 3, 8, 6, 9, 10, 15, 19, 2, 4, 5, 6, 9,
11, 10, 9, 10, 9, 15, 16, 18, 13])
- 绘制分组经验的分布图:
nbins = 21
n, bins, patches = plt.hist(grp_exp, bins = nbins)
- 添加图的轴标签和标题:
plt.xlabel("Experience in years")
plt.ylabel("Frequency")
plt.title("Distribution of Experience in a Lateral Training
Program")
- 以平均经验在图中绘制红色垂直线:
plt.axvline(x=grp_exp.mean(), linewidth=2, color = 'r')
- 在屏幕上显示图:
plt.show()
工作原理
以下是代码的说明:
grp_exp
是一个 NumPy 数组,其中包含多年的经验数据。- 通过指定
nbins = 21
将此数据分为 21 个大小相等的桶。 plt.hist()
以grp_exp
和nbins
作为参数绘制直方图。 它返回三个参数n
,bins
和patches
。n
是包含的列表,每个箱中有个项目;bins
是另一个指定箱的起点的列表,patches
是每个箱中的对象的列表。 这些可以在程序的后面用于任何其他目的。- 在屏幕上显示直方图之前,添加标题以及 x 和 y 轴标签。
plt.axvline()
在数据的平均值处绘制一条垂直线,仅表示平均值在两侧的分布方式。 这是输出的样子:
更多
在 y 轴上,您可以绘制每个仓位中grp_exp
列表中的所有条目的总和的百分比,而不是绘制频率, 通过在plt.hist()
中指定density=1
。 您还可以使用,数据的均值和标准差绘制近似正态分布,以查看此分布遵循正态分布的程度:
- 创建一个 NumPy 数组,其中包含横向培训班的参与者的工作(年):
grp_exp = np.array([12, 15, 13, 20, 19, 20, 11, 19, 11, 12, 19, 13,
12, 10, 6, 19, 3, 1, 1, 0, 4, 4, 6, 5, 3, 7, 12,
7, 9, 8, 12, 11, 11, 18, 19, 18, 19, 3, 6, 5, 6,
9, 11, 10, 14, 14, 16, 17, 17, 19, 0, 2, 0, 3,
1, 4, 6, 6, 8, 7, 7, 6, 7, 11, 11, 10, 11, 10,
13, 13, 15, 18, 20, 19, 1, 10, 8, 16, 19, 19,
17, 16, 11, 1, 10, 13, 15, 3, 8, 6, 9, 10, 15,
19, 2, 4, 5, 6, 9, 11, 10, 9, 10, 9, 15, 16, 18,
13])
- 绘制经验分布图:
nbins = 21
n, bins, patches = plt.hist(grp_exp, bins = nbins, density=1)
- 添加轴标签:
plt.xlabel("Experience in years")
plt.ylabel("Percentage")
plt.title("Distribution of Experience in a Lateral Training
Program")
- 计算
grp_exp
数据的平均值(mu
)和标准差(sigma
):
mu = grp_exp.mean()
sigma = grp_exp.std()
- 为计算出的
mu
和sigma
添加一条最适合正态分布的线:
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma
* (bins - mu))**2))
plt.plot(bins, y, '--')
- 在屏幕上显示图:
plt.show()
输出图如下所示:
显然,数据没有遵循正态分布,因为在正态曲线的最佳拟合的上方或下方有太多的条带。
箱形图
箱形图用于可视化连续变量的描述统计量。 它直观地显示了第一个和第三个四分位数,中值(平均值)和胡须是四分位数范围(IQR)的 1.5 倍 -- 第三个和第一个四分位数之间的差异是离群值。 第一个四分位数(矩形框的底部)标记了一个点,低于该点的总数下降 25%。 第三四分位数(矩形框的顶部)标记了一个点,低于该点的点数下降 75%。
如果没有异常值,则胡须将显示最小值和最大值。
再次用于统计分析。
准备
我们将在此示例中使用葡萄酒质量数据集的示例。 我们将考虑三个属性:alcohol
,fixed acidity
和quality
。 通常,针对不同的维度(例如地理或时间)绘制相同的属性,以比较沿这些维度的数据分布。 在这里,我们绘制了三个不同属性的箱形图:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下是绘制三个箱形图的代码块,每个属性一个图:
- 将数据从 CSV 文件读取到 Pandas 数据帧中:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
- 使用
Wine Quality
数据集创建的三个属性的data
列表:
data = [wine_quality['alcohol'], wine_quality['fixed acidity'],
wine_quality['quality']]
- 绘制箱形图:
plt.boxplot(data)
- 在屏幕上显示图:
plt.show()
工作原理
plt.boxplot()
是绘制箱形图的方法。data
参数可以是一个或多个属性的列表。 默认情况下,每个框中的黄线代表属性的中值(也可以更改为平均值)。 底部胡须距离盒子底线 1.5 IQR,顶部胡须顶部盒子上方 1.5 IQR。 框的底行是的第一个四分位数,框的的上一行是数据的第三个四分位数。- 胡须上方和下方的点是异常值。 在第一箱和第二箱图中,在底部胡须以下没有离群值,而所有三个离群值顶部胡须之上:
更多
在plt.boxplot()
中,通过指定showfliers=False
自变量 ,您可以抑制离群值,因此仅在两侧的胡须上绘图。 通过指定vert=False
自变量 ,您可以水平绘制箱形图,还可以自定义具有不同形状和颜色的离群值:
plt.boxplot(data, vert=False, flierprops=dict(markerfacecolor='r',
marker='D'))
plt.show()
您应该看到以下输出:
提琴图
提琴图是直方图和箱形图的组合。 它提供有关数据完整分布的信息,以及均值/中值,最小值和最大值。
准备
在此示例中,我们还将使用与和箱形图相同的数据。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下是绘制提琴图的代码块:
- 将数据从 CSV 文件读取到 Pandas 数据帧中:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
- 准备
wine_quality
的三个属性的列表:
data = [wine_quality['alcohol'], wine_quality['fixed acidity'],
wine_quality['quality']]
- 绘制提琴图:
plt.violinplot(data, showmeans=True)
- 在屏幕上显示图:
plt.show()
工作原理
这是代码的说明:
plt.violinplot()
绘制提琴图。 底部胡须是最小值,是顶部胡须是最大值,水平线在是平均值。 在的两侧,垂直线是代表和数据实际分布的数据直方图。 通过将showmeans=True
替换为showmedian=True
,我们可以用一条横线代表数据的中位数,而不是表示的意思:
读取和显示图像
Matplotlib.pyplot
具有使我们能够读取.jpeg
和.png
图像并将它们转换为像素格式以显示为图像的函数。
准备
导入所需的库:
import matplotlib.pyplot as plt
操作步骤
这是读取 JPEG 文件作为像素值列表并将其显示为屏幕上的图像的代码块:
- 将图像
louvre.jpg
读入三维数组(彩色图像具有三个通道,而黑白图像仅具有一个通道):
image = plt.imread('louvre.jpg')
- 打印图像的大小:
print("Dimensions of the image: ", image.shape)
- 绘制图像:
plt.imshow(image)
- 在屏幕上显示图像:
plt.show()
工作原理
plt.imread()
方法将图像读取为像素数组。plt.imshow()
方法在屏幕上显示图像。image.shape
给出读取图像的列表的大小。print()
在屏幕上显示图像的大小。
热图
热图用于以不同的强度可视化不同颜色的数据范围。 在这里,我们以绘制相关矩阵作为热图为例。 相关矩阵的元素指示两个变量之间的线性关系的强度,并且矩阵包含给定数据中属性的所有组合的此类值。 如果数据具有五个属性,则相关矩阵将是5 x 5
矩阵。
准备
在此示例中,我们还将使用“葡萄酒质量”数据集。 它具有 12 个不同的属性。 我们将首先获得一个相关矩阵,然后将其绘制为热图。 目前尚无热图函数/方法,因此我们将使用和相同的imshow
方法来读取和显示图像。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下是绘制和相关矩阵的热图的代码块:
- 将数据从 CSV 文件读取到 Pandas 数据帧中:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
- 获得
wine_quality
所有属性的相关矩阵:
corr = wine_quality.corr()
- 指定图形大小:
plt.figure(figsize=(12,9))
- 绘制热图:
plt.imshow(corr,cmap='hot')
- 绘制颜色条来映射哪种颜色代表哪些数据值:
plt.colorbar()
- 标签, x 和 y 轴刻度。 显示旋转度为
20
的 x 轴标签:
plt.xticks(range(len(corr)),corr.columns, rotation=20)
plt.yticks(range(len(corr)),corr.columns)
- 在屏幕上显示图:
plt.show()
工作原理
以下是代码的说明:
wine_quality.corr()
方法返回数据集中所有属性的相关矩阵。- 相关值的范围从 -1(高度负)到 +1(高度正)。 负值从红色到黑色表示,正值从深黄色到白色表示。 纯白色是+1,这是最高的正相关,而纯黑色是最高的负相关。
- 不出所料,所有对角线框都是白色的,因为它们彼此相关,必须为 +1。 pH 和固定酸度值之间的相关性为黑色,这表示高度负值,接近 -1
我们得到的输出如下:
Hinton 图
Hinton 图是一个二维图,用于可视化深度学习应用中的权重矩阵。 Matplotlib 没有直接的方法来绘制此图。 因此,我们将不得不编写代码来对此进行绘制。 权重矩阵取自和机器学习算法之一,该算法对图像进行分类。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下代码块定义了该函数并调用了该函数以绘制 Hinton 图:
- 从 Excel 文件中读取重量矩阵数据:
matrix = np.asarray((pd.read_excel('weight_matrix.xlsx')))
- 实例化图形和轴域:
fig, ax = plt.subplots()
- 为轴域设置参数:
ax.patch.set_facecolor('gray')
ax.set_aspect('equal', 'box')
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
- 绘制 Hinton 图:
max_weight = 2 ** np.ceil(np.log(np.abs(matrix).max()) / np.log(2))
for (x, y), w in np.ndenumerate(matrix):
color = 'white' if w > 0 else 'black'
size = np.sqrt(np.abs(w) / max_weight)
rect = plt.Rectangle([x - size / 2, y - size / 2], size, size, facecolor=color, edgecolor=color)
ax.add_patch(rect)
ax.autoscale_view()
- 在屏幕上显示:
plt.show()
工作原理
这是代码的说明:
pd.read_excel()
将 Excel 文件读入 Pandas 数据帧。np.asarray()
根据进一步处理的需要将数据帧转换为 NumPy 数组。 它是20 x 7
的矩阵。np.abs()
返回作为输入给出的矩阵的绝对值。np.abs(matrix).max()
从绝对矩阵返回最大值。np.log()
返回所传递参数的自然对数值。- 对于给定的浮点数,
np.ceil()
将参数四舍五入到下一个最大值,例如,np.ceil(2.2) = 3.0
。 ax.patch.set_facecolor('gray')
将每个方框的颜色设置为灰色。ax.set_aspect('equal', 'box')
将长宽比(宽高比)和图形上要点的形状指定为方框。ax.xaxis.set_major_locator(plt.NullLocator())
将 x 轴刻度设置为空,这样就不会标记任何刻度,也不会放置任何刻度标签。- 启动
for
循环以遍历权重矩阵的每个元素,并将颜色设置为白色(正值),黑色(负值)和与max_weight
成比例的大小。 最后,ax.autoscale_view()
整齐地排列所有框并绘制 Hinton 图。
您应该获得如下输出:
等高线图
等高线图通常用于显示误差如何随机器学习算法(例如线性回归)中优化的系数的变化而变化。 如果线性回归系数为theta0
和theta1
,并且预测值和实际值之间的误差为Loss
,则对于给定的Loss
值,theta0
和theta1
的所有值 ]形成轮廓。 对于Loss
的不同值,通过更改和theta1
的值形成不同的轮廓。
准备
Loss
,theta0
,theta1
和theta
的数据(theta0
和theta1
具有最低误差)来自绘制轮廓图的回归问题之一。 如果theta0
和theta1
是大小为1 x n
的向量,则Loss
将为n x n
矩阵形式。
导入所需的库。 我们将从 Matplotlib 引入另一个用于颜色映射的库:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import cm
我们还需要了解网格的概念,因为等高线,曲面和流图也使用此概念:
- 网格是在几何空间中从两个向量派生的网格。 向量中的每个数据项均充当坐标,并且来自两个向量的坐标组合形成 2D 几何空间中的点。 这些向量坐标的所有可能组合所散布的区域以网格形式定义,例如:
x = [-3.0, 0., 3.0]
和y = [-2.0, 2.0]
。 向量x
具有三个数据点,向量y
具有两个数据点。 因此,我们在 2D 几何空间中总共有六个点(3 * 2
),而这六个点是(-3.0, -2)
,(-3.0, 2.0)
,(0, -2.0)
,(0, 2.0)
,(3.0, -2.0)
和(3.0, 2.0)
。 现在,这六个点和 12 个数据项(6 * 2
)再次表示为两个矩阵x
和y
,其中适用以下条件:X = [[-3.0, 0., 3.0], [-3.0, 0., 3.0]]
,一个2 x 3
矩阵(行数等于Y
的长度),Y = [[-2.0, 2.0], [-2.0, 2.0], [-2.0, 2.0]]
,3 x 2
矩阵(行数等于X
的长度)。 NumPy 具有函数np.meshgrid(x, y)
,用于使用x
和y
向量创建这些X
和Y
矩阵。 这就是我们将用于所有需求的东西。
操作步骤
以下是在给定回归问题中绘制损失函数的等高线图的代码:
- 从保存的文件中读取
Loss
,theta0
和theta1
值:
Loss = pd.read_excel('Loss.xlsx')
theta0_vals = pd.read_excel('theta0.xlsx')
theta1_vals = pd.read_excel('theta1.xlsx')
- 指定图形大小:
fig = plt.figure(figsize=(12,8))
- 为
X
和Y
坐标创建网格:
X, Y = np.meshgrid(theta0_vals, theta1_vals)
- 绘制等高线图,并用相应的损耗值标记等高线:
CS = plt.contour(X, Y, Loss, np.logspace(-2,3,20), cmap=cm.coolwarm)
plt.clabel(CS, inline=1, fontsize=10)
- 在屏幕上显示轮廓图:
plt.show()
工作原理
这是代码的说明:
theta0 = np.linspace(-10, 10, 100)
和theta1 = np.linspace(-1, 4, 100)
帮助我们计算Loss
,这是theta0
和theta1
值范围的误差。 所有这些数据都以 Excel 文件的形式提供,因此我们使用pd.read_excel()
读取它们。np.meshgrid()
在theta0
和theta1
之间创建网格,以获得X
和Y
,然后传递X
,Y
和Loss
绘制轮廓图。CS = plt.contour()
绘制轮廓图。np.logspace(-2,3,20)
为Loss
属性指定对数刻度的值范围,需要在等高线图中绘制。 在线性范围内,此范围为 0.01(10 的 -2 次方)到 1,000(10 的 3 次方)。20
是它在此范围内绘制的样本数,使用它们绘制等高线。plt.clabel()
指定将实际损耗值作为标签绘制在轮廓上。 从图中可以看出,损失(误差)的值从零一直到 545.559!
我们得到的输出如下:
更多
先前的屏幕截图仅代表theta0
和theta1
给定集合的Loss
函数的各种轮廓。 我们还可以在同一图上绘制theta0
和theta1
的最佳值,以表示最小损失:
## Plot the minimum point(Theta at Minimum cost)
plt.plot(theta[0], theta[1], 'rx', markersize=15, linewidth=2)
plt.show()
这是绘图的样子。 红叉位置描绘了最佳theta
,该最优theta
为该回归问题提供了最低的误差:
三角剖分
三角剖分用于绘制地理地图,这有助于理解各个点之间的相对距离。 经度和纬度值用作 x,y 坐标来绘制点。 要绘制三角形,需要三个点。 用图中点的相应索引指定这些值。 对于给定的一组坐标,Matplotlib 可以自动计算三角形并绘制图形,或者可选地,我们也可以提供三角形作为参数。
准备
导入所需的库。 我们将介绍用于三角剖分的tri
包:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
操作步骤
以下代码块生成 50 个随机点,自动创建三角形,然后绘制三角剖视图:
data = np.random.rand(50, 2)
triangles = tri.Triangulation(data[:,0], data[:,1])
plt.triplot(triangles)
plt.show()
工作原理
我们首先使用np.random.rand function
生成50
随机点,它会生成0
和1
之间的数字。tri.Triangulation()
函数自动创建三角形,而plt.triplot()
绘制三角剖分图。
这是输出图的外观:
更多
在上一个图中,我们自动生成了三角形。 在这里,我们将学习如何手动添加三角形:
- 以弧度为单位设置经度和纬度数据:
xy = np.array([[-0.101, 0.872], [-0.080, 0.883], [-0.069, 0.888],
[-0.054, 0.890], [-0.045, 0.897], [-0.057, 0.895],
[-0.073, 0.900], [-0.087, 0.898],
[-0.090, 0.904], [-0.069, 0.907]])
- 将
xy
从弧度转换为度:
x = np.degrees(xy[:, 0])
y = np.degrees(xy[:, 1])
- 从
xy
坐标中选择要转换为角度的三角形:
triangles = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6], [2, 5, 6],
[6, 7, 8], [6, 8, 9], [0, 1, 7]])
- 绘制三角剖分图:
plt.triplot(x, y, triangles, 'go-', lw=1.0)
- 绘制标签和标题:
plt.title('triplot of user-specified triangulation')
plt.xlabel('Longitude (degrees)')
plt.ylabel('Latitude (degrees)')
- 在屏幕上显示图:
plt.show()
下面是它的工作原理:
xy
是弧度的坐标数组。np.degrees()
将弧度转换为度;x
和y
以弧度表示,然后转换为度,其中x
和y
分别代表经度和纬度值。
三角形是要绘制的每个三角形的三点元组的数组。 数字是x
和y
中点的索引(0 至 9,共 10 点)。 输出如下:
流图
流图也称为流线图,用于可视化向量场。 它们主要用于工程和科学界。 他们使用向量及其速度作为基础向量的函数来绘制这些图。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
操作步骤
以下代码块创建一个流图:
- 准备流图的数据:
x, y = np.linspace(-3,3,100), np.linspace(-2,4,50)
- 创建网格:
X, Y = np.meshgrid(x, y)
- 计算速度
U
和V
分别是X
和Y
的函数:
U = 1 - X**2
V = 1 + Y**2
- 绘制流图:
plt.streamplot(X, Y, U, V)
- 设置绘图的标题:
plt.title('Basic Streamplot')
- 在屏幕上显示图形:
plt.show()
工作原理
np.linspace(-3, 3, 100)
在-3 到 3 的范围内创建 100 个数据点,并且连续点之间的间隔相等。x
和y
是长度为100
和50
的随机生成的向量,分别为 -3 至 3 和 -2 至 4。np.meshgrid(x, y)
按照本章前面的说明创建网格。U
和V
是作为x
和y
的函数的速度向量。 流图是向量x
,y
和速度U
和V
的组合。plt.streamplot(X, Y, U, V)
绘制流图,如下所示:
更多
在上一节中,我们已经看到了基本的流图。 我们可以根据流线的,速度和颜色来控制密度和厚度。 以下是代码及其输出:
## Define the speed as a function of U and V
speed = np.sqrt (U*U + V*V)
## Varying line width along a streamline
lw = 5 * speed / speed.max()
strm = plt.streamplot(X, Y, U, V, density=[0.5, 1], color=V,
linewidth=lw)
plt.colorbar(strm.lines)
plt.title('Varying Density, Color and Line Width')
plt.show()
np.sqrt(U*U + V*V)
定义速度; 线宽(lw
)定义为速度的函数。plt.streamplot()
使用提供的参数绘制流图。density=[0.5, 1]
指定要使用的密度值,color=V
指定应基于V
的值改变流线的颜色,linewidth
指定应如何改变流线的宽度:
路径
Path
是 Matplotlib 提供的一种用于绘制自定义图表的方法。 它使用 Matplotlib 提供的助手函数补丁。 让我们看看如何将其用于绘制简单图。
准备
导入所需的库。 这里将介绍两个新的包Path
和patches
:
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
操作步骤
以下代码块定义了点以及相关的直线和曲线,以形成整体图:
- 定义第一条曲线的点
verts1 = [(-1.5, 0.), # left, bottom
(0., 1.), # left, top
(1.5, 0.), # right, top
(0., -1.0), # right, bottom
(-1.5, 0.)] # ignored
- 绘制连接步骤 1 中定义的点的图形:
codes1 = [Path.MOVETO, # Go to first point specified in vert1
Path.LINETO, # Draw a line from first point to second
point
Path.LINETO, # Draw another line from current point to
next point
Path.LINETO, # Draw another line from current point to
next point
Path.CLOSEPOLY] # Close the loop
- 使用步骤 1 和步骤 2 中定义的点和线/曲线创建完整路径:
path1 = Path(verts1, codes1)
- 对第二个曲线重复相同的操作:
verts2 = [(-1.5, 0.), # left, bottom
(0., 2.5), # left, top
(1.5, 0.), # right, top
(0., -2.5), # right, bottom
(-1.5, 0.)] # ignored
codes2 = [Path.MOVETO, # Move to the first point
Path.CURVE3, # Curve from first point along the control
point and terminate on end point
Path.CURVE3, # Curve from current point along the control
point and terminate on end point
Path.CURVE3,
Path.CURVE3] # close by the curved loop
path2 = Path(verts2, codes2)
- 定义图形和轴域:
fig = plt.figure()
ax = fig.add_subplot(111)
- 创建第一个补丁并将其添加到轴域中:
patch1 = patches.PathPatch(path1, lw=4, zorder=2)
ax.add_patch(patch1)
- 创建第二个补丁并将其添加到轴域:
patch2 = patches.PathPatch(path2, facecolor='orange', lw=2,
zorder=1)
ax.add_patch(patch2)
- 设置
x
和y
轴的限制:
ax.set_xlim(-2,2)
ax.set_ylim(-2,2)
- 在屏幕上显示图:
plt.show()
工作原理
verts1
和verts2
定义了必须沿其绘制曲线的点。path1
和path2
定义了要绘制的每条曲线的完整路径。Path.MOVETO
使曲线的起点到达verts
中指定的第一点。Path.LINETO
从当前位置的到指定的下一个点画一条线。Path.CLOSEPOLY
关闭多项式曲线循环。Path.CURVE3
沿着控制点从给定点绘制一条曲线,然后在第三点处终止。Path.CURVE4
(在此示例中未使用)进行相同的操作,但是在两个控制点而不是一个。patches.PathPatch
是一个辅助函数,可沿给定路径绘制曲线。zorder
参数会覆盖绘制不同补丁的默认顺序。 在这种情况下,我们希望先绘制第二个补丁,然后再绘制第一个补丁,以便两个都可见。 否则,较小的补丁将隐藏在较大的补丁之后。lw
指定线宽,facecolor
指定要填充在色块内部的颜色,覆盖默认颜色。
这是代码的输出:
三、绘制多个图表和子图
在本章中,我们将介绍以下秘籍:
- 在同一轴域上绘制多个图形
- 在同一图中绘制子图
- 在一个会话中绘制多个图形
- 使用对数刻度
- 使用度量单位
介绍
在上一章中,我们了解了如何分别绘制各种图形。 在本章中,我们将学习如何在同一坐标轴域上绘制多个图形,在同一图形中绘制多个坐标轴/曲线以及在一个会话中绘制多个图形。 我们还将学习如何使用对数刻度和度量单位,例如厘米,英寸等。
在同一轴域上绘制多个图形
正如我们从第一章中学到的,轴域是绘制图形的空间,通常在图中看到的所有元素都是轴域的一部分。 我们在一幅图中可以有多个轴域。 在本秘籍中,我们将学习如何在同一轴域上绘制多个图表。
准备
我们将使用一个受试者工作特性(ROC)曲线的示例,通过它可以使用多个机器学习(ML)算法来比较给定的分类问题,并且针对该问题选择了表现最佳的算法。 ROC 曲线用真阳性率(TPR)以及假阳性率(FPR)的阈值概率范围绘制。 目的是随着和阈值概率的变化,看到 TPR 和 FPR 的敏感性。覆盖最大 ROC 曲线下面积(AUC)的算法是在分类准确性方面表现最佳的算法。
我们将 TPR 和 FPR 数据用于一组算法, k 最近邻算法(k-NN),多层感知器 MLP),随机梯度下降(SGD),随机森林(RF)和决策树(DT)在分类问题上运行以绘制图形。 该数据集作为本书代码库的一部分提供。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
这是在同一轴域上绘制多个 ROC 曲线的代码块:
- 使用
pandas
从各自的 Excel 表中读取各种算法的 FPR 和 TPR 数据:
## K-nearest neighbor (KNN)
fpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'fpr_KNN')
tpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'tpr_KNN')
## Multilayer Perceptron(MLP)
fpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'fpr_MLP')
tpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'tpr_MLP')
## Stochastic Gradient Descent (SGD)
fpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'fpr_SGD')
tpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'tpr_SGD')
## Random Forest (RF)
fpr_RF = pd.read_excel('ROC_Curves.xlsx', 'fpr_RF')
tpr_RF = pd.read_excel('ROC_Curves.xlsx', 'tpr_RF')
## Decision Trees (DT)
fpr_DT = pd.read_excel('ROC_Curves.xlsx', 'fpr_DT')
tpr_DT = pd.read_excel('ROC_Curves.xlsx', 'tpr_DT')
- 绘制线形图,包括黑色阈值线,使用
fpr
和tpr
数据,在上一步中读取五种算法的每一种:
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr_KNN, tpr_KNN, label='KNN',color='green')
plt.plot(fpr_DT, tpr_DT, label='DecisionTree', color='orange')
plt.plot(fpr_RF, tpr_RF, label='Random Forest',color='purple')
plt.plot(fpr_MLP, tpr_MLP, label='MLP',color='red')
plt.plot(fpr_SGD, tpr_SGD, label='SGD', color='pink')
- 打印标签,标题和图例:
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve')
plt.legend(loc='best')
- 在屏幕上显示图:
plt.show()
工作原理
这是代码工作方式的说明:
pd.read_excel()
语句读取五种算法(KNN
,MLP
,SGD
,RF
和DT
)的 TPR 和 FPR 数据。plt.plot([0, 1], [0, 1], 'k--')
以 45 度角绘制黑色虚线。 这是基本表现水平(参考线),与所有其他曲线相比,ROC 曲线在此线之上并覆盖其下最大面积的算法是被认为是表现最佳的算法 。- 随后的
plt.plot()
语句绘制了五个选定算法中每个算法的 ROC 曲线。 每个绘图语句都在相同的轴域上绘制图形。 您可以在plt.show()
之前绘制所需数量的图形,以在屏幕上显示图形。 - 参数标签和颜色在图形上区分了每种算法。 我们将在随后的章节中了解有关这些参数的更多信息。
plt.xlabel()
,plt.ylabel()
和plt.title()
是绘图上的标签, 图例是这些图形标签放在图形上的位置。
您应该看到以下图:
从图中可以清楚地看出,SGD Classifier
算法与所有其他算法相比效果不佳,因为该图表下的区域最低(或者最接近参考的参考) 虚线)。 对于该特定分类问题,MLP 算法是这五种算法中最好的,因为该曲线下的面积最高(或距参考块虚线最远)。
在同一图形上绘制子图
Matplotlib 提供了许多不同的方法和辅助函数,这些函数和辅助函数利用,axes
方法在同一图形上绘制多个图并将它们布置为各种网格格式。 这使我们能够开发复杂的仪表板应用。
准备
对于本章中的示例,我们将使用与第 2 章“基本绘图入门”中介绍的相同的Wine Quality
和Iris
数据集。
图中的多个图排列在m x n
网格中,其中m
是行数,n
是列数。 如果图中有六个绘图,我们可以将它们全部排成一排(每个都由 161、162、163、164、165 或 166 标识)或3 x 2
(321、322,323、324、325 和 326)或2 x 3
(231、232、233、234、235 和 236)或一列(611、612、613、614、615 和 616)。 前两位数字表示,行和列的数量的最后一位数字表示从 1 到 6 的连续数字(绘图总数),并从左向右,然后从上到下读取。
也可以将图指定为(3, 2, 1
)而不是(321
)。 当网格中有九个以上的绘图时,后一种表示法会造成混淆,而 Matplotlib 不接受它。 在这种情况下,如果您有一个(...
),则必须使用(3, 4, 10
),(3, 4, 11
)或(3, 4, 12
)而不是(3410
),(3411
)或(3412
)。 3 x 4
网格,共有 12 个绘图。
我们还可以绘制少于网格中允许的最大值的图,例如,在2 x 2
网格中绘制 3 个图(其中是最大值)。
导入所需的库:
import pandas as pd
import matplotlib.pyplot as plt
操作步骤
以下代码块在一个图中绘制了三个图:
- 用三个轴域定义图形及其布局:
fig = plt.figure()
ax1 = plt.subplot(221)
ax2 = plt.subplot(222)
ax3 = plt.subplot(212)
- 在每个轴域上绘制折线图:
ax1.plot([1,2])
ax2.plot([2,1])
ax3.plot([2,4])
- 在屏幕上显示图:
plt.show()
工作原理
这是代码的说明:
plt.figure()
为图形创建对象并为其分配空间。plt.subplot(221)
在2 x 2
网格中为第一个绘图创建轴域。plt.subplot(222)
在2 x 2
网格中为第二个图创建另一个轴域,该网格位于同一第一行中。plt.subplot(212)
为第三个图又创建了一个轴域,但这是另一个2 x 1
网格(212
的前两位数字)的一部分,它是此2 x 1
网格中的第二个图,因此放在第二行。由于第一个2 x 2
网格未使用第二行,因此该网格将占据整个空间。
我们得到的输出如下:
如果我们为第三个图编码了plt.subplot(211)
,它将覆盖前两个图,因为 211 表示2 x 1
网格中的第一个图,它将从第一行开始! 如果我们要绘制相同的三个图,但在第一列中排列两个,在第二列中排列一个,而不是第一行中当前的前两个图和第二行中的第三个图,那么我们将不得不指定绘图顺序为 221、223 和 122。 试试看作为练习!
更多
由于存在许多此类可能的网格,因此我们将再看到一个示例,该示例在2 x 2
网格中包含四个不同的图,每个图具有不同类型的图形,直方图,折线图,散点图和条形图。 在最后一个示例中,我们一直使用和plt.subplot()
方法一个接一个地添加轴域。 在此示例中,我们将一次定义网格中的所有轴域,然后使用索引来访问每个轴域并绘制不同的图形:
- 从
.csv
文件中读取Wine Quality
和Iris
数据集,并为计算每个属性的均值和标准差:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris_mean = iris.mean()
iris_std = iris.std()
- 这定义了图及其布局:
fig, axs = plt.subplots(2, 2, figsize=(8, 8))
- 在的第一个轴域上,将的直方图绘制为,的
alcohol
属性,Wine Quality
数据集。
axs[0, 0].hist(wine_quality['alcohol'])
axs[0, 0].set_title('Histogram')
axs[0, 0].set_xlabel('Alcohol Bins')
axs[0, 0].set_ylabel('Frequency')
- 在的第二个轴域上绘制
sepal_length
和sepal_width
的线形图:
axs[0, 1].plot(iris['sepal_length'], iris['sepal_width'])
axs[0, 1].set(title='Line', xlabel='Sepal Length', ylabel='Sepal
Width')
- 使用
petal_length
和petal_width
属性在第三轴域上绘制散点图:
axs[1, 0].scatter(iris['petal_length'], iris['petal_width'])
axs[1, 0].set(title='Scatter', xlabel='Petal Length', ylabel='Petal
Width')
- 在第四轴域上绘制条形图:
axs[1, 1].bar(['sepal_l','sepal_w', 'petal_l', 'petal_w'],
iris_mean, yerr=iris_std)
axs[1, 1].set(title='Bar', xlabel='Category', ylabel='Category
Mean')
- 设置整个图的标题:
plt.suptitle('Subplots Demo')
- 调整绘图之间的空间:
plt.tight_layout(pad=3, w_pad=1.0, h_pad=1.0)
- 在屏幕上显示图:
plt.show()
这是代码工作方式的说明:
iris.mean()
和iris.std()
计算Iris
数据集中所有四个属性的均值和标准差。 这些将用于在该图的第四轴域上绘制条形图。fig, axs = plt.subplots(2, 2, figsize=(8, 8))
定义2 x 2
网格并将其分配给轴域列表,在每个轴域上绘制图形时,将使用相应的索引进行访问。axs[0, 0].hist(wine_quality['alcohol'])
绘制和Wine Quality
数据集中,酒精属性的直方图。axes[0,0]
代表第一行第一列的第一个图,Python 索引从 0 开始。axs[0, 0].set_title('Histogram')
设置第一个绘图的标题。axs[0, 0].set_xlabel('Alcohol Bins')
设置 x 轴的标签,axs[0, 0].set_ylabel('Alcohol Bins')
设置 y 轴的标签。axs[0, 1]
代表第二个图的,位于第一行的中,第二列的上,在此轴域上绘制一条线形图。axs[0, 1].set()
使用一个命令而不是三个单独的命令来设置标题,xlabel
和ylabel
。axs[1, 0]
代表第三个图,放置在第二个行中,放置在第一个行中,并在此轴域上绘制了一个散点图。- 最后,
axs[1, 1]
代表的第四个图,放置在的第二个行,的第二个列,并在此轴域上绘制条形图。yerr
属性代表条形图代表的组的标准差,并在每个条形图上方显示为黑色垂直线。 线的长度是相对于条上所有其他线的长度; 线越长,该组(或条形图)的标准差越高。 plt.suptitle('Subplots Demo')
设置图形的标题(所有四个图形的组合在一起)。plt.tight_layout(pad=3, w_pad=1.0, h_pad=1.0)
确保四个图上的标签不相互重叠。pad
参数控制图顶部的空间; 数字越大,图形标题与的标头和标头之间的空隙就越大,在其下方的两个图上。w_pad
控制一行中两个图之间的间隔,h_pad
控制一列中两个图之间的间隔。
您应该看到输出图,如下图所示:
在这种基于索引的轴域方法中,所有图都将具有相同的大小,因此我们无法像在本秘籍开始时在示例中所做的那样来管理不同大小的图。
在一个会话中绘制多个图形
到目前为止,我们已经学习了如何在单个轴域和一个图形中的多个轴域上绘制多个图。 在本秘籍中,我们将学习如何在给定的会话中绘制多个图形。
准备
在此示例中,我们还将使用相同的Iris
数据集。 我们将绘制两个图形,并在每个图形中绘制多个图形。 在第一个图中,我们将使用另一种方法来创建具有不同大小图的网格。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
操作步骤
以下代码块绘制了两个图形,每个图形中都有多个图形:
- 从 Excel 读取
Iris
数据:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
- 清除画布以开始一个新图:
plt.close('all')
- 使用相关的布局定义图 1 和子图:
fig = plt.figure(1, figsize=(12, 9))
ax1 = plt.subplot2grid((3, 3), (0, 0))
ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
- 在步骤 3 中定义的四个轴域上的每个轴域上绘制图形:
ax1.hist(iris['petal_width'])
ax2.scatter(iris['petal_length'], iris['petal_width'], s=50*iris['petal_length']*iris['petal_width'], alpha=0.3)
ax3.scatter(iris['sepal_length'], iris['sepal_width'])
ax4.violinplot(iris['petal_length'])
- 设置标题并调整绘图之间的间隔:
plt.suptitle('Figure 1: Grid Plotting Demo', fontsize=20)
plt.tight_layout(pad=5, w_pad=0.5, h_pad=1.0)
- 定义图 2 及其大小:
plt.figure(2, figsize=(12, 5))
- 设置条形图的数据:
names = ['group_a', 'group_b', 'group_c', 'group_d', 'group_e']
values = [1, 10, 50, 100, 500]
- 定义第一轴域并绘制条形图:
plt.subplot(131)
plt.bar(names, values, color='orange')
- 定义第二轴域并绘制散点图:
plt.subplot(132)
plt.scatter(names, values, color='orange')
- 定义第三轴域和一个折线图:
plt.subplot(133)
plt.plot(names, values, color='orange')
- 设置整体图形的标题,并调整图形中各图之间的空间:
plt.suptitle('Figure 2: Row Plotting Demo', fontsize=20)
plt.tight_layout(pad=5, w_pad=0.5, h_pad=1.0)
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
plt.close('all')
在开始新图形之前清除空间。fig = plt.figure(1, figsize=(12, 9))
定义了图 1 ,其大小等于(12, 9)
。ax1 = plt.subplot2grid((3, 3), (0, 0))
创建ax1
轴域,将在其中绘制第一个图,ax1
是9
个轴域的3 x 3
网格中的第一个轴域。 Python 索引从 0、1 和 2 开始,分别代表第一,第二和第三行或列。ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
创建ax2
轴域,该轴域跨越3 x 3
网格的两列,从第一个行和第二个列开始。ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
创建一个ax3
轴域,该轴域跨越两列和两行,从第二行和第一列开始。ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
创建一个ax4
轴域,该轴域跨越两行一列,从第二行行和第三列开始。- 与上一个秘籍一样,我们现在分别在四个轴域上分别绘制直方图,气泡图,散点图和提琴图。
plt.suptitle('Figure 1: Grid Plotting Demo', fontsize=20)
设置图 1 的标题,字体大小为20
。plt.tight_layout(pad=5, w_pad=0.5, h_pad=1.0)
调整图之间的间隔,以使标签不重叠。plt.figure(2, figsize=(12, 5))
以(12, 5)
的大小开始第二个图形。- 名称和值是要绘制在三个图上的, x ,和 y 轴上要绘制的数据的 Python 列表。
- 与前面的示例一样,我们在
1 x 3
的网格中绘制三个图,并绘制一个条形图,一个散布图和一个线形图。 然后,我们为图形设置标题,并调整图之间的空间,以使其没有重叠,就像其他子图一样。
您应该看到如下所示的输出数字:
更多
Matplotlib 还提供了另一个名为AxesGrid
的工具包,它涵盖了更高级的网格选项,包括网格中的图像。 我们将在第 13 章“使用axis_grid1
工具包”中进行介绍。
对数刻度
当数据的范围从很小的值到很大的值时,按线性比例绘制它可能无法使正确理解和数据点的相对大小。 在这种情况下,将使用对数刻度。
准备
对于此示例,我们将使用一些虚拟数据来演示线性刻度和对数刻度之间的差异。
导入所需的库:
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了三个图形,一个以线性刻度绘制,和其他两个以对数刻度绘制。 两个对数图还演示了如何调整物理大小和数据规模:
- 定义图及其布局:
fig, (ax1, ax2, ax3) = plt.subplots(1, 3)
- 在轴域
ax1
上以线性比例绘制折线图:
ax1.plot([0.1, 5, 10, 500], [0.01, 25, 100, 10000], "x-")
ax1.set(title="Linear Scale", xlim=(1e1, 1e3), ylim=(1e2, 1e4))
- 在 x 和 y 轴域上绘制一个具有对数刻度的空图:
ax2.set(title="adjustable = box", xscale="log", yscale="log", xlim=
(1e1, 1e3), ylim=(1e2, 1e3), aspect=2)
- 在
ax3
, x 和 y 轴上以对数刻度在ax3
上绘制线形图:
ax3.plot([0.1, 5, 10, 500], [0.01, 25, 100, 10000], "o-")
ax3.set(title="adjustable = datalim", xscale="log", yscale="log",
adjustable="datalim", xlim=(1e-1, 1e3),
ylim=(1e-2, 1e4), aspect=1)
- 调整绘图之间的空间,并在屏幕上显示图形:
plt.tight_layout()
plt.show()
工作原理
这是代码的说明:
fig
和(ax1, ax2, ax3) = plt.subplots(1, 3)
定义图形的布局,其中三个坐标轴对象将被绘制成一行。- 在
ax1
轴域上绘制了一个简单的折线图,其中设置了, x 和 y 轴限制。 由于数据范围非常大,因此并非所有点都清晰可见,并且之间的相对间隙不容易可视化。 - 在
ax2
上,显示了对数刻度,其中没有任何图表。ax2.set()
设置绘图的所有参数。xscale="log"
和yscale="log"
将 x 和 y 轴设置为对数刻度。aspect=2
将 y 刻度数据设置为 x 刻度数据的大小的两倍。 如您所见, y 轴上 10^2 到 10^3 之间的距离是 x 轴上距离的两倍。 - 在
ax3
上,此处绘制了对数刻度和在ax1
上绘制的相同折线图,以显示差异。 在这里,我们可以清楚地看到所有四个点,还可以看到它们之间的相对距离。adjustable="datalim"
调整/扩展 x 或 y 限制,以适应指定的长宽比。 的第二个图(ax2
)中省略了此属性,因此的默认参数box
会调整物理对象大小(而不是数据规模)来适应宽高比。
您应该看到如下输出图:
更多
让我们再举一个关于如何使用对数刻度的示例。 假设在组织中,员工根据其职位分为五类。 这五个类别中的每一个都进一步分为男人和女人。 对于这 10 个类别中的每个类别(5 名男性和 5 名女性),我们都有平均薪水和标准差。 绘制此数据以查看薪水数据如何在男女群体之间分配。
以下是代码及其工作方式:
- 导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
- 定义包含男性和女性均值和标准差数据的 Python 列表:
menMeans = [3, 10, 100, 500, 50]
menStd = [0.75, 2.5, 25, 125, 12.5]
womenMeans = [1000, 3, 30, 800, 1]
womenStd = [500, 0.75, 8, 200, 0.25]
- 定义图形布局,
ind
列表,其中menMeans
条将放置在 x 轴,每个条形的width
,然后以红色绘制men
数据的条形图,并在其顶部显示黑线,指示该组的标准差的大小:
fig, ax = plt.subplots()
ind = np.arange(len(menMeans))
width = 0.35
p1 = ax.bar(ind, menMeans, width, color='lightblue', bottom=0,
yerr=menStd)
- 同样,以黄色绘制
womenMeans
条形图,与menMeans
条形相邻,然后设置标题、xticks
的位置及其 x 轴标签:
p2 = ax.bar(ind + width, womenMeans, width, color='orange',
bottom=0, yerr=womenStd)
ax.set_title('Scores by category and gender')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(('C1', 'C2', 'C3', 'C4', 'C5'))
- 最后,
ax.set_yscale('log')
将 y 轴刻度设置为对数,ax.legend((p1[0], p2[0]), ('Men', 'Women'))
设置图例。 然后,plt.show()
在屏幕上显示绘图。
这是输出条形图的外观:
Matplotlib supports four different scales. The default is linear, and we have covered log in this recipe. You can refer to the Matplotlib documentation for the other two scales: symlog and logit.
使用度量单位
有时,我们可能具有使用一个度量单位的数据,但是想要使用不同的度量单位来绘制图,或者有时我们可能想要对, x 和 y 轴使用不同的度量单位,例如 x 轴为厘米,y 轴为英寸。 当我们绘制角度时,度数和弧度也是如此。 Matplotlib 没有内置这些功能,但是 GitHub 上有一个扩展工具basic_units.py
,可启用这些不同的度量单位。 该 Python 模块当前仅支持厘米/英寸和弧度/度。 对于其他度量单位,例如千克/磅,千米/海里等,我们将必须更新此工具模块。
basic_units.py
is not a standard package to be installed like all other Python packages. It is a user-defined Python program that needs to be copied into your working directory. Then, in the main program, import the functions from this program similar to the way we import any other package or user-defined programs.
准备
将basic_units.py
复制到工作目录后,即可开始使用那里的所有可用功能。
导入所需的库。 在这里,我们将介绍 Matplotlib 的另外两个函数lines
,它具有用于绘制线条的对象和text
,用于在图表上标注对象:
import matplotlib.lines as lines
import matplotlib.text as text
from basic_units import cm, inch
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了两个图,一个是厘米,另一个是英寸,以演示两个度量单位之间的差异:
- 定义一个具有两个连续图的图形:
fig, ax = plt.subplots(1,2)
- 定义
line
和要添加到第一个轴域的text
艺术家:
line = lines.Line2D([0*cm, 1.5*cm], [0*cm, 2.5*cm], lw=2,
color='black', axes=ax[0])
t = text.Text(3*cm, 2.5*cm, 'text label', ha='left', va='bottom',
axes=ax[0])
- 将艺术家添加到轴域
0
,并设置限制,度量单位和网格:
ax[0].add_line(line)
ax[0].add_artist(t)
ax[0].set_xlim(-1*cm, 10*cm)
ax[0].set_ylim(-1*cm, 10*cm)
ax[0].xaxis.set_units(cm)
ax[0].yaxis.set_units(cm)
ax[0].grid(True)
- 定义要添加到第二轴域的
line
和text
艺术家:
line = lines.Line2D([0*cm, 1.5*cm], [0*cm, 2.5*cm], lw=2,
color='black', axes=ax[1])
t = text.Text(3*cm, 2.5*cm, 'text label', ha='left', va='bottom',
axes=ax[1])
- 将艺术家添加到坐标轴
1
并设置限制,度量单位和网格:
ax[1].add_artist(line)
ax[1].add_artist(t)
ax[1].set_xlim(-1*cm, 10*cm)
ax[1].set_ylim(-1*cm, 10*cm)
ax[1].xaxis.set_units(inch)
ax[1].yaxis.set_units(inch)
ax[1].grid(True)
- 设置图的标题并调整图之间的间距:
plt.suptitle("Demonstration of Units Of Measurement")
plt.tight_layout(pad=3)
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码工作方式的说明:
fig, ax = plt.subplots(1,2)
使用同一行上的两个轴域对象定义图形。 由于只有两行的一行,因此ax
是一维向量,因此我们将使用ax[0]
和ax[1]
进行访问。line = lines.Line2D([0*cm, 1.5*cm], [0*cm, 2.5*cm], lw=2, color='black', axes=ax[0])
在轴域ax[0]
上绘制黑线段,并以lw=2
绘制输入数据,单位为厘米。- 类似地,
t = text.Text(3*cm, 2.5*cm, 'text label', ha='left', va='bottom', axes=ax[0])
将ax[0]
的ax[0]
定义为指定位置(3, 2.5)
的ax[0]
对象,以厘米为单位,左侧对齐为水平,底部对齐为垂直。
It should be noted that Matplotlib does not support sharing objects across different axes; we need to explicitly specify for each object in which axes it is to be included. We specified axes=ax[0]
for the line plot, since the same line is plotted again on ax[1]
, and we had to tell Matplotlib on which axis it is plotting the line at any given time. This also means that if the same line or text is to be drawn on two different axis, then it will have to be repeated twice.
ax[0].add_line(line)
和ax[0].add_artist(t)
在ax[0]
上添加行和文本对象。 记住,艺术家是一个实际在画布/图表上绘制对象的对象。 实际上,add_line
也可以用add_artist
代替,就像我们稍后对ax[1]
所做的那样。ax[0].xaxis.set_units(cm)
和ax[0].yaxis.set_units(cm)
设置 x 轴和 y 轴的测量单位,以进行实际显示。 对于ax[0]
,它设置为厘米,对于ax[1]
,它设置为英寸。 对于两个轴域,输入数据均以厘米为单位。ax[0].grid(True)
显示网格以及 x 和 y 轴上的主要刻度。 这有助于可视化图形上任何位置的精确坐标值。plt.suptitle()
设置图形标题,plt.tight_layout(pad=3)
调整图形之间的间距,pad=3
确保图形标题足够在图形之前。- 对
ax[1]
重复完全相同的步骤,唯一的区别是ax[1].xaxis.set_units(inch)
和ax[1].yaxis.set_units(inch)
是用英寸而不是cm
指定的。
该图的外观如下:
由于在两个图上的比例都是和相同,因此线条的大小以英寸为单位要比以厘米为单位要小。
更多
这是在 x 和 y 轴上使用厘米和英寸的混合的另一个示例。 我们有四个条形图,其中和相同的输入数据绘制在2 x 2
的网格上。
导入所需的库:
import numpy as np
from basic_units import cm, inch
import matplotlib.pyplot as plt
下面的代码在2 x 2
的网格中用四个条形图绘制图形:
- 定义数据和度量单位:
cms = cm * np.arange(0, 21, 3)
bottom = 0 * cm
width = 0.8 * cm
- 定义图及其布局:
fig, axs = plt.subplots(2, 2)
- 在第一轴域上绘制条形图,并以厘米为单位设置
xticks
:
axs[0, 0].bar(cms, cms, bottom=bottom)
axs[0, 0].set_xticks(cm * np.arange(0, 21, 3))
- 在第二轴域上绘制条形图,其中, x 轴以厘米为单位, y 轴以英寸为单位:
axs[0, 1].bar(cms, cms, bottom=bottom, width=width, xunits=cm,
yunits=inch)
axs[0, 1].set_xticks(cm * np.arange(0, 21, 3))
- 在第三轴域上绘制条形图,其中, x 轴以英寸为单位, y 轴以厘米为单位:
axs[1, 0].bar(cms, cms, bottom=bottom, width=width, xunits=inch,
yunits=cm)
axs[1, 0].set_xticks(cm * np.arange(0, 21, 3))
axs[1, 0].set_xlim(2, 6)
- 以 x 和 y 轴为单位在第四轴域上绘制条形图,以英寸为单位:
axs[1, 1].bar(cms, cms, bottom=bottom, width=width, xunits=inch,
yunits=inch)
axs[1, 1].set_xticks(cm * np.arange(0, 21, 3))
axs[1, 1].set_xlim(2 * cm, 6 * cm)
- 调整绘图之间的间距,并在屏幕上显示图形:
fig.tight_layout()
plt.show()
以下是其工作原理的说明:
- 准备 x 和 y 坐标的输入数据,设置条形的底部偏移量和条形的宽度。
fig, axs = plt.subplots(2, 2)
在2 x 2
网格中定义图形布局。axs[0, 0].bar(cms, cms, bottom=bottom)
在axs[0, 0]
和上绘制条形图,输入数据以厘米为单位。axs[0, 0].set_xticks(cm * np.arange(0, 21, 3))
在 x 轴上设置刻度线,以使其与条形对齐。axs[0, 1]
上的条形图与axs[0, 0]
完全相同,除了轴域的单位从厘米变为英寸,这是在绘图上可见的。axs[1, 0]
上的条形图再次类似于axs[0, 0]
上的条形图,但 x 轴上的单位更改为英寸,而axs[1, 0].set_xlim(2, 6)
将 x 轴限制设置为(2
,6
)。 在这里,仅使用标量来设置限制值,没有任何测量单位,这意味着无论 x 轴测量单位是什么,限制值都适用,在这种情况下,范围为两到六英寸。axs[1,1]
上的条形图使用英寸作为, x 和 y 轴的度量单位,并设置 x 轴限制(2 到 6 厘米),将 x 轴的度量单位转换为英寸。 因此它将转换为英寸,在这种情况下将转换为 0.79 到 2.362 英寸。
您应该看到如下图:
四、开发可视化来提高发布质量
在本章中,我们将介绍以下秘籍:
- 颜色,线条样式和标记自定义
- 使用标准颜色表
- 用户定义的颜色和颜色表
- 处理图例
- 自定义标签和标题
- 使用自动缩放和轴限制
- 自定义刻度和刻度标签
- 自定义轴线
- 双生轴域
- 使用图案填充
- 使用标注
- 使用样式表
介绍
Matplotlib 提供了许多功能来自定义图形的所有属性。 它还提供了许多不同的方法来实现相同的功能,从而提供最大的灵活性和多种选择。 在本章中,我们将介绍每个图形属性可用的标准功能,例如颜色,标签,标题,图例,刻度线,轴线,样式,阴影和标注。 第 6 章和“带有高级功能的绘图”将介绍诸如属性循环,变换,GridSpec
和路径效果之类的高级主题。
颜色,线条样式和标记自定义
Matplotlib 支持许多不同的方式来指定颜色,线条样式和标记。 在本秘籍中,我们将学习如何使用这些功能。
准备
导入以下必需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
下面的代码块绘制了五个不同的图,以演示用于指定颜色,线条样式和标记的大多数可能组合:
- 定义图形布局,如下所示:
fig = plt.figure(figsize=(12,6))
- 为每个图定义轴域名称:
ax1 = plt.subplot(321)
ax2 = plt.subplot(322)
ax3 = plt.subplot(323)
ax4 = plt.subplot(324)
ax5 = plt.subplot(325)
ax6 = plt.subplot(326)
- 设置
x
坐标的数据:
x = np.linspace(0, 10, 20)
- 以下是许多颜色规格的演示:
xkcd:sky blue
:xkcd
颜色调查的名称green
:CSS4 颜色名称1F1F1F1F
:RGBA 格式的十六进制值; 数字范围为 0-F。b
:CSS4 颜色的缩写1C0B2D
:RGB 格式的十六进制值pink
:色表C4
:属性周期中的颜色; 这是区分大小写的,必须将C
大写
我们用以下代码格式表示它们:
color_list = ['xkcd:sky blue', 'green', '#1F1F1F1F', 'b', '#1C0B2D',
'pink', 'C4']
for i, color in enumerate(color_list):
y = x - (-5*i + 15)
ax1.plot(x, y, color)
ax1.set_title('colors demo')
- 以下是许多线条样式的演示:
line_style = ['-', '--', '-.', ':', '.']
for i, ls in enumerate(line_style):
y = x - (-5*i + 15)
line, = ax2.plot(x, y, ls)
ax2.set_title('line style demo')
plt.setp(line, ls='steps')
- 这是许多标记规格的演示:
marker_list = ['.', ',', 'o', 'v', '^', 's', 'p', '*', 'h', 'H',
'D']
for i, marker in enumerate(marker_list):
y = x - (-5*i + 15)
ax3.plot(x, y, marker)
ax3.set_title('marker demo')
- 以下是指定颜色,线条样式和标记的组合的演示:
y = x # reset y to x
ax4.plot(x, y-10, 'k-d')
ax4.plot(x, y-5, 'c--')
ax4.plot(x, y, '|')
ax4.plot(x, y+5, '-.')
ax4.plot(x, y+10, color='purple', ls=':', marker='3')
ax4.plot(x, y+15, color='orange', linestyle=':', marker='1')
ax4.set_title('combination demo')
- 以下是指定线条和标记的颜色和大小的演示:
ax5.plot(x, y-10, 'y-D', linewidth=2, markersize=4,
markerfacecolor='red',
markeredgecolor='k',markeredgewidth=1)
ax5.plot(x, y-5, 'm-s', lw=4, ms=6, markerfacecolor='red',
markeredgecolor='y', markeredgewidth=1)
ax5.set_title('Line and Marker Sizes Demo')
- 以下是虚线端帽样式的演示:
dash_capstyles = ['butt','projecting','round']
for i, cs in enumerate(dash_capstyles):
y = x - (-5*i + 15)
ax6.plot(x, y, ls='--', lw=10, dash_capstyle=cs)
ax6.set_title('dash capstyle demo')
- 仅使用绘图之间的空间,然后在屏幕上显示图形:
plt.tight_layout()
plt.show()
工作原理
以下是代码的输出,后面是其工作原理的解释:
np.linspace(0, 10, 20)
在 0 到 20 的范围内创建 20 个值,它们映射到 x 轴。fig = plt.figure(figsize=(12,6))
定义大小为(12, 6)
的图形,然后使用plt.subplot()
定义六个子图。- 第一个图展示了可以在图中指定颜色的各种方法。
color_list
是绘制线条图的颜色列表。for
循环遵循列表中每种颜色的绘图线。for
循环中的enumerate
允许两个变量:一个用于从零开始的索引,另一个用于列表中的实际项目:xkcd:sky blue
-这是xkcd
颜色调查中的一种颜色。xkcd:
必须在实际颜色代码之前。 请在此站点上找到颜色的完整列表。- 颜色代码(
b
,g
,r
,c
,m
,y
,k
,w
)及其扩展名(blue
,green
,red
,cyan
,magenta
,yellow
,black
,white
)。 - (
tab:blue
,tab:orange
,tab:green
,tab:red
,tab:purple
,tab:brown
,tab:pink
,tab:gray
,tab:olive
,tab:cyan
)是来自表格的颜色T10
分类调色板(这也是默认的颜色周期)。 我们可以在它们之前使用tab:
来指定这些颜色,也可以不使用tab
来指定这些颜色。 两者都是可以接受的。 - 我们也可以指定 RGB 或 RGBA 格式的十六进制值。 任何通道的十六进制值范围从
00
到FF
。 因此,RBG 的范围从000000
到FFFFFF
,而 RGBA 的范围从00000000
到FFFFFFFF
。A
代表 Alpha,代表颜色的透明度; 朝向00
高度透明,朝向FF
不透明。 - 所有这些都不区分大小写,因此我们可以使用大写或小写字母。
- 另外一个选项是
CN
,其中C
区分大小写,并且必须是大写字符,后跟数字,这是默认颜色周期中颜色的索引。 如上所述,默认周期中的第一种颜色是蓝色,然后是橙色,绿色,红色,紫色,等等。 因此,C0
代表蓝色,C1
代表orange
,依此类推。
- 第二个图演示了六种可用的线型。 它们是破折号(
-
),实线(--
),破折号和点(-.
),冒号(:
),点(.
)和实线(' '
)。 最后一条实线用于演示属性设置函数plt.setp()
的可用的steps
样式。 此选项不能像其他线型一样直接使用。 - 第三幅图展示了各种标记。 并非所有可用的标记都在此处绘制。 有关标记的完整列表,请参阅此处的 Matplotlib 文档。
- 第四幅图演示了如何指定颜色,线条样式和标记及其缩写或全名的组合。 我们可以在字符串中指定所有三个参数,例如
g-^
,也可以只指定其中一个或两个参数,例如g
或--
或D
,在这种情况下,它对此处未指定的属性的其他参数使用默认值。 我们还可以单独指定颜色,例如,颜色为purple
,线型为:
,标记为>
等。 - 图五演示了如何为标记的线宽,标记大小,边缘和面颜色指定大小和颜色参数。
- 最后,图六展示了虚线样式下的端帽样式。
使用标准颜色表
在上一秘籍中,我们看到了在绘制图形时如何使用颜色。 如果我们想用视觉感知的颜色可视化数据范围以了解数据中的图案,那么创建与所需范围内的数据变化匹配的颜色组合将很繁琐。 Matplotlib 提供了一系列预定义的颜色表,可以利用这些颜色表满足任何特定要求。 Matplotlib 还启用了用户定义的颜色表,这些颜色表将在下一个秘籍中介绍。
In Python notebooks, you can type matplotlib.pyplot.cm.
and press Tab or type help (matplotlib.pyplot.cm)
to get a complete list of the available colormaps.
准备
在此示例中,我们将使用熟悉的Iris
数据集。 我们将首先创建一个相关矩阵,并应用标准的颜色表以查看其外观。 在第 2 章和“基本图入门”中,我们看到了相同的相关矩阵作为热图绘制。 在那里,我们使用了hot
色彩表,但是我们没有涉及色彩表的细节。 我们将在这里解释。
导入以下必需的库:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
操作步骤
以下代码块绘制了具有Blues
颜色表的相关矩阵:
- 从 Excel 文件中读取
winequality
数据:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
corr = wine_quality.corr()
- 定义图及其大小:
plt.figure(figsize=(12,8))
- 绘制相关图,关联的
x
和y
刻度以及色条:
plt.imshow(corr, cmap='Blues')
plt.colorbar()
plt.xticks(range(len(corr)),corr.columns, rotation=45)
plt.yticks(range(len(corr)),corr.columns)
- 在屏幕上显示该图:
plt.show()
工作原理
以下是其工作原理的说明:
pd.read_csv()
读取winequality
数据,wine_quality.corr()
计算相关矩阵。plt.imshow(corr, cmap='Blues')
将相关矩阵显示为图像并应用标准色表之一:Blues
。plt.colorbar()
显示颜色条,该颜色条指示哪个颜色份额代表哪个数据范围。plt.xticks()
和plt.yticks()
绘制代码(数据集中每个属性一个)和 x 和 y 轴的相应代码标签。plt.xticks()
中的参数rotation=45
表示报价标签应与相应轴成 45 度角放置。
您应该看到以下热图。 不出所料,数据范围为 -0.6 到 1.0(相关性只能在 -1.0 和 1.0 之间)。 1.0 一端用dark blue
颜色表示,另一端用white
颜色表示 -1,深蓝色和白色之间的深到浅阴影表示 1.0 和 -1.0 之间的数字:
更多
在上图中,我们显示了输入数据中可用的完整数据范围。 但是,我们可以使用plt.clim()
方法限制要进行颜色编码的数据范围。 当存在异常值时(变量的一些条目与其余数据相比太大或太小),这很有用,然后默认情况下,颜色表会扩展整个数据范围的颜色代码。 当存在离群值时,由于范围较大,大多数值会变得模糊,并且离群值会以极端的颜色突出。 如果要抑制离群值的影响,可以限制不包含离群值的数据范围,并在颜色条中使用完整的颜色列表来绘制所需范围。 这给出了数据分布的真实情况。 这是我们可以完成此操作的方法。
首先,我们将噪声添加到已创建图像的图像像素的 10% 中。 我们将不得不做一些数据预处理以添加噪声,从而使数据范围超出 -1 到 1。然后,我们将绘制具有完整数据范围和 -1 到 1 的数据范围的同一图像 ,看看两者之间的区别。 可以看出,在第一张图像中,一些单元格(归因噪声或离群值)以蓝色或白色亮着,而所有其他单元格都模糊了,但是在第二张图像中,所有单元格颜色在 -1 到 1 的范围内均匀地有所不同:
- 在图像像素的 10% 中产生噪声:
np.random.seed(0)
mask = (np.random.random(corr.shape) < 0.1)
columns = corr.columns
corr1 = np.array(corr)
corr1[mask] = np.random.normal(0, 5, np.count_nonzero(mask))
corr = pd.DataFrame(corr1, columns=columns)
- 定义图及其大小:
plt.figure(figsize=(12, 5))
- 定义第一个轴域并在上面绘制相关图:
plt.subplot(121)
plt.imshow(corr, cmap='Blues')
plt.colorbar()
plt.xticks(range(len(corr)),corr.columns, rotation=75)
plt.yticks(range(len(corr)),corr.columns)
- 定义第二个轴域并绘制相关图,并限制数据:
plt.subplot(122)
plt.imshow(corr, cmap='Blues')
plt.colorbar(extend='both')
plt.clim(-1, 1)
plt.xticks(range(len(corr)),corr.columns, rotation=75)
plt.yticks(range(len(corr)),corr.columns)
- 调整绘图之间的空间,并在屏幕上显示图形:
plt.tight_layout()
plt.show()
这是代码及其工作方式的说明:
np.random.seed(0)
设置种子,以便每次我们运行随机数生成器时,我们都会获得相同的数据。 当我们多次运行相同的代码时,这可以确保结果的可重复性。mask = (np.random.random(corr.shape) < 0.1)
创建一个大小为corr
的矩阵,所有小于 0.1 的值都以True
作为条目; 否则为False
。columns = corr.columns
从corr
Pandas 数据帧中提取列名称,以供以后使用。corr1 = np.array(corr)
为我们的corr
数据帧创建了一个 NumPy 数组,因为下一条语句与 NumPy 数组(而不是数据帧)一起很好地工作。corr1[mask] = np.random.normal(0, 5, np.count_nonzero(mask))
通过为 10% 的条目生成随机正态值来替换corr1
中与掩码中的True
条目相对应的条目,并且该分布的平均值为零,标准差为 5。 想法是用代表噪声的较大值替换 10% 的条目。corr = pd.DataFrame(corr1, columns=columns)
为噪声估算的相关矩阵创建数据帧。plt.subplot(1, 2, 1)
为第一个绘图创建轴域,我们将在其中显示噪声输入的图像。plt.imshow(corr, cmap='Blues')
在plot1
中绘制图像,后跟颜色条,刻度和刻度标签。plt.subplot(1, 2, 2)
创建第二个绘图的轴域,在其中将数据范围限制在 -1 和 1 之间。lt.colorbar(extend='both')
绘制带有两端箭头的颜色条,指示范围超出了显示范围。plt.clim(-1, 1)
将颜色(实际上是数据范围)限制在 -1 和 1 之间。
您应该看到以下图:
用户定义的颜色和颜色表
在上一个秘籍中,我们学习了如何利用预定义的颜色和颜色表以及如何针对特定需求自定义它们。 在本秘籍中,我们将学习如何创建自己的颜色表。 在此示例中,我们将使用Iris
数据集。
准备
我们将首先学习如何创建离散的颜色表,然后是连续的颜色表。
导入以下必需的库:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
操作步骤
以下代码块显示了三个图表; 第一个使用标准色表coolwarm
,另外两个使用用户定义的离散色表。 在两个用户定义的颜色中,第一个使用纯红色(1, 0, 0)
,绿色(0, 1, 0)
和蓝色(0, 0, 1)
,而另一个使用 RGB 的混合颜色(1, 0.5, 0)
,(0.25, 1, 0)
,(0, 0.5, 1)
以生成三种离散颜色。 请注意,在第一个颜色表元组(1, 0, 0)
中,只有红色是 1; 绿色和蓝色为零。 在第二个颜色中,第一个和第二个颜色是(1, 0.5, 0)
和(0.25, 1, 0)
表示它们是红色和绿色的组合,而第三个颜色是绿色和蓝色的组合。
我们在这里使用三种离散的颜色,因为我们在输入数据集中有三个聚类。 我们应该具有与簇数一样多的颜色:
- 从 Excel 读取
Iris
数据并将文本类名称替换为数值:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
- 定义图及其布局:
fig, axs = plt.subplots(1,3, figsize=(9,6))
fig.subplots_adjust(left=0.0, bottom=0.05, right=0.9, top=0.95,
wspace=0.6)
- 定义一个函数来绘制图形:
def plot_graph(axes, cm, cbaxs):
im = axes.scatter(iris.petal_length, iris.petal_width,
s=10*iris.petal_length*iris.petal_width, c=iris.species,
cmap = cm)
caxs = plt.axes(cbaxs)
fig.colorbar(im, caxs, ticks=range(3), label='clusetr #')
- 使用从预定义的颜色表
coolwarm
中选择的三种颜色绘制Iris
数据集簇:
cbaxs = [0.24, 0.05, 0.03, 0.85] # left, bottom, width and height
plot_graph(axs[0], plt.cm.get_cmap('coolwarm', 3), cbaxs)
- 使用纯红色,绿色和蓝色的自定义颜色绘制
Iris
数据群集:
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] # R -> G -> B
cm = LinearSegmentedColormap.from_list('custom_RGB_cmap', colors,
N=3)
cbaxs = [0.58, 0.05, 0.03, 0.85]
plot_graph(axs[1], cm, cbaxs)
- 使用自定义颜色混合颜色组合来绘制
Iris
数据群集:
colors = [(1, 0.5, 0), (0.25, 0.5, 0.25), (0, 0.5, 1)] # R -> G -> B
cm = LinearSegmentedColormap.from_list('dummy', colors, N=3)
cbaxs = [0.95, 0.05, 0.03, 0.85]
plot_graph(axs[2], cm, cbaxs)
- 在屏幕上显示该图:
plt.show()
工作原理
以下是代码及其工作方式的说明:
fig, axs = plt.subplots(1,3, figsize=(9,6))
定义具有连续三幅图的图形布局,图形大小为(9, 6)
。fig.subplots_adjust(left=0.0, bottom=0.05, right=0.9, top=0.95, wspace=0.6)
定义图形的边界框,在图形的左侧,底部,右侧和顶部定义的所有四个方向上都留有空间。wspace
定义一行中各图之间要保留的空间量,以使它们的标签或图之间没有重叠。hspace
是另一个参数,它控制列中各图之间的间隔。 在本示例中,我们没有使用它,因为我们仅将所有图形绘制在一行中。plot_graph()
是用户定义的函数,用于绘制具有给定参数,轴域,颜色表和颜色条轴域的图形。axs.scatter()
使用给定的参数绘制散点图。caxs = plt.axes(cbaxs)
在给定的坐标轴上定义颜色条。fig.colorbar()
为具有定义颜色的每个群集绘制带有三个刻度的色条,并使用cluster #
标记色条。- 我们将第一个图形绘制在
axes[0]
上,预定义的颜色表coolwarm
的前三个颜色和色条轴域cbaxs =[0.24, 0.05, 0.03, 0.85]
上。 这些是left
和bottom
以及小节的width
和height
中图形的分数。 我们将在第 6 章和“带有高级功能的绘图”中了解有关坐标系统的更多信息。 - 我们在
axes[1]
上绘制第二张图,并使用自定义颜色colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
,它们是纯红色,绿色和蓝色。 cmap_name = 'custom_RGB_cmap'
定义第一个用户定义的颜色表的名称。 如果我们必须注册它以将其包括在标准颜色表库中,这将很有用。cm = LinearSegmentedColormap.from_list(cmap_name, colors2, N=3)
使用先前定义的三种颜色的列表定义颜色表。- 对于第二张图,我们将色条放置在以下坐标上:
cbaxs = [0.58, 0.05, 0.03, 0.85]
。 - 同样,我们用
colors = [(1, 0.5, 0), (0.25, 0.5, 0.25), (0.8, 0.8, 0.25)]
绘制第三张图并将它们放置在坐标cbax = [0.95, 0.05, 0.03, 0.85]
上。 再次将红色,绿色和蓝色通道中的每种颜色与不同值的红色,绿色和蓝色组合在一起,以创建新的自定义颜色。
您应该看到以下图:
更多
以前,我们已经学习了如何创建离散的用户定义的颜色表。 现在让我们看看如何创建用户定义的连续色彩图。 区别在于颜色规格。 在离散的颜色表中,我们的 RGB 元组的数量与数据中簇的数量一样多,因此每种颜色代表一个簇。 但是,在连续的颜色表中,颜色必须沿着整个数据范围从光谱的一端逐渐移到另一端。
我们知道,每种颜色都用三个数字的元组表示:R,G 和 B 通道。 在某些情况下,第四通道alpha
也用于表示颜色的透明度(或不透明度)。 这是我们需要指定颜色的方式。 让我们举个例子:
cdict1 = {'red': ((0.0, 0.0, 0.25), (0.5, 0.4, 0.4), (1.0, 0.8,
1.0)),
'green': ((0.0, 0.0, 0.25), (0.25, 0.5, 0.5), (0.75, 0.75,
0.75), (1.0, 0.9, 1.0)),
'blue': ((0.0, 0.0, 0.25), (0.5, 0.5, 0.5), (1.0, 0.75,
1.0))}
假设每个元组中的第一项是x
,第二项是y0
,第三项是y1
。 在每种颜色组合中,x
必须从 0.0 逐渐移至 1.0。 从顶部到底部的行必须从y1
(顶部行)逐渐过渡到y0
(下一行),从y0
到y1
在同一行中显示,然后在下一行中再次y1
至yo
应该是渐进的。 在红色的情况下,x
从 0.0 移至 0.5,然后移至 1.0。 同样,y1
从 0.25 移至 0.4、0.4、0.8,这也是渐进的。 我们可以在每种颜色中包含任意数量的元组。 在这种情况下,红色和蓝色分别具有三种,而绿色则具有四种。
同样,我们还定义了三个其他颜色字典,其中一个也带有alpha
,只是为了演示所有可能的组合:
cdict2 = {'red' : ((0.0, 0.0, 0.0), (0.5, 0.0, 1.0), (1.0, 0.1, 1.0)),
'green': ((0.0, 0.0, 0.0), (1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.1), (0.5, 0.5, 0.5), (1.0, 0.8, 0.8)) }
cdict3 = {'red': ((0.0, 0.0, 0.0), (0.25, 0.0, 0.0), (0.5, 0.8, 1.0),
(0.75, 1.0, 1.0),(1.0, 0.4, 1.0)),
'green': ((0.0, 0.0, 0.0), (0.25, 0.0, 0.0), (0.5, 0.9, 0.9),
(0.75, 0.0, 0.0), (1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.4), (0.25, 1.0, 1.0), (0.5, 1.0, 0.8),
(0.75, 0.0, 0.0), (1.0, 0.0, 0.0))}
cdict4 = {'red': ((0.0, 0.0, 0.5), (0.5, 0.8, 1.0), (0.75, 1.0, 1.0),
(1.0, 0.9, 1.0)),
'green': ((0.0, 0.0, 0.5), (0.25, 0.75, 0.0), (0.5, 0.9,
0.9), (1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.4), (0.25, 1.0, 1.0), (0.75, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'alpha': ((0.0, 1.0, 1.0), (0.5, 0.4, 0.4), (1.0, 0.7, 1.0)) }
下面的代码块使用前面定义的四个颜色字典来绘制四个颜色表。 这与我们在离散色表的情况下所见相似。
读取Iris
数据集和数字代码的映射类名称:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" : 1,
"virginica" : 2})
定义图形,布局,大小,并调整各图之间的空间:
fig, axs = plt.subplots(1,4, figsize=(16,6))
fig.subplots_adjust(left=0.0, bottom=0.0, right=0.95, top=0.94,
wspace=0.4)
定义一个函数以绘制图表:
def plot_graph(name, dictionary, axs, cbaxs):
custom = LinearSegmentedColormap(name, dictionary)
im = axs.scatter(iris.petal_length, iris.petal_width, s=100*iris.petal_length*iris.petal_width,
c=iris.species, cmap=custom)
caxs = plt.axes(cbaxs) # left, bottom, width and height
fig.colorbar(im, caxs)
绘制每种颜色组合的图形,并将其显示在屏幕上:
plot_graph('custom1', cdict1, axs[0], [0.2, 0.01, 0.01, 0.93])
plot_graph('custom2', cdict2, axs[1], [0.45, 0.01, 0.01, 0.93])
plot_graph('custom3', cdict3, axs[2], [0.7, 0.01, 0.01, 0.93])
plot_graph('custom4', cdict4, axs[3], [0.97, 0.01, 0.01, 0.93])
plt.show()
输出图如下所示:
处理图例
图例是给定轴域上每个图的描述。 每个轴域都有其自己的图例。 Matplotlib 提供了许多不同的方式来指定图例。 我们将涵盖尽可能多的组合,尽管我们将无法涵盖本书中的一整套可能性。
准备
导入以下必需的库:
import matplotlib as plt
import numpy as np
import matplotlib.patches as mpatches
from numpy.random import randn
操作步骤
以下代码块绘制了 11 种可以指定图例的不同方式:
- 定义图形的大小:
plt.figure(figsize=(15, 10))
- 使用内联标签绘制第一个图形:
plt.subplot(3,4,1)
line, = plt.plot([1, 2, 3], label='Inline label')
plt.legend()
- 使用
set_label
方法用图例绘制第二张图:
plt.subplot(3,4,2)
line, = plt.plot([1, 2, 3])
line.set_label('Label via method')
plt.legend()
- 用两条线绘制第三个图形,并用标签列表绘制图例:
plt.subplot(3,4,3)
plt.plot([1, 2, 3])
plt.plot([3, 2, 1])
plt.legend(['Positive Slope', 'Negative Slope'])
plt.title('List of Labels')
- 用三条线绘制第四个图形,并用图柄和标签绘制图例:
plt.subplot(3,4,4)
line1, = plt.plot([1, 2, 3])
line2, = plt.plot([3, 2, 1])
line3, = plt.plot([2,2])
plt.legend((line3, line2, line1), ('Zero Slope', 'Negative Slope',
'Positive Slope'))
plt.title('Handles and Labels')
- 用三条线和图例以及部分手柄列表来绘制第五张图:
plt.subplot(3,4,5)
line_up, = plt.plot([1,2,3], label='Line 2')
line_down, = plt.plot([3,2,1], label='Line 1')
line_3, = plt.plot([2,3,4], label='no label')
plt.legend(handles=[line_up, line_down])
plt.title('Labels for given handles')
- 用三条线以及一部分手柄和标签绘制第六张图:
plt.subplot(3,4,6)
line_up, = plt.plot([1,2,3], label='Line 2')
line_down, = plt.plot([3,2,1], label='Line 1')
line_3, = plt.plot([2,3,4], label='no label')
plt.legend([line_up, line_down], ['Line Up', 'Line Down'])
plt.title('partial handles & labels')
- 用补丁作为标签绘制第七张图:
plt.subplot(3,4,7)
red_patch = mpatches.Patch(color='red', label='The red data')
plt.legend(handles=[red_patch])
plt.title('Patch as a label')
- 绘制第八张图, 在图例中带有类别标签:
plt.subplot(3,4,8)
z = randn(10)
blue_dot, = plt.plot(z, "bo", markersize=15)
## Put a white cross over some of the data.
white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3,
markersize=15)
plt.legend([blue_dot, (blue_dot, white_cross)], ["Attr A", "Attr
A+B"])
plt.title('category labels')
- 在两列中将第九个图和图例放在图的顶部:
plt.subplot(3,4,9)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")
## Place a legend above this subplot, expanding itself to
## fully use the given bounding box.
plt.legend(bbox_to_anchor=(0, 1.02, 1., .102), #left, bottom, width,
height
ncol=2, mode="expand", borderaxespad=0.5)
ax = plt.gca()
ax.set_title('Legend on top', pad=20)
- 绘制第十张图,图例在图的右侧:
plt.subplot(3,4,10)
plt.plot([1, 2, 3], label="test1")
plt.plot([3, 2, 1], label="test2")
## Place a legend to the right of this smaller subplot.
plt.legend(bbox_to_anchor=(1.02, 1.0), borderaxespad=0)
plt.title('Legend on right')
- 绘制第十一张图,将图例分为多个图例:
plt.subplot(3,4,11)
line1, = plt.plot([1, 2, 3], label="Line 1", linestyle='--')
line2, = plt.plot([3, 2, 1], label="Line 2", linewidth=4)
## Create a legend for the first line.
first_legend = plt.legend(handles=[line1], loc=1)
## Add the legend manually to the current Axes. Repeated calls to plt.legend()
## will overwrite previous calls, so only last one remains
ax = plt.gca().add_artist(first_legend)
## Create another legend for the second line.
plt.legend(handles=[line2], loc=4)
plt.title('Split Legend')
- 清空第十二个绘图空间:
plt.subplot(3,4,12)
plt.axis('off')
- 调整绘图之间的空间,并在屏幕上显示图形:
plt.tight_layout(w_pad=5, h_pad=5)
plt.show()
工作原理
这是对十一个绘图的解释:
- 图 1:标签指定为线形图本身的一部分。
- 图 2:创建线对象后,将标签指定为直线轴域上的方法。
- 图 3:标签定义为
plt.legend()
命令本身的列表。 - 图 4:句柄(轴域对象)和标签作为元组传递到
plt.legend()
函数。 - 图 5:三个句柄中只有两个传递给
plt.legend()
,因此图例中未显示line_3
。 - 图 6:类似于图五,但句柄和标签都传递给
plt.legend()
。 - 图 7:贴片用作标签。
mpatches.Patch()
创建一个红色补丁。 - 图 8:绘制两个不同类别的数据并分别标记它们。
- 图 9:在图的顶部绘制图例,标签从左到右分布,并且不与标题重叠。
plt.legend(bbox_to_anchor=(0, 1.02, 1., .102), ncol=2, mode="expand", borderaxespad=0.5)
使用bbox_to_anchor
将标签放置在图的顶部(与图的大小成比例,从左起 0,从底部起 1.02,宽度为 1.0,高度为 0.102)。ncol=2
指定标签应放在两列中,而不是两行中,这是默认设置。 - 图 10:再次使用
bbox_to_anchor()
坐标,图例位于图的右侧。 - 图 11:将标签分为两部分,并将它们放置在不同的位置。 多次调用
plt.legend()
将覆盖以前的图例; 只有最后一个占优势,因此不能用于将标签拆分和放置在其他位置。 其中之一必须通过ax=plt.gca().add_artist(first_legend)
手动放置。plt.gca()
获取当前轴域,然后add_artist()
在该轴域上添加标签。 对于第二个标签,请使用标准plt.legend()
。 - 图 12:由于没有第十二部分,我们必须清理轴线,壁虱和壁虱标签。 否则,它们将无任何显示地出现! 我们很快将在本章中学习轴线和壁虱。
以下是各图例与相应图例的外观:
更多
使用图例的另一个更常见的选项是plt.legend()
上的loc
参数。 该参数可以使用代码 0 到 10 来指定绘图上的不同位置。 它们每个都有一个文本描述,可以在 Matplotlib 文档上找到。
以下是两个可能选项的示例代码:
plt.legend(loc='best') or plt.legend(loc=0)
plt.legend(loc=‘upper right’) or plt.legend(loc=1)
自定义标签和标题
在本秘籍中,我们将学习如何自定义轴标签,刻度标签,图形和图形标题。 对于其中的一些自定义设置,我们将设置plt.rcParams
默认参数。 但是,这些设置将处于活动状态,并适用于会话中的所有绘图。
准备
让我们导入所需的库并设置plt.rcParams()
,这对于此秘籍也是必需的。 这些设置将适用于此会话中绘制的所有图:
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['figure.titlesize'] = 15
plt.rcParams['legend.fontsize'] = 12
plt.rcParams['axes.labelsize'] = 12
plt.rcParams['axes.labelweight'] = 'bold'
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
操作步骤
以下代码块绘制了三个带有各种标签的图,以演示如何进行自定义:
- 定义图形,布局和大小,并在图之间留出足够的空间:
fig, ax = plt.subplots(1, 3, figsize=(10,4))
fig.subplots_adjust(wspace=0.7)
- 使用自定义标签和标题在第一个轴域上绘制直方图:
ax[0].hist(np.random.randn(1000))
ax[0].set(xlabel='Bins', ylabel='Frequency')
atitle = ax[0].set_title('Histogram', fontstyle='italic',
fontsize=14)
plt.setp(atitle,color='blue')
- 在第二个轴域上绘制条形图:
## Plot the bars for men's data
menMue = [3, 10, 100, 500, 50]
menSigma = [0.75, 2.5, 25, 125, 12.5]
index = np.arange(len(menMue)) # the x locations for the groups
width = 0.35 # the width of the bars
p1 = ax[1].bar(index, menMue, width, color='r', bottom=0,
yerr=menSigma)
## Plot the bars for women's data
womenMue = [1000, 3, 30, 800, 1]
womenSigma = [500, 0.75, 8, 200, 0.25]
p2 = ax[1].bar(index + width, womenMue, width, color='y', bottom=0,
yerr=womenSigma)
## customize title and labels for the figure
atitle = ax[1].set_title('Scores by category and gender',
fontstyle='italic', fontsize=14)
plt.setp(atitle,color='blue')
ax[1].set(xticks=(index + width / 2), xticklabels=('C1', 'C2', 'C3',
'C4', 'C5'), yscale='log')
ax[1].legend((p1[0], p2[0]), ('Men', 'Women'), bbox_to_anchor=
(1.05,1))
- 在第三轴域上绘制散点图:
ax[2].scatter(np.random.rand(100),np.random.rand(100),
s=100*np.random.rand(100)*np.random.rand(100))
atitle = ax[2].set_title('Scatter Plot', fontstyle='italic',
fontsize=14)
plt.setp(atitle,color='blue')
- 设置图的标题:
ftitle= plt.suptitle('Figure Title', fontname='arial', fontsize=20,
fontweight='bold')
plt.setp(ftitle,color='green')
- 调整绘图之间的间距,并在屏幕上显示图形:
plt.tight_layout(pad=3, w_pad=5)
plt.show()
工作原理
以下是其工作原理的说明:
fig, ax = plt.subplots(1, 3, figsize=(10,4))
定义图形布局。fig.subplots_adjust(wspace=0.5)
调整子图之间的空间。ax[0].hist(np.random.randn(1000))
在 0 轴域上绘制直方图,然后是 X 和 Y 轴的标签,然后是该图的标题。ax[0].set_title()
除了标题文本外,还包含字体样式和大小参数,但没有color
参数; 因此,我们使用plt.setp(atitle,color='blue')
设置标题的颜色。plt.rcParams['axes.labelsize'] = 10
和plt.rcParams['axes.labelweight'] = 'bold'
设置所有图的 x 和 y 轴标签的字体大小和粗细。 在这里,我们仅对第一个图具有标签,因此,它们以fontsize
或10
的粗体显示。p1
和p2
是男性和女性在第一轴域上的柱状图。ax[1].set_xticks(ind + width / 2)
设置刻度线,然后设置ax[1].set_xticklabels(('C1', 'C2', 'C3', 'C4', 'C5'))
,在 x 轴上设置ticklabels
。 对于 x 轴,我们使用默认刻度和ticklabels
作为对数刻度。 通常,我们为类别变量覆盖ticklables
以给出有意义的名称。- 最后,
plt.suptitle()
和plt.setp()
为给定的字体名称,大小和颜色定义整体图形的标题。 plt.tight_layout(pad=3)
调整绘图之间的间隔,pad=3
调整图形标题与各个绘图标题之间的间隔,以使它们之间没有重叠。
我们得到的输出如下:
更多
字体fontstyle
,fontsize
,fontweight
以及字体颜色应用于轴标签,刻度标签,轴域标题和图形标题的选项组合有多种可能性。 利用所有这些功能,我们可以绘制专业的质量可视化图像。
使用自动缩放和轴限制
Matplotlib 自动将 x 和 y 轴的整个数据范围拟合到输入数据中,将其拆分为桶,并相应地显示刻度和刻度标签。 有时,我们可能希望在任一轴域上更紧密地查看特定范围的数据,而不是完整的数据范围。 在本秘籍中,我们将学习如何做。
准备
让我们导入所需的库:
import numpy as np
import matplotlib.pylab as plt
from matplotlib.ticker import FuncFormatter
操作步骤
以下代码显示了相同输入数据的两个图,但是第一个使用默认设置,因此它在 x 和 y 轴上都显示了完整范围的数据,而第二个图限制了 x 和 y 轴范围:
- 为图表准备数据:
x = np.linspace(-50,50,500)
y = x**2 + np.cos(x)*100
- 定义一个函数以在打印到绘图上之前格式化数字数据:
def Num_Format(x, pos):
"""The two arguments are the number and tick position"""
if x >= 1e6:
string = '${:1.1f}M'.format(x*1e-6)
else:
string = '${:1.0f}K'.format(x*1e-3)
return string
- 将先前定义的函数应用于
formatter
,并使用大小和布局定义图形:
formatter = FuncFormatter(Num_Format)
fig, axs = plt.subplots(1,2, figsize=(8,5))
- 使用自动缩放在第一个轴域上绘制折线图:
axs[0].plot(x, y**2) axs[0].yaxis.set_major_formatter(formatter)
axs[0].set_title('Full Data/Autoscale')
- 再次绘制同一图,并在 x 和 y 轴上都施加限制:
axs[1].plot(x, y**2)
axs[1].set(xlim=(-5,5), ylim=(0,10000), title='X and Y limited')
axs[1].yaxis.set_major_formatter(formatter)
- 在屏幕上显示该图:
plt.show()
工作原理
- 对于 x 轴坐标,
x = np.linspace(-50,50,500)
创建 500 个点,它们之间的等距距离在-50 到+50 之间。 def Num_Format(x, pos)
是根据数字是千位还是数百万位将大数字格式化为$K
或$M
的函数。FuncFormatter(Num_Format)
是一个 matplotlib 函数,它使用用户定义的函数货币作为参数,然后将此FuncFormatter
应用于 x 或 y 轴上,在其上使用axs[0].yaxis.set_major_formatter(formatter)
来格式化数字。axs[0].plot(x, y**2)
使用 x 和 y 轴的默认设置在轴域 0 上绘制图形,因此它显示来自输入的全部数据。axs[1].plot(x, y**2)
在第一个轴域上再次绘制相同的图形。axs[1].set_xlim(-5,5)
在 x 轴上将数据限制从 -5 设置为 +5,axs[1].set_ylim(0,10000)
在 y 轴上将数据限制从 0 设置为 10,000。 这些限制设置为第一轴域上的图。
您应该得到两个图,如下所示:
自定义刻度和刻度标签
到目前为止,我们已经看到 Matplotlib 根据输入数据自动放置刻度和刻度标签。 在本秘籍中,我们将学习如何在 x 和 y 轴上自定义这些默认设置,以用于分类变量和数值变量。
准备
让我们导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,
AutoMinorLocator)
from matplotlib.ticker import FuncFormatter
操作步骤
以下代码块绘制了两个男人和女人的条形图。 在 y 轴上,绘制了平均工资,在 x 轴上,绘制了男女类别中的各个类别。 因此,我们在 y 轴上有一个数字变量,在 x 轴上有一个分类变量。
以下代码块对 y 轴上的刻度和刻度标签使用默认设置,但对 x 轴使用自定义设置:
- 设置数据并绘制男性数据的条形图:
menMue = [3, 10, 100, 500, 50]
menSigma = [0.75, 2.5, 25, 125, 12.5]
fig, ax = plt.subplots()
ind = np.arange(len(menMue)) # the x locations for the groups
width = 0.35 # the width of the bars
p1 = ax.bar(ind, menMue, width, color='lightblue', bottom=0,
yerr=menSigma)
- 设置数据并绘制女性数据的条形图:
womenMue = [1000, 3, 30, 800, 1]
womenSigma = [250, 0.75, 8, 200, 0.25]
p2 = ax.bar(ind + width, womenMue, width, color='orange', bottom=0,
yerr=womenSigma)
- 设置图形的标题,标签和图例:
ax.set_title('Scores by group and gender')
ax.set(xticks=(ind + width / 2), xticklabels=('C1', 'C2', 'C3',
'C4', 'C5'), yscale='log')
ax.legend((p1[1], p2[1]), ('Men', 'Women'), bbox_to_anchor=(1.3,1))
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
ax.set_xticks(ind + width / 2)
设置将每个刻度准确放置在 x 轴上的位置。 由于ind
是根据男性数据定义的,因此会将刻度线放置在男性条的中间(浅蓝色),然后通过向每个索引中添加width / 2
,将刻度在两个条之间移动。ax.set_xticklabels(('C1', 'C2', 'C3', 'C4', 'C5'))
在 x 轴上设置刻度标签:
更多
让我们再举一个例子,说明如何自定义刻度线的大小,长度和颜色。 以下代码块显示了三个图表; 第一个使用刻度和刻度标签的默认设置,第二个被自定义以显示主要和次要刻度,第三个被自定义以指定主要和次要刻度的长度,厚度和颜色:
- 定义用于格式化数字数据的函数:
def Num_Format(x, pos):
"""The two arguments are the number and tick position"""
if x >= 1e6:
string = '${:1.1f}M'.format(x*1e-6)
else:
string = '${:1.0f}K'.format(x*1e-3)
return string
- 定义一个函数来绘制图形:
def plot_graph(axes, axis, major_step_size, minor_step_size):
majorLocator = MultipleLocator(major_step_size)
minorLocator = MultipleLocator(minor_step_size)
if axis == 'x':
axes.xaxis.set_major_locator(majorLocator)
axes.xaxis.set_minor_locator(minorLocator)
else:
axes.yaxis.set_major_locator(majorLocator)
axes.yaxis.set_minor_locator(minorLocator)
axes.yaxis.set_major_formatter(formatter)
- 设置图的数据:
x = np.linspace(-50,50,500)
y = x**2 + np.cos(x)*100
- 定义图形,布局和大小,并调整各图之间的空间:
fig, axs = plt.subplots(1,3, figsize=(15,5))
fig.subplots_adjust(wspace=0.5)
- 使用 y 轴应用
formatter
绘制图形:
formatter = FuncFormatter(Num_Format)
axs[0].plot(x, y**2)
axs[0].set_title('Default Ticks and Ticklabels')
axs[0].yaxis.set_major_formatter(formatter)
- 在第二轴域上用主要和次要刻度画线形图:
axs[1].plot(x, y**2)
plot_graph(axs[1], 'y', 500000, 250000)
plot_graph(axs[1], 'x', 10, 2)
axs[1].set_title('Major and Minor Ticks')
- 使用自定义刻度和刻度标签在第三个轴域上绘制折线图:
axs[2].plot(x, y**2)
plot_graph(axs[2], 'x', 10, 2)
minorLocator = AutoMinorLocator()
axs[2].xaxis.set_minor_locator(minorLocator)
axs[2].tick_params(which='major', length=10, color='g')
axs[2].tick_params(which='minor', length=4, color='r')
axs[2].tick_params(which='both', width=2)
axs[2].set_title('Customised Ticks')
axs[2].grid(True)
- 在屏幕上显示该图:
plt.show()
这是代码及其工作方式的说明:
- 零轴域上的第一个绘图使用默认设置,它会自动为 y 轴选择一百万个仓位,并为 x 轴选择 20 个单位仓位,并相应地放置刻度和刻度标签 。
- 轴域 1 上的第二个图
majorLocator = MultipleLocator(500000)
指定应以500000
间隔放置主要刻度线,axs[1].yaxis.set_major_locator(majorLocator)
在 y 轴主要刻度上设置此间隔。majorFormatter = FormatStrFormatter('%d')
指定要显示的刻度标签编号的格式,axs[1].yaxis.set_major_formatter(majorFormatter)
将格式应用于 y 轴的主刻度标签。 - 对于 x 轴重复相同的过程,其中
10
单元箱用于主要刻度,而2
单元用于次刻度。 - 第三幅图与第二幅图相似,只将次要刻度线限制在 x 轴上,并为主要和次要刻度线设置了长度,宽度和颜色设置。
tick_params()
设置这些参数,和参数which=
指定要应用的主要,次要或两个刻度。
这是前面代码的生成的输出:
自定义轴线
默认情况下,Matplotlib 在图的顶部,底部,左侧和右侧显示所有四个轴线,并在其周围创建一个边界框。 它仅在左侧(y 轴)和底部(x 轴)上显示刻度和刻度标签。 但是,它允许我们自定义它们的位置,并根据需要省略任何轴线。
准备
我们将绘制六个具有相同数据的图,但为轴线设置各种选项。
导入以下必需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下代码块显示六个具有相同数据,但轴线的选项不同的图:
- 设置图的数据:
theta = np.linspace(0, 2*np.pi, 128)
y = np.sin(theta)
- 定义图形的大小:
fig = plt.figure(figsize=(8,6))
- 定义第一个轴域,并用默认的轴线绘制正弦波:
ax1 = fig.add_subplot(2, 3, 1)
ax1.plot(theta, np.sin(theta), 'b-*')
ax1.set_title('default spines')
- 定义用于绘制图形的函数:
def plot_graph(axs, title, lposition, bposition):
ax = fig.add_subplot(axs)
ax.plot(theta, y, 'b-*')
ax.set_title(title)
ax.spines['left'].set_position(lposition)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_position(bposition)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
- 绘制五个具有不同轴线位置的图形:
plot_graph(232, 'centered spines', 'center', 'center')
plot_graph(233, 'zeroed spines', 'zero', 'zero')
plot_graph(234, 'spines at axes [0.25, 0.75]', ('axes', 0.25),
('axes', 0.75))
plot_graph(235, 'spines at data [1.0, -1.0]', ('data', 1.0),
('data', -1.0))
plot_graph(236, 'adjusted spines', ('outward', 10), ('outward', 10))
- 调整绘图之间的空间,并在屏幕上显示图形:
plt.tight_layout()
plt.show()
工作原理
- 曲线 1 使用默认设置的轴线。 因此,它将显示所有四个轴线,左侧和底部分别代表 y 和 x 轴,并带有适当的刻度和刻度标签。
- 在曲线 2 中,使用
set_visible(False)
方法使顶部和右侧轴线不可见。set_position('center')
将 x 和 y 轴放置在相应数据范围之间。 在这种情况下, y 轴上的数据范围是 -1 到 +1,所以中心点是 0,而 x 轴上的数据范围是 0 到 6,所以中心点是3
。 因此,交点为(3, 0)
。 - 线形图 3 放置左轴线和底轴线,使它们在
(0, 0)
相交。 - 线形图 4 以在 x 轴上的 0.25 范围和在 y 轴上的 0.75 范围内相交的方式放置左轴线和底轴线。
[0.25, 0.75]
为0.25 * x 范围 = 0.25 * (0 到 6) = 1.5
,0.75 * y 范围 = 0.75 * (-1 到 1) = 0.5
。 因此,交点为(1.5, 0.5)
。axes
选项基本上将 x 轴的底部 25%(第一个四分位数)和 y 轴的底部 75%(第三个四分位数)设置为最低。 - 在图 5 中,我们使用
data
选项指定输入数据中的位置。 因此,它将左脊和下脊置于(1, -1)
交点。 - 在图 6 中,我们使用
outward
参数将轴线放置在远离图形的位置指定数量的单位; 在这里是10
:
双生轴域
有时,我们可能希望在同一轴域上绘制两个图表,但是数据规模不同。 如果我们在左右轴线上使用具有相同比例尺的标准图,则由于数据比例尺的巨大差异,图表可能看起来不正确。 在这种情况下,我们可以使用 Matplotlib 提供的双生轴域功能。 我们将在本秘籍中学习如何使用它。
在此示例中,我们将在制造工厂中使用一个月的产品缺陷数据。 我们将通过原因代码(例如 0 到 5,代表生产缺陷产品的各种原因)和累积百分比折线图(缺陷代码上汇总的缺陷产品总数)绘制条形图。
轴域联动有三种选择:
twinx
:为两个图形共享 x 轴,而左轴和右轴表示两个不同的比例twiny
:为两个图形共享 y 轴,而顶部和底部轴表示两个比例no sharing
:其中一张图使用底部轴和左轴,第二张图使用顶部轴和右轴
我们将学习如何在本秘籍中实现所有三种可能性。
准备
我们将使用给定月份的制造工厂中的产品缺陷数据。 它具有缺陷原因代码和许多缺陷。 因此,我们将通过缺陷原因代码绘制条形图以显示缺陷数量,并绘制一条线形图以累积缺陷占总缺陷的百分比。 显然,缺陷数量和累积百分比的数据范围会发生很大变化,因此,通用的 y 轴无法提供正确的数据图。 在这种情况下,将轴域缠绕在一起可以进行救援。
我们将绘制两个不同的图; 本节中一个使用twinx()
,另一个使用twiny()
。 我们将学习如何在任何轴域上绘制no sharing
的第三个选项。本秘籍还有更多...* 部分。
导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
操作步骤
这是绘制所需图形所涉及的步骤:
- 准备绘图数据:
x = [0, 1, 2, 3, 4, 5]
y = [19, 12, 6, 4, 3, 2]
y1 = [41, 67, 80, 89, 96, 100]
- 定义图形和所需的轴域,包括双生轴域:
fig = plt.figure(figsize=(10,6))
ax1 = plt.subplot(121) # first plot
ax2 = ax1.twinx() # share x axis
ax3 = plt.subplot(122) # second plot
ax4 = ax3.twiny() # share y axis
- 使用
twinx()
选项绘制条形图和折线图:
b = ax1.bar(x, y, label='Number of Defects')
l, = ax2.plot(x, y1, color='g', lw=5, label='Cumulative Defects as %')
- 设置第一个图的标签和图例:
majorLocator = MultipleLocator(2)
ax1.yaxis.set_major_locator(majorLocator)
ax1.set(xlabel='Defect Reason Codes', ylabel='Number of Defects')
ax2.set(ylabel='Cumulative Defects as %')
ax1.legend([b, l],['Number of Defects','Cumulative Defects as %'],
loc=5)
- 使用
twiny()
选项绘制条形图和折线图:
b1 = ax3.barh(x, y, label='Number of Defects')
l1, = ax4.plot(y1, x, color='g', lw=5, label='Cumulative Defects as
%')
- 设置第二个绘图的标签和图例:
ax3.xaxis.set_major_locator(majorLocator)
ax3.set(xlabel='Number of Defects', ylabel='Defect Reason Codes')
ax4.set(xlabel='Cumulative Defects as %')
ax3.legend([b1, l1], ['Number of Defects', 'Cumulative Defects as
%'], loc=1)
ax3.set_ylim(-1,6)
- 打印图形的标题,并调整两个图形之间的空间:
plt.suptitle('Product Defects - August 2018', fontname='arial',
fontsize=20,
fontweight='bold')
plt.tight_layout(w_pad=5, pad=3)
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
x = [0, 1, 2, 3, 4, 5]
是产品缺陷代码的列表,y = [19, 12, 6, 4, 3, 2]
是给定月份中每个缺陷代码的缺陷数量的列表,y1 = [41, 67, 80, 89, 96, 100]
是累积缺陷占总缺陷百分比的列表。ax1 = plt.subplot(121)
定义第一个图的主轴域,121
表示它是1 x 2
网格中的第一个图。ax2 = ax1.twinx()
定义第一个绘图的双生轴域。 它不会在物理上创建另一个轴域,而是仅使用主轴域,并将右轴线用作此新逻辑轴域ax2
的 y 轴,并共享底部轴线作为ax1
和ax2
的 x 轴。ax3 = plt.subplot(121)
定义第二个绘图的主轴域,122
表示它是1 x 2
网格中的第二个绘图。ax4 = ax3.twinx()
定义第二个绘图的双生轴域。 同样,它不会在物理上创建其他轴域,而仅使用主轴域,并将右脊用作次轴域ax4
,并为ax3
和ax4
共享底部轴线作为 x 轴。b = ax1.bar(x, y, label='Number of Defects')
绘制条形图,缺陷代码与缺陷数量的关系。l, = ax2.plot(x, y1, color='g', lw=5, label='Cumulative Defects as %')
绘制线形图:缺陷代码与累积缺陷%
。majorLocator = MultipleLocator(2)
定义主要刻度线的步长为 2。ax1.yaxis.set_major_locator(majorLocator)
向第一幅图的主轴域的 y 轴应用主定位器。ax1.set(xlabel='Defect Reason Codes', ylabel='Number of Defects')
为主轴域设置 x 和 y 轴标签。ax2.set(ylabel='Cumulative Defects as %')
为双生轴域设置ylabel
,并且由于共享 x 轴; 再次没有标签在这里。ax1.legend([b, l], ['Number of Defects', 'Cumulative Defects as %'], loc=5)
设置主轴域的图例:[b,l]
分别是条形图和折线图的句柄列表。['Number of Defects', 'Cumulative Defects as %']
分别是条形图和折线图的标签列表。loc=5
指定图例应以右对齐的方式放置在轴域的中心。
b1 = ax3.bar(x, y, label='Number of Defects')
绘制条形图,缺陷代码与缺陷数量的关系。l1, = ax4.plot(x, y1, color='g', lw=5, label='Cumulative Defects as %')
绘制折线图,缺陷代码与累积缺陷%
。majorLocator = MultipleLocator(2)
, 定义主要刻度线的步长为 2。ax3.yaxis.set_major_locator(majorLocator)
将主定位器应用于第一幅图的主轴域的 y 轴。ax3.set(xlabel='Defect Reason Codes', ylabel='Number of Defects')
设置主轴域的 x 和 y 轴标签。ax4.set(ylabel='Cumulative Defects as %')
为双生轴域设置ylabel
,并且由于 x 轴已共享,此处不再有标签。ax3.legend([b1, l1], ['Number of Defects', 'Cumulative Defects as %'], loc=1)
设置第二个绘图主轴域的图例。ax3.set_ylim(-1,6)
设置第二个图的主轴域的 y 轴的上下限。plt.suptitle('Product Defects - August 2018', fontname='arial', fontsize=20, fontweight='bold')
用各种属性(例如字体名称,大小和粗细)绘制整个图形的标题。plt.tight_layout(w_pad=5, pad=3)
调整绘图之间的空间,以使它们没有重叠:w_pad=5
指定两个图之间的间隙量。pad=3
在图的顶部指定为标题腾出空间的数量空间。
plt.show()
在屏幕上显示图形。
运行前面的代码后,您应该在屏幕上看到下图:
更多
我们已经了解了如何使用双生轴域功能分别共享 x 和 y 轴。 现在,让我们看一下不共享两个轴的选项,而是对一个图形使用左轴线和底轴线,对另一个图形使用上轴线和右轴线。 所有四个轴线使用不同的刻度,因此ticks
和ticklabels
不同。
在此示例中,我们将使用熟悉的Iris
数据集。 众所周知,有四个属性:petal_width
,petal_leangth
,sepal_width
和sepal_length
。 因此,正如我们在本书中多次看到的那样,当我们使用petal_width
和petal_length
绘制散点图时,我们看到了三个不同的簇,但是当我们使用sepal_length
和sepal_width
绘制散点图时,我们不会观察到任何此类簇。
这是绘制此代码所需的代码。 由于我们已经看过很多次了,因此这里不再逐行解释。 唯一的区别是ax1 = ax.twinx().twiny()
。 而不是使用twinx()
或twiny()
,我们都使用了两者,以便将上轴域和右轴域用于此新逻辑轴域(ax1
),而将左轴域和底轴域用于主轴域(ax
):
import matplotlib.pyplot as plt
import pandas as pd
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species'] = iris['species'].map({"setosa" : 0, "versicolor" : 1,
"virginica" : 2})
plt.figure(figsize=(8,6))
ax = plt.subplot(111)
h1 = ax.scatter(iris.petal_width, iris.petal_length, s=5*iris.petal_width*iris.petal_length, c='b')
ax1 = ax.twinx().twiny()
h2 = ax1.scatter(iris.sepal_width, iris.sepal_length,
s=5*iris.sepal_width*iris.sepal_length, c='g')
ax.legend([h1, h2], ['petals', 'sepals'], loc='best')
plt.show()
运行前面的代码后,您应该在屏幕上看到下图:
从该图可以看出,使用花瓣的宽度和长度绘制的蓝色点确实形成了三个不同的簇,而以萼片的宽度和长度绘制的绿色点散布在各处,没有任何特定的图案!
Please also note the scale of data on each of the four axes. All of them have a different scale!
使用图案填充
图案填充用于填充指定区域中的图案。 我们将在本秘籍中学习如何使用它。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块创建了五个表示领带的图表,并在上面印刷了不同的颜色和图案:
## Set up the data
x = np.array([0.2, 0.4, 0.6, 0.8, 0.5])
y = [1, 6, 6, 1, 0]
## Plot a tie graph 5 times with different colors and hatches
plt.fill(x+1, y, color='g', hatch='+*')
plt.fill(x+2, y, color='b', hatch='-o')
plt.fill(x+3, y, color='y', hatch='+x')
plt.fill(x+4, y, color='r', hatch='\\')
plt.fill(x+5, y, color='m', hatch='Ox')
plt.title('Hatch Demo')
plt.show()
工作原理
x
和y
是表示二维空间上的五个点的列表。 这五个点所覆盖的区域会形成平局。 使用plt.fill()
方法中的hatch
自变量填充颜色和图案:
使用标注
通过指向文本中描述的区域,标注用于描述绘图上的特定细节。 我们将在秘籍中介绍一个简单的示例。 在后面的章节中将进行更详细的描述。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块显示了一个绘图,在该绘图上用箭头标注了一个点(3, 0
):
plt.plot(theta, np.sin(theta), 'b-*')
a = plt.annotate("(3,0)", xy=(3, 0), xycoords='data', xytext=(4.0,
0.5), textcoords='data',
arrowprops=dict(arrowstyle="->", color="green", lw=5,
connectionstyle=("arc3,rad=0.")))
plt.setp(a, size=25)
plt.show()
工作原理
这是代码的说明:
plt.annotate()
方法使用指定的详细信息标注图形。(3, 0)
指定要显示为描述的文本。xy = (3, 0)
指定图形上要标注的点的坐标。xycoords='data'
指定所指定的xy
坐标是相对于数据(输入数据中的点)的。arrowprops()
指定从文本到要标注的点要使用的箭头的style
,linewidth
,color
,connectionstyle
。plt.setp()
将文本(3, 0)
的字体大小设置为25
。
通过运行前面的代码,我们得到以下输出:
使用样式表
我们已经学习了如何使用图形的各种属性来创建专业图形。 但是,找出这么多不同的组合并获得漂亮的图形非常耗时。 Matplotlib 提供了称为样式表的现成模板的列表,这些模板使用各种属性的预定义组合。 在本秘籍中,我们将学习如何使用这些预定义的样式表。
You can use print(plt.style.available)
to get the list of all the available style sheets.
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块绘制了四种不同类型的图,所有图都具有相同的样式表,以演示如何使用样式表:
- 定义要在此会话中应用于所有图形的样式:
plt.style.use('seaborn-bright')
- 定义图形,大小并调整图之间的空间:
fig, ax = plt.subplots(1, 4, figsize=(10,5))
fig.subplots_adjust(wspace=0.5)
- 在第一个轴域上绘制直方图:
ax[0].hist(np.random.randn(1000))
- 在第二个轴域上绘制三个折线图:
for i in range(3):
ax[1].plot(np.random.rand(10))
ax[1].legend(['a', 'b', 'c'], loc='lower left')
- 在第三个轴域上绘制散点图:
ax[2].scatter(np.random.rand(100),np.random.rand(100),
s=100*np.random.rand(100)*np.random.rand(100))
- 在第四个轴域上绘制饼图:
labels = ['SciFi', 'Drama', 'Thriller', 'Comedy', 'Action',
'Romance']
sizes = [5, 15, 10, 20, 40, 10] # Add upto 100%
explode = (0, 0, 0, 0, 0.1, 0)
ax[3].pie(sizes, explode=explode, labels=labels, autopct='%1.0f%%',
pctdistance=0.7,
shadow=True, startangle=90)
ax[3].axis('equal') # Equal aspect ratio ensures that pie is drawn
as a circle.
- 设置图形的标题并将其显示在屏幕上:
plt.suptitle('seaborn-bright', color='b', weight='bold')
plt.show()
工作原理
这是刚刚给出的代码的说明:
plt.style.use('seaborn-bright')
设置要使用的特定样式表。 相同的样式表将应用于此会话中的所有绘图。 在此示例中,我们使用seaborn-bright
样式表。
剩余的代码绘制了四个图形,正如我们之前所看到的。
如您所见,我们没有为任何图形属性指定任何特定参数。 它们都是从我们一开始提供的样式表中借用的:
更多
为了演示更多样式表,下面的代码块使用与之前相同的四个图,但是应用style_list
中指定的样式表列表。
由于相同的代码将重复多次,因此我们定义一个函数,并在每次使用不同style
参数的for
循环中调用它:
style_list = ['classic', 'dark_background', 'ggplot', 'grayscale',
'seaborn']
def plot_the_graph(style):
np.random.seed(0)
fig, ax = plt.subplots(1, 4, figsize=(12,5))
fig.subplots_adjust(wspace=0.5)
ax[0].hist(np.random.randn(1000))
for i in range(3):
ax[1].plot(np.random.rand(10))
ax[1].legend(['a', 'b', 'c'], loc='lower left')
ax[2].scatter(np.random.rand(100),np.random.rand(100),
s=100*np.random.rand(100)*np.random.rand(100))
labels = ['SciFi', 'Drama', 'Thriller', 'Comedy', 'Action',
'Romance']
sizes = [5, 15, 10, 20, 40, 10] # Add upto 100%
explode = (0, 0, 0, 0, 0.1, 0) # only "explode" the 2nd slice (i.e.
'Hogs')
ax[3].pie(sizes, explode=explode, labels=labels, autopct='%1.0f%%',
pctdistance=0.7,
shadow=True, startangle=90)
ax[3].axis('equal') # Equal aspect ratio ensures that pie is drawn
as a circle.
plt.suptitle(style)
plt.show()
for style in style_list:
with plt.style.context(style):
plot_the_graph(style)
执行前面的代码后,您应该在屏幕上看到以下五个单独的图形,每个图形具有style_list
中指定的不同样式:
使用面向对象的 API 进行绘图
在本章中,我们将使用以下秘籍来学习pyplot
API 和面向对象的 API 之间的区别:
- 使用
pyplot
和面向对象的 API 绘制相关矩阵 - 使用面向对象的 API 绘制补丁
- 使用面向对象的 API 绘制集合
介绍
如第 1 章,“Matplotlib 的剖析”中所述,Matplotlib 具有三层架构。 顶层称为脚本层,并通过pyplot()
API 实现。 该 API 是为没有太多编程经验的用户设计的,因此它使用户免受使用底部两层(艺术家和后端)创建和渲染图的复杂性的困扰。 对于使用高级功能(例如补丁,集合,使用事件,回调,动画和窗口小部件的交互式绘图)的复杂应用,我们将必须使用面向对象的 API。 但是,要利用此 API 的全部潜能,需要大量的 Python 编码经验。 随着新版本 Matplotlib 的发布,越来越多的这些功能正在移入pyplot
API 中,从而减少了对面向对象 API 的依赖。
面向对象的 API 名称有点让人困惑,因为它可能给人以pyplot
API 不是面向对象的印象,这是不正确的。 这仅意味着面向对象的 API 会直接使用艺术家和后端层,而绕过脚本层(不使用pyplot
API)。 这提供了使用 Matplotlib 提供的完整功能的灵活性,而pyplot
API 提供了它的一个子集。
应该注意的是,对于任何绘图或图形,都不必是pyplot
API 或面向对象的 API; 它可以是两者的结合。 实际上,到目前为止,我们开发的许多图形都将两者结合使用。 当我们必须使用复杂的网格结构在图形中放置图时,我们使用了面向对象的 API。 当分别绘制每个图形并创建图形对象和基础画布时,我们使用了pyplot
API。 一旦我们看到了两种 API 之间的差异,您将了解两种 API 的结合使用。
使用pyplot
和面向对象的 API 绘制相关矩阵
在本秘籍中,我们将学习pyplot
与面向对象的 API 之间的区别。 我们将首先使用pyplot
API,然后使用面向对象的 API 绘制相同的相关矩阵。 我们将使用相同的Wine Quality
数据集绘制相关矩阵。
准备
为pyplot
API 导入以下库:
import pandas as pd
import matplotlib.pyplot as plt
导入以下库以获取面向对象的 API:
import pandas as pd
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from IPython.core.display import display
matplotlib.backends
具有一组支持的后端。 在这里,我们要导入FigureCanvasAgg
,它提供了绘制图形的空间并将其映射到定义的后端设备。
IPython.core.display
可以将绘图显示在输出设备上。
操作步骤
以下代码块使用 pandas 读取数据并使用pyplot
API 绘制相关矩阵。 这与我们在第 2 章“基本绘图入门”中绘制热图的方式相同:
- 将数据从 CSV 文件读取到 Pandas 数据帧中:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
- 获取
wine_quality
所有属性的相关矩阵:
corr = wine_quality.corr()
- 定义图形及其大小,并绘制图像和相关的颜色条:
plt.figure(figsize=(12,9))
plt.imshow(corr,cmap='hot')
plt.colorbar()
- 设置图形的标题和刻度,并在屏幕上显示:
plt.title('Correlation Matrix')
plt.xticks(range(len(corr)),corr.columns, fontsize=10, fontweight='bold',rotation=45)
plt.yticks(range(len(corr)),corr.columns)
plt.show()
前面的代码块中的所有命令都是我们熟悉的,因为我们已经在第 2 章,“基本绘图”和第 4 章,“为发布质量开发可视化”中学习了它们。
以下代码块使用面向对象的 API(不使用pyplot
API)绘制相同的相关图:
- 将数据从 CSV 文件读取到 Pandas 数据帧中:
wine_quality = pd.read_csv('winequality.csv', delimiter=';')
- 获取
wine_quality
所有属性的相关矩阵:
corr = wine_quality.corr()
- 定义图形的大小:
fig = Figure(figsize=(12,9))
- 将图形附加到画布上:
FigureCanvas(fig)
- 定义图中的轴域,我们需要绘制相关图,并绘制相关图和颜色条:
axs = fig.add_subplot(111)
corimage = axs.imshow(corr,cmap='hot')
fig.colorbar(corimage)
- 设置
ticks
和ticklabels
:
axs.set(xticks=range(len(corr)), yticks=range(len(corr)),
title='Correlation Matrix')
fontd = {'fontsize': 10,
'fontweight': 'bold',
'rotation': 45}
axs.set_xticklabels(corr.columns, fontdict=fontd)
axs.set_yticklabels(corr.columns)
- 在屏幕上显示该图:
display(fig)
工作原理
pyplot
API 代码块是不言自明的。 这是输出图表:
以下是面向对象的 API 代码块的说明:
Figure(figsize=(12,9))
实例化大小为(12, 9)
的图形对象。FigureCanvas(fig)
附加画布(需要绘制图形的区域,该区域最终显示在连接的后端设备上)。 对于pyplot
API,我们无需这样做,因为pyplot
API 会处理它。fig.add_subplot(111)
在先前创建的图形对象内创建轴域对象。 请注意,我们可以在一个图形对象内创建多个轴域对象。 在这里,我们只创建一个轴域,因为我们只绘制一个图。axs.imshow(corr,cmap='hot')
使用标准色表hot
将相关矩阵创建为图像。fig.colorbar(corimage)
将颜色条附加到之前创建的图像。- 要为 x 和 y 轴创建
ticks
和ticklabels
,pyplot
API 具有plt.xticks
和plt.yticks
方法,它们同时具有刻度位置和刻度线作为参数,并使用一个命令进行管理。 但是,对于面向对象的 API,我们将不得不单独进行。 axs.set(xticks=range(len(corr)), yticks=range(len(corr)), title='Correlation Matrix')
定义了 x 和 y 轴刻度和图形标题。 它需要的刻度声与相关矩阵中的属性一样多。fontd
是具有要应用于xticklabels
的所有属性的字典。 如果需要,我们也可以对yticklabels
执行相同的操作。axs.set_xticklabels(corr.columns, fontdict=fontd)
用定义的属性设置xticklabels
。axs.set_yticklabels(corr.columns)
将 y 轴设置为ticklabels
。
执行前面的代码后,您应该看到以下图表:
使用面向对象的 API 绘制补丁
Matplotlib 使用补丁和集合类提供了一些特殊类型的图。 在本秘籍中,我们将学习如何使用面向对象的 API 使用patches
。 在下一个秘籍中,我们将学习collections
。
准备
我们将需要为该秘籍导入以下库:
from IPython.core.display import display
from matplotlib.backends import backend_agg
from matplotlib.patches import Ellipse, Polygon
操作步骤
以下代码块在同一图中将两个补丁绘制为单独的图:
- 使用
figure_manager
定义图形及其大小,然后将其附加到画布上:
figure_manager = backend_agg.new_figure_manager(1, figsize=(12,6))
fig = figure_manager.canvas.figure
- 定义第一个轴域并在其上绘制一个椭圆形色块:
axs1 = fig.add_subplot(121)
axs1.add_patch(Ellipse((3, 1.0), 4, 1.0, hatch='/', facecolor='g'))
## centre=(3, 1.0), width=4, height=1.0
axs1.set_xlim((0, 6))
axs1.set_ylim((0, 2.5))
- 定义第二个轴域并在其上绘制一个补丁:
axs2 = fig.add_subplot(122)
axs2.add_patch(Polygon([[0, 0], [4, 1.1], [6, 2.5], [2, 1.4]],
color='b', lw=5, fill=False, hatch='+*'))
axs2.set_xlim((0, 6))
axs2.set_ylim((0, 2.5))
- 在屏幕上显示该图:
display(fig)
工作原理
以下是上述代码及其工作方式的说明:
- 为了定义图形和画布,我们在本秘籍中使用另一种方法
new_figure_manager()
,只是为了演示 Matplotlib 提供的多种选项。 我们也可以使用与先前秘籍相同的方法。 这种方法更适合于循环处理多个图形。 它使用参数作为图形编号和图形大小。 fig.add_subplot(121)
实例化第一个图形的第一个轴域。axs1.add_patch(Ellipse((3, 1.0), 4, 1.0, hatch='/', facecolor='g'))
在axs1
上添加了椭圆形补丁。(3, 1.0)
定义椭圆中心的坐标;4
是椭圆的宽度,1.0
是椭圆的高度。facecolor
指定填充色块的颜色,hatch
指定椭圆内部的填充图案。axs1.set_xlim((0, 6))
和axs1.set_ylim((0, 2.5))
定义 x 和 y 轴的限制。 如果没有定义这些限制,将不会绘制补丁,因为它不知道确切地将补丁放置在坐标系中的什么位置。axs2.add_patch(Polygon([[0, 0], [4, 1.1], [6, 2.5], [2, 1.4]], color='b', lw=5, fill=False, hatch='+*'))
在axs2
上绘制多边形补丁:- 由四点的
x, y
坐标指定 fill=False
指定补丁内的区域不应填充任何颜色- 与
lw=5
类似,color='b'
用于多边形的边缘 - 在这里,我们为
hatch
使用+*
字符
- 由四点的
这是输出图:
使用面向对象的 API 绘制集合
collections
是包含许多属性的相似对象的容器。
准备
导入所需的库:
from matplotlib import collections
from IPython.core.display import display
from matplotlib.backends import backend_agg
import numpy as np
操作步骤
以下代码块绘制了一组多边形,这些多边形在给定数量的大小和给定的颜色列表之间循环:
- 定义用于绘制多边形集合的数据:
nsizes = 50 #number of different sizes to be used to plot the items in the collection
npts = 100 # number of items in the collection
r = np.arange(nsizes)
theta = np.linspace(0, 2*np.pi, nsizes)
xx = r * np.sin(theta)
- 绘制集合项的偏移坐标:
rs = np.random.RandomState([125])
xo = rs.randn(npts)
yo = rs.randn(npts)
xyo = list(zip(xo, yo))
- 定义图形大小并将其附加到画布上,并在此图形上定义一个轴域:
figure_manager = backend_agg.new_figure_manager(1, figsize=(8,6))
fig = figure_manager.canvas.figure
axs1 = fig.add_subplot(111)
- 绘制六面正多边形作为集合:
col = collections.RegularPolyCollection(6, sizes=np.fabs(xx) * 20,
offsets=xyo, transOffset=axs1.transData)
axs1.add_collection(col, autolim=True)
- 列出要循环的
colors
:
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w', 'tab:blue',
'tab:orange', 'tab:green', 'tab:red',
'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray',
'tab:olive', 'tab:cyan']
col.set_color(colors)
- 设置标题和
autoscale_view
以调整两个轴上的比例:
axs1.autoscale_view()
axs1.set_title('RegularPolyCollection')
- 在屏幕上显示该图:
display(fig)
工作原理
这是代码的说明:
nsizes
和npts
指定集合中的大小数和项目数。 如果剩余点的nsizes
小于npts
,则nsizes
将从头开始,循环继续进行。 颜色也是如此。xx = r * np.sin(theta)
计算所有nsizes
的实际大小。xyo = list(zip(xo, yo))
为集合中的每个项目计算 x 和 y 坐标。zip
是一个 Python 函数,它从两个或多个列表中获取项目,并创建两个或多个元组。col = collections.RegularPolyCollection()
创建多边形的集合。 数字6
是多边形的边数,np.fabs()
将xx
中的所有数字转换为其绝对值(因为大小不能为负),offsets=xy0
指定实际坐标,其中多边形将被绘制。axs1.transData
是坐标系的内部表示,其解释超出了本书的范围。axs1.add_collection(col, autolim=True)
将集合对象连接到定义的轴域axs1
,autolim=True
确保调整轴限制,以使整个集合都在该范围内。col.set_color(colors)
指定要循环显示的颜色列表,以覆盖集合中的所有项目。
输出图如下所示:
五、使用高级功能的绘图
在本章中,我们将学习以下秘籍:
- 使用属性循环器
- 绘制路径效果
- 使用转换
- 控制轴域位置
- 使用
gridspec
- 结合使用
gridspec_kw
和pyplot.subplots
- 对齐绘图的
gridspec
- 使用受限布局
- 使用原点和范围进行图像绘制
- 使用 Pandas 的地理绘图
使用属性循环器
我们在第 4 章和“开发可视化来提高发布质量”时了解到,Matplotlib 具有默认的颜色循环,当我们在给定轴域上绘制更多图形时,该颜色循环将重复出现。 通过属性循环器,我们可以在单个函数中为多个属性定义此类循环器。 如果要绘制具有重复图案的轴域,则可以使用属性循环器实现。
准备
我们将在此处使用面向对象的 API。 在第 4 章“开发可视化以提高发布质量”中,在此示例中使用了pyplot
API。 导入所需的库:
from cycler import cycler
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from IPython.core.display import display
操作步骤
以下代码块绘制了六个领带对象; 后两个是前两个的重复。 在此示例中,它在每四个对象之后重复循环:
- 定义图形并将其附加到画布上:
fig = Figure()
FigureCanvas(fig)
- 为图形设置
facecolor
,edgecolor
和alpha
并添加一个轴域:
fig.set(facecolor='grey', alpha=0.2, edgecolor='m')
ax = fig.add_subplot(111)
- 设置用于绘制图形的数据:
x = np.array([0.2, 0.4, 0.6, 0.8, 0.5])
y = [1, 6, 6, 1, 0]
- 为
color
和hatch
属性定义custom_cycler
,并将其设置为轴域:
custom_cycler = cycler('color', ['g', 'blue', 'y', 'c']) + \
cycler('hatch', ['+*', 'xx', '+x', '+O.'])
ax.set_prop_cycle(custom_cycler)
- 绘制六个领带对象的图形:
ax.fill(x+1, y)
ax.fill(x+2, y)
ax.fill(x+3, y)
ax.fill(x+4, y)
ax.fill(x+5, y)
ax.fill(x+6, y)
- 在屏幕上显示该图:
display(fig)
工作原理
以下是代码的说明:
fig = Figure()
定义图形对象。FigureCanvas(fig)
将图形对象附加到将在其上绘制图形的画布。fig.set(facecolor='grey', alpha=0.2, edgecolor='m')
设置图形的各种属性。 通常,我们在轴域级别的单个图上使用这些属性。 但是在这里,我们在图形级别使用它们。ax = fig.add_subplot(111)
实例化轴域。x
和y
定义绘制领带对象的数据坐标。cycler()
用两个属性以及每个属性的四个值定义属性周期。 如果我们为每个属性提供更多值,则在覆盖列表中的所有值后,将重复和循环。ax.set_prop_cycle(custom_cycler)
激活先前定义的自定义属性循环器。fill()
使用属性循环器的中定义的数据坐标和属性绘制领带对象。display(fig)
在屏幕上显示图形。
您应该在屏幕上输出以下图:
更多
我们还可以在全局参数rcParams
文件中设置属性循环器,该文件随后成为给定会话的默认循环器。
这是实现此目的的代码:
import matplotlib as mpl
from cycler import cycler
mpl.rc('axes', prop_cycle=cycler('color', ['r', 'orange', 'c', 'y']) +\
cycler('hatch', ['x', 'xx-', '+O.', '*']))
使用路径效果
我们在第 2 章“基本绘图入门”中学习了如何使用和Path
方法绘制自定义绘图。 在这里,我们将学习如何在各种绘图对象上使用path_effetcts
属性创建简单阴影和阴影阴影等效果。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patheffects import PathPatchEffect, SimpleLineShadow, Normal
操作步骤
以下代码块在图形上绘制了 Sigmoid 曲线和文本对象,并具有和path_effects
属性:
- 定义此会话中所有绘图要使用的样式:
plt.style.use('seaborn-darkgrid')
- 定义图形和图形大小:
plt.subplots(figsize=(10,6))
- 定义图的数据:
x = np.linspace(-10, 10, 50)
y = 1.0 / (1 + np.exp(-x))
- 使用和所需的路径效果定义要在图上打印的文本:
t = plt.text(-10., 1.15, 'Sigmoid with Path Effects', fontsize=40,
weight=50, va='center', path_effects=[PathPatchEffect(offset=(3, -3),
hatch='xxxx', facecolor='gray'),
PathPatchEffect(edgecolor='white', linewidth=1.1,
facecolor='black')])
- 使用,指定的路径效果绘制 Sigmoid 曲线,并在屏幕上显示该图:
plt.plot(x, y, linewidth=8, color='blue', path_effects=
[SimpleLineShadow(), Normal()])
plt.show()
工作原理
这是代码的说明:
plt.style.use('seaborn-darkgrid')
指定用作图的背景的样式。plt.subplots()
实例化图形对象以指定图形的大小。 如果要使用和默认大小,则不需要此语句。x
和y
定义用于绘制 Sigmoid 曲线的数据。plt.text()
创建一个文本对象,并将其放置在指定的坐标的处:(-10., 1.15)
是放置此文本对象的轴域上的坐标。- 文本为
Sigmoid with Path Effects
。 weight
与字体粗细(粗体深度)相同va
是垂直对齐。path_effects[]
指定要应用于文本对象的PathPatchEffects
的列表。PathPatchEffect()
启用具有各种属性的自定义路径效果。
plt.plot()
再次使用path_effects[]
绘制了一个 Sigmoid 曲线。 在这里,我们使用,预定义路径效果SimpleLineShadow()
和Normal()
。
这是输出的样子:
更多
我们已经演示了如何在此秘籍中使用预定义和自定义路径效果。 但是,Matplotlib 中提供了许多预定义的路径效果。 有关所有可能性的完整列表,请参考 Matplotlib 文档。
使用转换
要引用图形上的特定点,我们需要其坐标。 Matplotlib 使用四种参考数据,轴域,图形和显示的坐标系。 在本秘籍中,我们将学习如何使用这些坐标系以及如何从一个坐标系转换为另一个坐标系:
- 数据:数据坐标系以输入数据点为坐标,并由
xlim
和ylim
参数控制以在图上限制要绘制的数据范围。 从数据坐标系转换为显示坐标系的方法是ax.transData
。 - 轴域:轴域坐标系引用的轴域对象,
(0, 0)
为的轴域的左下角,而(1, 1)
是轴域的右上角。 指向轴域中心的点的坐标为(0.5, 0.5)
。 从轴域坐标系转换为的显示坐标系的方法是ax.transAxes
。 - 图形:这是图形对象的引用。 同样,
(0, 0)
表示图的左下角,而(1, 1)
表示图的右上角。 从图形坐标系转换为显示坐标系的方法是ax.transFigure
。 - 显示:这引用输出图形的输出设备,并且以像素坐标表示。
我们还可以使用混合坐标系,其中一个轴使用数据坐标系,另一个轴使用轴域坐标系。
很少使用显示和图形坐标。数据和轴域坐标系使用得更频繁。
我们将有两个秘籍,一个用来演示数据坐标的转换以显示坐标,另一个演示数据的轴域和混合坐标系统。
转换数据坐标来显示坐标
在本秘籍中,我们将演示如何转换数据坐标以显示坐标。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码绘制了一个正弦波,并在数据和显示坐标中标注了图形上的一个点:
- 定义图形并为其添加轴域:
fig = plt.figure()
ax = fig.add_subplot(111)
- 定义正弦曲线的数据并绘制:
theta = np.linspace(0, 2*np.pi, 128)
y = np.sin(theta)
ax.plot(theta, y, 'r-*')
- 在数据坐标系上定义点,并将其转换为显示坐标系:
xdata, ydata = 3, 0
xdisplay, ydisplay = ax.transData.transform_point((xdata, ydata))
- 定义要在文本描述周围使用的边框的属性:
bbox = dict(boxstyle="round", fc="1.0")
- 定义要在和标注中使用的箭头属性:
arrowprops = dict(arrowstyle="->", color='green', lw=5,
connectionstyle="angle,angleA=0,angleB=90,rad=10")
- 定义用于指定,坐标的偏移量,以在绘图上放置文字描述:
offset = 72
- 在数据坐标系中定义该点的标注:
data = ax.annotate('data = (%.1f, %.1f)' % (xdata, ydata),
(xdata, ydata), xytext=(-2*offset, offset),
textcoords='offset points', bbox=bbox, arrowprops=arrowprops)
- 在显示坐标系中定义该点的标注:
disp = ax.annotate('display = (%.1f, %.1f)' % (xdisplay, ydisplay),
(xdisplay, ydisplay), xytext=(0.5*offset, -offset),
xycoords='figure pixels', textcoords='offset
points',bbox=bbox, arrowprops=arrowprops)
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
theta
和y
是绘制正弦波的数据点。 零到2 * pi
覆盖了一个波周期。xdata
和ydata
是数据坐标系中的坐标; 在这种情况下,其值为3
和0
。 我们将看到该特定点在绘图上的位置。xdisplay
和ydisplay
是显示格式中同一点的坐标。 我们已经使用ax.transData.transform_point((xdata, ydata))
对其进行了转换。bbox
指定将在其中显示文本的边框样式。arrowprops
指定描述点和图形上实际点的文本之间的连接样式。 在下一章中,我们将学习有关文本标注的更多信息。offset=72
用于指定要放置文本框的坐标。 该偏移量相对于要标注的点的xy
坐标。x 坐标的正偏移量表示该点的右侧,而负值表示该点的左侧。 同样 y 坐标的正偏移量表示该点上方,而负值表示该点下方。ax.annotate()
绘制标注(描述观察点的文本),该标注指向和观察,并给出观察的文本描述。 第一个annotate()
语句为数据坐标系绘制标注,为,第二个语句为显示系统坐标系绘制标注。annotate()
中的第一个参数是标注的文本描述(xdata, ydata)
是要标注的点的坐标xycoords
(第一个标注中未提供,因为它使用默认数据坐标系)指定xy
使用哪个坐标系xytext
指定要放置文字说明的坐标textcoords
指定文本坐标的坐标系- 偏置点中的点是单位长度,等于 1/72 英寸,因此当我们指定
72
偏置点时,它等于 1 英寸
- 在第二个
annotate()
语句中,我们明确指定了xycoords='figure pixels'
,因为我们不想使用默认值,而是使用figure pixels
坐标。
以下是输出图:
请注意,箭头未完全对准同一点。 这是因为各种输出设备的默认设置有所不同。 这就是为什么不经常使用显示坐标的原因。 它们仅在需要捕获键盘或鼠标事件的交互式绘图中有用。
更多
在标注的上下文中,有许多选项可以指定图上某个点的坐标。 有关选项的完整列表,请参阅 Matplotlib 文档。
使用轴域和混合坐标系转换
在本秘籍中,我们将学习如何使用,轴域和混合坐标系。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as patches
import matplotlib.transforms as transforms
from scipy.stats import norm
from matplotlib.ticker import MultipleLocator
操作步骤
以下代码块绘制了两个图表,以演示轴域和数据的混合坐标系:
- 固定随机状态以确保可重复性,并设置要在此会话中使用的样式:
np.random.seed(19681211)
plt.style.use('ggplot')
- 用大小定义图形并为其添加轴域:
fig = plt.figure(figsize=(10,5))
ax1 = fig.add_subplot(121)
- 定义散点图的数据,并使用
plot
方法而不是scatter
方法对其进行绘制:
x, y = 50*np.random.rand(2, 500)
ax1.plot(x, y, 'cH')
- 定义一个椭圆形补丁并将其添加到轴域:
ellipse = patches.Ellipse((0.5, 0.5), 0.6, 0.3, transform=ax1.transAxes,
facecolor='blue', alpha=0.3)
ax1.add_patch(ellipse)
## remove the comment below to check if Ellipse remains at the same place,
## since it is on axes co-ordinates
##ax.set_xlim(10,40)
- 在第二个轴域上定义,并在其上绘制两个具有不同均值的正态分布,但标准差相同:
ax2 = fig.add_subplot(122)
mu1, mu2 = 0, 0.3
sigma = 0.1
x1 = np.linspace(mu1 - 3*sigma, mu1 + 3*sigma, 100)
ax2.plot(x1, norm.pdf(x1, mu1, sigma))
x2 = np.linspace(mu2 - 3*sigma, mu2 + 3*sigma, 100)
ax2.plot(x2, norm.pdf(x2, mu2, sigma))
- 为第二个轴域设置的标题和
xaxis_major_locator
:
ax2.set_title(r'$\sigma=0.05 \/ \dots \/ \sigma=0.25$', fontsize=16)
ax2.xaxis.set_major_locator(MultipleLocator(0.1))
- 将的 y 坐标转换为轴域坐标,并将 x 坐标保持为数据坐标:
trans = transforms.blended_transform_factory(ax2.transData, ax2.transAxes)
- 用矩形框突出显示 0.05 到 0.25
stddev
区域,在数据中显示 x 坐标,并且在轴域上显示 y 坐标:
rect = patches.Rectangle((0.05, 0), width=0.2, height=1,transform=trans,
color='green', alpha=0.3)
ax2.add_patch(rect)
plt.show()
工作原理
这是代码的说明:
np.random.seed()
is required to ensure that we get the same data points from any np.random.*
function we may use subsequently. This ensures repeatability of the graph.
plt.style.use('ggplot')
指定用于图形的样式。ax1.plot(x, y, 'cH')
在ax1
色块上绘制 500 个随机点。Ellipse()
在ax1
轴域中心添加一个椭圆形色块。(0.5, 0.5)
是,椭圆中心的坐标,0.6 是宽度,而 0.3 是高度。transform=ax1.transAxes
指定在将图片显示在屏幕上之前,轴域坐标系中的坐标必须转换为显示坐标。
- 在
ax2
上,我们使用的norm
函数绘制了两个均值(mu
)和标准差(sigma
)正态分布的图。 ax2.set_title(r'$\sigma=0.05 \/ \dots \/ \sigma=0.25$', fontsize=16)
使用正则表达式将设置为标题。 在下一章有关文本和数学表达式的章节中,我们将学到更多信息。ax2.xaxis.set_major_locator(MultipleLocator(0.1))
确保在 x 轴上以 0.1 个间隔放置刻度线,而不是使用默认刻度线。trans = transforms.blended_transform_factory(ax2.transData, ax2.transAxes)
定义要用于 x 和 y 轴的坐标系。rect = patches.Rectangle((0.05, 0), width=0.2, height=1, transform=trans, color='green', alpha=0.3)
定义一个矩形补丁:(0.05, 0)
是矩形左下角的坐标width=0.2
是数据坐标系在中的宽度,因此在 x 轴上转换为 0.25(从 0.05 开始)height=1
是轴域坐标系中中矩形的高度,因此跨越轴域完整高度(100%)transform=trans
是要使用的坐标系(在上一步中定义)。
这是输出的样子:
控制轴域位置
在第 3 章和“绘制多个图表,子图和图形”中,我们了解了用于创建各种图形布局的plt.subplot()
,plt.subplots()
和plt.subplot2grid()
函数。 我们将在本章稍后再学习一个函数GridSpec()
。 它们每个都为设计和所需的图形布局提供了更高的灵活性。 但是,它们都带有预定义的参数,使用这些参数可以控制图中的轴域位置。 用户可以获得的最大灵活性是能够指定精确的坐标和放置在和图形布局中的轴域的大小。 这就是我们将从本秘籍中学到的东西。
准备
我们将在此秘籍中使用或面向对象的 API。 导入所需的库:
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg as
FigureCanvas
from matplotlib.figure import Figure
from IPython.core.display import display
操作步骤
以下代码块绘制了四个图形,第四个是三个轴域的子集,因此它是其他轴域内的轴域(重叠):
- 固定随机状态以确保可重复性:
np.random.seed(19681211)
- 使用,图形大小和图像分辨率定义图形并将图形附加到画布上:
fig = Figure(figsize=(10,6), dpi=100)
FigureCanvas(fig)
fig.set(facecolor='c', alpha=0.1, edgecolor='m')
- 定义第一轴域并设置
title
和ylabel
:
ax1 = fig.add_axes([0.0, 0.55, 0.4, 0.4])
ax1.set_ylabel('volts')
ax1.set_title('a sine wave')
- 定义正弦波的数据,并将其绘制在的第一个轴域上:
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2*np.pi*t)
line, = ax1.plot(t, s, color='blue', lw=2)
- 在第二个轴域上定义并绘制直方图:
ax2 = fig.add_axes([0.0, 0.1, 0.4, 0.4])
n, bins, patches = ax2.hist(np.random.randn(1000), 50,
facecolor='yellow', edgecolor='blue')
ax2.set_xlabel('time (s)')
- 为接下来的两个绘图定义数据:
x = np.linspace(0, 10, 20)
y = (x+5)*(x-7)*(x-9) - 150
- 定义或第三轴域(左,底,宽度,高度),并绘制由
x
和y
定义的曲线:
ax3 = fig.add_axes([0.5, 0.1, 0.4, 0.85])
ax3.plot(x, y, 'g--')
ax3.set(xlabel='x', ylabel='y', title='outer axes')
- 定义第四轴域,并通过反转
x
和y
绘制相同的曲线:
ax4 = fig.add_axes([0.575, 0.6, 0.2, 0.25])
ax4.plot(y, x, 'r-*')
ax4.set(xlabel='y', ylabel='x', title='inset axes')
- 在屏幕上显示该图:
display(fig)
工作原理
这是代码的说明:
ax1 = fig.add_axes([0.0, 0.55, 0.4, 0.4])
向图形对象添加新轴域:- 坐标位于的图形坐标系中,并指定为距离左侧和底部的轴域起点,以及轴域的宽度和高度。
- 第一个坐标
0.0
表示,轴域从最左端开始 - 第二个坐标
0.55
表示轴域从底部底部图形高度的的 55% 开始 - 第三个坐标
0.4
指定该轴域的宽度的为该图宽度的的 40% - 第四个坐标
0.4
指定轴域的高度的是该图的高度的 40% - 在此轴域上绘制了一个正弦图
ax2 = fig.add_axes([0.0, 0.1, 0.4, 0.4])
是第二个轴域,它的大小也与和的第一个相同,从到的最左端开始,是图形高度从底部开始的 10%。 在此轴域上绘制直方图。ax3 = fig.add_axes([0.5, 0.1, 0.4, 0.85])
是第三个轴域。 它从左侧图形的 50% 开始,从底部底部图形的 10% 开始,的宽度是的图形宽度的 40% , 的高度为身高的的 85%。 在此轴域上绘制了一个绿色多项式。ax4 = fig.add_axes([0.575, 0.6, 0.2, 0.25])
是图中带有标题inset axes
的第四个轴域。 该轴域从图形宽度(距离左侧)的 57.5% 处开始,以及从图形高度(距离底部)的 60% 开始,宽度为图形宽度的 20% ,高度为图形高度的 25%。 从和先前的轴域中提取相同的多项式,但是用红色表示 x 和 y 轴的互换。
从此处的输出中可以看出,第四轴域在第三轴域之内; 它是另一个轴域内的一个轴域:
用于图形布局的GridSpec
GridSpec()
是用于复杂图形布局的另一个强大函数。plt.subplot()
和plt.subplot2grid()
实例化图形后,一次添加一个图,并且在中指定图形布局,每个子图中的行数和列数,其后是图的序列号,从右到上到下。 但是plt.subplots()
一次就定义了整个图形布局,就行数和列数而言,然后使用和对应索引访问了每个图/轴域。GridSpec()
允许在图形布局中创建多个网格,每个网格类似于plt.subplots()
。 在本秘籍中,我们将学习如何使用GridSpec()
以及如何将GridSpec()
关键字参数与plt.subplots()
一起使用。
使用GridSpec
在本秘籍中,我们将学习如何将GridSpec()
用于图形布局。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.gridspec import GridSpec
操作步骤
以下代码块使用GridSpec()
定义了两个3 x 3
网格。 在grid1
中,我们绘制了四个图形,每个图形具有不同的宽度和高度。 在grid2
中,我们使用宽度和高度比绘制了九个图,以使高度在同一行中对所有图都是,相同,而宽度是,对于列中的所有图形都相同:
- 固定随机状态以提高可重复性:
np.random.seed(19681211)
- 定义此会话中要使用的样式:
plt.style.use('seaborn')
- 定义图形的大小并定义布局:
fig = plt.figure(figsize=(14,10))
gs1 = GridSpec(ncols=3, nrows=3, left=0.05, right=0.5, wspace=0.2,
hspace=0.1)
- 在
gs1
上定义一个轴域:
ax1 = fig.add_subplot(gs1[0, 0])
- 定义一个椭圆形补丁并将其添加到
ax1
轴域中:
ellipse = patches.Ellipse((0.5, 0.5), 0.7, 0.3, transform=ax1.transAxes, facecolor='blue', alpha=0.3)
ax1.add_patch(ellipse)
- 在
gs1
上定义第二个轴域并在其上绘制直方图:
ax2 = fig.add_subplot(gs1[0, 1:])
ax2.hist(np.random.randn(1000), 50, facecolor='yellow',
edgecolor='blue')
- 在
gs1
上定义第三个轴域,并在其上绘制散点图:
ax3 = fig.add_subplot(gs1[1:, 0])
x, y = 50*np.random.rand(2, 500)
ax3.plot(x, y, 'cH', alpha=0.3)
- 在
gs1
上定义第四个轴域,并绘制polar
图:
ax4 = fig.add_subplot(gs1[1:, 1:], projection='polar')
N = 30
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = 10 * np.random.rand(N)
width = np.pi / 4 * np.random.rand(N)
bars = ax4.bar(theta, radii, width=width, bottom=0.0)
- 在极坐标图上使用自定义颜色和透明度:
for r, bar in zip(radii, bars):
bar.set_facecolor(plt.cm.BuPu(r / 10.))
bar.set_alpha(0.5)
- 使用宽度和高度比率参数定义第二个
GridSpec
gs2
:
widths = [2, 3, 1.5]
heights = [1, 3, 2]
gs2 = GridSpec(ncols=3, nrows=3, left=0.55, right=0.95, wspace=0.2,
hspace=0.1, width_ratios=widths, height_ratios=heights)
- 定义另一个
polar
图的数据,绘制 9 个极坐标图,并在屏幕上显示整个图形:
theta = np.arange(0., 2., 1./180.)*np.pi
for row in range(3):
for col in range(3):
ax = fig.add_subplot(gs2[row, col], projection='polar')
ax.plot((col+2)*theta, theta/(row+6))
ax.plot(theta, np.cos((row+5)*theta))
ax.plot(theta, [1.25]*len(theta))
plt.show()
工作原理
代码的工作方式如下:
plt.style.use('seaborn')
指定,将使用 seaborn 样式。gs1 = GridSpec(ncols=3, nrows=3, left=0.05, right=0.5, wspace=0.2, hspace=0.1)
创建第一个网格:ncols
和nrows
指定网格布局,在这种情况下为3 x 3
网格left
和right
坐标在的图形坐标系中,并指定网格从,left
处开始以及在处结束的位置right
wspace
控制各图之间的行间隔hspace
控制各图之间的列间隔
ax1 = fig.add_subplot(gs1[0, 0])
为网格中的第一个单元格创建一个轴域实例。patches.Ellipse()
定义了一个椭圆形补丁,其坐标在轴域坐标系的中指定。ax1.add_patch(ellipse)
将椭圆补丁添加到轴域ax1
。ax2 = fig.add_subplot(gs1[0, 1:])
为的第二个和的第一行的的第三个单元格创建轴域实例ax2
的。 在此轴域上绘制直方图。ax3 = fig.add_subplot(gs1[1:, 0])
为的第二个和的第一列的中的第三个单元创建轴域实例ax3
。 在该轴域上绘制了 500 个随机数的散点图。ax4 = fig.add_subplot(gs1[1:, 1:], projection='polar')
为第一行和第二行以及第一行和第二列创建一个极坐标轴域实例ax4
。 它占据gs1
的2 x 2
个单元格。 在此轴域上绘制了一个极坐标图。gs2 = GridSpec(ncols=3, nrows=3, left=0.55, right=0.95, wspace=0.2, hspace=0.1, width_ratios=widths, height_ratios=heights)
创建第二个网格的,同样是3 x 3
网格:- 同样这里左右坐标位于图形坐标系中
width_ratios
和height_ratios
分别指定行和列中的相对宽度和高度- 如宽度和高度比率参数中所指定的,在此网格中使用
widths
和heights
不同绘制了九个极坐标图
您应该看到下图是上述代码的输出:
更多
在前面的示例中,我们使用width_ratios
和height_ratios
参数使用GridSpec()
定义所需的网格。 可以将相同的参数传递给plt.subplots()
以绘制我们在前面的示例中创建的相似网格。 这是代码:
widths = [2, 3, 1.5]
heights = [1, 3, 2]
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2*np.pi*t)
#### Passing keyword specs to plt
gs_kw = dict(width_ratios=widths, height_ratios=heights)
fig, axes = plt.subplots(ncols=3, nrows=3, figsize=(10,8), gridspec_kw=gs_kw)
for r, row in enumerate(axes):
for c, ax in enumerate(row):
ax.plot(t, s)
label = 'Width: {}\nHeight: {}'.format(widths[c], heights[r])
ax.annotate(label, (0.1, 0.5), xycoords='axes
fraction', va='center')
fig.tight_layout()
plt.show()
这是输出,具有与使用GridSpec()
之前看到的布局完全相同的布局:
GridSpec
对齐
当我们创建多个网格并将其并排放置在图中时,有时它们可能在,顶部,底部或两者处未对齐。 在本秘籍中,我们将学习如何避免此类对齐问题。
准备
我们将为此示例使用一个误差线形图示例。 我们还将学习如何创建恒定误差线,对称和非对称误差线以及误差线采样。
让我们导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
操作步骤
以下代码块绘制了五个图,其中第一个网格中有三个,第二个网格中有两个。 我们在第一个网格上绘制恒定误差线以及对称和非对称误差线,在第二个网格上绘出所有误差线和采样误差线:
- 定义图形的大小并设置此会话要使用的样式:
fig = plt.figure(figsize=(8,8))
plt.style.use('seaborn-deep')
- 定义用于绘制图形的函数:
def plot_errorbar(axs, x, y, xerr=None, yerr=None, errevery=1,
title=None, xlabel=None, ylabel=None, fmt=None):
ax = fig.add_subplot(axs)
ax.errorbar(x, y, xerr=xerr, yerr=yerr, errorevery=errevery,
fmt=fmt)
ax.set(title=title, xlabel=xlabel, ylabel=ylabel)
- 使用
GridSpec
使用3 x 1
布局定义第一个网格gs1
:
gs1 = GridSpec(3, 1)
- 定义指数曲线的数据:
x = np.arange(0.1, 5, 0.5)
y = np.exp(-x)
- 在 x 和 y 轴域上绘制带有恒定误差的误差线:
plot_errorbar(gs1[0], x, y, xerr=0.8, yerr=0.3, title='Constant
Errors', xlabel='X', ylabel='Y', fmt='-o')
- 将的变化误差定义为
x
的函数,然后仅绘制yerror
:
error = 0.1 + 0.25 * x
plot_errorbar(gs1[1], x, y, yerr=error, title='Variable Symmetric
Error', xlabel='X', ylabel='Y', fmt='-o')
- 定义和边界误差以创建不对称误差栏:
lower_error = 0.5 * error
upper_error = error
asymmetric_error = [lower_error, upper_error]
plot_errorbar(gs1[2], x, y, xerr=asymmetric_error, title='Variable
Asymmetric Error', xlabel='X', ylabel='Y', fmt='o')
- 在第一个网格
gs1
的上调整图之间的间距:
gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])
- 用较小的间隔为指数曲线定义数据:
x = np.arange(0.1, 5, 0.1)
y = np.exp(-x)
- 用
2 x 1
布局定义第二个网格gs2
:
gs2 = GridSpec(2, 1)
- 将和变化误差定义为
x
的非线性函数,并在误差栏中绘制所有误差点:
yerr = 0.1 + 0.1 * np.sqrt(x)
plot_errorbar(gs2[0], x, y, yerr=yerr, title='All Errorbars', xlabel='X', ylabel='Y', fmt='-')
- 仅绘制每五个样本误差:
plot_errorbar(gs2[1], x, y, yerr=yerr, errevery=5, title='only every 5th errorbar',
xlabel='X', ylabel='Y', fmt='-')
- 调整
gs2
上各图之间的间隔:
gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5)
- 如果的两个网格在的顶部或底部未对齐,请尝试匹配它们以正确对齐:
top = min(gs1.top, gs2.top)
bottom = max(gs1.bottom, gs2.bottom)
gs1.update(top=top, bottom=bottom)
gs2.update(top=top, bottom=bottom)
plt.show()
这个怎么运作 ...
这是代码的说明:
plot_errorbar()
是用户定义的函数,用于使用,给定要绘制的参数,例如axes
,data
和其他控制曲线的参数来绘制误差图。gs1 = GridSpec(3, 1)
定义了一个3 x 1
的网格gs1
。plot_errorbar()
在 x 和 y 轴上均以恒定误差绘制轴域gs1[0]
上的误差线:- 图中水平线的长度表示
X
中的误差大小。 - 垂直线的长度表示
Y
中的误差大小。 - 在第一个图中,它们的大小和的大小相同,但它们的值相差很大,分别为 0.8 和 0.3。 这是因为,
x
,和y
轴上的比例不同。 如果我们想将它们放置在和相同的比例尺上,则应在绘图上设置aspect=1
。
- 图中水平线的长度表示
plot_errorbar()
仅绘制第二个误差线,用于随x
变化但对称的yerror
,曲线的两侧误差相等。- 为
xerror
绘制了第三条误差线,该xerror
也在变化,但在和平均值两侧的值不相等的情况下是不对称的。 在这种情况下,如果将误差限制在上下限的某些边界内,则会发生这种情况。 gs1.tight_layout(fig, rect=[0, 0, 0.5, 1])
确保使用图形坐标系统设置gs1
的边界,从图形的左下角到图形宽度的一半和全高。 正如我们在第 3 章,“绘制多个图表,子图和图形”中所了解的tight_layout()
一样,这也确保了网格内各图之间有足够的间隙。gs2 = GridSpec(2, 1)
定义第二个网格,即2 x 1
。- 在此网格上,我们再次绘制仅用于
yerror
的标准误差线,该误差线随的第一个轴域的变化,而在的第二个轴域上的变化,我们绘出另一个误差线 ,但每 5 个误差进行一次采样,而不是像在第一轴域上那样绘制每个误差项。 - 当我们有两个大小不等的网格时,它们的顶部,底部或两者的对齐方式可能不太好。 其中一个可能相对于另一个网格上升或下降。 在这种情况下,您需要在,顶部和底部分别计算两个网格的,的最小值或最大值,并强制两个网格都遵循这些最小值/最大值,以便它们都对齐 。
top = min(gs1.top, gs2.top)
计算两个顶部的最小值。bottom = max(gs1.bottom, gs2.bottom)
从两个底部计算最大值。gs1.update(top=top, bottom=bottom)
和gs2.update(top=top, bottom=bottom)
强制两个网格具有相同的顶部和底部位置,以便它们对齐。
执行上述代码后,您应该在屏幕上看到下图:
约束布局
约束布局类似于紧密布局,但是使用了一种不同的算法,该算法被认为更加准确和高效。 但是,在撰写本文时,它仍在测试中,因此可能会或可能不会继续。
对于此秘籍,我们将使用与上一个秘籍相同的误差线,但使用具有受约束布局的单个网格。
准备
导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
操作步骤
以下代码块在同一网格中绘制了五个误差线形图,并使用受约束的布局来确保图之间的正确对齐和适当的间距,以使标签或刻度上没有重叠:
- 定义图形和大小,并设置约束布局,然后设置用于此会话的样式:
fig = plt.figure(figsize=(8,8), constrained_layout=True)
plt.style.use('bmh')
- 定义函数来绘制误差条形图:
def plot_errorbar(ax, x, y, xerr=None, yerr=None, errevery=1,
title=None, xlabel=None, ylabel=None, fmt=None):
ax.errorbar(x, y, xerr=xerr, yerr=yerr, errorevery=errevery, fmt=fmt)
ax.set(title=title, xlabel=xlabel, ylabel=ylabel)
- 为指数曲线定义和数据:
x = np.arange(0.1, 5, 0.5)
y = np.exp(-x)
- 使用
GridSpec
使用6 x 2
布局定义网格gs
并向其中添加轴域:
gs = GridSpec(6, 2, figure=fig)
ax = fig.add_subplot(gs[0:2, 0])
- 在
x
和y
上绘制一个带有恒定误差的误差线:
plot_errorbar(ax, x, y, xerr=0.1, yerr=0.3, title='Constant Errors',
xlabel='X', ylabel='Y', fmt='-o')
- 绘制带有
x
和y
对称误差的函数的误差条:
error = 0.1 + 0.2 * x
ax = fig.add_subplot(gs[2:4, 0])
plot_errorbar(ax, x, y, yerr=error, title='Variable Symmetric
Error', xlabel='X', ylabel='Y', fmt='-o')
- 在
x
上定义一个有界误差,产生不对称误差条,并绘制误差条:
lower_error = 0.4 * error
upper_error = error
asymmetric_error = [lower_error, upper_error]
ax = fig.add_subplot(gs[4:, 0])
plot_errorbar(ax, x, y, xerr=asymmetric_error, title='Variable
Asymmetric Error', xlabel='X', ylabel='Y', fmt='o')
- 为指数曲线以较小的间隔定义和数据:
x = np.arange(0.1, 5, 0.1)
y = np.exp(-x)
- 再次根据
x
定义误差,但为非线性函数,并绘制误差线:
yerr = 0.1 + 0.1 * np.sqrt(x)
ax = fig.add_subplot(gs[:3, 1])
plot_errorbar(ax, x, y, yerr=yerr, title='All Errorbars', xlabel='X', ylabel='Y', fmt='-')
- 将一个轴域添加到网格,并使用每五个误差项来绘制误差线,而不是绘制所有误差线,以创建示例误差线:
ax = fig.add_subplot(gs[3:, 1])
plot_errorbar(ax, x, y, yerr=yerr, errevery=5, title='only every 5th
errorbar', xlabel='X', ylabel='Y', fmt='-')
- 调整绘图之间的间距,并在屏幕上显示图形:
fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72.,
hspace=0.2, wspace=0.2)
plt.show()
工作原理
大部分解释已在先前的秘籍中给出:
fig = plt.figure(figsize=(8,8), constrained_layout=True)
指定图形大小,设置constrained_layout
并实例化图形。fig.set_constrained_layout_pads(w_pad=2./72., h_pad=2./72., hspace=0.2, wspace=0.2)
确保网格中各图之间的正确对齐和间距:- 它有四个参数,我们可以设置这些参数来控制绘图之间的间隔。
w_pad
和h_pad
以英寸为单位指定,并在数据坐标系中固定,因此,即使图形大小发生变化,图之间的空间也不会改变,因为它是固定空间 。- 当我们在的图形坐标系中指定
wspace
和hspace
时,如果图形大小发生变化,则图之间的间距也会成比例地变化。 w_pad
和wspace
控制同一行中图之间的空间,而h_pad
和hspace
控制一列中图之间的空间。
这是输出的外观。 背景与之前的和秘籍不同,因为在这种情况下我们使用了不同的样式:
使用GridSpecFromSubplotSpec
GridSpecFromSubplotSpec()
是可用于多个网格中图形布局的另一种方法。 这有点类似于subplot2grid()
方法,我们在第 3 章和“绘制多个图表,子图和图形”中了解到。 我们还将看到GridSpecFromSubplotSpec()
创建的复杂网格如何利用constrained_layout
更好地对齐图中所有网格中的所有图。
准备
导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
操作步骤
以下代码块在一张图中绘制了不同格数和大小的三个网格:
- 定义用于此会话的样式,带有大小的图形,然后设置
constrained_layout
:
plt.style.use('ggplot')
fig = plt.figure(figsize=(12,6), constrained_layout=True)
- 用
1 x 3
布局定义网格,该布局连续包含三个网格:
gs0 = GridSpec(1, 3, figure=fig)
- 定义每个网格布局:
gs00 = GridSpecFromSubplotSpec(2, 2, subplot_spec=gs0[0])
gs01 = GridSpecFromSubplotSpec(3, 2, subplot_spec=gs0[1])
gs02 = GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[2])
- 使用
for
循环为每个网格绘制每个网格内的每个单元格:
for a in range(2):
for b in range(2):
fig.add_subplot(gs00[a, b])
for a in range(3):
for b in range(2):
fig.add_subplot(gs01[a, b])
for a in range(3):
for b in range(3):
fig.add_subplot(gs02[a, b])
- 调整绘图之间的间距,并在屏幕上显示图形:
fig.set_constrained_layout_pads()
plt.show()
工作原理
在此示例中,我们没有绘制任何图形,只是绘制单元格以演示如何使用,GridSpecFromSubplotSpec()
方法:
fig = plt.figure(figsize=(12,6), constrained_layout=True)
定义并实例化具有constrained_layout
设置为True
的图形对象。 重要的是在此处将constrained_layout
标志设置为True
,否则,在代码末尾将无法识别fig.set_constrained_layout_pads()
语句。 与tight_layout()
相比,这是有区别的,如我们先前所见,即使在图形实例化时未将此标志设置为true
的情况下,它也可以工作。gs0 = GridSpec(1, 3, figure=fig)
定义图中的网格结构。 在这里,我们定义了三个网格,它们全部排成一行:- 如果要使用
constrained_layout
选项,则需要figure=fig
引用GridSpec()
中的图形实例。 对于tight_layout()
,无需指定此参数。
- 如果要使用
gs00 = GridSpecFromSubplotSpec(2, 2, subplot_spec=gs0[0])
定义网格内的布局。 在这里,我们为第一个网格使用2 x 2
布局。- 类似地,我们为第二个网格使用
3 x 2
,为第三个网格使用3 x 3
。 fig.set_constrained_layout_pads()
应用,约束布局,以在网格内和网格之间的图之间正确对齐和间隔。 我们在此使用所有和默认参数。
该图的外观如下:
作为练习,您可以尝试使用严格的layout()
替换约束布局选项。 即使对所有可用参数(例如pad
,w_pad
,h_pad
)进行了任何级别的优化,也可能无法获得与constrained_layout
一样清晰的对齐方式和间距。
为图像方向使用原点和范围
我们已经学习了如何使用imshow()
方法绘制二维彩色图像。 默认情况下,imshow()
使用轴域左上角的作为数据坐标的原点(0, 0)
,并相对于这些坐标填充图像。 如果我们想将其更改为左下角,并沿每个轴扩展数据限制,则imshow()
方法的圆点和范围参数会有所帮助。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
操作步骤
以下代码块在两个图中绘制了一张鸟图像六次,其中是默认参数,而是可选原点和范围参数,每个参数都有不同的选项来演示这些参数如何影响图像的方向:
- 阅读鸟的图像(改编自 Coursera 的“机器学习”课程):
img = plt.imread('bird_small.png')
- 定义一个函数来绘制图像:
def plot(ax, origin, extent, title):
ax.imshow(img, origin=origin, extent=extent)
ax.xaxis.set_major_locator(MultipleLocator(25))
ax.yaxis.set_major_locator(MultipleLocator(25))
ax.set_title(title)
- 定义图形,大小和布局:
fig1, axs1 = plt.subplots(1, 3, figsize=(12,6))
- 使用和原点参数为同一张图片绘制三个图像,并使用不同的选项:
plot(axs1[0], None, None, title='default')
plot(axs1[1], 'upper', None, title='origin=upper')
plot(axs1[2], 'lower', None, title='origin=lower')
plt.tight_layout()
- 定义第二个图形,其大小和布局为:
fig2, axs2 = plt.subplots(1, 3, figsize=(12,6))
- 使用范围参数用不同的选项绘制同一张图片的三幅图像:
plot(axs2[0], None, None, title='default')
plot(axs2[1], 'upper', (-25, 150, 150, -25), title='origin=upper \n
extent=(-25, 150, 150, -25)')
plot(axs2[2], 'lower', (-25, 150, -25, 150), title='origin=lower \n
extent=(-25, 150, -25, 150)')
- 调整绘图之间的间距,并在屏幕上显示图形:
plt.tight_layout()
plt.show()
工作原理
这是此代码如何工作的说明:
img = plt.imread('bird_small.png')
将图像读取到 NumPy 数组中,Matplotlib 可以理解。- 为了避免为每个绘图重复代码,我们定义了
plot
函数,该函数针对给定的参数集绘制图形。 ax.xaxis.set_major_locator(MultipleLocator(25)
在 x 轴上的上以25
的间隔设置刻度线。 我们对 y 轴也重复相同的操作。- 在图 1 的第一行中,我们使用和默认参数
origin
和extent
绘制图,然后分别使用范围参数的默认值origin='upper'
和origin='lower'
来绘制。请注意,默认值和origin='upper'
相同。 使用origin='lower'
时,的图像会上下颠倒,因为 y 坐标会从上到下从下到上(从 0 到 125)变化。 现在您可以在图片的左下角看到(0, 0)
坐标。 - 在图 2 中,我们设置了与默认范围选项不同的扩展区选项,以查看区别:
- 在数据坐标系的中设置范围参数(左,右,下,上)。
- 对于第一张图像,我们使用默认参数。
- 对于第二张图像,我们使用
(-25, 150, 150, -25)
,表示左侧为 -25,右侧为 150,底部为 150,顶部为 -25。 这将设置适合图像的边框。 如果这些坐标超出原始图像的数据限制,则它将使用插值选项填充其他像素; 如果它们较小,则它将使用重新采样选项来减小大小。
该图的外观如下:
使用 GeoPandas 的地理绘图
在本秘籍中,我们将学习如何使用 Matplotlib 随附的geopandas
包绘制地理地图。 Matplotlib 支持用于高级地理地图的第三方第三方包,例如Basemap
(将于 2020 年停用)和Cartopy
(替代底图)。 我们将在第 14 章“使用 Cartopy 绘制地理地图”中学习使用 Cartopy。
准备
导入所需的库:
import geopandas as gpd
import matplotlib.pyplot as plt
操作步骤
以下代码块突出显示了全球各地气象站的位置。 这些站监视天气和气候变化:
- 从世界银行集团的气候变化知识门户下载要在地图上绘制位置的形状文件:
world_wc = gpd.read_file('GRDC.shp')
world_wc.head() # View the first 5 rows of the data, it is a pandas
function
形状文件包含全球气象站的位置,这些位置监视着全球的天气变化。 尽管我们在这里使用.shp
文件,但它需要相应的.shx
,.sbx
等。 ZIP 文件中的所有文件均应解压缩并放置在工作目录中。 否则,此代码将失败。 所有形状文件都是如此。
- 从 thematicmapping.org 下载世界边界的形状文件:
world_borders = gpd.read_file('TM_WORLD_BORDERS_SIMPL-0.3.shp')
world_borders.head()
- 初始化图形和坐标轴,并设置用于此会话的样式:
plt.style.use('dark_background')
fig,ax = plt.subplots(figsize=(12,9))
- 在
ax
上绘制全球天气变化数据:
world_wc.plot(ax=ax)
- 绘制简单的世界地图边框:
world_borders.boundary.plot(ax=ax,color='#cccccc',linewidth=0.6)
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
- 从代码中提到的 URL 下载形状文件(
.shp
)。 - 第一个具有气象站的位置,和的位置,第二个具有和世界的边界。
- 这些文件位于一个 ZIP 文件中,该文件包含具有不同文件扩展名的多个不同文件。 我们应该提取所有这些文件并将它们放在工作目录中。 尽管我们在代码中仅使用
.shp
文件进行读取,但它会内部调用 ZIP 文件中的其他文件。 gpd.read_file()
读取.shp
文件的的内容。 第一次读取会加载气象站位置数据,将加载至边界数据。world_wc.plot(ax=ax)
在地图上绘制气象站的位置。world_borders.boundary.plot()
绘制边界信息。 请注意,此处我们使用的是,Pandasplot
函数,而不是 Matplotlibplot
函数。 这就是为什么您在这里看不到绘图方法的常用格式的原因!
蓝点表示气象站的位置。
六、嵌入文本和表达式
在本章中,我们将学习如何使用以下秘籍将文本和数学表达式嵌入绘图中:
- 将数学表达式与字体字典配合使用
- 在极坐标图上标注点
- 使用
ConnectionPatch
- 使用文本框
- 绘制积分曲线下的面积
- 定义自定义标记
- 使用小数,常规数学表达式和符号
- 二维空间中的词嵌入
介绍
如果您想将用户的注意力吸引到绘图的特定区域,想要提供其他信息或为绘图的某些部分提供说明,则的标注和文本会很方便。 它们还有助于创建故事绘图,并为任何正式演示提供对数据的更多见解。 在本章中,我们将学习如何使用这些功能。
将数学表达式与字体字典配合使用
在本秘籍中,我们将学习如何使用字体字典将数学表达式嵌入文本中,以将相同的属性应用于绘图上的所有文本,包括标题,标签和文本表达式。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了一个衰减的指数函数。 首先,我们定义具有所有必需属性的字体字典,然后将其应用于图形上的每个文本元素,包括标题以及 x 和 y 标签。 这样可以确保图形上的文本外观和感觉一致:
- 定义
font
字典以应用于绘图中的所有文本:
font = {'family': 'DejaVu Sans', 'name': 'Times New Roman',
'style': 'italic', 'color': 'orange',
'weight': 'bold', 'size': 16}
- 定义指数衰减曲线的数据并绘制:
t = np.linspace(0.0, 5.0, 100)
y = np.sin(2*np.pi*t) * np.exp(-t/2)
plt.plot(t, y, 'm')
- 定义文本,标题和标签,然后在绘图上打印它们:
plt.text(2, 0.65, r'$\sin(2 \pi t) \exp(-t/2)$', fontdict=font)
plt.title('Damped exponential decay', fontdict=font)
plt.xlabel('time (s)', fontdict=font)
plt.ylabel('voltage (mV)', fontdict=font)
- 调整空间以防止
ylabel
出现剪切,并在屏幕上显示该图:
plt.subplots_adjust(left=0.15)
plt.show()
工作原理
这是代码的说明:
font
是我们要应用于每个文本项的各种文本属性的字典:family
和name
代表字体系列和字体名称style
表示它是斜体还是正常weight
表示它是否为粗体size
代表字体大小
t = np.linspace(0.0, 5.0, 100)
在 0.0 到 5.0 的范围内定义 100 个点,它们之间的间距相等y
被定义为sin
,exponential
和t
的函数plt.title()
,plt.xlabel()
和plt.ylabel()
现在都已经为您所熟悉,但是我们添加了一个附加的fontdict
参数,该参数为特定属性定义了特定参数字典plt.text(2, 0.65, r'$\sin(2 \pi t) \exp(-t/2)$', fontdict=font)
在数据坐标系上的坐标(2, 0.65)
上打印文本:text
以正则表达式格式表示; 因此,它包含在r'..... '
中- 当文本包含数学符号/表达式,例如
sin
或pi
时,则必须将其括在$....$
中 - 具有特殊含义的字符之前应加反斜杠(
\
),以便它们的特殊含义将出现在图形上,例如pi
执行代码后,您应该获得以下输出图:
在极坐标图上标注点
在本秘籍中,我们将学习如何标注极坐标图上的特定点。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了一个极坐标图,并在其上标注了一个点:
- 定义图形和坐标轴,并声明极坐标投影:
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
- 定义极坐标图的数据并绘制:
r = np.arange(0,1,0.001)
theta = 2 * 2*np.pi * r
ax.plot(theta, r, color=[0.9,0.4,0.7], lw=3)
- 在极坐标曲线的 600 点绘制一个带有菱形标记的点:
ind = 600
pointr, pointtheta = r[ind], theta[ind]
ax.plot([pointtheta], [pointr], 'D', markersize=10)
- 定义极坐标点的标注并在屏幕上显示图形:
ax.annotate('a polar annotation',
xy=(pointtheta, pointr), xytext=(1.0, 0.75),
textcoords='figure
fraction', arrowprops=dict(facecolor='red',
shrink=0.05),
horizontalalignment='right',
verticalalignment='bottom')
plt.show()
工作原理
这是代码的说明:
fig.add_subplot(111, projection='polar')
定义轴域并将其声明为极坐标图。 您也可以使用polar=True
代替projection='polar'
r
和theta
设置极坐标图的半径和角度数据ax.plot(theta, r, color=[0.9,0.4,0.7], lw=3)
用theta
和r
绘制极坐标图:- 使用 R,G 和 B 颜色值指定颜色以创建自定义颜色。 R,G 和 B 值从 0(暗)到 1(亮)变化。
lw=3
为极坐标图指定 3 的线宽。
ax.plot([pointtheta], [pointr], 'D', markersize=10)
在极坐标图上绘制菱形点,坐标为pointtheta
和pointr
; 它在用于绘制极坐标图的数据点列表中由其索引(600)表示:ax.annotate()
用其文本描述('a polar annotation'
)标注该点:xy
指定要标注的点的坐标(极坐标)xytext
指定放置文字说明的坐标textcoords
为指定的文本坐标指定坐标系统,在这种情况下为图形坐标arrowprops
指定文本和绘图上的点之间的箭头的属性
您应该在屏幕上看到以下图形:
使用ConnectionPatch
在本秘籍中,我们将学习如何使用ConnectionPatch()
方法连接同一图形上的两个点或同一图形上的两个不同图形。 当试图显示绘图上两个点之间的关系时,这很方便。
准备
导入所需的库:
from matplotlib.patches import ConnectionPatch
import matplotlib.pyplot as plt
操作步骤
以下代码块绘制了两个轴域,四个点以及它们之间的连通性。 这是一种没有任何文本的标注:
- 定义图形,大小,布局和轴域:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
- 在数据坐标系上定义两个点,并为其声明坐标系:
pointA = (0.2, 0.2)
pointB = (0.8, 0.8)
coordsA = "data"
coordsB = "data"
- 定义两点之间的连接:
con = ConnectionPatch(pointA, pointB, coordsA, coordsB, arrowstyle="fancy",
shrinkA=5, shrinkB=5, fc="k")
- 在
ax1
上用标记"o"
绘制两个点:
ax1.plot([pointA[0], pointB[0]], [pointA[1], pointB[1]], "o")
- 将连接艺术家添加到
ax1
:
ax1.add_artist(con)
- 在
ax1
上打印A
,B
和C
点的文本,并设置 x 和 y 轴限制:
ax1.text(0.06, 0.18, 'A', size=25, weight=50)
ax1.text(0.83, 0.8, 'B', size=25, weight=50)
ax1.text(0.3, 0.15, 'C', size=25, weight=50)
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
- 再定义两个点
C
和D
,并分配坐标系; 两者都是相同的坐标,但在两个不同的轴域上:
pointC = (0.3, 0.2)
coordsC = "data"
coordsD = "data"
- 定义
C
和D
之间的连接,将其添加到ax2
,添加文本标注并为 x 和 y 轴设置限制:
con = ConnectionPatch(xyA=pointC, xyB=pointC, coordsA=coordsC,
coordsB=coordsD, axesA=ax2, axesB=ax1,
arrowstyle="wedge", shrinkB=5)
ax2.add_artist(con)
ax2.text(0.3, 0.15, 'D', size=25, weight=50)
ax2.set_xlim(0, .5)
ax2.set_ylim(0, .5)
- 在屏幕上显示该图:
plt.show()
工作原理
这是代码的说明:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
定义大小为(6, 3)
的图形,并在图形上连续显示两个轴域。pointA
和pointB
是两点的坐标。coordsA
和coordsB
是各自的坐标系。ConnectionPatch()
定义pointA
和pointB
之间的连接:arrowstyle
指定一个"fancy"
箭头。shrinkA
和shrinkB
指定箭头尖端应与它们指向的点相距多远,shrink
越高,距离就越长。fc='k'
将前景颜色指定为黑色。
ax1.add_artist(con)
绘制先前在轴域 1 上定义的连接路径- 然后在适当的坐标上使用
ax1.text()
在轴域 1 上绘制A
,B
和C
点。 pointC
和pointD
在数据坐标系上具有完全相同的坐标,但在两个不同的轴域上。- 正如我们之前所做的,绘制
pointC
和pointD
之间的连接,唯一的区别是arrowstyle="wedge"
我们得到以下输出:
您可以用任何描述连接点之间关系的文字替换 A,B,C 和 D!
使用文本框
在本秘籍中,我们将学习如何嵌入文本框以标识图中的不同聚类。 我们将使用一个熟悉的Iris
数据集,其中包含三个数据簇。
准备
导入所需的库:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
操作步骤
以下代码块在两个不同的轴域上两次绘制Iris
数据。 一个使用常规图例来指示三个具有不同颜色和标签的不同群集。 另一个在点群集中使用文本框指示类:
- 定义图形,大小及其布局:
fig, ax = plt.subplots(1,2, figsize=(10,6))
- 使用 Pandas 读取
Iris
数据集:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
iris['species1'] = iris['species'].map({"setosa" : 0, "versicolor" :
1, "virginica" : 2})
- 使用
Iris
数据集的两个属性绘制散点图:
ax[0].scatter(iris.petal_length, iris.petal_width,
s=10*iris.petal_length*iris.petal_width,
c=iris.species1)
- 定义要嵌入到图形中的文本框的边界框属性:
bbox_props = dict(boxstyle="round", fc="w", ec="0.25", alpha=0.9)
- 定义文本框并在第一个轴域上绘制它们:
ax[0].text(2.75, 0.25, "Setosa", ha="center", va="center", size=15,
color='m', bbox=bbox_props)
ax[0].text(5.5, 1.0, "Versicolor", ha="center", va="center",
size=15,color='g', bbox=bbox_props)
ax[0].text(6.0, 2.0, "Virginica", ha="center", va="center", size=15,
rotation=45, color='y', bbox=bbox_props)
- 使用另一种方法通过标签和图例来区分群集:
x,y = iris['petal_length'], iris['petal_width']
classes = set(iris['species'])
for name in classes:
index = iris['species'] == name
ax[1].scatter(x[index], y[index], marker='o', label=name)
plt.legend()
plt.show()
工作原理
这是代码的说明:
- 正如我们之前所做的那样,首先使用 Pandas 读取数据,然后在相同的
Iris
数据集中创建另一个新的species1
属性,以将数字类别分别保存为 0、1、2 如map
函数中所给。 ax[0].scatter()
绘制了petal_length
和petal_width
的散点图,因为存在三类,所以数据点形成了三个簇,以不同的颜色显示。bbox_props = dict(boxstyle="round", fc="w", ec="0.25", alpha=0.9)
定义带有以下内容的文本框:boxstyle
为圆形边缘- 前景色是白色
- 边缘颜色为浅灰色
- 透明度降低
ax[0].text()
绘制文本框,每个群集一个。 它类似于我们先前所学的绘制文本,只是现在文本位于bbox
的内部(如先前所定义)。 整个文本框位于数据坐标系中的默认坐标处,这是默认值。- 前两个文本框是水平的,但是第三个文本框是自变量中指定的 45 度旋转。
- 然后,我们使用标签和图例属性绘制相同的图,只是为了展示实现相同输出的另一种方式。 当我们在第 2 章和“基本绘图”入门中介绍了散点图时,我们没有解释图例来指示哪个类/颜色属于哪个类名。 在这里,我们将学习如何做到这一点:
x,y = iris['petal_length'], iris['petal_width']
将petal_length
和petal_width
赋给x
和y
坐标classes = set(iris['species']
在数据集中获得唯一的类
for
循环一次绘制每个类的散点图:index = iris['species'] == name
获取给定类名称的索引ax[1].scatter(x[index], y[index])
绘制给定索引的散点图
以下是执行代码后应获得的输出图:
更多
在此示例中,我们使用了预定义的"round"
boxstyle
。 有许多预定义的选项,例如"circle"
,"darrow"
,"larrow"
,"rarrow"
,"square"
,"sawtooth"
和"roundtooth"
。
我们还可以自定义开发这些boxstyle
,如下所示:
- 导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.path import Path
- 定义一个用于绘制自定义文本框的函数:
def tbox_custom_style(x0, y0, width, height, size, mutation_aspect=1):
pad = 0.5 * size
x0, y0 = x0 - pad, y0 - pad
width, height = width + 2 * pad, height + 2 * pad
x1, y1 = x0 + width, y0 + height
# Define the points along with first curve to be drawn
verts = [(x0, y0), (x1, y0),(x1 + 2*pad, y0 + 2*pad),(x1, y1),
(x0, y1), (x0, y0)]
# How to draw the plot along above points
codes = [Path.MOVETO, # Go to first point specified in verts
Path.LINETO, # Draw a line from first point to
second point
Path.LINETO,
Path.LINETO, # Draw another line from current point to
next point
Path.LINETO, # Draw another line from current point to
next point
Path.CLOSEPOLY] # Close the loop
# Create complete path with points and lines/curves
path = Path(verts, codes)
return path
- 定义图形,并在文本框的四个角添加一个文本框和文本标签:
fig, ax = plt.subplots()
ax.text(0.5, 0.5, 'Text Box', size=25, va="center", ha="center",
rotation=25,
color='b', bbox=dict(boxstyle=tbox_custom_style, alpha=0.25,
fc='r',ec='k'))
ax. text(0.35, 0.22, '(x0,y0)', size=15)
ax. text(0.7, 0.5, '(x1,y0)', size=15)
ax. text(0.6, 0.75, '(x1,y1)', size=15)
ax. text(0.15, 0.45, '(x0,y1)', size=15)
plt.show()
下面是它的工作原理:
tbox_custom_style(x0, y0, width, height, size, mutation_aspect=1)
是用户定义的绘制框的函数:- 它采用
ax.text()
方法提供的size
参数,并在内部按比例计算width
和height
。 - 它以
(x0, y0)
为参考点(0, 0)
。 mutation_aspect
是与我们提供的大小成比例的比例因子。- 此自定义
boxstyle
函数在定义中需要所有这些参数。 我们可以使用这些参数在此函数中绘制任何自定义对象。
- 它采用
- 要绘制带框的箭头,我们需要连接五个点。 我们使用大小
x0, y0
,width
和height
定义了这五个点。 然后我们使用path
方法连接这五个点,正如我们在第 2 章和“基本绘图入门”中所了解的那样。 - 我们在
ax.text()
调用中提供此自定义函数作为boxstyle=tbox_custom_style
的参数:size=25
指定文本的字体大小,与字体大小成正比va
和ha
指定文本的垂直和水平对齐方式rotation
指定文本框的旋转角度color
指定文本的颜色fc
指定前景颜色ec
指定边缘颜色alpha
指定文本框的透明度
您应该看到以下作为代码输出:
绘制积分曲线下的区域
在本秘籍中,我们将学习如何在曲线下绘制定义的区域,以及如何将等式作为文本嵌入到绘图中。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
操作步骤
以下代码块绘制了一个三阶y = x ** 3
的多项式,并绘制了该曲线下 x 轴上两点之间的面积,这是受两点限制的函数的积分:
- 定义两个点 a 和 b,它们是要绘制的积分的限制以及积分函数的数据:
a, b = 5, 9 # integral limits in which the area to be plotted
x = np.linspace(0, 10)
y = x ** 3 # 3rd order Polynomial curve
- 定义图形和轴域并绘制积分函数,在下限将 y 轴限制设置为
0
:
fig, ax = plt.subplots()
plt.plot(x, y, 'r', linewidth=2)
plt.ylim(0)
- 在
a
和b
的两个边界之间绘制阴影区域:
intx = np.linspace(a, b)
inty = intx ** 3
verts = [(a, 0)] + list(zip(intx, inty)) + [(b, 0)]
poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
ax.add_patch(poly)
- 将积分函数作为文本嵌入到绘图中:
plt.text(0.5 * (a + b), 60, r"$\int_a^b f(x)\mathrm{d}x$",
horizontalalignment='center', fontsize=20)
- 绘制 x 和 y 轴符号:
x
和y
:
plt.figtext(0.9, 0.1, 'x', size=20)
plt.figtext(0.1, 0.9, 'y', size=20)
- 使右轴线和上轴线不可见:
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
- 设置 x 轴的刻度和刻度标签,并且不设置 y 轴的刻度:
ax.set_xticks((a, b))
ax.set_xticklabels(('a=5', 'b=9'), size=15)
ax.set_yticks([])
plt.show()
工作原理
这是代码的说明:
a
和b
是我们需要绘制面积的积分限制。x
是 50 个(默认)值的数组,均等分布在 0 到 10 之间,y
是 x 的三阶多项式。plt.plot(x, y, 'r', linewidth=2)
绘制多项式曲线,plt.ylim(0)
将 y 轴的下限设置为 0。intx
是在a
和b
之间平均分布的 50 个点的数组。inty
是与intx
中的 50 个点相对应的 50 个点的数组,它们落在a
和b
之间的多项式曲线上。verts
是形成从点(a,0)
到intx
和inty
以及随后的(b,0)
形成的所有点的多项式的点的列表。poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
使用facecolor=0.9
(接近白色)和edgecolor=0.5
(灰色)定义verts
数组中所有点形成的多边形。ax.add_patch(poly)
将poly
色块添加到轴域上。plt.text()
在(0.5*(a+b), 60)
坐标处加上fontsize
为20
的文本。- 在数学表达式中,以下内容适用:
int
是整数符号_a
是下标a
,它是积分的下限^b
是作为积分上限的上标f(x)
保持原样mathrm{d}
指定要以罗马字体打印d
x
将按原样打印
plt.figtext(0.9, 0.1, 'x', size=20)
是在图形坐标系上绘制的文本,并绘制了大小为 20 的 x 轴。类似地, y 轴绘制为(0.1, 0.9)
在图形坐标系上。ax.spines['right'].set_visible(False)
设置右脊为不可见,ax.spines['top'].set_visible(False)
设置顶脊为不可见。ax.set_xticks((a, b))
在a
和b
设置刻度。ax.set_xticklabels(('a=5', 'b=9'), size=15)
将fontsize
设置为15
。
我们得到的输出如下:
定义自定义标记
在第 2 章和“基本绘图入门”中,我们学习了如何使用 Matplotlib 提供的预定义标记。 在这里,我们将学习如何定义我们自己的标记并使用它们绘制正弦曲线。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下是绘制每个标记的正弦曲线的代码:
- 定义用于绘制正弦曲线的数据:
x = np.arange(1, 2.6, 0.1)
y = np.sin(2 * np.pi * x)
- 定义图形和大小:
plt.subplots(figsize=(10,8))
- 定义自定义标记的列表:
custom_markers = ['$'+x+'$' for x in
['£','\$','\%','\clubsuit','\diamondsuit',
'\spadesuit','\heartsuit','\sigma', '" />']]
- 绘制每个标记的正弦曲线:
for i,marker in enumerate(custom_markers):
plt.plot(x, 2*(i+2)*y, marker=marker, markersize=15)
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
x
和y
是绘制正弦曲线的数据点。custom_markers
是自定义标记的列表; 它支持所有数学符号和 unicode 支持的表情符号。 这就是为什么需要将它们包含在'$....$'
中。for
循环绘制custom_markers
列表中每个标记的正弦曲线,markersize
为 15。
这是输出的样子:
小数,常规数学表达式和符号
在本秘籍中,我们将学习如何将小数,二项式,符号和数学表达式嵌入绘图以及属性(例如标签和标题)。 在每个图上绘制的函数与其中嵌入的各种文本元素均不相关。 它们全部旨在演示如何在图上打印各种文本元素。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
下面的代码块连续绘制两个图表,每个图表中有两个函数,并且每个图表上都有各种文本元素:
- 定义图形,大小和布局:
fig, ax = plt.subplots(1,2, figsize=(12,6))
- 定义要绘制的曲线的数据:
x = np.linspace(0, 9, 10)
y = 10*np.sqrt(x**2)
y1 = x ** 2
- 用数学表达式和数学符号绘制曲线和图例:
ax[0].plot(x, y, 'g', label=r'$y=10*\sqrt{x^2}$')
ax[0].plot(x, y1, 'b',label=r'$y={x^2}$')
ax[0].legend()
- 使用数学表达式和数学符号设置
x
和y
标签和标题:
ax[0].set_xlabel(r'$\Theta_i^j$', fontsize=20, color='#800080')
ax[0].set_ylabel(r'$\Theta_{i+1}^j$', fontsize=20, color='#800080')
ax[0].set_title(r'$\Delta_i^j \hspace{0.4} \mathrm{versus} \hspace{0.4} '
r'\Delta_{i+1}^j$', fontsize=20, color='m')
- 将 y 轴限制设置为 0 到 100,以便有足够的空间来嵌入图例和所有其他文本:
ax[0].set_ylim(0,100)
- 定义三个文本对象并将它们嵌入到相同的轴域上:
text1 = r'$\frac{2}{3} \binom{2}{3} \stackrel{2}{3}$'
text2 = r'$\left(\frac{3 - \frac{1}{x}}{2}\right)$'
text3 = r'$\mathcal{R}\prod_{i=\alpha_{i+1}}^\infty \gamma_i\/\sin(2 \pi f x_i)$'
ax[0].text(1.5, 60, text1, fontsize=20, va='bottom', color='b')
ax[0].text(1.5, 40, text2, fontsize=20, va='bottom', color='g')
ax[0].text(3.5, 0, text3, fontsize=20, va='bottom', color='r')
- 定义要在第二条轴域上绘制的曲线的数据:
A, B = 1, 2
t = np.arange(0.0, 4.0, 0.01)
s = A*np.sin(np.pi*t)
c = B*np.cos(np.pi*t)
- 绘制正弦曲线和余弦曲线,并以它们的函数作为标签:
ax[1].plot(t,s, label=r'$\mathcal{A}\mathrm{sin}(2 \omega t)$')
ax[1].plot(t,c, label=r'$\mathcal{B}\mathrm{cos}(2 \mathit{\omega} t)$')
- 使用数学符号设置标题以及 x 和 y 轴标签和图例:
ax[1].set_title(r'$\alpha_i > \beta_i$', fontsize=20, color='#A1F92F')
ax[1].set_xlabel('time (s)', labelpad=20, color=(0.25, 0.5, 0.9))
ax[1].set_ylabel('Amplitude', color=(0.25, 0.5, 0.9))
ax[1].legend(bbox_to_anchor=(1.02, 1.05), borderaxespad=2)
- 用数学表达式和数学符号嵌入文本:
ax[1].text(1.9, -0.6, r'$\sum_{i=0}^\infty x_i$', fontsize=20, color='#808080')
- 调整绘图之间的空间,并在屏幕上显示图形:
plt.tight_layout()
plt.show()
工作原理
现在让我们看看这段代码是如何工作的:
-
x
,y
和y1
定义要在第一张图表上绘制的两条曲线的数据 -
label=r'$y=10*\sqrt{x^2}$'
定义了以绿色绘制的第一条曲线的标签- 它是一个正则表达式,因此包含在
r'......'
中 sqrt
是数学符号,因此整个表达式都包含在$ ..... $
中
- 它是一个正则表达式,因此包含在
-
同样,打印第二条曲线的
label
(以blue
颜色绘制) -
在
Theta_i^j
中,Theta
表示大写希腊字母Θ
,'*_*'
表示下标,'*^*'
表示上标。 -
在
r'$\Delta_i^j \hspace{0.4} \mathrm{versus} \hspace{0.4}
和r'\Delta_{i+1}^j$'
中,'
连接两个正则表达式,它们跨越两行:Delta_i^j
代表大写希腊字母Δ
,其中下标为i
和上标为j
hspace{0.4}
代表之间的空白mathrm{versus}
以罗马字体打印versus
(mathrm
中的rm
代表罗马)Delta_{i+1}^j
是Δ
,带有下标i + 1
和上标j
-
在
r'$\frac{2}{3} \binom{2}{3} \stackrel{2}{3}$'
中:frac{2}{3}
在 3 上打印 2,中间有一条水平线,frac
代表小数binom{2}{3}
在括号内打印 2 和 3stackrel{2}{3}
在 3 上面堆叠打印 2
-
在
r'$\left(\frac{3 - \frac{1}{x}}{2}\right)$'
中:'left('
打印横跨整个表达式的左方括号"("
"right)"
打印右关闭括号")"
frac
是分数,其工作方式与之前所述的相同
-
在
r'$\mathcal{R}\prod_{i=\alpha_{i+1}}^\infty \gamma_i\/\sin(2 \pi f x_i)$'
中,以下内容适用mathcal{R}
以书法字体打印R
(mathcal
中的cal
代表书法):prod
以大字体打印大写希腊字母Π
prod
之后的"*_*"
是下标,但与prod
和sum
之类的大符号一起使用时,它的工作原理略有不同。alpha
是小写希腊字母α
infty
打印无穷大符号∞
gamma
打印小写希腊字母γ
\/
打印空白(类似于hspace
)sin
代表正弦函数pi
打印小写希腊字母π
。
-
ax[0].text()
在指定为前两个参数的 x 和 y 坐标的ax[0]
轴域上打印文本,然后以指定的字体大小,对齐方式和颜色在要打印的图形上打印文本。 -
在
ax[1]
轴域上,我们分别绘制了振幅为 A 和 B 的正弦和余弦曲线。 -
mathcal
打印书法字体,mathrm
打印罗马字体,mathit
打印斜体字体。 -
omega
打印小写希腊字母ω
,alpha
打印小写希腊字母α
,beta
打印小写希腊字母β
。 -
sum
以大字体打印大写希腊字母∑
。
我们得到以下输出:
更多
让我们举一个实际的例子,结合使用文本框和数学符号。
让我们为正态分布生成随机数并绘制直方图。 然后,我们将该直方图的描述性统计信息作为图形框嵌入文本框中。 以下代码块为我们做到了:
- 导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import kurtosis, skew
- 设置可重复性的种子,使用大小和轴域定义图形:
np.random.seed(19681211)
fig, ax = plt.subplots(figsize=(8,5))
- 定义直方图的数据,并计算此分布的描述统计量:
x = np.random.normal(25, 5, 25000)
mu = x.mean()
median = np.median(x)
sigma = x.std()
minimum = x.min()
maximum = x.max()
kurt = kurtosis(x)
skw = skew(x)
- 定义一个包含所有描述性统计量的文本字符串:
textstr =
'$\mathrm{min}=%.2f$\n$\mathrm{max}=%.2f$\n$\mathrm{median}=%.2f$\n$\mathcal{ \mu=%.2f}$\n
$\mathcal{\sigma=%.2f}$\n\$\mathit{kurtosis}=%.2f$\n$\mathit{skew}=%.2f$\n'
% (minimum, maximum, median, mu, sigma, kurt, skw)
- 绘制直方图:
ax.hist(x, 50)
- 定义要在其中放置描述性统计信息的边界框的属性:
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
- 在轴域坐标的左上方放置一个文本框:
ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14,
verticalalignment='top', bbox=props)
- 在屏幕上显示该图:
plt.show()
您应该从此代码块获得以下输出:
二维的词嵌入
对于自然语言处理(NLP)应用,由于机器只能处理数字数据,因此需要以数字格式表示单词。 在数字数组中表示单词的过程称为“单词嵌入”,因为这些数组(单词表示形式)中的每一个都是 n 维空间中的一个点,其中n
是维数/特征数(数组)代表每个单词。
根据 NLP 应用的类型,对机器学习(ML)算法进行了训练,以学习单词表示。 单词表示的典型长度可以在 50 到 300 维之间变化,这是无法可视化或理解的。 使用降维技术(例如 PCA 或 t-SNE),可以将该高维空间缩小为二维或三维空间,以便可以将其绘制在图形上以可视化相似词是否彼此接近 。 如果是这样,那么我们的机器学习算法就可以正常工作; 否则,事实并非如此。
对于此示例,我采用了用跳过语法算法学习的单词表示,并使用 t-SNE 算法将其简化为二维空间。 在此秘籍中绘制了最终的二维输出。
对于同一示例,我们还将在第 11 章和“使用 mplot3d 工具包”的 3D 图中看到三维表示形式和相应的图。
准备
导入所需的库。 请注意,pickle
是一个 Python 包,用于以二进制格式保存和检索文件。 我们将在这里使用它来加载以前保存的二维单词表示形式和一个单词字典,该单词字典将数字表示形式映射到将在绘图上显示的文本单词:
import matplotlib.pyplot as plt
import pickle
操作步骤
以下步骤实现了所需的逻辑:
- 使用
pickle
加载数据:
twod_embeddings = pickle.load(open('twod_embeddings','rb'))
reverse_dictionary = pickle.load(open('word_reverse_dictionary','rb'))
- 使用
rcParams
设置图形参数:
plt.rcParams['axes.labelsize'] = 20
plt.rcParams['axes.labelweight'] = 'bold'
plt.rcParams['xtick.labelsize'] = 15
plt.rcParams['ytick.labelsize'] = 15
- 定义图形和轴域:
fig, ax = plt.subplots(figsize=(20,20))
- 绘制散点图并使用
annotate
嵌入单词:
num_points = 400
words = [reverse_dictionary[i] for i in range(1, num_points+1)]
for i, label in enumerate(words):
x, y = twod_embeddings[i,:]
ax.scatter(x, y)
ax.annotate(label, xy=(x, y), xytext=(5, 3), textcoords='offset points',ha='right', va='bottom')
- 设置标签:
ax.set_xlabel('X')
ax.set_ylabel('Y')
- 在屏幕上显示图:
plt.show()
工作原理
这是前面代码的解释:
twod_embeddings = pickle.load(open('twod_embeddings','rb'))
加载二维单词表示。 如前所述,pickle
是 Python 包,用于以二进制格式保存和检索文件。 我们正在从twod_embeddings
文件加载数据,'rb'
表示以二进制格式读取。reverse_dictionary = pickle.load(open('word_reverse_dictionary','rb'))
加载用于将数字映射到相应文本单词的单词字典,该单词字典将显示在绘图上。plt.rcParams['axes.labelsize'] = 20
设置 x 和 y 轴labelsize
。plt.rcParams['axes.labelweight'] = 'bold'
设置 x 和 ylabelweight
。plt.rcParams['xtick.labelsize'] = 15
设置 x 轴刻度值的大小。plt.rcParams['ytick.labelsize'] = 15
设置 y 轴刻度值的大小。fig, ax = plt.subplots(figsize=(20,20))
定义并实例化绘制绘图的图形和轴域。num_points = 400
,我们仅绘制前 400 个单词。 我们使用 t-SNE 算法在减小大小的同时设置了此限制,因为超过此数量可能会导致绘图中的单词重叠。words = [reverse_dictionary[i] for i in range(1, num_points+1)]
创建一个包含 400 个单词的列表,reverse_dictionary
存储这些单词,它们的索引从 1 到 400+(训练集的总词汇量)开始。x, y = twod_embeddings[i,:]
从twod_embeddings
降维数组中读取单词的坐标,并将其映射到x
和y
。ax.scatter(x, y)
绘制由x
和y
坐标表示的单词。ax.annotate(label, xy=(x, y), xytext=(5, 3), textcoords='offset points',ha='right', va='bottom')
在绘制的点旁边绘制相应的单词,label
表示该单词。 此外,xy
表示要标注的点的坐标,xytext
表示要绘制文字的坐标;textcoords
指定xytext
的坐标系,最后ha
和va
指定文本的水平和垂直对齐。ax.set_xlabel('X')
设置 x 轴标签。ax.set_ylabel('Y')
设置 y 轴标签。plt.show()
在屏幕上显示绘图。
在运行前面的代码时,您应该得到如下图。 稍后将以红色圆圈标记的单词组添加到图中,以表示相似的单词彼此相邻显示,这表明学习算法做得相当好:
七、以不同格式保存图形
在本章中,我们将学习如何使用以下秘籍将图形保存为可以打印或嵌入其他应用的各种格式:
- 以多种格式保存图形
- 保存图形时避免截断
- 保存部分图形
- 管理图像分辨率
- 管理 Web 应用的透明度
- 创建多页 PDF 报告
介绍
Matplotlib 创建的报告和仪表板可以以不同的方式使用。 它们可以在上游 Web 应用中使用,它们可以作为 PDF 文件分发,可以嵌入到 GUI 工具箱中,或者可以交互方式在线使用。
在本章中,我们将学习如何以各种格式保存报告,以便可以将它们分发给使用者以直接使用(例如 PDF 格式),也可以嵌入到其他应用(例如 GUI 工具箱)中。
以多种格式保存图形
Matplotlib 支持 PNG,SVG,SVGZ,PDF,PS 和 EPS 格式以保存图形。 我们需要在计算机上拥有各自的阅读器,才能查看这些输出格式。 在本秘籍中,我们将学习如何以所有这些格式保存直方图。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块绘制了一个直方图,并将其保存为 Matplotlib 支持的所有格式:
- 设置可重复性的种子,并使用大小定义图形:
np.random.seed(19681211)
plt.figure(figsize=(6,4))
- 定义直方图的数据,对其进行绘制,然后将
ylabel
设置为histogram
:
nd = np.random.normal(25, 5, 10000)
plt.hist(nd)
plt.ylabel('histogram')
- 创建所有受支持的文件扩展名的列表:
file_ext = ['png', 'pdf', 'svg', 'svgz','eps','ps']
- 使用
for
循环将图形保存为以下每种文件格式,然后在屏幕上显示图形:
for extension in file_ext:
print('saving Histogram.%s ' % (extension))
plt.savefig('Histogram.%s' % (extension), dpi=300)
plt.show()
工作原理
这是代码的说明:
plt.hist(nd)
绘制带有随机生成的nd
数据的直方图。plt.ylabel('histogram')
将 y 轴标记为histogram
。file_ext
是所有支持的文件格式的列表。for
循环显示以所有格式保存的图形。plt.savefig()
将图形保存为名称Histogram.file_ext
,例如Histogram.png
,Histogram.pdf
等。plt.savefig()
类似于在屏幕上显示图形的plt.show()
,而plt.savefig()
以指定的格式将图形发送到工作目录。
您可以在同一个会话中使用这两种方法,就像我们在此处所做的那样,以便它将指定格式的文件保存到工作目录中,并在屏幕上显示它。
您可以打开保存在工作目录中的文件并查看保存的图形的外观时,我们已裁剪了 PDF,SVG 和 PNG 格式的图像,并在此处显示以供参考。 打开并查看相应的文件时,应该看到以下屏幕截图:
请注意,标题不属于所保存的图像; 它们已添加到图像上,以显示哪个图像属于哪种输出格式。
更多
在plt.savefig()
调用中,可以使用facecolor
和edgecolor
和许多其他选项来修改图形,然后再将其保存为所选格式。 我们将在以下秘籍中探讨其中一些内容。
默认情况下,Matplotlib 查看文件名中指定的文件扩展名,以决定图形需要保存的格式。 您也可以使用·参数指定输出格式,在这种情况下,它将忽略指定的文件扩展名,并以·参数指定的格式保存图形。 但是,当您尝试打开文件阅读器时,文件阅读器可能会与文件扩展名不匹配以及其实际保存格式混淆。
保存图形时避免截断
当您使用所有默认选项保存图形时,有时它可能会被截断。 在本秘籍中,我们将学习如何避免此类问题。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块绘制了一个直方图,并使用bbox_inches='tight'
参数将其保存为默认参数,然后添加pad_inches=1
:
- 设置可重复性的种子,并用
figsize
定义figure
:
np.random.seed(19681211)
plt.figure(figsize=(6,4))
- 定义直方图的数据,绘制直方图,然后设置
ylabel
:
nd = np.random.normal(25, 5, 10000)
plt.hist(nd)
plt.ylabel('histogram', labelpad=20)
- 创建所有受支持的文件格式的列表:
file_ext = ['png', 'pdf', 'svg', 'svgz','eps','ps']
- 对于每个文件扩展名,使用
bbox_inches='tight'
参数并添加pad_inches=1
参数将图形保存为默认模式:
for extension in file_ext:
print('saving Histogram_truncated.%s ' % (extension))
plt.savefig('Histogram_truncated.%s' % (extension), dpi=300)
print('saving Histogram_tight.%s ' % (extension))
plt.savefig('Histogram_tight.%s' % (extension), dpi=300,
bbox_inches='tight')
print('saving Histogram_tight_padded.%s ' % (extension))
plt.savefig('Histogram_tight_padded.%s' % (extension), dpi=300,
bbox_inches='tight', pad_inches=1)
plt.show()
工作原理
这是代码的解释:
plt.ylabel('histogram', labelpad=20)
将ylable
绘制为'histogram'
,并将其从 y 轴轴线放置 20 个单位。- 当
yticklabels
长时需要这样做,以使ylabel
与yticklabels
不重叠。 - 但是,保存图形时可能会导致截断,如以下图像所示,再次从此代码生成的各个输出文件中提取了图形。
前面的代码生成以下输出:
请注意,所有输出格式都缺少ylabel
!
现在让我们看一下在plt.savefig()
方法上使用bbox_inches='tight'
参数时生成的输出。 这实质上是尝试使整个图适合输出中包括标签文本的整个图形。 现在,您可以在 y 轴上看到直方图标签:
但是,如果ylabel
与 y 轴轴线相距太远,则即使此参数也无法避免截断。 您可以尝试更改labelpad=30
而不是 20,然后尝试保存该图。
从图中可以看到,上图太紧密地插入到输出中,沿外部边界没有太多空间。 这就是为什么我们必须将标题放在框内; 与之前不同,我们可以将标题放在方框上方!
因此,为了在边界上创建一些额外的空间,我们使用pad_inches=1
参数。 让我们看一下添加此选项后的输出图形:
现在,您可以在框的所有侧面看到更多的空间。
保存部分图形
有时,我们可能只想保存图形的一部分,尤其是当图形具有多个网格时。 在本秘籍中,我们将学习如何做。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
操作步骤
以下代码块在同一图中的两个轴域上绘制了极坐标图和直方图。 然后,它分别保存每个图,以演示保存图的一部分而不是整个图:
- 设置可重复性的种子并定义图:
np.random.seed(19681211)
plt.figure(figsize=(8, 6))
- 准备用于绘制极坐标图的数据:
N = 250
r = 10 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = r**2
colors = theta
- 在第一个轴域上绘制极坐标图:
ax1 = plt.subplot(121, projection='polar')
ax1.scatter(theta, r, c=colors, s=area, cmap='plasma', alpha=0.6)
ax1.set_title('Polar Plot', color='m', size=15, weight='bold')
- 在第二个轴域上绘制直方图:
ax2 = plt.subplot(122)
nd = np.random.normal(25, 5, 10000)
ax2.hist(nd, color='c', alpha=0.6)
ax2.set_title('Histogram', color='b', size=15, weight='bold')
- 调整绘图之间的空间,以确保没有重叠:
plt.tight_layout(pad=5, w_pad=2)
- 标记要保存区域的边界,并以 PNG 和 PDF 格式保存该区域:
bounds = np.array([[0.0,0.0], [4.1, 6.0]])
plt.savefig('polar.png', bbox_inches=Bbox(bounds))
plt.savefig('polar.pdf', bbox_inches=Bbox(bounds))
- 标记图的剩余区域的边界以单独保存:
bounds = np.array([[3.9,0.0], [8.0, 6.0]])
plt.savefig('hist.png', bbox_inches=Bbox(bounds))
plt.savefig('hist.pdf', bbox_inches=Bbox(bounds))
- 在屏幕上显示该图并清除画布区域:
plt.show()
plt.close()
工作原理
这是代码的说明:
ax1.scatter()
绘制极坐标图。ax2.hist()
都在一张图中绘制直方图。
您应该看到如下图:
bounds = np.array([[0.0,0.0], [4.1, 6.0]])
指定要保存的图形的边界。 它们代表要保存区域的左下角和右上角,并且它们在图形坐标系中。- 我们指定了
figsize=(8,6), [[0.0,0.0], [4.1, 6.0]]
,它代表图的左侧,[3.9,0.0], [8.0, 6.0]]
代表图的右半部分。
首先,让我们看一下极性和直方图输出的 PDF 版本:
现在,让我们看一下极坐标和直方图的 PNG 版本。 在这里,极坐标图从圆到椭圆有点失真:
管理图像分辨率
当输出文件中的图形需要打印在纸上时,打印输出的质量很重要。 关于照片购物的详细说明超出了本书的范围,但在这里我们将进行足够的介绍,以了解可用的参数,同时保存会影响打印输出质量的图形。
打印输出的质量取决于图像(保存的图像)中的像素数量,要在其上打印纸张的页面大小以及打印机分辨率。
通常,图像中的像素数取决于相机的分辨率,例如 5MP,7MP,10MP 等。 纸张大小由称为每英寸像素(PPI)的设置控制。 像素是图像的最小可测量元素,并且是微小的小正方形。 如果我们有一个600 x 400
像素的图像,并使用 100 PPI,则纸张大小将为6 x 4
英寸。 这就是用给定数量的像素,PPI 和以英寸为单位的大小创建图像的方式。
当要打印图像时,打印机具有另一种影响打印输出质量的分辨率,称为每英寸点数(DPI)。 它以英寸的长度(宽度相同)指定打印机需要喷射的墨水点数。 DPI 越高,一英寸长度内的墨水量越大,因此打印输出的质量越好。
因此,PPI 是创建图像时使用的分辨率的输入端。 DPI 是打印图像时使用的分辨率的输出端。 对于给定的设备,PPI 和 DPI 由制造商预先确定; 例如,计算机显示器具有固定的 PPI,而打印机具有固定的 DPI。
plt.savefig()
方法具有dpi
参数,该参数与图形大小一起以像素数确定图像(图形)的大小。 在这里,DPI 是错误的称呼; 理想情况下,它应该是 PPI。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下代码块绘制了一个直方图,并保存了两个不同的dpi
参数以进行比较:
- 设置种子并准备用于绘制直方图的数据:
np.random.seed(19681211)
nd = np.random.normal(25, 5, 10000)
- 用大小定义图并在其上绘制直方图:
plt.figure(figsize=(6,4))
plt.hist(nd)
- 在图上绘制网格线:
plt.grid()
- 使用
300
DPI 将图形保存为 PNG 格式,并将其显示在屏幕上:
plt.savefig('histogram_300.png', dpi=300)
plt.show()
- 定义另一个更大的图形,绘制直方图,并使用
100
DPI 将其保存为 PNG 格式:
plt.figure(figsize=(18,12))
plt.hist(nd)
plt.grid()
plt.savefig('histogram_100.png', dpi=100)
plt.show()
工作原理
这是代码的说明:
plt.figure(figsize=(6,4))
将图形大小设置为6 x 4
。plt.hist(nd)
绘制直方图。- 由于我们使用的是
dpi=300
,它将创建具有1,800 x 1200
像素(6 * 300 x 4 * 300
)的图形图像。
histogram_300.png
中保存的图形如下:
如果必须在100
DPI 打印相同的1800 x 1200
像素图形,则需要18 x 12
的图形大小。我们再次使用18 x 12
的大小和dpi=100
保存图形。 这是保存的输出的外观:
应该注意的是,与我们之前用dpi=300
和figsize=(6, 4)
保存的图形相比,刻度标签和网格线已经变得更小。 当您在较小的区域上展开相同数量的像素(宽度和高度)时,像素的密度将很高,质量也将很高。 因此,在创建和保存图形时,请选择图形大小和 DPI 设置以根据所需打印输出的质量为图形的宽度和高度创建尽可能多的像素。 宽度和高度的像素数越高,打印输出的质量越好。
管理 Web 应用的透明度
通常,Matplotlib 绘图和图形默认情况下具有白色背景,可以使用facecolor
参数将其更改为我们想要的任何颜色。 如果我们必须将这些数字嵌入到其他任何应用中,则该背景色将保留下来。 但是,Matplotlib savefig()
方法提供了一个选项,可以使用透明参数来保存没有此背景色的图形。 在本秘籍中,我们将学习如何使用此选项。
准备
我们将绘制四个图,将它们保存为普通模式和透明选项,然后将其嵌入 HTML 页面中以查看它们的外观。
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
操作步骤
以下代码块绘制了四个图形,并将它们保存为.png
格式:
- 设置可重复性的种子:
np.random.seed(19681211)
- 准备极坐标图的数据:
N = 250
r = np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 500 * r**2
colors = theta
- 用
size
定义图形并绘制极坐标图:
plt.figure(figsize=(6,4))
ax = plt.subplot(111, projection='polar')
c = ax.scatter(theta, r, c=colors, s=area, cmap='plasma', alpha=0.6)
plt.title('Polar Plot', color='m', size=15, weight='bold')
- 将图形保存为 PNG 格式,并将
transparent
设置为True
,然后在屏幕上显示该图形:
plt.savefig('polar_transparent.png', dpi=300, transparent=True)
plt.show()
- 使用
size
定义另一个图形,准备直方图的数据,然后绘制它:
plt.figure(figsize=(6,4))
nd = np.random.normal(25, 5, 10000)
plt.hist(nd, color='c', alpha=0.6)
plt.title('Histogram', color='b', size=15, weight='bold')
- 将图形保存为 PNG 格式,并将
transparent
设置为True
:
plt.savefig('Histogram_Transparent.png', dpi=300, transparent=True)
- 使用
size
定义另一个图,准备饼图数据并绘制:
plt.figure(figsize=(6,4))
labels = ['grocery', 'transportation', 'apparel', 'education',
'capital', 'savings', 'others']
percentage = [15, 5, 19, 8, 30, 13, 10]
explode = [0, 0, 0, 0, 0.1, 0, 0]
plt.pie(percentage, labels=labels, explode=explode,
autopct='%.1f%%', shadow=True)
plt.title('Pie Chart', color='r', size=15, weight='bold')
plt.axis('equal')
- 以 PNG 格式保存图形并将
transparent
设置为True
:
plt.savefig('Pie_Transparent.png', dpi=300, transparent=True)
plt.show()
- 使用
size
定义另一个图形,读取Iris
数据集,并绘制Iris
簇:
plt.figure(figsize=(6,4))
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
x,y = iris['petal_length'], iris['petal_width']
classes = set(iris['species'])
for name in classes:
index = iris['species'] == name
plt.scatter(x[index], y[index], s=20*x[index]*y[index], marker='o', label=name, alpha=0.6)
plt.legend()
plt.title('Iris Classification', color='g', size=15, weight='bold')
- 将图形保存为 PNG 格式,并将
transparent
设置为True
:
plt.savefig('iris_Transparent.png', dpi=300, transparent=True)
plt.show()
工作原理
所有这些图对我们来说已经很熟悉了,因此无需解释绘制它们的代码。 但是,以下是保存绘图的代码的说明:
plt.savefig('polar_transparent.png', dpi=300, transparent=True)
保存图形。transparent=True
使您可以在没有任何背景颜色的情况下打印图表。- 该参数的默认值为
False
。 - 当您要将这些图形嵌入到具有所需背景的任何应用中时,请使用
transparent=True
选项保存图形。 - 我们还保存了没有
transparent=True
选项的这些数字,并以_opaque
而不是_transparent
命名它们。 - 然后,我们将它们嵌入到两个 html 页面中。 我们用作浅蓝色作为 HTML 页面的背景色。
以下是 HTML 页面的图像,其中我们没有使用transparent=True
选项来保存图形:
以下是 HTML 页面的图像,我们在其中使用了transparent=True
选项来保存图形:
从 HTML 页面可以看出,在第一个 HTML 页面中继承的白色背景和 HTML 背景颜色在图的边界之外,在图的边界内可见。
在第二个 HTML 页面中,绘图没有任何背景色,因此 HTML 背景颜色在每个绘图中均可见。
创建多页 PDF 报告
在本秘籍中,我们将学习如何创建包含多张包含多个图形的多页 PDF 文档。 如果您必须为特定用户或部门创建一堆报告并将其作为一个文档发送,这将很方便。
准备
我们将创建三个图形,每个图形有两个图,并将每个图形放置在 PDF 文档的一页中。
让我们导入所需的库:
import datetime
import numpy as np
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt
import calendar
操作步骤
以下代码块绘制了所需的图表,并将它们作为三个单独的页面保存到 PDF 文档中。 所有这些图都已在较早的章节中使用过,因此绘制每个图的细节已经为您所熟悉。 在这里,重点是如何排列这些图表以将其保存在 PDF 文档的各个页面中:
- 设置可重复性的种子:
np.random.seed(19681211)
- 定义一个绘制极坐标图的函数:
def Plot_Polar():
plt.figure(figsize=(6, 4))
N = 250
r = 10 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = r**2
colors = theta
ax1 = plt.subplot(121, projection='polar')
ax1.scatter(theta, r, c=colors, s=area, cmap='plasma',
alpha=0.6)
ax1.set_title('Polar Plot', color='m', size=15, weight='bold')
- 定义一个函数来绘制直方图:
def Plot_Histogram():
ax2 = plt.subplot(122)
nd = np.random.normal(25, 5, 10000)
n, bins, patches = ax2.hist(nd, color='c', alpha=0.6)
n, bins, patches = ax2.hist(nd, color='c', alpha=0.6, density=1)
mu, sigma = 25, 5
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 /
sigma * (bins - mu))**2))
ax2.plot(bins, y, '--')
ax2.set_title('Histogram', color='b', size=15, weight='bold')
- 定义一个绘制饼图的函数:
def Plot_Pie():
plt.figure(figsize=(8, 6))
ax1 = plt.subplot(121)
labels = ['grocery', 'transportation', 'apparel', 'education',
'capital', 'savings', 'others']
percentage = [15, 5, 19, 8, 30, 13, 10]
explode = [0, 0, 0, 0, 0.1, 0, 0]
ax1.pie(percentage, labels=labels, explode=explode,
autopct='%.1f%%', shadow=True)
ax1.set_title('Expenses Pie Chart', color='r', size=15,
weight='bold')
ax1.axis('equal')
- 定义一个函数以绘制
Iris
群集图:
def Plot_iris():
ax2 = plt.subplot(122)
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
x,y = iris['petal_length'], iris['petal_width']
classes = set(iris['species'])
for name in classes:
index = iris['species'] == name
ax2.scatter(x[index], y[index], s=20*x[index]*y[index],
marker='o', label=name, alpha=0.6)
ax2.legend()
ax2.set_title('Iris Classification', color='g', size=15,
weight='bold')
- 定义一个绘制条形图的函数:
def Plot_Bar():
fig = plt.figure(figsize=(10, 8))
ax1 = plt.subplot(121)
month_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
units_sold = [500, 600, 750, 900, 1100, 1050, 1000, 950, 800,
700, 550, 450]
plot = ax1.bar(month_num, units_sold)
plt.xticks(np.arange(12)+1, calendar.month_name[1:13],
rotation=75)
for rect in plot:
height = rect.get_height()
ax1.text(rect.get_x() + rect.get_width()/2.,
1.002*height,'%d' % int(height),
ha='center', va='bottom')
ax1.set_title('Batteries Sold', color='y', size=15,
weight='bold')
return fig
- 定义一个绘制流图的函数:
def Plot_Steamplot(fig):
ax2 = plt.subplot(122)
x, y = np.linspace(-3,3,100), np.linspace(-2,4,50)
X, Y = np.meshgrid(x, y)
U = 1 - X**2
V = 1 + Y**2
speed = np.sqrt(U*U + V*V)
# Varying line width along a streamline
lw = 5*speed / speed.max()
strm = ax2.streamplot(X, Y, U, V, density=[0.5, 1], color=V,
linewidth=lw)
fig.colorbar(strm.lines, plt.axes([0.95, 0.125, 0.03, 0.75]))
ax2.set_title('Varying Density, Color and Line Width')
- 定义一个函数来更新文档属性:
def Set_Doc_Properties():
doc_prop = pdf.infodict()
doc_prop['Title'] = 'Multipage PDF Reports'
doc_prop['Author'] = 'P Srinivasa Rao'
doc_prop['Subject'] = 'saving matplotlib plots in a pdf
document'
doc_prop['Keywords'] = 'PdfPages multipage author title subject'
doc_prop['CreationDate'] = datetime.datetime(2018, 7, 24)
doc_prop['ModDate'] = datetime.datetime.today()
- 定义用于创建多页 PDF 报告的主程序:
with PdfPages('pdf_reports.pdf') as pdf:
# Page1
Plot_Polar()
Plot_Histogram()
plt.suptitle('Page One', color='C5', size=20, weight='bold')
plt.tight_layout(pad=5, w_pad=2)
pdf.attach_note("polar & histogram")
pdf.savefig(dpi=300)
plt.show()
plt.close()
# Page2
Plot_Pie()
Plot_iris()
plt.suptitle('Page Two', color='C8', size=20, weight='bold')
pdf.attach_note("pie and scatter")
plt.tight_layout(pad=5, w_pad=10)
pdf.savefig(dpi=300)
plt.show()
plt.close()
# Page3
fig = Plot_Bar()
Plot_Steamplot(fig)
plt.suptitle('Page Three', color='C9', size=20, weight='bold')
pdf.attach_note("bar & stream")
pdf.savefig(dpi=300)
plt.show()
plt.close()
# Set document properties
Set_Doc_Properties()
工作原理
这是代码的说明:
-
PdfPages()
是有助于创建 PDF 文档的包。 -
with PdfPages('pdf_reports.pdf') as pdf
是 Python 上下文,在我们将多个图形保存到此 PDF 文档中时,它负责文件的打开和关闭。pdf_reports.pdf
文件是保存数字的文件。 -
plt.figure(figsize=(6, 4))
定义大小为(6, 4)
的第一个图形:ax1.scatter(theta, r, c=colors, s=area, cmap='plasma', alpha=0.6)
在第一个轴域上绘制极坐标图。ax2.hist(nd, color='c', alpha=0.6, density=1)
在第二轴域上绘制直方图。ax2.plot(bins, y, '--')
在同一轴域上绘制了直方图的最佳拟合概率密度函数。plt.suptitle('Page One', color='C5', size=20, weight='bold')
绘制具有已定义属性的图形标题(第一页)。pdf.attach_note("polar & histogram")
按照参数中的说明为该页面编写标注,当我们打开 PDF 文档页面作为标注时,该标注将可见。pdf.savefig(dpi=300)
将具有dpi=300
的当前图形保存到上下文中指定的 PDF 文档中。plt.show()
在屏幕输出上显示数字。plt.close()
关闭图形并清理绘图区域,以便可以开始下一个图形。
-
plt.figure(figsize=(8, 6))
定义第二个图形,其大小为(8, 6)
:ax1.pie(percentage, labels=labels, explode=explode, autopct='%.1f%%', shadow=True)
在第一个轴域上绘制了支出饼图。ax2.scatter(x[index], y[index], s=20*x[index]*y[index], marker='o', label=name, alpha=0.6)
在第二轴域上绘制了鸢尾花的散布图。plt.suptitle('Page Two', color='C8', size=20, weight='bold')
绘制图形的标题(Page Two
)。pdf.savefig(dpi=300)
将图形保存到下一页上的相同 PDF 文档。plt.show()
将图形显示在屏幕上。plt.close()
关闭图形并清除下一个图形的绘图区域。
-
fig = plt.figure(figsize=(10, 8))
定义大小为(10, 8)
的下一个图形:plot = ax1.bar(month_num, units_sold)
在一个轴域上绘制条形图。ax1.text()
在每个条形上写入单位数。ax2.streamplot(X, Y, U, V, density=[0.5, 1], color=V, linewidth=lw)
在两个轴域上绘制流图。fig.colorbar(strm.lines, plt.axes([0.95, 0.125, 0.03, 0.75]))
绘制流图的颜色条。plt.suptitle('Page Three', color='C9', size=20, weight='bold')
设置图形的标题(Page Three
):
-
doc_prop = pdf.infodict()
实例化包含文档属性的字典,当我们打开 PDF 文档时可以在属性中看到。 我们保存了Title
,Author
,Subject
,Keywords
,CreationDate
和ModifiedDate
进入该字典,该字典将传递给文档属性。 -
运行此代码后,您应该在工作目录中看到一个名为
pdf_reports.pdf
的 PDF 文档。 如果您打开文档,您应该看到以下三个图为三页。 正如我们在代码中定义的那样,它们每个都有不同的大小:
八、开发交互式绘图
交互式绘图是一个非常大的主题。 有很多书籍涵盖了它的各个方面。 在本章中,我们将涵盖三个不同的领域,每个领域都有关键秘诀,如下所示:
- 事件和回调:
- 异常处理
- 按键和释放事件,用于使图例在保持时间内可见/不可见
- 按键按下事件,用于进行缩放
- 运动通知和按键按下事件,用于跟踪坐标
- 选择活动,用于在选择图例标签后激活艺术家
- 图形和轴域进入和离开事件,用于更改前景颜色并使艺术家可见/不可见
- 使用双生轴域绘制四个温度刻度
- 小部件:
- 光标
- 按键
- 复选按键
- 单选按键
- 文本框
- 动画:
- Sigmoid 动画
- 将动画保存到 MP4 文件
tan
函数呈指数衰减- 气泡图动画
- 多个线形图的动画
- 图像动画
介绍
对于交互式绘图,通常的%matplotlib inline
不起作用,因为它将静态图形输出到屏幕,需要使用 Matplotlib 支持的后端之一。 您可能还记得后端是 Matplotlib 架构的最底层,其中发送了 Matplotlib 创建的输出图进行显示。 后端有两种类型:一种允许用户与输出交互并用于交互式绘图,另一种用于保存图形以供打印或嵌入到其他应用中。
本章中的所有秘籍均通过以下后端进行了测试:
nbAgg
Qt5Agg
TkAgg
WXAgg
我们已经观察到某些功能不适用于某些后端。
使用以下选项之一激活这些后端中的任何一个:
import matplotlib
matplotlib.use('nbAgg')
或使用此:
import matplotlib.pyplot as plt
plt.switch_backend('nbAgg')
如果选择第一个选项,则必须在导入matplotlib.pyplot
模块之前执行此代码,因为pyplot
模块将加载所选后端所需的所有元素。 默认情况下,pyplot
会按照和rcParams
文件的定义加载后端,如果这些语句是在导入pyplot
之后执行的,则模块可能与此后端冲突。
如果您选择第二个选项,则pyplot
将通过加载新后端的相关模块将当前后端替换为新后端。 为了使其正常工作,在切换到新后端之前应该已经设置了一些后端。
nbAgg
是 Jupyter 笔记本使用的标准后端,它显示在笔记本的输出单元中,而其他后端则打开另一个用于输出的弹出窗口。
所有这些交互式后端均提供标准的交互式导航功能,尽管外观略有不同。 Matplotlib 文档位于这个页面中,提供了各种功能的导航和键盘映射的详细说明。
事件和回调
事件是用户与绘图进行交互时所执行的操作,例如鼠标操作,键盘单击或只是在可视化文件上输入和退出图形和轴域。 回调是事件触发时对事件的响应。 程序运行时引发的异常也是事件。 但是,除了KeyboardInterrupt
以外,大多数都不涉及用户干预。
虽然我们尝试在此处涵盖尽可能多的事件,但要获取受支持事件的完整列表,请参阅 Matplotlib 文档。
异常处理
在运行程序的过程中,会引发许多不同的异常。 如果未编写适当的操作,则程序将崩溃,并且需要紧急干预来解决问题并重新启动程序。 在本秘籍中,我们将学习如何处理两个异常KeyboardInterrupt
和DivideByZero
及其相应的回调动作。
准备
为了模拟异常,我们将开始运行直到异常发生的循环,捕获异常,触发合适的回调响应函数,最后关闭程序。
对于KeyboardInterrupt
异常,一旦程序启动,您将在笔记本的“输入”单元中看到*
,单击笔记本顶部的内核选项卡,然后按下拉框中的中断选项。
如果 30 秒内没有KeyboardInterruption
,则它将执行代码,从而导致DivideByZero
异常。
导入所需的库:
import time
操作步骤
我们将使用适当的方法编写一个类来模拟循环,并捕获异常和回调函数。 为了便于说明,我们提供了该类中各种方法的逐步说明; 为了执行,您将必须立即采用整个类来运行代码。 请参考本章提供的代码文件:
- 定义类:
class EventLoop:
- 定义
init
方法以初始化状态变量,并定义event_handlers
字典,该字典将事件映射到和对应的回调函数:
def __init__(self):
self.status = None
self.event_handlers = {"interrupt": self.handle_interrupt,
"DivideByZero": self.handle_DivideByZero}
- 定义
start()
方法以运行循环,捕获异常并为每个异常调用对应的回调函数:
def start(self):
try:
self.loop()
except KeyboardInterrupt:
self.handle_event("interrupt")
except ZeroDivisionError:
self.handle_event("DivideByZero")
finally:
print('Ending the program')
- 定义创建和运行事件循环的方法:
def loop(self):
self.status = "loop"
strt_time = time.time()
while self.status == "loop":
elapsed_time = time.time() - strt_time
if elapsed_time > 30:
5 / 0
- 定义处理事件/异常的方法:
def handle_event(self, event: str):
self.event_handlers[event]()
- 为
KeyBoardInterrupt
异常的回调操作定义方法:
def handle_interrupt(self):
print("Stopping event loop Due to KeyboardInterrupt...")
- 为
DivideByZero
异常的回调操作定义方法:
def handle_DivideByZero(self):
print("Stopping event loop due to DivideByZero Error...")
- 实例化类对象并调用
start
方法:
el = EventLoop()
el.start()
工作原理
以下是其工作原理的说明:
class EventLoop:
定义事件循环的类函数。__init__(self)
是EventLoop
类对象的初始化函数。 它会初始化status
变量,并使用两个具有相应回调函数的中断来定义event_handlers
字典。start(self)
是启动EventLoop
,捕获异常并将各自的回调函数路由到的方法:try: self.loop()
运行loop
方法。exceptKeyboardInterrupt: self.handle_event("interrupt")
捕获KeyBoardInterrupt
,并用interrupt
参数调用handle_event
方法。exceptZeroDivisionError: self.handle_event("DivideByZero")
捕获DivideByZero
异常,并使用DivideByZero
参数调用handle_event
方法。finally: print('Ending the program')
在循环结束时打印Ending the program
。 即使在发生异常的情况下也会执行此操作,在这种情况下,它将首先执行相应的回调函数,然后执行finally
子句下的代码。
loop(self)
是运行事件循环直到发生异常之一的方法。 当发生任何指定的异常时,控制就会退出循环,并移至方法中中except
中指定的异常处理方法:self.status
将变量状态设置为等于循环。start_time
是循环的开始时间。while self.status == "loop":
会启动循环并运行,只要状态保持循环或发生异常。elapsed_time
是从开始循环开始的时间。- 如果没有
KeyboardInterrupt
的时间超过 30 秒,则程序将进入if loop
的内部,并尝试将五除以零,从而导致DivideByZero
异常。
def handle_event(self, event: str): self.event_handlers[event]()
是采用异常/事件并在event_handlers
字典中查找以选择 [ 对应的callback
方法并对其进行调用。def handle_interrupt(self): print("Stopping event loop Due to KeyboardInterrupt...")
是KeyboardInterrupt
异常的callback
方法。 它仅显示以下消息:由于KeyboardInterrupt
异常而导致 , 事件循环停止。def handle_DivideByZero(self): print("Stopping event loop due to DivideByZero Error...")
是DivideByZero
异常的callback
方法。 它仅显示以下消息:由于DivideByZero
错误, , 事件循环正在停止。el = EventLoop()
实例化EventLoop
对象,el.start()
调用实例类的start
方法。
当您运行程序并从内核中断程序时,您应该在输出单元格中看到以下文本:
Stopping event loop Due to KeyboardInterrupt...
Ending the program
当您运行该程序并只是不执行任何操作时,在 30 秒后,您应该在输出单元格中看到以下文本:
Stopping event loop due to DivideByZero Error...
Ending the program
更多
Python 编程环境中有许多此类异常。 由于它们不涉及任何用户交互,因此它们与交互式绘图无关。 如果您有兴趣,可以在这里找到关于它们的详尽文献。
按下和释放事件
在本秘籍中,我们将学习如何捕获键盘press
和release
事件,并使用它们将图例的显示切换为可见/不可见并显示按键被按下的时间(按键事件和按键释放事件之间的时间差)。
按下X
键,保持一段时间,然后松开时,它会将图例的图例状态从可见变为不可见,或相反,并显示时间(单位为秒),在释放之前按住键多长时间。
如果按下,按住和释放任何其他键,则它将不会更改图中的任何内容,但是程序打印按下的键的名称和保持时间到sysout
。
当使用 Matplotlib 时,我们不需要显式创建事件循环,因为pyplot
模块会自动处理该功能。 仅当我们使用 Python 代码时才需要它,就像我们在前面的秘籍中所做的那样。
准备
导入所需的库并设置后端:
import numpy as np
import matplotlib.pyplot as plt
plt.switch_backend('Qt5Agg')
from time import time
操作步骤
这是带有图例和标题的sin
和cos
函数的绘图,并捕获键盘事件和相关的回调函数以响应键盘事件的代码:
- 定义一个响应
key_press_event
的回调函数:
def press(event):
global prst
prst = time()
print('press', event.key)
- 定义一个响应
key_release_event
的回调函数:
def release(event):
relt = time()
ht = relt - prst
print('hold time:',round(ht,2))
if event.key == 'x':
visible = lg.get_visible()
lg.set_visible(not visible)
tm = 'hold time: ' + str(round(ht, 2))
t = plt.text(np.random.randint(1,4),
np.random.randint(-3,4), tm)
plt.setp(t, color='r', size=15, weight='bold')
ax.add_artist(t)
fig.canvas.draw()
- 准备要绘制的曲线的数据:
x = np.arange(1, 2.6, 0.1)
y = 3*np.sin(2 * np.pi * x)
y1 = 3*np.cos(2 * np.pi * x)
- 实例化图形和轴域对象:
fig, ax = plt.subplots()
- 在轴域上绘制曲线:
ax.plot(x ,y, 'go-', label='sin')
ax.plot(x, y1, 'bd-', label='cos')
- 设置图例和标题:
lg = ax.legend(loc='upper center', fontsize=15)
ax.set_title('Press a key', size=25)
- 捕获事件并为每个事件映射回调函数:
fig.canvas.mpl_connect('key_press_event', press)
fig.canvas.mpl_connect('key_release_event', release)
- 在设置的后端上显示该图:
plt.show()
工作原理
以下是其工作原理的说明:
fig, ax = plt.subplots()
定义并实例化图形对象和轴域对象。ax.plot(x ,y, 'go-', label='sin')
和ax.plot(x, y1, 'bd-', label='cos')
绘制正弦和余弦函数。lg = ax.legend(loc='upper center', fontsize=15)
和ax.set_title('Press a key', size=25)
设置绘图的图例和标题。 在这里,我们将图例捕获到变量lg
中,稍后将在回调函数中使用。fig.canvas.mpl_connect()
是从后端捕获事件并将它们连接到相应的回调函数以响应事件的方法。 这等效于我们在先前秘籍中定义的 ,handle_event()
函数。fig.canvas.mpl_connect('key_press_event', press)
会在按下任何键时捕获,并调用"press"
回调函数。fig.canvas.mpl_connect('key_release_event', release)
在释放键时捕获,并调用"release"
回调函数。press
是callback
函数,可响应任何按键事件:- 回调函数以
event
作为参数,这是 Matplotlib 用来传递可捕获事件特定细节的预定义事件的关键字,在这种情况下,此事件为键的名称。 global prst
定义一个全局变量prst
,用于捕获按键按下的时间。 它被定义为全局变量,因为在中需要release
函数。prst = time()
捕获prst
变量中的当前时间,表示按下该键的时间。print('press', event.key)
将被按下的键的名称打印到sysout
中,您可以在笔记本电脑的输出单元中看到它,它声明为prst
并具有全局范围,我们不需要将其返回以传递给release
函数。
- 回调函数以
release
是另一个响应任何键释放事件的回调函数:- 它还将
event
作为第一个参数。 relt
捕获的当前时间,代表的键释放时间。ht
是按键被按下与释放之间经过的保持时间。print('hold time:', round(ht,2))
将保持时间打印到sysout
,将时间四舍五入到小数点后两位。if event.key == 'x':
检查所按下的键是否为x
; 如果是,那么它将执行如下指令集。 否则,它什么都不做:lg.get_visible()
获取lg
图例对象的当前状态true
或false
,以指示图例当前可见还是不可见,并将其状态分配给visible
对象。lg.set_visible(not visible)
反转当前状态,这意味着如果可见,则现在不可见,如果不可见,则现在将可见。tm = 'hold time: ' + str(round(ht, 2))
准备放置在图形上的保持时间的文本字符串。t = plt.text(np.random.randint(1,4), np.random.randint(-3,4), tm)
创建要放置在图形上随机位置的文字艺术家。plt.setp(t, color='r', size=15, weight='bold')
将颜色,大小和权重属性设置为先前定义的文本艺术家。ax.add_artist(t)
将文本艺术家添加到轴域。fig.canvas.draw()
最后在所选后端上显示输出图形。
- 它还将
运行该程序时,您应该在左侧看到该图。 按住X
键时,应该会显示图例切换,并且保持时间出现在绘图上。 当您按下G
键时,您应该在绘图上看到网格线。 然后,您应该在此处看到右侧显示的图:
请注意,后端导航具有一些具有特殊功能的键的映射,例如对于主页的h
,对于主网格的g
,在 y 轴上的对数刻度的l
,以及用于平移, 缩放,后退,前进,全屏等的一些其他键。 当按下这些键中的任何一个时,您将在绘图上看到其定义的功能,因此请不要与用户定义的功能混淆。 您可能要避免为这些键定义自己的功能,以免发生冲突。
鼠标按下事件
在本秘籍中,我们将学习如何捕获鼠标按键按下事件,并使用坐标在主窗口上按下和鼠标按键的点周围缩放绘图,并将其显示在[ 缩放窗口。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下步骤说明了如何编码和所需逻辑:
- 在主窗口和缩放窗口中定义图形和轴域:
figmain, axmain = plt.subplots()
figzoom, axzoom = plt.subplots()
- 设置主轴域和缩放轴域的属性:
axmain.set(xlim=(-5, 5), ylim=(-75, 175), autoscale_on=False, title='Click to zoom')
axzoom.set(xlim=(-2, 2), ylim=(-8, 8), autoscale_on=False, title='Zoom window')
- 准备绘图数据:
x = np.arange(-5, 5, 0.1)
y = x ** 3
- 在主轴域和缩放轴域上绘制相同的曲线:
axmain.plot(x, y, 'g-d')
axzoom.plot(x, y, 'b-.o')
- 定义响应鼠标按键按下事件的回调函数:
def onbuttonpress(event):
if event.button == 1: # left = 1, scroll=2, right=3
x, y = event.xdata, event.ydata
axzoom.set_xlim(x - 1, x + 1)
axzoom.set_ylim(y - 10, y + 10)
figzoom.canvas.draw()
- 将按键按下事件连接到回调函数:
figmain.canvas.mpl_connect('button_press_event', onbuttonpress)
- 在指定的后端显示数字:
plt.show()
工作原理
以下是前面代码的说明:
figmain, axmain = plt.subplots()
定义主窗口的图形和轴域,figzoom, axzoom = plt.subplots()
定义缩放窗口的图形和轴域。axmain.set(xlim=(-5, 5), ylim=(-75, 175), autoscale_on=False, title='Click to zoom')
设置属性,例如 x 和 y 轴限制,自动缩放是打开还是关闭,以及主轴域标题。axzoom.set(xlim=(-2, 2), ylim=(-8, 8), autoscale_on=False, title='Zoom window')
为缩放轴域定义了和相同的属性。x = np.arange(-5, 5, 0.1)
和y = x ** 3
是用于绘制非线性曲线的数据。axmain.plot(x, y, 'g-d')
在主轴域上绘制非线性曲线,axzoom.plot(x, y, 'b-.o')
在变焦轴域上绘制非线性曲线。onbuttonpress(event)
是响应按键按下事件的回调函数。 通常,event
是函数接收的参数:if event.button == 1:
检查是否按下了左键(滚动按键代码为2
按键代码为3
)。 如果是按左键,则执行后续步骤,如下所示。 否则,它将不执行任何操作而完成该函数。x, y = event.xdata, event.ydata
捕获绘制点上按下鼠标按键的点的坐标,在数据坐标系中。 应当注意,event.x
和event.y
在显示坐标系中具有相同的坐标。axzoom.set_xlim(x - 1, x + 1)
将缩放轴域的 x 轴限制从按下鼠标键的位置(鼠标单击)设置为+/-1
。 因此,仅在这些限制内的曲线上的点将出现在缩放窗口中。axzoom.set_ylim(y - 10, y + 10)
将缩放轴域的 y 轴限制从按下鼠标键的点开始设置为+/- 10
。 因此,仅在这些限制范围内的曲线上的点将出现在缩放窗口中。figzoom.canvas.draw()
用新的限制绘制数字。
figmain.canvas.mpl_connect('button_press_event', onbuttonpress)
捕获按键按下事件,并调用回调函数来响应该事件。plt.show()
将输出发送到指定的后端。
运行代码时,您应该在单独的窗口中看到两个图,如下所示。 当它们都出现时,它们可能彼此重叠,因此您必须拖动图 2 使其从图 1 移开:
在点(2, 11.5)
上单击图 1 中的图时,则图 2 中的图应更改,如下所示。 它是图 1 中围绕点(2, 11.5)
的绘图的缩放版本,因此它包含 X 范围为 1 至 3,为。 Y 的范围大约为 0 到 20:
运动通知和鼠标按键按下事件
在本秘籍中,我们将学习如何捕获motion_notify_event
和button_press_event
并显示发生这些事件的点的坐标。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
from time import time
操作步骤
以下步骤说明了如何编码和所需逻辑:
- 设置要绘制的图的数据:
t = np.arange(0.0, 1.0, 0.01)
s = np.sin(2 * np.pi * t)
- 定义图形和轴域:
fig, ax = plt.subplots()
- 绘制图形:
ax.plot(t, s)
- 在
str_time
变量中捕获开始时间:
str_time = time()
- 定义响应鼠标移动事件的回调函数:
def on_move(event):
if event.inaxes:
print('onmove data coords %.2f %.2f' % (event.xdata,
event.ydata))
elapsed_time = time() - str_time
print('elapsed time', elapsed_time)
if elapsed_time > 10:
print('Closing onmove event after 10 sec')
plt.disconnect(binding_id)
- 定义响应鼠标按键按下事件的回调函数:
def on_click(event):
if event.inaxes is not None:
if event.button == 1:
print('left click data coords %.2f %.2f' % (event.xdata, event.ydata))
ax.text(event.xdata, event.ydata, 'left click here',
weight='bold', color='m')
elif event.button == 2:
print('scroll click data coords %.2f %.2f' % (event.xdata, event.ydata))
ax.text(event.xdata, event.ydata, 'scroll click here',
weight='bold', color='m')
elif event.button == 3:
print('right click data coords %.2f %.2f' % (event.xdata, event.ydata))
ax.text(event.xdata, event.ydata, 'right click here', weight='bold', color='m')
fig.canvas.draw()
- 将事件连接到对应的回调函数:
binding_id = plt.connect('motion_notify_event', on_move)
plt.connect('button_press_event', on_click)
- 在指定的后端显示图形:
plt.show()
工作原理
以下是上述代码的说明:
on_move(event)
是响应鼠标移动事件的回调函数:if event.inaxes
检查鼠标移动事件是否在轴域内或轴域外发生。 如果在轴域内,则执行下一组指令 ; 否则,事实并非如此。print()
打印数据坐标系中的坐标,在鼠标移至sysout
的轴域上的点的时候。 您可以在笔记本的输出单元中看到它。elapsed_time
是从程序开始到现在的经过时间。 这用于停用move_event
回调函数,因为鼠标移动事件会产生大量sysout
] 通过打印语句。if elapsed_time > 10
检查经过时间是否大于 10 秒; 如果是,它将closing onmove event after 10 sec
打印到sysout
,并且plt.disconnect(binding_id)
断开on_move
事件的连接。binding_id
是定义事件和回调之间的连接时捕获的标识。on_click(event)
是响应鼠标单击(按键按下)事件的回调函数。 鼠标上有三个按键:左侧为 1,滚动为2
,右侧为3
。 每次单击按键时,它会在绘图本身上打印相应消息:if event.button == 1:
检查按下的按键是否为左键,然后将坐标打印到sysout
和ax.text(event.xdata, event.ydata, 'left click here', weight='bold', color='m')
创建要在绘图上显示的文字艺术家,当调用draw()
函数时,该艺术家将可见。- 按键 2(滚动)和 3(右)重复相同的功能。
binding_id = plt.connect('motion_notify_event', on_move)
将运动通知事件与相应回调函数on_move()
相连,并且其标识保存在binding_id
和中,如果以后要断开此事件,则需要使用此标识。plt.connect('button_press_event', on_click)
将按键按下事件与对应的回调函数on_click()
连接起来。- 请注意,在此秘籍中,我们已使用
plt.connect()
方法将该事件与相应的回调函数连接,而之前我们使用canvas
类的方法mpl_connect()
。 区别在于plt.connect()
是pyplot
API 的一部分,而mpl_connect()
是面向对象的 API 的一部分,我们在第 5 章“使用面向对象的 API 进行绘图”中了解。
运行该程序时,您应该看到以下图表,并将鼠标悬停在该图表上时,在输出单元格中的 10 秒钟内,您将在sysout
中看到文本消息elapsed time 0.6132094860076904, onmove data coords 0.14 -1.04
。 实际的经过时间和坐标对您而言将有所不同,具体取决于您将鼠标悬停在绘图上的时间和位置:
10 秒后,如果按住鼠标左键(1),滚动(2)或鼠标右键(3),您将在图形上以及在输出单元格中看到相应消息。 该图应如下所示:
拾取事件
在本秘籍中,我们将学习如何捕获一个拾取事件,并使用它来激活/去激活给定轴域上一组线形图中的特定线形图。 我们使用图例来选择特定的线形图。
准备
我们将使用 受试者工作特性(ROC)曲线数据,该数据在第 3 章“绘制多个图表,子图和图”中引入,来绘制各种折线图,与相关的图例。
导入所需的库并设置后端:
import matplotlib.pyplot as plt
plt.switch_backend('nbAgg')
import pandas as pd
操作步骤
以下步骤对逻辑进行了编码,以演示选择事件的用法:
- 从 Excel 文件中读取
fpr
和tpr
数据以获取各种算法:
fpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'fpr_logreg')
tpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'tpr_logreg')
fpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'fpr_KNN')
tpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'tpr_KNN')
fpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'fpr_MLP')
tpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'tpr_MLP')
fpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'fpr_SGD')
tpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'tpr_SGD')
fpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'fpr_GNB')
tpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'tpr_GNB')
fpr_svc = pd.read_excel('ROC_Curves.xlsx', 'fpr_svc')
tpr_svc = pd.read_excel('ROC_Curves.xlsx', 'tpr_svc')
fpr_RF = pd.read_excel('ROC_Curves.xlsx', 'fpr_RF')
tpr_RF = pd.read_excel('ROC_Curves.xlsx', 'tpr_RF')
fpr_DT = pd.read_excel('ROC_Curves.xlsx', 'fpr_DT')
tpr_DT = pd.read_excel('ROC_Curves.xlsx', 'tpr_DT')
- 定义并实例化图形:
fig = plt.figure(figsize=(10,8))
- 绘制所有折线图:
plt.plot([0, 1], [0, 1], 'k--')
l1, = plt.plot(fpr_logreg, tpr_logreg, label='LogReg',color='purple')
l2, = plt.plot(fpr_KNN, tpr_KNN, label='KNN',color='green')
l3, = plt.plot(fpr_DT, tpr_DT, label='DecisionTree', color='orange')
l4, = plt.plot(fpr_RF, tpr_RF, label='Random Forest',color='yellow')
l5, = plt.plot(fpr_MLP, tpr_MLP, label='MLP',color='red')
l6, = plt.plot(fpr_svc, tpr_svc, label='SVC',color='violet')
l7, = plt.plot(fpr_GNB, tpr_GNB, label='GNB',color='grey')
l8, = plt.plot(fpr_SGD, tpr_SGD, label='SGD', color='pink')
- 将 alpha(透明度)设置为
0.4
来设置标签,标题和图例:
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve')
lgd = plt.legend(loc='lower right', fancybox=True, shadow=True)
- 创建一个字典以使用和对应的图例标签映射绘图线:
pltlines = [l1, l2, l3, l4, l5, l6, l7, l8]
leg_ln_map = dict()
for leg_line, plot_line in zip(lgd.get_lines(), pltlines):
leg_line.set_picker(10)
leg_ln_map[leg_line] = plot_line
- 定义响应和
on_pick
事件的回调函数:
def onpick(event):
# on the pick event, find the plot line corresponding to the legend line, and toggle the visibility
leg_line = event.artist
plot_line = leg_ln_map[leg_line]
vis = not plot_line.get_visible()
plot_line.set_visible(vis)
# Change the alpha on the line in the legend so we can see what lines have been toggled
if vis:
leg_line.set_alpha(1.0)
else:
leg_line.set_alpha(0.2)
fig.canvas.draw()
- 将事件与对应的回调函数连接:
fig.canvas.mpl_connect('pick_event', onpick)
- 将输出图形发送到选定的后端:
plt.show()
工作原理
以下是上述代码的说明:
- 读取数据,定义图形以及绘制各种折线图的前三个步骤已经为我们所熟悉。
lgd = plt.legend(loc='lower right', fancybox=True, shadow=True)
设置图例,fancybox=True
指定在图例项周围绘制边界框,shadow=True
指定该边界框具有阴影。pltlines = [l1, l2, l3, l4, l5, l6, l7, l8]
是图中所有绘图线的列表。leg_ln_map = dict()
是将绘图线映射到相应图例标签的字典。for
循环为每个图例标签设置选择器,并将它们映射到和对应的线形图。leg_line.set_picker(5)
设置图例标签行的选择器。 数字 10 表示,即鼠标单击被捕获以触发相应对应选择事件的点数。 1 点是 1/72 英寸。 如果此数字太大,则单击可能会变得足够接近多个图例项目,并且所有这些项目可能会同时被触发! 因此,请将其设置得足够小以避免给定鼠标单击时图例行之间的重叠。- 选择器的此参数还有其他选项,
None
表示禁用选择器,布尔值True
表示在图例行上单击时触发事件; 它也可以是用户定义的函数。 onpick(event)
是pick_event
的回调函数:leg_line = event.artist
捕获发生 , 鼠标单击的特定图例行。plot_line = leg_ln_map[leg_line]
获得与图例线相对应的绘图线。vis = not plot_line.get_visible()
获取绘图线的当前可见性状态,并将其设置为与vis
相反。plot_line.set_visible(vis)
设置绘图线的新可见性状态。if
和else
语句使用[alpha]为对应的图例行设置相同的状态。1
表示完全可见,0.2
表示部分可见。fig.canvas.draw()
在输出设备上绘制图形。
fig.canvas.mpl_connect('pick_event', onpick)
将pick
事件与对应的回调函数onpick
连接起来。
运行程序并在图例中单击 LogReg,Random Forest 和 SVC 标签时,应该看到以下图表。 禁用它们,因此您在图中看不到这些曲线:
请注意,此图中,标头和导航工具栏与以前秘籍中显示的数字有所不同。 在这种情况下,已使用nbAgg
后端,而使用了较早的Qt5Agg
。 虽然外观不同,但所有后端在工具栏中都提供和相同的功能。
图和轴域的进入和离开事件
在本秘籍中,我们将学习如何捕获图形输入和离开事件以及轴域进入和离开事件,并使用它们来更改图形和轴域的属性,并使轴域上的线形图可见/不可见。
准备
导入所需的库:
import matplotlib.pyplot as plt
import numpy as np
操作步骤
以下是编码所需逻辑的步骤:
- 定义图形
ax1
和ax2
,并设置图形标题:
fig = plt.figure()
fig.suptitle('mouse hover over figure or axes to trigger events')
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
- 准备用于绘制正弦和余弦函数的数据:
x = np.arange(1, 2.0, 0.1)
y = np.sin(2 * np.pi * x)
y1 = np.cos(2 * np.pi * x)
- 在
ax1
上绘制正弦函数,在ax2
上绘制余弦函数:
ax1.plot(x,y, color='g')
ax2.plot(x, y1, color='b')
- 为
figure_enter_event
定义回调函数:
def figure_enter(event):
print('figure_enter', event.canvas.figure)
event.canvas.figure.patch.set_facecolor('grey')
event.canvas.draw()
- 为
figure_leave_event
定义回调函数:
def figure_exit(event):
print('figure_exit', event.canvas.figure)
event.canvas.figure.patch.set_facecolor('red')
event.canvas.draw()
- 为
axes_enter_event
定义回调函数:
def axes_enter(event):
print('axes_enter', event.inaxes)
event.inaxes.patch.set_facecolor('white')
event.inaxes.get_lines()[0].set_visible(True)
event.canvas.draw()
- 为
axes_leave_event
定义回调函数:
def axes_exit(event):
print('axes_exit', event.inaxes)
event.inaxes.patch.set_facecolor('orange')
event.inaxes.get_lines()[0].set_visible(False)
event.canvas.draw()
- 将事件与对应的回调函数连接:
fig.canvas.mpl_connect('figure_enter_event', figure_enter)
fig.canvas.mpl_connect('figure_leave_event', figure_exit)
fig.canvas.mpl_connect('axes_enter_event', axes_enter)
fig.canvas.mpl_connect('axes_leave_event', axes_exit)
工作原理
以下是上述代码步骤的说明:
- 前三个步骤是定义图形及其布局,准备数据和绘制图表。
figure_enter(event)
是响应figure_enter_event
的回调函数。print('figure_enter', event.canvas.figure)
将文本figure enter
输出到sysout
,然后是图形对象。event.canvas.figure.patch.set_facecolor('grey')
将图形的前景颜色设置为灰色。event.canvas.draw()
在输出设备的上绘制更新的图形。
figure_exit(event)
是响应figure_leave_event
的回调函数。 此函数还将文本打印到sysout
,将图形的前景颜色设置为红色,并绘制更新的图形。axes_enter(event)
是响应axes_enter_event
的回调函数。print('axes_enter', event.inaxes)
将文本axes_enter
打印到sysout
,随后是访问对象。event.inaxes.patch.set_facecolor('white')
将轴域的面色设置为白色。event.inaxes.get_lines()[0].set_visible(True)
将轴域上的线形图设置为可见状态; 方法get_lines()
从轴域获取所有线对象,因此它是对象列表,我们需要使用index [0]
从列表中获取第一个对象。event.canvas.draw()
在输出设备上绘制更新的图形
axes_exit(event)
是响应axes_leave_event
的回调函数。 还将,文本和轴域对象打印到sysout
,将轴域的面色设置为橙色,并将线形图设置为不可见状态。fig.canvas.mpl_connect('figure_enter_event', figure_enter)
将figure_enter_event
连接到对应的回调函数figure_enter
。 同样,其他三个事件也分别连接到它们各自的回调函数。
运行该程序时,应该看到如下所示的第一个图; 当鼠标在上方时,您应该看到第二个图; 当鼠标在该图的边界之外时,您应该看到第三个图:
使用双生轴域绘制四个温度刻度
在第 4 章,“开发可视化来提高发布质量”的“双生轴域”秘籍中,我们学习了如何在左和右轴域绘制两个不同的比例尺的两个独立变量。 当我们在交互模式下使用此功能时,缩放和平移功能也可以正常工作,因为两个变量是独立的。 但是,当两个变量相互依赖时,例如以弧度和度为度量单位; 公斤和磅; 或华氏温度,摄氏温度,开尔文温度和朗肯温度,那么两个变量必须同步。
在本秘籍中,我们将通过一个温度示例学习如何做到这一点。 我们将在,主轴域上使用摄氏温度单位,并在从属轴域上使用华氏,开尔文和朗肯。
准备
设置交互式分析的后端,在导入所需的库,并设置用于生成随机数的种子:
import matplotlib
matplotlib.use('tkagg')
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(19681211)
操作步骤
以下是绘制和所需图形的步骤:
- 定义函数,将摄氏温度转换为和其他三个测量单位:
def c2f(temp):
return (9\. / 5.) * temp + 32
def c2k(temp):
return temp + 273.15
def c2r(temp):
return (9\. / 5.) * temp + 427.9
- 根据主轴域上的摄氏刻度的当前限制来定义更新所有刻度的函数:
def refresh_scales(ax_c):
y1, y2 = ax_c.get_ylim()
ax_f.set_ylim(c2f(y1), c2f(y2))
ax_f.figure.canvas.draw()
ax_k.set_ylim(c2k(y1), c2k(y2))
ax_k.figure.canvas.draw()
ax_r.set_ylim(c2r(y1), c2r(y2))
ax_r.figure.canvas.draw()
- 定义图形,主轴域和三个从属轴域,其他三个测量单位各一个:
fig, ax_c = plt.subplots()
ax_f = ax_c.twinx()
ax_r = ax_c.twinx()
ax_k = ax_c.twinx()
- 在图的右侧定义两个从属轴域,远离图的默认右轴域:
ax_k.spines["right"].set_position(("axes", 1.15))
ax_r.spines["right"].set_position(("axes", 1.30))
- 将
ylim_changed
事件连接到相应的回调函数:
ax_c.callbacks.connect("ylim_changed", refresh_scales)
- 在主轴域上以摄氏度为单位绘制
30
天的随机温度:
ax_c.plot(np.random.uniform(low=-40., high=40., size=(30,)))
ax_c.set_xlim(0, 30)
- 为所有四个比例绘制图形标题和 y 轴标签:
ax_c.set_title('Temperature on Four different Scales')
ax_c.set_ylabel('Celsius', color='g')
ax_f.set_ylabel('Fahrenheit')
ax_k.set_ylabel('Kelvin')
ax_r.set_ylabel('Rankine')
- 为所有轴域设置 y 轴标签的颜色:
ax_f.yaxis.label.set_color('b')
ax_k.yaxis.label.set_color('r')
ax_r.yaxis.label.set_color('m')
- 设置的颜色,所有 y 轴的刻度和刻度标签:
ax_c.tick_params(axis='y', colors='g')
ax_f.tick_params(axis='y', colors='b')
ax_k.tick_params(axis='y', colors='r')
ax_r.tick_params(axis='y', colors='m')
- 设置所有 y 轴轴线的颜色:
ax_c.spines["left"].set_edgecolor('g')
ax_f.spines["right"].set_edgecolor('b')
ax_k.spines["right"].set_edgecolor('r')
ax_r.spines["right"].set_edgecolor('m')
- 在屏幕上显示该图:
plt.show()
工作原理
这是前面代码的解释:
def c2f(temp):
是将摄氏温度转换为华氏温度的函数。def c2k(temp):
是将摄氏温度转换为开尔文的函数。def c2r(temp):
是将摄氏温度转换为朗肯的函数。def refresh_scales(ax_c):
是根据当前摄氏温度限制刷新和从属轴域上所有刻度的函数:y1, y2 = ax_c.get_ylim()
在主轴域上获得当前摄氏刻度的上限和下限。ax_f.set_ylim(c2f(y1), c2f(y2))
使用给定的摄氏限制设置了华氏刻度的新限制。ax_f.set_ylim(c2k(y1), c2f(y2))
使用给定的摄氏限制设置了开尔文刻度的新限制。ax_f.set_ylim(c2r(y1), c2f(y2))
使用给定的摄氏限制设置了朗肯刻度的新限制。
fig, ax_c = plt.subplots()
定义了主轴域和从属轴域上的摄氏刻度。ax_f = ax_c.twinx()
定义了主轴域和从属轴域上的华氏刻度。ax_k = ax_c.twinx()
定义了主轴域从属轴域上的开尔文刻度。ax_r = ax_c.twinx()
定义了主轴域从属轴域上的朗肯刻度。ax_k.spines["right"].set_position(("axes", 1.15))
将从属轴域向右侧移动主轴域宽度的 15%。ax_r.spines["right"].set_position(("axes", 1.30))
将从属轴域向右侧移动主轴域宽度的 30% ,以使所有轴刻度线,刻度标签或轴标签都不相互重叠。ax_c.callbacks.connect("ylim_changed",refresh_scales)
将"ylim_changed"
事件连接到相应的回调函数refresh_scales
。ax_c.plot(np.random.uniform(low=-40., high=40., size=(30,)))
在摄氏刻度上绘制-40 至 40 之间的 30 个随机数。ax_c.set_xlim(0, 30)
将 X 轴的下限和上限分别设置为零和 30 天。ax_c.set_title('Temparature on Four different Scales')
绘制该图的标题。ax_c.set_ylabel('Celsius', color='g')
将 y 轴标签设置为摄氏度。ax_f.set_ylabel('Fahrenheit')
将 y 轴标签设置为华氏度。ax_k.set_ylabel('Kelvin')
将 y 轴标签设置为开尔文。ax_r.set_ylabel('Rankine')
将 y 轴标签设置为朗肯。ax_f.yaxis.label.set_color('b')
设置华氏度的 y 轴标签的颜色; 通常的set_ylabel(color='b')
不适用于从属轴域。ax_k.yaxis.label.set_color('r')
将 y 轴标签的颜色设置为开尔文刻度。ax_r.yaxis.label.set_color('m')
设置朗肯刻度的 y 轴标签的颜色。ax_c.tick_params(axis='y', colors='g')
设置摄氏刻度的刻度和刻度标签的颜色。ax_f.tick_params(axis='y', colors='b')
设置华氏刻度的刻度和刻度标签的颜色。ax_k.tick_params(axis='y', colors='r')
设置开尔文刻度的刻度和刻度标签的颜色。ax_r.tick_params(axis='y', colors='m')
设置朗肯刻度的刻度和刻度标签的颜色。ax_c.spines["left"].set_edgecolor('g')
设置摄氏刻度轴的颜色。ax_f.spines["right"].set_edgecolor('b')
设置华氏度刻度轴的颜色。ax_k.spines["right"].set_edgecolor('r')
设置开尔文刻度轴的颜色。ax_r.spines["right"].set_edgecolor('m')
设置朗肯刻度轴的颜色。
运行前面的代码后,您应该在屏幕上看到下图:
小部件
在上一节中,我们学习了如何在粒度级别捕获事件并使用这些事件执行某些基本任务。 可以扩展它来开发丰富的图形用户界面(GUI)应用,这些应用包括按键,复选框,单选按键,滑块和跨度控制器等功能。 但是,这需要大量的编程工作。 因此,Matplotlib 预定义了许多这些功能,称为小部件,我们可以轻松使用这些功能来开发我们需要的 GUI 应用。
在本节中,我们将学习如何使用其中的一些小部件。
光标
当您将鼠标悬停在图形/轴域上时,Cursor
小部件会用十字突出显示图形中的特定点。 这类似于我们在“运动通知和鼠标按下事件”秘籍中所做的操作,但是在这里我们将使用易于使用的小部件。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Cursor
操作步骤
以下是实现逻辑的步骤:
- 准备绘图数据:
x = np.arange(-5, 5, 0.1)
y = x ** 2
- 设置图形,布局和轴域:
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, facecolor='skyblue')
- 绘制图形:
ax.plot(x, y, 'o')
- 实例化光标小部件:
cursor = Cursor(ax, color='red', linewidth=5)
- 将输出发送到指定的后端:
plt.show()
工作原理
以下是上述代码步骤的说明:
- 前三个步骤定义了数据和图形的布局,并绘制了图表。
cursor = Cursor(ax, color='red', linewidth=5)
定义并激活光标小部件。
您应该看到小部件,如此处所示。 请注意,此图已使用TkAgg
后端:
按键
单击按键可启用某些功能。 通常,它们用于通过prev
和next
按键来回滚动数据。 我们将学习如何使用此功能。
准备
我们将使用熟悉的Iris
数据集,该数据集具有三个不同的数据簇。 我们将实现prev
和next
按键来回滚动这些数据簇。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.widgets import Button
操作步骤
以下代码步骤实现了我们所需的逻辑:
- 使用
prev
和next
方法定义类以表示要显示的群集:
class Cluster(object):
ind = 0 # index to move back and forth as we click prev and
next buttons
## Method for next button click
def next(self, event):
self.ind += 1
i = self.ind % len(species)
index = iris['species'] == species[i]
axs.clear()
axs.scatter(x[index], y[index], s=50, marker='o')
axs.set_title(species[i], size=25, color='r')
plt.draw()
## Method for prev button click
def prev(self, event):
self.ind -= 1
i = self.ind % len(species)
index = iris['species'] == species[i]
axs.clear()
axs.scatter(x[index], y[index], s=50, marker='o')
axs.set_title(species[i], size=25, color='r')
plt.draw()
- 实例化
cluster
对象:
cluster = Cluster()
- 读取和
Iris
数据,并设置属性,以绘制三个群集:
iris = pd.read_csv('iris_dataset.csv', delimiter=',')
species = ['setosa', 'versicolor', 'virginica']
x,y = iris['petal_length'], iris['petal_width']
index = iris['species'] == species[cluster.ind]
- 定义图形和轴域:
fig, axs = plt.subplots()
- 绘制第一个群集:
axs.scatter(x[index], y[index], s=50, marker='o')
axs.set_title(species[cluster.ind], size=25, color='r')
- 定义上一个和下一个按键的轴域:
axprev = plt.axes([0.7, 0.005, 0.1, 0.05])
axnext = plt.axes([0.81, 0.005, 0.1, 0.05])
- 实例化上一个和下一个按键:
bnext = Button(axnext, 'Next')
bprev = Button(axprev, 'Previous')
- 将的回调函数映射到
prev
和next
的on_clicked
事件:
bnext.on_clicked(cluster.next)
bprev.on_clicked(cluster.prev)
- 在指定的后端显示图形:
plt.show()
工作原理
以下是和先前代码的解释:
class Cluster(object):
定义一个名为Cluster
的类。ind = 0
初始化索引,当按下prev
和next
按键时,索引将来回移动。def next(self, event):
将next
方法定义为next
按键的callback
函数:self.ind += 1
将索引增加 1。- 对于物种中个簇的数量,
i = self.ind % len(species)
将运行索引转换为零,1 或 2。 index = iris['species'] == species[i]
拾取与next
群集相对应的数据的索引。axs.clear()
清除轴域上的先前数据。 如果我们不这样做,则所有群集都将在轴域上可见,并且只有正在刷新的群集的颜色才会根据属性循环中设置的默认颜色来修改。axs.scatter(x[index], y[index], s=50, marker='o')
使用之前计算的索引绘制新的群集数据。axs.set_title(species[i], size=25, color='r')
将轴域的标题设置为,即当前群集名称。plt.draw()
刷新图形。
def prev(self, event):
将prev
方法定义为prev
按键的回调函数:self.ind -= 1
将索引减少 1。i = self.ind % len(species)
将物种的簇数转换为 0、1 或 2。index = iris['species'] == species[i]
拾取与上一个簇相对应的数据索引。axs.clear()
清除轴域上的先前数据。 如果不这样做,则所有群集都将在轴域上可见,并且仅刷新的群集的颜色将根据属性周期中设置的默认颜色进行更改。axs.scatter(x[index], y[index], s=50, marker='o')
使用计算出的索引绘制新的群集数据。axs.set_title(species[i], size=25, color='r')
将轴域的标题设置为当前群集名称。plt.draw()
刷新图形。
cluster = Cluster()
实例化Cluster
对象。iris = pd.read_csv('iris_dataset.csv', delimiter=',')
读取iris
数据。species = ['setosa', 'versicolor', 'virginica']
列出唯一的群集名称。x,y = iris['petal_length'], iris['petal_width']
从鸢尾数据集的 x 和 y 坐标中选取所需属性。index = iris['species'] == species[cluster.ind]
获得与和第一簇相对应的数据的索引。 请注意,cluster.ind
已初始化为零。fig, axs = plt.subplots()
实例化图形和轴域。axs.scatter(x[index], y[index], s=50, marker='o')
绘制第一个群集的散点图,axs.set_title(species[cluster.ind], size=25, color='r')
设置当前群集名称作为图形的标题。axprev = plt.axes([0.7, 0.005, 0.1, 0.05])
定义图中prev
按键的轴域,axnext = plt.axes([0.81, 0.005, 0.1, 0.05])
定义图中next
按键的轴域。 如第 6 章中的解释,“带有高级功能的绘图”,“控制轴域位置”秘籍,轴域的定义是从左,下,宽度和高度, 它们位于轴域坐标系中。bnext = Button(axnext, 'Next')
使用,Next
标签和,bnext
连接 ID 实例化next
按键,并且bprev = Button(axprev, 'Previous')
用和实例化上一个按键。 ]prev
标签和-bprev
连接 ID。bnext.on_clicked(cluster.next)
将回调函数映射到next
按键的事件,bprev.on_clicked(cluster.prev)
将callback
函数映射到prev
按键的事件。plt.show()
将输出发送到指定的后端。
当您运行程序并单击Next
时,您将看到以下三个图,代表每个群集,如每个图的标题所示:
如果注释掉axs.clear()
语句,则该图将如下所示:
复选按键
复选框用于选择或取消选择一组属性以可视化数据。 在本秘籍中,我们将学习如何使用,CheckButtons
小部件来实现复选框功能。
准备
我们将使用 ROC 图来实现CheckButtons
。
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.widgets import CheckButtons
操作步骤
以下是实现逻辑的步骤:
- 从本章前面的“选择事件”秘籍中使用的相同 Excel 文件中读取数据:
fpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'fpr_logreg')
tpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'tpr_logreg')
fpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'fpr_KNN')
tpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'tpr_KNN')
fpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'fpr_MLP')
tpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'tpr_MLP')
fpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'fpr_SGD')
tpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'tpr_SGD')
fpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'fpr_GNB')
tpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'tpr_GNB')
fpr_svc = pd.read_excel('ROC_Curves.xlsx', 'fpr_svc')
tpr_svc = pd.read_excel('ROC_Curves.xlsx', 'tpr_svc')
fpr_RF = pd.read_excel('ROC_Curves.xlsx', 'fpr_RF')
tpr_RF = pd.read_excel('ROC_Curves.xlsx', 'tpr_RF')
fpr_DT = pd.read_excel('ROC_Curves.xlsx', 'fpr_DT')
tpr_DT = pd.read_excel('ROC_Curves.xlsx', 'tpr_DT')
- 定义并实例化图形:
fig = plt.figure(figsize=(10,8))
- 绘制所有 ROC 曲线:
plt.plot([0, 1], [0, 1], 'k--')
l1, = plt.plot(fpr_logreg, tpr_logreg,
label='LogReg',color='purple')
l2, = plt.plot(fpr_KNN, tpr_KNN, label='KNN',color='green')
l3, = plt.plot(fpr_DT, tpr_DT, label='DecisionTree', color='orange')
l4, = plt.plot(fpr_RF, tpr_RF, label='Random Forest',color='yellow')
l5, = plt.plot(fpr_MLP, tpr_MLP, label='MLP',color='red')
l6, = plt.plot(fpr_svc, tpr_svc, label='SVC',color='violet')
l7, = plt.plot(fpr_GNB, tpr_GNB, label='GNB',color='grey')
l8, = plt.plot(fpr_SGD, tpr_SGD, label='SGD', color='pink')
- 设置图形的属性,并在和左侧调整空间,以容纳和复选框:
plt.xlabel('False Positive Rate', size=20, color='m')
plt.ylabel('True Positive Rate', size=20, color='m')
plt.title('ROC curve', size=25, color='b')
plt.subplots_adjust(left=0.35)
- 准备
CheckButtons
所需的每条曲线的数据轴域,标签和可见性状态:
lines = [l1, l2, l3, l4, l5, l6, l7, l8]
cax = plt.axes([0.05, 0.27, 0.15, 0.5])
labels = [str(line.get_label()) for line in lines]
visibility = [line.get_visible() for line in lines]
- 使用先前准备的必需属性实例化
CheckButtons
对象。
check = CheckButtons(cax, labels, visibility)
- 定义响应复选框点击的回调函数:
def onclick(label):
index = labels.index(label)
lines[index].set_visible(not lines[index].get_visible())
plt.draw()
- 将事件映射到对象上的回调函数。
工作原理
这是前面代码块的说明。
前四个步骤已经很熟悉,因此我们将在步骤 5 中进行说明:
lines = [l1, l2, l3, l4, l5, l6, l7, l8]
是所有 ROC 线形图的列表。cax = plt.axes([0.05, 0.27, 0.15, 0.5])
定义绘制,CheckButtons
框的轴域。labels = [str(line.get_label()) for line in lines]
定义 ROC 图中每个的标签列表。 这是,与绘制这些曲线时所给的标签相同。 在这里,我们不再使用系统函数line.get_label()
对其进行硬编码。visibility = [line.get_visible() for line in lines]
是所有 ROC 曲线的可见性状态列表(可见或不可见)。check = CheckButtons(cax, labels, visibility)
实例化CheckButtons
对象。def onclick(label):
是单击复选按键时激活的回调函数。label
是系统变量,例如event
,其中包含标签和单击的复选按键的标签:index = labels.index(label)
从所有标签列表中获得单击的标签的索引,该索引将用于访问该标签的 ROC 图。lines[index].set_visible(not lines[index].get_visible())
切换单击的标签的的可见性状态。plt.draw()
刷新图。
check.on_clicked(onclick)
将点击事件与对应的回调函数连接起来。plt.show()
将输出发送到指定的后端。
运行程序时,您应该获得第一个数字,并且取消选中 K 最近邻(KNN),决策树(DT)和多层感知器(MLP)曲线,那么您应该看到第二个图:
单选按键
RadioButtons
与CheckButtons
相似,只是在任何时候它的一个属性都将处于活动状态。 在本秘籍中,我们将学习如何使用RadioButtons
小部件。
准备
我们将为该秘籍定义美国,中国的 GDP 数据以及和英国的 Python 列表,并将其用于此秘籍。
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import RadioButtons
操作步骤
以下是实现RadioButtons
逻辑的步骤:
- 定义图形和轴域,然后在左侧的上调整空间以容纳
RadioButtons
:
fig, axs = plt.subplots()
plt.subplots_adjust(left=0.3)
- 准备要在轴域上绘制的数据:
## Data taken from https://data.worldbank.org/country
Year = ['2007', '2008', '2009', '2010', '2011', '2012', '2013',
'2014', '2015', '2016']
China_GDP = [3.552, 4.598, 5.11, 6.101, 7.573, 8.561, 9.607, 10.482,
11.065, 11.191]
US_GDP = [14.478, 14.719, 14.419, 14.964, 15.518, 16.155, 16.692,
17.428, 18.121, 18.624]
UK_GDP = [3.074, 2.891, 2.383, 2.441, 2.62, 2.662, 2.74, 3.023,
2.886, 2.651]
- 绘制图形并设置标签,标题和轴限制:
line, = axs.plot(Year, US_GDP, lw=5, color='g', ls='-.')
axs.set_ylim(1,20)
axs.set_title('GDP(in trillion $)')
axs.set_xlabel('Year')
- 定义将绘制单选按键的轴域,并实例化对象:
rax = plt.axes([0.05, 0.5, 0.15, 0.25], facecolor='skyblue')
radio = RadioButtons(rax, ('USA', 'China', 'UK'))
- 定义单击
RadioButtons
之一时执行的回调函数:
countrydict = {'USA': [US_GDP, 'g', '-.'], 'China': [China_GDP, 'b',
'--'], 'UK': [UK_GDP, 'm', '-']}
def country(label):
ydata, color, ls = countrydict[label]
line.set_ydata(ydata)
line.set_color(color)
line.set_linestyle(ls)
plt.draw()
- 将点击事件连接到先前定义的对应的回调函数:
radio.on_clicked(country)
- 将输出发送到指定的后端:
plt.show()
工作原理
这是前面代码块的解释:
-
Year
是要绘制 GDP 数据的年份的列表。 -
China_GDP
是,年列表中指定的年份的 GDP 清单,以兆美元($
)表示,US_GDP
和UK_GDP
同样。 -
rax = plt.axes([0.05, 0.5, 0.15, 0.25], facecolor='skyblue')
定义将绘制RadioButtons
的轴域,并且将面色设置为skyblue
。 -
radio = RadioButtons(rax, ('USA', 'China', 'UK'))
在给定轴域上实例化RadioButtons
对象,并使用实例化给定标签。 -
countrydict()
是包含country
作为key
以及相关的 GDP 和的字典,绘图属性color
和linestyle
作为values
。 -
def GDP(label):
定义了响应单击RadioButtons
而被激活的回调函数。label
是一个系统变量,其中包含单击的RadioButton
的标签:ydata, color, ls = countrydict[label]
从与单击的标签相对应的字典中获取 GDP,颜色和线条样式。line.set_ydata(ydata)
设置 y 轴的数据。line.set_color(color)
设置绘图的颜色。line.set_linestyle(ls)
设置线条样式。plt.draw()
刷新图。
-
radio.on_clicked(GDP)
将点击事件与相应的回调函数country
连接起来。 -
plt.show()
将输出发送到指定的后端。
当您运行该程序并开始检查其他单选按键时,您应该看到下图:
文本框
TextBox
小部件是求值任何表达式的自由格式实现。 如果您想检查各种不同的数学表达式/函数,这将非常方便。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import TextBox
操作步骤
以下是实现TextBox
小部件的步骤:
- 定义图形和轴域,并在底部调整空间以适应
TextBox
:
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.2)
- 准备要绘制的初始数据:
x = np.arange(-5.0, 5.0, 0.01)
y = x ** 5
- 绘制数据:
l, = plt.plot(x, y, lw=2)
- 定义提交
TextBox
中的新表达式时要执行的回调函数:
def submit(text):
ydata = eval(text)
l.set_ydata(ydata)
ax.set_ylim(np.min(ydata), np.max(ydata))
plt.draw()
- 定义
TextBox
实现所需的轴域和initial_text
:
axbox = plt.axes([0.1, 0.05, 0.8, 0.075])
initial_text = "x ** 5"
- 实例化
TextBox
对象:
text_box = TextBox(axbox, 'Evaluate', initial=initial_text)
- 将提交事件与先前定义的对应的回调函数连接:
text_box.on_submit(submit)
- 将输出发送到指定的后端:
plt.show()
工作原理
这是前面的代码块的说明:
- 前三步很熟悉,因此我们将从第四步开始。
def submit(text):
定义了提交回调函数。text
是系统变量,包含提交之前在文本框中输入的表达式:eval()
是 Python 函数,用于计算作为参数提供的表达式。eval(text)
是执行在TextBox
中输入并将ydata
变量分配给的表达式的结果。l.set_ydata(ydata)
将和新ydata
设置为线对象的 y 轴。ax.set_ylim(np.min(ydata), np.max(ydata))
设置, x 和 y 轴的限制,并使用和当前数据进行缩放。plt.draw()
刷新图。
axbox = plt.axes([0.1, 0.05, 0.8, 0.075])
定义将放置TextBox
的轴域。initial_text = "x ** 5"
是在第一次出现时出现的绘图时TextBox
中出现的表达式。text_box = TextBox(axbox, 'Evaluate', initial=initial_text)
定义并实例化TextBox
对象。text_box.on_submit(submit)
将submit
事件与对应的回调函数submit
连接起来。plt.show()
将输出发送到指定的后端。
运行该程序时,应该看到第一个数字。 当您将文本更改为不同的表达式时,您将看到第二个和第三个数字:
动画
在本节中,我们将介绍绘图的动画。 动画是用于根据原始数据创建故事绘图的强大工具。 它是一系列视觉图表框架,这些框架连接在一起以创建视频。 Matplotlib 中的动画图可以另存为.mp4
文件,可以像其他任何视频一样使用媒体播放器进行播放。
Matplotlib 为和提供了以下两个类来实现动画绘图:
FuncAnimation
ArtistAnimation
在本节中,我们将学习如何使用它们。
Sigmoid 曲线动画
在本秘籍中,我们将学习如何使用和FuncAnimation
类为 Sigmoid 曲线制作动画。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
操作步骤
以下是实现所需逻辑的步骤:
- 定义图形和轴域:
fig, ax = plt.subplots()
- 准备要绘制的图形的数据,在这种情况下为 Sigmoid,然后进行绘制:
x = np.arange(-10, 10, 0.01)
y = 1 / (1 + np.exp(-x))
line, = ax.plot(x, y)
- 定义初始化函数
init()
:
def init():
line.set_ydata([np.nan] * len(x))
return line
- 定义动画函数
animate()
:
def animate(i):
line.set_ydata(1 / (1 + np.exp(-(x+i/100)))) # keep refreshing frame by frame
return line,
- 激活动画:
ani = FuncAnimation(fig, animate, 1000, init_func=init, blit=True,
interval=2, save_count=50,
repeat=False, repeat_delay=1000)
- 将输出发送到指定的后端:
plt.show()
工作原理
这是前面代码块的解释:
ani = FuncAnimation(fig, animate, 1000, init_func=init, blit=True, interval=2, save_count=50, repeat=False, repeat_delay=1000)
激活动画。 由于我们需要维护对象的状态,因此必须将其分配给变量,如此处所做的:ani
。 这也有助于将动画保存到.mp4
文件,我们将在下一个秘籍中学习如何做:fig
是正在动画的图形。animate
是用于指示将和动画应用于绘图的方式的函数:i
是系统变量,包含正在处理的当前帧的帧号。- 我们将 x 轴数据保持不变,但将 y 轴数据更改为帧号的函数。
1000
是完成动画的帧数。 该数字可以是任意数字,具体取决于您希望动画运行多长时间。 这也可以是为animate
函数提供数据的另一个功能。 我们将在后续秘籍中学习。init_func=init
一次指定要在开始时应用的初始化函数。 这是一个可选函数,也可以省略。 仅在重新启动blit=True
时有用。 在这种情况下,我们只是将数据设置为nan
(不是数字)。blit=True
指定仅刷新从前一帧更改为当前帧的图形部分。 这提高了处理速度。interval=2
指定连续帧之间的时间延迟为 2 毫秒。save_count=50
指定要保存在和高速缓存中的帧数,以提高性能。repeat=False
指定在完成所有 1,000 帧后停止动画。 如果我们说True
,那么它将一次又一次地重复 1,000 帧的循环,直到结束会话为止。repeat_delay=1000
指定在完成上一个周期后的 1000 毫秒开始下一个周期。
您应该在动画的末尾看到下图:
将动画保存到 mp4 文件
在本秘籍中,我们将学习如何保存可由媒体播放器播放的动画。 我们将重新创建在上一个秘籍中学习到的动画并将其保存。
您需要在计算机上安装ffmpeg
包,才能以.mp4
文件格式保存动画。 对于 Windows 安装,您可以在此处获取说明。 有关此包及其应用的更多详细信息,请参见此处的文档。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
操作步骤
您可以一次运行先前秘籍的的所有步骤,如下所示,以创建动画:
fig, ax = plt.subplots()
x = np.arange(-10, 10, 0.01)
y = 1 / (1 + np.exp(-x))
line, = ax.plot(x, y)
def init(): # only required for blitting to give a clean slate.
line.set_ydata([np.nan] * len(x))
return line
def animate(i):
line.set_ydata(1 / (1 + np.exp(-(x+i/100)))) # update the data.
return line
ani = FuncAnimation(fig, animate, 1000, init_func=init, blit=True,
interval=2, save_count=50, repeat=False, repeat_delay=1000)
有两种方法可以保存图形:
ani.save("sigmoid.mp4")
您也可以这样保存它:
from matplotlib.animation import FFMpegWriter
writer = FFMpegWriter(fps=25, metadata=dict(title='expdecay',artist='line'),
bitrate=1800)
ani.save("sigmoid.mp4", writer=writer)
工作原理
ani.save("sigmoid.mp4")
将ani
动画保存到工作目录中,名称为sigmoid.mp4
。
第二个选项也做同样的事情,但是通过传递各种参数,在保存文件的方式上提供了更大的灵活性。 您可以参考文档详细了解这些参数,以及 Matplotlib 支持的其他编写器函数。 有关详细信息,请参见这里。
您可以在代码库中看到sigmoid.mp4
文件。 您可以运行它并查看动画的工作方式。
呈指数衰减的tan
函数
在本秘籍中,我们将使用指数衰减函数图来查看FuncAnimation
的另一个示例。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
操作步骤
以下是实现和所需逻辑的步骤:
- 定义图形和轴域:
fig, ax = plt.subplots()
- 绘制空白直线:
xdata, ydata = [], []
line, = ax.plot(xdata, ydata)
- 将限制和网格设置为
True
:
ax.set_xlim(0, 10)
ax.set_ylim(-3.0, 3.0)
ax.grid()
- 定义生成数据的函数,该函数将代替和帧数使用:
def frame_gen(x=0):
while x < 50:
x += 0.1
yield x, np.tan(2*np.pi*x) * np.exp(-x/5.)
- 定义用于引导动画的函数:
def animate(data):
x, y = data
xdata.append(x)
ydata.append(y)
xmin, xmax = ax.get_xlim()
if x >= xmax:
ax.set_xlim(xmin, 2*xmax)
ax.figure.canvas.draw()
line.set_data(xdata, ydata)
return line
- 激活动画:
ani = FuncAnimation(fig, animate, frame_gen, blit=True, interval=2, repeat=False)
- 将输出发送到指定的后端:
plt.show()
工作原理
这是前面代码块的说明。 它的工作方式类似于之前的 Sigmoid 动画的工作方式。
但是,我们这里不使用init_func
,而是在main
函数本身中进行初始化。 代替使用固定数量的帧,我们使用一个函数为每个帧生成数据,直到x
的值达到50
为止。 当 x 达到 50 时,一个周期完成,如果设置了repeat=yes
,则整个周期将继续重复。 否则,它将在一个周期后停止:
ax.set_xlim(0, 10)
将的 x 的轴限制设置为从 0 到 10,ax.set_ylim(-3.0, 3.0)
将的 y 的轴限制设置为 -3.0 至 +3.0。def frame_gen(x=0):
是以x
的 0.1 增量逐一生成帧的函数。while
循环在x
达到值 50 时终止。返回x
和y
=np.tan(2*np.pi*x) * np.exp(-x/5.)
def animate(data):
是指示动画必须起作用的方法的函数:- 它将
frame_gen()
,函数返回的帧接收到,data
变量中。 data
变量将其分为 x 和 y 坐标。- 当前帧的 x 和 y 坐标和当前帧被附加到包含所有先前帧的列表中。
xmin
,xmax = ax.get_xlim()
得到 x 的当前限制xmin
和xmax
变量。if x >= xmax:
检查当前帧的 x 坐标是否大于xmax
,如果是,则ax.set_xlim(xmin, 2*xmax)
为 x 轴设置了新的上限,并将上限加倍 。ax.figure.canvas.draw()
刷新图形以激活新限制。line.set_data(xdata, ydata)
绘制带有 , 新框架的图形,包括所有 , 先前的框架。
- 它将
- 对
frame_gen()
和animate()
的调用发生在FuncAnimation
中,因此我们不必担心在函数之间传递数据。
您应该在动画的末尾看到下图。 您还可以在代码库中找到Exp_decay.mp4
,可以运行它并查看:
气泡图动画
该示例已从 Matplotlib 中采用。 原始示例模拟雨滴,但在这里我们添加了不同的颜色组合,使其成为带有动画的气泡图。
准备
导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
操作步骤
以下是实现和所需逻辑的步骤:
- 定义并实例化图形和轴域:
fig = plt.figure(figsize=(5, 5))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
- 定义气泡数据结构:
n_bubbles = 50
bubbles = np.zeros(n_bubbles, dtype=[('position', float, 2), ('size', float, 1),
('growth', float, 1), ('color', float, 4)])
- 随机初始化起始位置:
bubbles['position'] = np.random.uniform(0, 1, (n_bubbles, 2))
- 绘制散点图:
scat = ax.scatter(bubbles['position'][:, 0], bubbles['position'][:, 1],
s=bubbles['size'], lw=0.5, facecolors=bubbles['color'])
- 定义引导动画的动画函数:
def animate(frame_number):
# Get the index of the bubble to update in this frame, repeat the cycle after all
# bubbles are covered
current_index = frame_number % n_bubbles
# Make all colors more transparent as time progresses.
bubbles['color'][:, 3] -= 1.0/len(bubbles)
bubbles['color'][:, 3] = np.clip(bubbles['color'][:, 3], 0, 1)
# Increase the bubble size by growth factor
bubbles['size'] += bubbles['growth']
# reset position, size, color and growth factor for the current bubble
bubbles['position'][current_index] = np.random.uniform(0, 1, 2)
bubbles['size'][current_index] = 5
bubbles['color'][current_index] = (0.5, 0.2, 0.8, 0.8)
bubbles['growth'][current_index] = np.random.uniform(50, 250)
# Update the scatter collection, with the new colors, sizes and positions.
scat.set_facecolors(bubbles['color'])
scat.set_sizes(bubbles['size'])
scat.set_offsets(bubbles['position'])
- 激活动画:
animation = FuncAnimation(fig, animate, interval=20)
- 将输出发送到指定的后端:
plt.show()
工作原理
以下是和前面的代码块的解释:
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
设置轴域,frameon=False
指定不绘制轴线。n_bubbles = 50
将气泡数设置为 50。bubbles
使用位置,大小,增长因子和颜色为定义数据结构,并使用零初始化所有这些数据结构。 位置是 x 和 y 坐标,大小和增长分别是一个属性,颜色是 RGBA,因此是四个属性。bubbles['position'] = np.random.uniform(0, 1, (n_bubbles, 2))
随机设置所有气泡的初始位置,所有坐标都在零和 1 之间。ax.scatter()
使用位置坐标,大小和颜色参数绘制散点图。def animate(frame_number):
定义动画函数,该函数指示动画应如何表现:frame_number
指定当前正在处理的当前帧,由FuncAnimation
自动管理。current_index = frame_number % n_bubbles
得出在n_bubbles
范围内的当前气泡的索引。 在每一帧中,都会更新一个气泡。bubbles['color'][:, 3] -= 1.0/len(bubbles)
会降低所有气泡的透明度(alpha)属性,以便随着时间的推移它们会变得更加透明。bubbles['color'][:, 3] = np.clip(bubbles['color'][:, 3], 0, 1)
如果透明度属性的值小于零,则将其裁剪为零;如果大于 1,则将其为 1。bubbles['size'] += bubbles['growth']
以所有气泡的相应增长率增加它们的大小。 由于增长已初始化为零,因此第一次只会为所有气泡添加零。bubbles['position'][current_index] = np.random.uniform(0, 1, 2)
重置当前气泡的位置,两个坐标介于零和 1 之间。bubbles['size'][current_index] = 5
将当前气泡的大小重置为 5 点。bubbles['color'][current_index] = (0.5, 0.2, 0.8, 0.8)
将 RGBA 格式的颜色重置为当前气泡。bubbles['growth'][current_index] = np.random.uniform(50, 250)
重置当前气泡的增长因子。scat.set_facecolors(bubbles['color'])
重设气泡的脸色,scat.set_sizes(bubbles['size'])
重设大小,scat.set_offsets(bubbles['position'])
重设散点图上的位置。
animation = FuncAnimation(fig, animate, interval=20)
激活动画。plt.show()
将输出发送到指定的后端。
在动画的最后,figure
应该看起来像这里显示的那样。 您还可以在代码库中看到bubbles.mp4
:
多个折线图的动画
在本秘籍中,我们将学习如何使用ArtistAnimation
为序列中的多个线形图设置动画。 对于本示例,我们将使用本章已经使用过两次的相同 ROC 曲线数据。
准备
导入所需的库:
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.animation import ArtistAnimation
操作步骤
以下是实现和所需逻辑的步骤:
- 从和对应的 Excel 文件中读取所有 ROC 图的
tpr
和fpr
数据:
fpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'fpr_logreg')
tpr_logreg = pd.read_excel('ROC_Curves.xlsx', 'tpr_logreg')
fpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'fpr_KNN')
tpr_KNN = pd.read_excel('ROC_Curves.xlsx', 'tpr_KNN')
fpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'fpr_MLP')
tpr_MLP = pd.read_excel('ROC_Curves.xlsx', 'tpr_MLP')
fpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'fpr_SGD')
tpr_SGD = pd.read_excel('ROC_Curves.xlsx', 'tpr_SGD')
fpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'fpr_GNB')
tpr_GNB = pd.read_excel('ROC_Curves.xlsx', 'tpr_GNB')
fpr_svc = pd.read_excel('ROC_Curves.xlsx', 'fpr_svc')
tpr_svc = pd.read_excel('ROC_Curves.xlsx', 'tpr_svc')
fpr_RF = pd.read_excel('ROC_Curves.xlsx', 'fpr_RF')
tpr_RF = pd.read_excel('ROC_Curves.xlsx', 'tpr_RF')
fpr_DT = pd.read_excel('ROC_Curves.xlsx', 'fpr_DT')
tpr_DT = pd.read_excel('ROC_Curves.xlsx', 'tpr_DT')
- 定义图并绘制所有 ROC 曲线:
fig = plt.figure()
l0 = plt.plot([0, 1], [0, 1], 'k--')
l1 = plt.plot(fpr_logreg, tpr_logreg, label='LogReg', color='purple', animated=True)
l2 = plt.plot(fpr_KNN, tpr_KNN, label='KNN', color='green', animated=True)
l3 = plt.plot(fpr_DT, tpr_DT, label='DecisionTree', color='orange', animated=True)
l4 = plt.plot(fpr_RF, tpr_RF, label='Random Forest', color='yellow', animated=True)
l5 = plt.plot(fpr_MLP, tpr_MLP, label='MLP', color='red', animated=True)
l6 = plt.plot(fpr_svc, tpr_svc, label='SVC', color='violet', animated=True)
l7 = plt.plot(fpr_GNB, tpr_GNB, label='GNB', color='grey', animated=True)
l8 = plt.plot(fpr_SGD, tpr_SGD, label='SGD', color='pink', animated=True)
- 设置图的标签,标题和图例:
plt.xlabel('False Positive Rate', size=15, color='m')
plt.ylabel('True Positive Rate', size=15, color='m')
plt.title('ROC curve', size=25, color='b')
plt.legend(loc='lower right', fancybox=True, shadow=True)
- 为所有 ROC 曲线的线定义一个列表:
lines = [l1, l2, l3, l4, l5, l6, l7, l8]
- 激活动画:
ani = ArtistAnimation(fig, lines, blit=True, interval=1000, repeat=True, repeat_delay=2500)
- 将输出发送到指定的后端:
plt.show()
工作原理
这是前面代码块的说明。
前三个步骤是您熟悉的,除了在每个 plot 语句中我们添加一个额外的参数animated=True
来指示艺术家将成为动画的一部分。
lines = [l1, l2, l3, l4, l5, l6, l7, l8]
是在动画步骤 2 中定义的所有艺术家的列表,并将其作为参数传递给ArtistAnimation
。
ani = ArtistAnimation(fig, lines, blit=True, interval=1000, repeat=True, repeat_delay=2500)
通过以 1,000 毫秒的时间间隔一次显示一位艺术家来激活动画,并以 2500 毫秒的时间延迟重复循环。
这是输出的外观。 您还可以在代码库中看到ROC_Curves.mp4
:
图像动画
在本秘籍中,我们将学习如何使用相同的ArtistAnimation
类对图像进行动画处理。
准备
导入所需的库:
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow, imread
from matplotlib.animation import ArtistAnimation
操作步骤
以下是实现和所需逻辑的步骤:
- 定义图形和轴域:
fig = plt.figure(figsize=(5,5), dpi=50)
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
- 阅读和所需的图像,并创建所有这些图像的列表:
images = []
image1 = imshow(imread("monet.png"), animated=True)
images.append([image1])
image2 = imshow(imread("louvre_small.png"), animated=True)
images.append([image2])
image3 = imshow(imread("vangogh.png"), animated=True)
images.append([image3])
image4 = imshow(imread("persepalis.png"), animated=True)
images.append([image4])
- 激活动画:
ani = ArtistAnimation(fig, images, interval=1000, blit=False,
repeat=True, repeat_delay=2500)
- 将输出发送到指定的后端:
plt.show()
工作原理
读取四个图像并将其保存到一个列表中,该列表将传递到ArtistAnimation
。 保存图像时,我们使用和animated=True
参数,这与我们在前面的秘籍中所做的类似。 动画将一次显示一张图像。 因此,这里我们没有显示这四个图像中的任何一个,但是您可以在动画图的代码库中看到images.mp4
文件 。
九、在图形用户界面中嵌入绘图
在本章中,我们将介绍以下秘籍:
- 使用 Matplotlib 的滑块和按钮小部件
- 使用嵌入在 Matplotlib 应用中的 Tkinter GUI 的滑块和按钮小部件
- 将 Matplotlib 嵌入到 Tkinter GUI 应用中
- 使用 Matplotlib 应用中嵌入的 wxPython GUI 的滑块和按钮小部件
- 在 wxPython GUI 应用中嵌入 Matplotlib
- 使用嵌入在 Matplotlib 应用中的 Qt GUI 的滑块和按钮小部件
- 将 Matplotlib 嵌入 Qt GUI 应用中
介绍
GUI 本身是一个非常大的主题,每个 GUI 框架/工具包都需要单独的一本书来全面地介绍它。 因此,对每个 GUI 框架功能的详细讨论超出了本书的范围。 此处的目的是演示某些 GUI 框架如何利用 Matplotlib 的可视化功能。
在上一章中,我们学习了如何使用三个图形用户界面(GUI)框架 Tkinter 使用事件,小部件和动画 , wxPython 和 Qt 作为后端。 在那里,我们仅将这些后端 GUI 用于显示目的,因此只需切换后端即可在所有 GUI 框架中使用相同的 Matplotlib 代码。
在本章中,我们将学习交互式绘图的另一个功能,即使用相同的三个 GUI 框架将 Matplotlib 嵌入 GUI。 首先,我们将学习如何利用 Matplotlib 图形中的 GUI 工具包的一些功能来代替 Matplotlib 的本机功能。 这意味着我们仍将运行 Matplotlib 应用来控制流程,包括打开和关闭应用。 这实际上是将 GUI 功能嵌入 Matplotlib 的图形中。 由于每个 GUI 框架都有自己的架构和语法,因此和相同的代码不能用于所有 GUI 框架,就像我们在上一章中所做的那样。 这对于三个 GUI 框架中的每一个都必须重复进行。
然后,我们将学习如何使用 GUI 框架运行应用,但如何利用 Matplotlib 的功能进行绘图。 当您的主应用以任何这些 GUI 框架编写时,这将派上用场,但是您想要在这些应用中利用 Matplotlib 丰富的可视化功能。
Matplotlib 支持许多 GUI 框架。 我们基于 Tkinter,wxPython 和 Qt 的流行程度以及它们带有标准发行版(例如 Anaconda)的事实选择了 Tkinter,wxPython 和 Qt,因此与其他 GUI 框架不同,不需要进一步的安装和配置。 但是,Matplotlib 接口类似于所有 GUI 框架,因此从这三个 GUI 框架中学习可以轻松扩展到其他 GUI 框架。
Matplotlib 和 GUI 应用之间的接口
在继续具体秘籍之前,重要的是了解内部工作原理,了解 Matplotlib 和, 后端 GUI 工具包有效。 这使您更容易理解三种操作模式之间的区别:
- 使用 GUI 后端的的 Matplotlib 应用,仅用于显示
- 一个 Matplotlib 应用,它使用一些 GUI 功能/部件(在 Matplotlib 应用的中嵌入了 GUI 功能)
- 使用 Matplotlib 绘图的 GUI 应用(将 Matplotlib 嵌入 GUI 应用中)
Matplotlib 中的以下三个对象与该接口有关:
- 图形
- 画布
- 管理器
尽管,内部工作原理和这些对象之间的关系有点复杂,但足以理解和图是进入整个绘图的所有艺术家的根艺术家(包括子图,网格等),画布是在其上绘制图形的游乐场,而管理器则是通过控制接口指定的后端。
管理器的工作是处理三个 GUI 元素:窗口,画布和导航工具栏。 窗口是主要的 GUI 应用,导航工具栏特定于和 GUI 应用,可对图形画布进行交互式分析。 每个 GUI 从FigureCanvasBase
继承其画布。 因此,GUI 和 Matplotlib 之间的接口是画布,GUI 框架和 Matplotlib 对象之间的交互由管理器管理。
在第一种操作模式下,后端仅用于显示,plt.figure()
调用的Figure
,FigureCanvas
和FigureManager
适用于指定的后端;FigureManager
依次将创建 GUI 的主窗口和导航工具栏对象,并将FigureCanvas
和导航工具栏打包到该窗口中。
在第二种操作模式下,在 Matplotlib 应用中使用了某些和 GUI 功能,我们仍将使用plt.figure()
来执行第一种模式中的功能; 此外, Matplotlib 应用通过主窗口完成事件循环,将 GUI 小部件和这些小部件上的事件与画布连接起来。
在第三种操作模式中,由于两个原因,我们将完全消除对pyplot
的使用,从而彻底取消对FigureManager
的使用。 首先,默认情况下pyplot
假定打开和关闭应用,而在这种模式下,我们需要 GUI 来控制应用流。 其次,FigureManager
的所有功能都是现在由 GUI 应用控制。 因此,在这种模式下,GUI 工具包功能控制着应用的打开,关闭以及 GUI 工具包与 Matplotlib 之间的交互。 这些功能因一个 GUI 工具箱的不同而异,因此没有通用的语法或代码。
使用 Matplotlib 的滑块和按钮小部件
我们在上一章中学习了 Matplotlib 的Button
小部件,但是滑块是一个新的小部件,我们将在这里学习。 但是,此秘籍的目的是演示如何仅通过更改后端即可在不进行任何代码更改的情况下跨 GUI 框架使用 Matplotlib 小部件应用。 我们还将在所有 GUI 框架中使用相同的极坐标图,以便我们可以看到它们工作方式上的差异,而不是迷失在图本身的细节中!
我们将使用Slider
确定极坐标图中要绘制的叶片数。 每次拖动Slider
时,都会使用Slider
的值来绘制该图中的许多叶子。
我们将使用Quit
按钮通过关闭图形对象和窗口对象来退出应用。
准备
让我们设置要使用的后端。 这是为不同的 GUI 框架更改的唯一代码,以跨,三个选定的 GUI 框架来运行此绘图:
import matplotlib matplotlib.use('tkagg')
让我们导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button, Slider
操作步骤
这是编码所需逻辑的所需步骤:
- 准备极坐标图的数据:
theta = np.arange(0., 2., 1./180.)*np.pi
- 定义并实例化图形:
fig = plt.figure(figsize=(6, 5), dpi=100)
- 定义轴域并在图中实例化它:
ax = fig.add_subplot(111, projection='polar')
- 绘制极坐标图:
initial_n = 4
ax.plot(theta, 5*np.cos(initial_n*theta))
- 定义并实例化
Slider
小部件:
ax_s = plt.axes([0.15, 0.05, 0.25, 0.05])
slider_n = Slider(ax_s, '#of leaves', 3, 10, valinit=initial_n,
valstep=1.0)
- 定义滑块小部件的回调函数:
def onchanged(s_value):
ax.clear()
ax.plot(theta, 5*np.cos(int(s_value)*theta))
- 将事件与对应的回调函数
onchanged
映射到Slider
小部件:事件和Slider
小部件:
slider_n.on_changed(onchanged)
- 定义并实例化
Button
小部件:
ebx = plt.axes([0.5, 0.005, 0.1, 0.05])
exit = Button(ebx, 'Quit')
- 定义按钮的回调函数:
def close(event):
plt.close('all')
- 将
on_clicked
事件与,对应的回调函数close
对应起来:
exit.on_clicked(close)
- 在指定的后端上显示图:
plt.show()
工作原理
这是代码的说明:
- 前四个步骤已经为您所熟悉。
ax_s = plt.axes([0.15, 0.05, 0.25, 0.05])
定义将放置Slider
小部件的轴域。slider_n = Slider(ax_s, '#of leaves', 3, 10, valinit=initial_n, valstep=1.0)
定义滑块:- 第一个参数是轴域引用,和第二个参数是要在图中的滑块上显示的标签。
- 滑块的最小值为 3,即起点,最大值为 10。 因此,通过使用鼠标拖动滑块,该值将从 3 更改为 10。
valinit
指定滑块上的起点,当图形第一次显示时显示。 在这里,我们将其指定为 4。valstep
指定当我们将鼠标拖动到滑块上时,值以什么步长增加。 在这里,我们将其指定为 1.0,因为它表示叶子数。
def onchanged(s_value):
是滑块的回调函数。 它接收滑块的当前值,清除先前在轴域上的图,并用新值绘制图形。slider_n.on_changed(onchanged)
捕获滑块上的on_changed
事件,然后调用回调函数onchanged
。ebx = plt.axes([0.5, 0.005, 0.1, 0.05])
定义要放置按钮的轴域,exit = Button(ebx, 'Quit')
定义按钮。ebx
是轴域引用;'Quit'
是要放置在图中按钮小部件上的标签def close(event):
是Button
小部件的回调函数。 它只是关闭所有图形窗口。exit.on_clicked(close)
捕获按钮上的on_clicked
事件 ,并调用回调函数close
plt.show()
在tkagg
后端上显示图。
运行前面的代码时,应该获得以下输出图。 第一个图是您第一次获得图时看到的。 当我们使用 4 初始化滑块时,它将具有四片叶子。将滑块拖动到 8.00 时,您将看到第二个图:
使用 Tkinter GUI 的滑块和按钮小部件
在本秘籍中,我们将学习如何使用,Tkinter GUI 的滑块和按钮小部件代替 Matplotlib 小部件。 该绘图的功能与先前秘籍的完全相同。 Matplotlib 仍具有程序控制流程,我们仍将使用plt.figure()
来调用,后端和关联的小部件。 此外,我们将调用 Tkinter 的tk.Scale
缩放器和tk.Button
按钮小部件,带有关联的回调函数,代替了我们在前面的秘籍中使用的 Matplotlib 的滑块和按钮小部件。
准备
设置后端:
import matplotlib
matplotlib.use('tkagg')
导入所需的库:
import tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下是实现逻辑所需的步骤:
- 准备极坐标图的数据:
theta = np.arange(0., 2., 1./180.)*np.pi
- 定义并实例化图形:
fig = plt.figure(figsize=(6, 5), dpi=100)
- 定义并实例化图中的轴域:
ax = fig.add_subplot(111,projection='polar')
- 绘制极坐标图:
ax.plot(theta, 5*np.cos(3*theta))
- 定义将要放置和 Tkinter 小部件的窗口:
window = fig.canvas.manager.window
- 定义滑块小部件的回调函数:
def update():
n=n_slider.get()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义并实例化滑块:
n_slider = tk.Scale(master=window,variable=tk.IntVar(), from_=3,
to=10, label='#of leaves', orient=tk.HORIZONTAL,length=int(fig.bbox.width),
width=int(fig.bbox.height * 0.05), command = lambda i :
update())
- 将滑块打包到窗口中:
n_slider.set(4)
n_slider.pack(after=fig.canvas.get_tk_widget())
- 定义退出按钮的回调函数:
def close():
plt.close('all')
window.quit()
- 定义并实例化
Button
:
button = tk.Button(master=window, text="Quit", command=close)
- 将按钮打包到窗口中:
button.pack(side=tk.BOTTOM)
- 在 Tkinter 后端上显示图:
plt.show()
工作原理
这是前面代码的解释:
- 前四个步骤已经为您所熟悉。
window = fig.canvas.manager.window
可通过其窗口访问 Tkinter 的应用。def update():
是tk.Scale
小部件的回调函数:n=n_slider.get()
获取拖动和释放鼠标时滑块的当前值,在这种情况下为 7。ax.clear()
删除轴域上的前一个图。ax.plot(theta, 5*np.cos(n*theta))
绘制新图,其当前值为n
。fig.canvas.draw()
刷新图形。
n_slider = tk.Scale()
定义带有以下参数的滑块小部件:master=window
指定将滑块小部件创建为主窗口的的子级。variable=tk.IntVar()
指定滑块变量是整数; 由于它代表绘图上的叶子数,因此将其定义为整数是有意义的。from_=3
和to=10
表示滑块的起始值和结束值,因此用户可以在 3 到 10 之间拖动滑块。label='#of leaves'
指定要在滑块左侧显示的滑块标签。orient=tk.HORIZONTAL
指定缩放器是水平绘制的,而不是垂直绘制的。length=int(fig.bbox.width)
指定窗口小部件的长度(以像素为单位)。fig.bbox.width
以浮点数返回图形的宽度,int
将其转换为整数。 因此,缩放器将完整的图形水平分布。width=int(fig.bbox.height * 0.05)
指定缩放器的高度(以像素为单位)。 通过乘以 0.05,我们得到的是缩放器总图形高度的 5%。command = lambda i : update()
将滑块的回调函数指定为update()
,因此,当我们在滑块上拖动鼠标并释放时,它将调用更新函数。
n_slider.set(4)
设置滑块的初始值,第一次显示绘图时,将显示 , 。 因此,当该图第一次显示时,我们应该看到有四个叶子。n_slider.pack(after=fig.canvas.get_tk_widget())
指定在画布下方(之后)绘制滑块小部件。 Tkinter 没有画布的子类,但是可以通过 ,get_tk_widget()
方法访问画布。pack()
是将小部件打包到窗口中的 Tkinter 方法。def close():
是按钮小部件的回调函数:plt.close('all')
关闭所有数字window.quit()
退出窗口应用
button = tk.Button()
定义了 Tkinter 的按钮小部件:master=window
指定应将按钮小部件创建为主窗口的子级。text="Quit"
指定按钮的标签,该标签将显示在按钮上。command=close
指定回调函数为close()
。
button.pack(side=tk.BOTTOM)
指定按钮应包装在底部的窗口中。plt.show()
在 Tkinter 后端上显示图形。
当您运行前面的代码时,您应该第一次获得第一张图。 将滑块拖动到 7 时,应该会看到第二个图。 您可以通过单击 退出按钮退出:
将 Matplotlib 嵌入到 Tkinter GUI 应用中
在本秘籍中,我们将学习如何将 Matplotlib 嵌入到 Tkinter GUI 应用中。 在这里,应用流程的控制将通过 Tkinter 进行。 在这里,我们将不使用, pyplot
模块和相关的plt.figure()
方法。 相反,我们调用 Tkinter 应用并将 Matplotlib 的画布作为小部件嵌入。
准备
在这里,我们将不会设置后端,因为应用本身将从 GUI 的启动。
导入所需的库:
import tkinter as tk
import numpy as np
from tkinter.font import Font
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
操作步骤
以下是实现逻辑要遵循的步骤:
- 定义并实例化图形:
fig = Figure(figsize=(6, 5), dpi=100)
- 定义 Tkinter 窗口并设置该窗口的标题:
window=tk.Tk()
window.wm_title("Embedding in Tk")
- 定义和画布和导航工具栏,然后将它们打包到 Tkinter 窗口中:
canvas = FigureCanvasTkAgg(fig, master=window)
toolbar = NavigationToolbar2Tk(canvas, window)
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
- 在各种小部件上定义用于文本的字体:
myfont = Font(family='Helvetica', size=12, weight='bold')
- 在图上定义轴域,准备数据,并绘制极坐标图:
ax = fig.add_subplot(111,projection='polar')
theta = np.arange(0., 2., 1./180.)*np.pi
ax.plot(theta, 5*np.cos(3*theta))
- 定义
Slider
小部件的回调函数:
def update():
n=n_slider.get()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义并实例化
Slider
小部件,并将其打包到window
中:
n_slider = tk.Scale(master=window,variable=tk.IntVar(), from_=3,
to=10, label='#of leaves',
orient=tk.HORIZONTAL,length=int(fig.bbox.width),
width=int(fig.bbox.height * 0.05), command =
lambda i : update(),font=myfont)
n_slider.set(4)
n_slider.pack(after=fig.canvas.get_tk_widget())
- 为退出按钮小部件定义
callback
函数:
def exit():
window.quit()
window.destroy()
- 定义并实例化
Quit
按钮并将其打包到window
中:
button = tk.Button(master=window, text="Quit", command=exit,
font=myfont)
button.pack(side=tk.BOTTOM)
- 启动
mainloop
以捕获用户触发的事件:
tk.mainloop()
工作原理
这是前面代码的解释:
fig = Figure(figsize=(6, 5), dpi=100)
定义并实例化图形对象。Figure()
从matplotlib.figure
类的导入。 在前两个秘籍中,我们为此目的使用了plt.figure()
!window=tk.Tk()
通过其主窗口小部件调用 Tkinter GUI 应用。window.wm_title("Embedding in Tk")
设置窗口的标题,该标题将显示在窗口顶部。canvas = FigureCanvasTkAgg(fig, master=window)
定义画布(图形的游乐场,例如绘制图形的纸张),并将图形附加到此画布上:master=window
指定画布是 Tkinter 窗口对象的子级。toolbar = NavigationToolbar2Tk(canvas, window)
再次将导航工具栏指定为 Tkinter 窗口的子级,并将其附加到画布上。
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
将画布和导航工具栏打包到 Tkinter 的主窗口中:side=tk.TOP
指定要放置在window
顶部的画布,要位于其下面的工具栏。fill=tk.BOTH
指定画布应在 X(水平)和 Y(垂直)方向上填充window
expand=1
指定在容纳所有小部件之后,将主window
中的任何附加空间均等地调整为具有expand=1
的小部件。myfont = Font(family='Helvetica', size=12, weight='bold')
定义了用于小部件上的文本的字体字典,以便它们在图中看起来都相似。
- 步骤 5 定义极坐标图的轴域,数据,并将其绘制在轴域上。
def update():
是滑块小部件的回调函数,如前面的秘籍中所述。n_slider = tk.Scale()
定义滑块控件,然后将其初始化为 4,然后将其打包到窗口中,如前面的秘籍中所述。def exit():
是退出按钮的回调函数,用于退出应用。 这与先前秘籍中使用的close()
函数不同:window.quit()
从mainloop
退出。window.destroy()
销毁了该应用,以避免特别是 Windows OS 中的错误。button = tk.Button()
和button.pack(side=tk.BOTTOM)
与前面的秘籍中所述相同。
tk.mainloop()
调用 Tkinter 的主应用循环以捕获事件,调用适当的回调函数。
运行前面的代码时,应该第一次看到第一个图,将滑块拖动到 9 时,应该看到第二个图。 您可以通过单击 退出按钮来退出应用:
使用 WxPython GUI 的滑块和按钮小部件
在本秘籍中,我们将学习如何使用 wxPython 的滑块和按钮小部件代替 Matplotlib 小部件,就像我们使用 Tkinter 小部件一样。
wxPython 是 wxWidgets 模块的包装。 它还与标准 Python 发行版(如 Anaconda)打包在一起。
准备
将后端设置为wxAgg
:
import matplotlib
matplotlib.use('wxagg')
导入所需的库:
import wx
import numpy as np
import matplotlib.pyplot as plt
操作步骤
以下是实现所需逻辑的步骤:
- 定义并实例化图形:
fig = plt.figure(figsize=(6, 5), dpi=100)
- 定义轴域,定义极坐标图的数据,然后绘制极坐标图:
ax = fig.add_subplot(111,projection='polar')
theta = np.arange(0., 2., 1./180.)*np.pi
ax.plot(theta, 5*np.cos(4*theta))
- 定义我们用来通过 Matplotlib 连接
wx
小部件的窗口:
window = fig.canvas.manager.window
- 为滑块小部件定义回调函数:
def update(event):
n=n_slider.GetValue()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义并实例化
wxPython
的滑块小部件,并将其与回调函数绑定:
n_slider = wx.Slider(window, wx.ID_ANY, 4, 3, 10, size=(250,10),
style=(wx.SL_AUTOTICKS | wx.SL_HORIZONTAL |
wx.SL_LABELS))
n_slider.Bind(wx.EVT_SCROLL, update)
- 为退出按钮小部件定义回调函数:
def close(event):
plt.close('all')
- 定义并实例化
Quit
按钮小部件并将其与回调函数绑定:
button = wx.Button(window, wx.ID_ANY, "Quit")
button.Bind(wx.EVT_BUTTON, close)
- 用定义当前
window
大小的sizer
:
sizer = window.GetSizer()
- 将按钮小部件插入到
window
中:
sizer.Insert(0, button, 0, wx.ALIGN_CENTER)
- 将滑块小部件插入
window
的中:
sizer.Insert(2, n_slider, 0, wx.ALIGN_RIGHT)
- 在
wxPython
后端上显示图形:
plt.show()
工作原理
这是前面代码的解释:
- 前两个步骤使用
plt.figure()
,轴域和数据定义图形,并在图形上绘制和极坐标图。 window = fig.canvas.manager.window
可以通过其窗口访问wxPython
应用。def update(event):
是wx.Slider()
小部件的回调函数。 在这里,我们必须将event
参数传递给函数:n=n_slider.GetValue()
获取滑块的当前值。 请注意,语法与 Tkinter 相比有所不同。- 此函数的其余三个步骤与 Tkinter 完全相同。
n_slider = wx.Slider(window, wx.ID_ANY, 3, 3, 10, size=(250,10), style=(wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS))
定义了滑块小部件:window
指定滑块是主窗口的子对象。wx.ID_ANY
指定为此小部件使用系统生成的标识号。- 滑块第一次出现时的初始值为 3。
- 3 和 10 是滑块的起始值和结束值。
size=(250,10)
指定滑块控件的长度和高度(以像素为单位)。style()
指定滑块的各种参数:wx.SL_AUTOTICKS
指定滑块应显示刻度线。wx.SL_HORIZONTAL
指定滑块应水平放置。wx.SL_LABELS
指定滑块的开始,当前值和结束值的打印标签。
n_slider.Bind(wx.EVT_SCROLL, update)
将滑块的滚动事件与对应的回调函数update()
连接起来。def close(event):
是退出按钮的回调函数。 它基本上关闭了所有数字。button = wx.Button(window, wx.ID_ANY, "Quit")
定义 WxPython 的按钮小部件:window
指定按钮是主窗口的子对象wx.ID_ANY
指定为此小部件使用系统生成的标识号"Quit"
是要在按钮小部件上打印的标签
button.Bind(wx.EVT_BUTTON, close)
将按钮的点击事件连接到相应的回调函数close()
上。sizer = window.GetSizer()
获取当前窗口大小。sizer
是 WxPython 创建绘制在图中的各种小部件的布局的方式。sizer.Insert(0, button, 0, wx.ALIGN_CENTER)
在主窗口中绘制按钮小部件:0
指定此窗口小部件在窗口中的放置顺序。 0 表示将其放置在索引 0 处,这意味着该按钮将位于窗口的顶部。button
将小部件放置在图形上。0
指定不进行窗口小部件的相对大小调整。wx.ALIGN_CENTER
指定窗口小部件应在中心对齐。
sizer.Insert(2, n_slider, 0, wx.ALIGN_RIGHT)
将滑块控件绘制在第二个索引处。 画布会自动放置在索引 1,将滑块推到窗口底部:wx.ALIGN_RIGHT
指定滑块小部件应在窗口中右对齐
plt.show()
在wxPython's
后端显示图形。
当您运行上述代码时,将滑块拖动到 10 时,您应该第一次看到的第一个图,第一次,的第二个图出现。您可以通过单击退出应用的 退出按钮:
将 Matplotlib 嵌入到 wxPython GUI 应用中
在本秘籍中,我们将学习如何在 wxPython GUI 应用中嵌入 Matplotlib 图。 我们将使用与本章相同的数据和绘图。
准备
导入所需的库:
import wx
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
操作步骤
以下是实现逻辑所需的步骤:
- 定义
wxPython
应用:
app = wx.App()
- 定义显示绘图和小部件的窗口:
window = wx.Frame(None, -1, "Embedding with wxPython")
- 定义并实例化
figure
,canvas
和toolbar
:
fig = Figure(figsize=(6, 5), dpi=100)
canvas = FigureCanvas(window, -1, fig)
toolbar = NavigationToolbar2WxAgg(canvas)
- 定义极坐标图的轴域和数据,并绘制极坐标图:
ax = fig.add_subplot(111,projection='polar')
theta = np.arange(0., 2., 1./180.)*np.pi
ax.plot(theta, 5*np.cos(3*theta))
- 为
Slider
小部件定义callback
函数:
def update(event):
n=n_slider.GetValue()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义
Slider
小部件并将其与callback
函数绑定:
n_slider = wx.Slider(window, wx.ID_ANY, 3, 3, 10, size=(250,20),
style=(wx.SL_AUTOTICKS | wx.SL_HORIZONTAL |
wx.SL_LABELS))
n_slider.Bind(wx.EVT_SCROLL, update)
- 在小部件上定义要应用于文本的字体:
myfont = wx.Font(12, wx.ROMAN, wx.ITALIC, wx.BOLD)
- 为滑块小部件设置字体:
n_slider.SetFont(myfont)
- 为
Quit
按钮小部件定义callback
函数:
def close(event):
window.Close()
- 定义
Quit
按钮小部件并将其与callback
函数绑定:
button = wx.Button(window, wx.ID_ANY, "Quit", size=
(int(fig.bbox.width),int(fig.bbox.height)*0.1))
button.Bind(wx.EVT_BUTTON, close)
- 在
Quit
按钮小部件中设置字体:
button.SetFont(myfont)
- 将
window
的初始大小设置为figure
的初始大小:
window.SetInitialSize(wx.Size(int(fig.bbox.width),
int(fig.bbox.height)))
- 定义
sizer
并将canvas
,toolbar
,slider
和button
小部件插入window
中:
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Insert(0, canvas, 1, wx.EXPAND | wx.ALL)
sizer.Insert(1, button, 0, wx.EXPAND)
sizer.Insert(2, n_slider, 0, wx.ALIGN_RIGHT)
sizer.Insert(3, toolbar, 0, wx.ALIGN_LEFT)
- 设置
window
以适合所有小部件:
window.SetSizer(sizer)
window.Fit()
window.Show()
- 启动
mainloop
来捕获用户触发的事件:
app.MainLoop()
工作原理
这是前面代码的解释:
app = wx.App()
启动wxPython
GUI 应用。window = wx.Frame(None, -1, "Embedding with wxPython")
定义并实例化window
对象,在其中显示,figure
的对象:None
指定,window
是父对象-1
指定window
标识号"Embedding with wxPython"
指定将显示在window
顶部的窗口标签
fig = Figure(figsize=(6, 5), dpi=100)
定义并实例化figure
canvas = FigureCanvas(window, -1, fig)
定义了连接图形并将其包装到window
中的画布toolbar = NavigationToolbar2WxAgg(canvas)
定义toolbar
并将其打包到canvas
中- 步骤 4 定义极坐标图的轴域和数据,并将其绘制在轴域上
def update(event):
与 , 先前秘籍的callback
函数相同n_slider = wx.Slider()
和n_slider.Bind()
与相同与相同与相同 ]myfont = wx.Font(12, wx.ROMAN, wx.ITALIC, wx.BOLD)
定义要应用于小部件上文本的字体字典,字体大小为 12,罗马字体,斜体样式和粗体。n_slider.SetFont(myfont)
将字体字典应用于滑块小部件上的文本def close(event):
是Quit
按钮的回调函数:window.Close()
关闭window
GUI 应用button = wx.Button()
和button.Bind()
分别与前面相同。 我们在此处为按钮小部件指定了特定的宽度和高度,而我们在前面的秘籍中使用了默认大小button.SetFont(myfont)
将字体字典应用于按钮上的文本。window.SetInitialSize(wx.Size(int(fig.bbox.width), int(fig.bbox.height)))
设置窗口大小等于图形大小sizer = wx.BoxSizer(wx.VERTICAL)
为具有垂直布局的图形的布局定义缩放器对象。 这意味着添加到此滑块上的所有小部件将垂直排列,一个在另一个下方:sizer.Insert(0, canvas, 1, wx.EXPAND | wx.ALL)
将画布添加到索引为 0(顶部)的缩放器中;wx.EXPAND | wx.ALL
确保图和画布的大小一致sizer.Insert(1, button, 0, wx.EXPAND)
向大小调整器添加一个按钮;wx.EXPAND
指定将按钮的全长展开sizer.Insert(2, n_slider, 0, wx.ALIGN_RIGHT)
向右对齐将 ,滑块添加到sizer
sizer.Insert(3, toolbar, 0, wx.ALIGN_LEFT)
将工具栏左对齐添加到大小调整器中
window.SetSizer(sizer)
将sizer
布局添加到主window
window.Fit()
调整空间,使所有小部件都正确地适合图形window.Show()
在window
中显示figure
。app.MainLoop()
启动 GUI 应用循环以捕获事件并触发各自的回调函数。
当您运行上述代码时,您应该第一次看到第一个绘图,它带有三个叶子,在将滑块拖动到滑块的末尾时,第二个绘图带有值 10 。
使用 Qt GUI 的滑块和按钮小部件
在本秘籍中,我们将学习如何利用, Qt GUI 滑块和按钮小部件代替 Matplotlib 小部件。 此代码以及和下一个秘籍中的代码均适用于, Qt4 和 Qt5 GUI 版本。
Qt GUI 非常类似于,wxPython
GUI。 我们将使用QHBoxLayout
和QVBoxLayout
代替和sizer
; 代替fig.canvas.manager.window
,我们将拥有fig.canvas.setLayout
; 并以connect
代替Bind
。
准备
- 将后端设置为
Qt5
:
import matplotlib
matplotlib.use('Qt5Agg')
- 导入所需的库:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5, QtGui
if is_pyqt5():
from matplotlib.backends.backend_qt5agg import FigureCanvas
else:
from matplotlib.backends.backend_qt4agg import FigureCanvas
操作步骤
以下是实现逻辑的步骤:
- 定义并实例化
figure
:
fig = plt.figure(figsize=(8, 6), dpi=100)
- 定义轴域和数据的极坐标图,并绘制极坐标图:
ax = fig.add_subplot(111,projection='polar')
theta = np.arange(0., 2., 1./180.)*np.pi
ax.plot(theta, 5*np.cos(4*theta))
- 定义滑块小部件的回调函数:
def update():
n=n_slider.value()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义滑块小部件:
n_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
n_slider.setRange(3, 10)
n_slider.setSingleStep(1)
n_slider.setValue(4)
n_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
n_slider.setTickInterval(1)
n_slider.setFont(QtGui.QFont("Arial",30))
- 将,滑块小部件与,对应的
callback
函数连接:
n_slider.sliderReleased.connect(update)
- 为的退出按钮定义
callback
函数:
def close():
plt.close('all')
- 定义和退出按钮小部件:
button = QtWidgets.QPushButton("Quit")
button.setGeometry(QtCore.QRect(250, 0, 75, 25))
- 将和退出按钮与和对应的
callback
函数连接起来:
button.clicked.connect(close)
- 在垂直框内定义,然后向其添加滑块和按钮小部件:
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(n_slider)
hbox.addWidget(button)
- 定义垂直框并添加,隔离对象和
hbox
水平布局框:
vbox = QtWidgets.QVBoxLayout()
vspace = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
vbox.addItem(vspace)
vbox.addSpacing(20)
vbox.addLayout(hbox)
- 将
vbox
垂直布局框连接到图形的画布:
fig.canvas.setLayout(vbox)
- 在 Qt 后端上显示该图:
plt.show()
工作原理
这是前面代码的解释:
- 您在前面的秘籍中已经看到了前两个步骤。
def update():
是滑块小部件的回调函数。n=n_slider.value()
获取滑块的当前值。 请注意和前面部分中其他两个 GUI 的语法差异。 此函数的其余三个语句与前面的秘籍完全相同和n_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
定义Qt
的滑块控件,并指定应水平绘制:n_slider.setRange(3, 10)
指定滑块的最小值和最大值n_slider.setSingleStep(1)
指定在滑块上拖动鼠标时每个步骤的大小。 在这里,我们将其指定为 1n_slider.setValue(4)
指定滑块首次出现时的初始值n_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
指定 , 滑块应绘制刻度线,并且应在滑块下方n_slider.setTickInterval(1)
指定刻度之间的间隔。 在这里,我们将其指定为 1n_slider.setFont(QtGui.QFont("Arial",30))
的字体设置为Arial
, 设置字体大小为 30。
n_slider.sliderReleased.connect(update)
将滑块事件"sliderReleased"
与对应的回调函数,update()
连接起来def close():
是Quit
按钮的回调函数,它与先前的 GUI 完全相同button = QtWidgets.QPushButton("Quit")
指定带有标签Quit
的按钮小部件button.setGeometry(QtCore.QRect(250, 0, 75, 25))
定义按钮的放置位置,长度和高度。(250, 0, 75, 25)
从图的左侧指定 250 像素,从底部指定 0 像素,长度为 75 像素,高度为 25 像素button.clicked.connect(close)
将按钮事件clicked
与对应的回调函数close()
连接,hbox = QtWidgets.QHBoxLayout()
定义水平布局框:hbox.addWidget(n_slider)
将滑块添加到水平框hbox.addWidget(button)
将按钮小部件添加到水平框- 滑块和按钮小部件将在一行中水平相邻放置
vbox = QtWidgets.QVBoxLayout()
定义垂直布局框:vspace = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
创建一个要包含在垂直布局框中的空间对象,以便在图的底部绘制 S 封面和按钮小部件。vbox.addItem(vspace)
向垂直布局框添加垂直空间vbox.addSpacing(20)
为垂直布局框中的像素增加了额外的空间vbox.addLayout(hbox)
将水平布局框添加到垂直布局框中fig.canvas.setLayout(vbox)
将垂直布局框连接到图形的画布。
plt.show()
在Qt5
后端显示图形。
运行前面的代码后,您应该第一次看到第一个图,将滑块拖动到 5 后,您应该看到第二个图:
将 Matplotlib 嵌入到 Qt GUI 应用中
在本秘籍中,我们将学习如何在Qt
GUI 应用中嵌入 Matplotlib 画布。
准备
导入所需的库:
import sys
import numpy as np
from matplotlib.figure import Figure
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5,
QtGui
if is_pyqt5():
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT
as NavigationToolbar)
else:
from matplotlib.backends.backend_qt4agg import (
FigureCanvas, NavigationToolbar2QT
as NavigationToolbar)
操作步骤
以下是实现逻辑的步骤:
- 定义 GUI 应用和窗口来绘制图形:
qApp = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
- 定义图形,画布和工具栏:
fig = Figure(figsize=(8, 6), dpi=100)
canvas = FigureCanvas(fig)
toolbar = NavigationToolbar(canvas, window)
- 定义轴域和数据,并绘制极坐标图:
ax = fig.add_subplot(111,projection='polar')
theta = np.arange(0., 2., 1./180.)*np.pi
ax.plot(theta, 5*np.cos(4*theta))
- 定义滑块的回调函数:
def update():
n=n_slider.value()
ax.clear()
ax.plot(theta, 5*np.cos(n*theta))
fig.canvas.draw()
- 定义滑块小部件并将其与对应的回调函数连接:
n_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
n_slider.setRange(3, 10)
n_slider.setSingleStep(1)
n_slider.setValue(4)
n_slider.setTickPosition(QtWidgets.QSlider.TicksBelow)
n_slider.setTickInterval(1)
n_slider.setFont(QtGui.QFont("Arial",20))
n_slider.sliderReleased.connect(update)
- 为退出按钮定义回调函数:
def close():
window.close()
- 定义退出按钮小部件,并将其连接到相应的回调函数:
button = QtWidgets.QPushButton("Quit")
button.setFont(QtGui.QFont("Arial",30))
button.clicked.connect(close)
- 定义水平框,然后将滑块及其标签项放在其中:
hbox = QtWidgets.QHBoxLayout()
minn = QtWidgets.QLabel('3')
minn.setFont(QtGui.QFont("Arial",20))
maxn = QtWidgets.QLabel('10')
maxn.setFont(QtGui.QFont("Arial",20))
hbox.addWidget(minn)
hbox.addWidget(n_slider)
hbox.addWidget(maxn)
- 定义垂直框并在其中放置工具栏,间隔,按钮小部件和水平框的:
vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(toolbar)
vspace = QtWidgets.QSpacerItem(0, 750)
vbox.addItem(vspace)
vbox.addSpacing(20)
vbox.addLayout(hbox)
vbox.addWidget(button)
- 将垂直框连接到图形画布:
fig.canvas.setLayout(vbox)
- 设置窗口标题并显示它:
window.setWindowTitle("Embedding with Qt")
window.setCentralWidget(canvas)
window.show()
- 启动应用循环以捕获用户操作:
qApp.exec_()
工作原理
这是前面代码的解释:
qApp = QtWidgets.QApplication(sys.argv)
调用Qt
GUI 应用。 它期望sys.argv
作为参数,即使它为空window = QtWidgets.QMainWindow()
定义显示图形的主窗口fig = Figure(figsize=(8, 6), dpi=100)
定义图形canvas = FigureCanvas(fig)
定义画布并将图形附加到画布上toolbar = NavigationToolbar(canvas, window)
定义了 GUI 的工具栏,并将其附加到主window
和canvas
- 步骤 3 定义极坐标图的轴域和数据,并绘制极坐标图
def update():
是滑块的回调函数, 是 ,与前面的秘籍完全相同n_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
定义了滑块,并且所有参数都完全相同 , 与先前的秘籍n_slider.sliderReleased.connect(update)
将"sliderReleased"
事件连接到相应的回调函数,update()
def close():
是Quit
按钮的回调函数,它仅关闭窗口,而不是应用button = QtWidgets.QPushButton("Quit")
定义Qt
的按钮小部件。 与 , 前面的秘籍不同,此处无需设置button.setGeometry(QtCore.QRect(250, -10, 75, 25))
,因为我们将按钮单独垂直放置在一行中button.setFont(QtGui.QFont("Arial",30))
设置字体为Arial
,字体大小为 30button.clicked.connect(close)
将按钮的"clicked"
事件连接到相应的回调函数,close()
hbox = QtWidgets.QHBoxLayout()
定义水平布局框:minn = QtWidgets.QLabel('3')
为要显示的滑块最小值定义标签对象minn.setFont(QtGui.QFont("Arial",20))
将字体和字体大小设置为最小值maxn = QtWidgets.QLabel('10')
定义要显示的滑块最大值的标签对象maxn.setFont(QtGui.QFont("Arial",20))
设置最大值的字体和字体大小hbox.addWidget(minn)
将minn
标签添加到hbox
hbox.addWidget(n_slider)
将滑块添加到hbox
hbox.addWidget(maxn)
将标签maxn
添加到hox
vbox = QtWidgets.QVBoxLayout()
定义垂直布局框vbox.addWidget(toolbar)
添加在图顶部的工具栏vspace = QtWidgets.QSpacerItem(0, 750)
定义空间对象vbox.addItem(vspace)
在画布/图形将出现的位置添加空间对象vbox.addSpacing(20)
在画布下添加了 20 个像素的额外空间vbox.addLayout(hbox)
添加包含 , 滑块以及相关的最小和最大标签的hbox
vbox.addWidget(button)
将按钮小部件添加到vox
fig.canvas.setLayout(vbox)
向图形画布添加了vbox
布局。window.setWindowTitle("Embedding with Qt")
设置主窗口的标题window.setCentralWidget(canvas)
将画布设置为中央小部件,以便主极图出现在中央window.show()
显示图形窗口qApp.exec_()
调用主循环以捕获事件并触发相应的回调函数
当您运行上述代码时,将滑块第一次拖动到 8 时,您应该会第一次看到左侧的图,而右侧则是右侧的图。您可以通过单击退出按钮退出应用: