Matplotlib-绘图秘籍-一-

73 阅读1小时+

Matplotlib 绘图秘籍(一)

原文:Matplotlib Plotting Cookbook

协议:CC BY-NC-SA 4.0

零、前言

matplotlib 是用于绘图的 Python 模块,并且是科学 Python 模块套件的组件。 matplotlib 允许您使用全面的 API 轻松定制专业级图形,以自定义图形的各个方面。 在本书中,我们将介绍不同类型的图形以及如何调整图形以满足您的需求。 秘籍是正交的,您将能够非常快速地编写自己的解决方案。

这本书涵盖的内容

第 1 章,“第一步”介绍了使用 matplotlib 的基础知识。 基本图形类型以最少的示例介绍。

第 2 章,“自定义颜色和样式”涵盖了如何控制图形的颜色和样式-包括标记,线条粗细,线条图案以及使用颜色表为图的几个项目着色。

第 3 章,“处理标注”涵盖如何标注图形-这包括添加轴域图例,箭头,文本框和形状。

第 4 章,“处理图形”涵盖了如何准备复杂图形-这包括合成多个图形,控制长宽比,轴范围和坐标系。

第 5 章,“处理文件输出”涵盖位图或向量格式的文件输出。 对诸如透明度,分辨率和多页之类的问题进行了详细研究。

第 6 章,“处理地图”涵盖了绘制类似矩阵的数据-包括地图,颤动图和流图。

第 7 章,“处理 3D 图形”涵盖了 3D 图-包括散点图,线图,表面图和条形图。

第 8 章,“用户界面”涵盖了一组用户界面集成解决方案,从简单,极简到复杂。

这本书需要什么

本书中的示例是为 Matplotlib 1.2 和 Python 2.7 或 3 编写的。

大多数示例都依赖于 NumPy 和 SciPy。 一些示例需要 SymPy,而另一些示例则需要 LaTeX。

这本书适合谁

这本书适合有一些 Python 和科学背景的读者。

约定

在本书中,您会发现许多可以区分不同类型信息的文本样式。 以下是这些样式的一些示例,并解释了其含义。

文本中的代码字,数据库表名称,文件夹名称,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄如下所示:“我们可以通过使用include指令来包含其他上下文。”

代码块设置如下:

[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)

当我们希望引起您对代码块特定部分的注意时,相关的行或项目将以粗体显示:

[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)

任何命令行输入或输出的编写方式如下:

## cp /usr/src/asterisk-addons/configs/cdr_mysql.conf.sample
 /etc/asterisk/cdr_mysql.conf

新术语重要词以粗体显示。 您在屏幕上看到的单词,例如在菜单或对话框中,将以如下形式出现:“单击下一步按钮将您移至下一个屏幕”。

注意

警告或重要提示会出现在这样的框中。

提示

提示和技巧如下所示。

一、第一步

在本章中,我们将介绍:

  • 安装 matplotlib
  • 绘制一条曲线
  • 使用 NumPy
  • 绘制多条曲线
  • 从文件数据绘制曲线
  • 绘制点
  • 绘制条形图
  • 绘制多个条形图
  • 绘制堆叠的条形图
  • 绘制背对背条形图
  • 绘制饼图
  • 绘制直方图
  • 绘制箱形图
  • 绘制三角剖分

简介

matplotlib 使科学绘图非常简单。 matplotlib 并不是使图形绘制变得容易的首次尝试。 matplotlib 带来的是一种在易用性和功能之间取得平衡的现代解决方案。 matplotlib 是 Python(一种编程语言)的模块。 在本章中,我们将简要概述使用 matplotlib 的感觉。 简约秘籍用于介绍 matplotlib 建立的原理。

安装 matplotlib

在使用 matplotlib 尝试之前,需要先安装它。 在这里,我们介绍了一些技巧,以使 Matplotlib 正常运行并没有太多麻烦。

操作步骤

我们有三种可能的场景:您可能正在使用 Linux,OSX 或 Windows。

Linux

大多数 Linux 发行版默认都安装了 Python,并在其标准包列表中提供了 matplotlib。 因此,您要做的就是使用发行版的包管理器自动安装 matplotlib。 除了 matplotlib,我们强烈建议您安装 NumPy,SciPy 和 SymPy,因为它们应该可以一起使用。 以下列表包含启用不同 Linux 版本中可用的默认包的命令:

  • Ubuntu :默认的 Python 包是为 python 2.7 编译的。 在命令终端中,输入以下命令:

    sudo apt-get install python-matplotlib python-numpy python-scipy python-sympy
    
    
  • ArchLinux:默认的 Python 包是针对 Python 3 编译的。 在命令终端中,输入以下命令:

    sudo pacman -S python-matplotlib python-numpy python-scipy python-sympy
    
    

    如果您更喜欢使用 Python 2.7,请在包名称中将python替换为python2

  • Fedora:默认的 Python 包是针对 Python 2.7 编译的。 在命令终端中,输入以下命令:

    sudo yum install python-matplotlib numpy scipy sympy
    
    

    注意

    还有其他安装这些包的方法。 在本章中,我们提出了最简单,最无缝的方法。

Windows 和 OSX

Windows 和 OSX 没有用于软件安装的标准包系统。 我们有两个选择-使用现成的自安装包或从代码源编译 matplotlib。 第二种选择涉及更多工作。 值得努力安装最新的最新版本的 matplotlib。 因此,在大多数情况下,使用现成的包装是更实际的选择。

现成的包装有个选择:Anaconda,Entought Canopy,Algorete Loopy 等! 所有这些包都一次性提供了 Python,SciPy,NumPy,matplotlib 等(文本编辑器和精美的交互式 shell)。 实际上,所有这些系统都安装了自己的包管理器,从那里可以像在典型的 Linux 发行版上那样安装/卸载其他包。 为了简洁起见,我们将仅提供 Enthought Canopy 的说明。 所有其他系统都在线提供大量文档,因此安装它们应该不会有太大问题。

因此,让我们通过执行以下步骤来安装 Enthought Canopy:

  1. 下载 Enthought Canopy 安装程序。 您可以选择免费的 Express 版本。 该网站可以猜测您的操作系统并为您建议合适的安装程序。
  2. 运行 Enthought Canopy 安装程序。 如果您不想与其他用户共享已安装的软件,则无需成为管理员即可安装包。
  3. 安装时,只需单击下一步,即可保留默认设置。 您可以在这个页面中找到有关安装过程的其他信息。

而已! 您将安装 Python 2.7,NumPy,SciPy 和 matplotlib 并准备运行。

绘制一条曲线

HelloWorld 的初始示例! 绘图软件的通常是要显示一条简单的曲线。 我们将保持这种传统。 它还将使您大致了解 matplotlib 的工作方式。

准备

您需要安装 Python(v2.7 或 v3)和 matplotlib。 您还需要一个文本编辑器(任何文本编辑器都可以)和一个命令终端来键入和运行命令。

操作步骤

让我们从任何绘图软件提供的最常见和最基本的图形之一,曲线开始。 在另存为plot.py的文本文件中,我们具有以下代码:

import matplotlib.pyplot as plt

X = range(100)
Y = [value ** 2 for value in X]

plt.plot(X, Y)
plt.show()

假设您已经安装了和 Python,并且现在可以使用 Python 解释该脚本。 如果您不熟悉 Python,那么确实是我们那里的 Python 脚本! 在命令终端中,使用以下命令在保存plot.py的目录中运行脚本:

python plot.py

这样做将打开一个窗口,如以下屏幕截图所示:

How to do it...

窗口显示曲线Y = X ** 2,其中X[0, 99]范围内。 您可能已经注意到,该窗口有几个图标,其中一些如下:

  • How to do it...:此图标打开一个对话框,可让您将图形另存为图片文件。 您可以将其另存为位图图片或向量图片。
  • How to do it...:使用此图标可以翻译和缩放图形。 单击它,然后将鼠标移到图形上。 单击鼠标左键将根据鼠标移动来平移图形。 单击鼠标右键将修改图形的比例。
  • How to do it...:此图标会将图形恢复到初始状态,取消您之前可能已应用的任何平移或缩放。

工作原理

假设您对 Python 还不是很熟悉,那么让我们分析上一节中演示的脚本。

第一行告诉 Python 我们正在使用matplotlib.pyplot模块。 为了节省输入时间,我们将名称plt等同于matplotlib.pyplot。 这是一种非常常见的做法,您会在 matplotlib 代码中看到。

第二行创建一个名为X的列表,所有整数值从 0 到 99。range函数用于生成连续数字。 您可以运行交互式 Python 解释器,如果使用 Python 2,则键入命令range(100),如果使用 Python 3,则键入命令list(range(100))。这将显示从 0 到 99 的所有整数值的列表。 ,sum(range(100))将计算 0 到 99 之间的整数之和。

第三行创建一个名为Y的列表,列表X中的所有值均平方。 通过将函数应用于另一个列表的每个成员来构建新列表是一个 Python 习惯用法,名为列表推导式。 列表Y将以相同顺序包含列表X的平方值。 因此Y将包含 0、1、4、9、16、25,依此类推。

第四条线绘制一条曲线,其中曲线点的 x 坐标在列表X中给出,而曲线点的 y 坐标在列表Y中给出。 请注意,列表名称可以是您喜欢的任何名称。

最后一行显示结果,您将在运行脚本时在窗口中看到该结果。

更多

那么到目前为止我们学到了什么? 与诸如 gnuplot 之类的绘图包不同,matplotlib 并不是专门用于绘图的命令解释器。 与 Matlab 不同,matplotlib 也不是用于绘图的集成环境。 matplotlib 是用于绘图的 Python 模块。 使用 Python 脚本描述图形,这些脚本依赖于 matplotlib 提供的(相当大)功能集。

因此,matplotlib 背后的理念是利用现有语言 Python。 理由是 Python 是一种完整的,设计良好的通用编程语言。 将 matplotlib 与其他包结合使用不会涉及任何技巧和黑客,而仅涉及 Python 代码。 这是因为有许多用于 Python 的包可以执行几乎所有任务。 例如,要绘制存储在数据库中的数据,您将使用数据库包读取数据并将其提供给 matplotlib。 要生成大量统计图形,您将使用科学计算包,例如 SciPy 和 Python 的 I/O 模块。

因此,与许多绘图包不同,matplotlib 是非常正交的,它仅作图而仅作图。 如果您想从文件中读取输入或进行一些简单的中间计算,则必须使用 Python 模块和一些粘合代码来实现。 幸运的是,Python 是一种非常流行的语言,易于掌握并且拥有庞大的用户群。 我们将一点一点地证明这种方法的强大功能。

使用 NumPy

使用 matplotlib 不需要 NumPy 。 但是,许多 matplotlib 技巧,代码示例和示例都使用 NumPy。 简短介绍 NumPy 的用法将向您显示原因。

准备

除了安装 Python 和 matplotlib 外,还安装了 NumPy。 您有一个文本编辑器和一个命令终端。

操作步骤

让我们绘制另一条曲线sin(x),其中x[0,2 * pi]区间内。 与先前脚本的唯一区别是我们生成点坐标的部分。 输入以下脚本并将其保存为sin-1.py

import math
import matplotlib.pyplot as plt

T = range(100)
X = [(2 * math.pi * t) / len(T) for t in T]
Y = [math.sin(value) for value in X]

plt.plot(X, Y)
plt.show()

然后,键入以下脚本并将其保存为sin-2.py

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(0, 2 * np.pi, 100)
Y = np.sin(X)

plt.plot(X, Y)
plt.show()

运行sin-1.pysin-2.py都会准确显示以下图形:

How to do it...

工作原理

第一个脚本sin-1.py仅使用 Python 的标准库生成正弦曲线的坐标。 以下几点描述了我们在上一节的脚本中执行的步骤:

  1. 我们创建了一个列表T,其编号为 0 到 99,我们的曲线将绘制 100 个点。
  2. 我们通过简单地重新缩放T中存储的值来计算 x 坐标,以使 x 从 0 变为2pirange()内置函数只能生成整数值)。
  3. 与第一个示例一样,我们生成了 y 坐标。

第二个脚本sin-2.pysin-1.py完全相同,其结果是相同的。 但是,由于sin-2.py使用 NumPy 包,因此它稍短一些并且更易于阅读。

提示

NumPy 是用于科学计算的 Python 包。 matplotlib 可以在没有 NumPy 的情况下工作,但是使用 NumPy 可以节省大量的时间和精力。 NumPy 包提供了一个功能强大的多维数组对象和许多用于操纵它的函数。

NumPy 包

sin-2.py中,X列表现在是一维 NumPy 数组,在 0 和2pi之间具有 100 个均匀间隔的值。 这是函数numpy.linspace的目的。 可以说,这比我们在sin-1.py中进行的计算更加方便。 Y列表也是一维 NumPy 数组,其值是根据X的坐标计算的。 NumPy 函数适用于整个数组,就像它们适用于单个值一样。 同样,不需要像在sin-1.py中那样一目了然地显式计算这些值。 与纯 Python 版本相比,我们的代码较短但可读性强。

更多

NumPy 可以一次对整个数组执行操作,从而在生成曲线坐标时为我们节省了很多工作。 此外,使用 NumPy 最有可能导致代码快于纯 Python 代码。 更容易阅读和更快的代码,不喜欢什么? 下面是一个示例,其中我们使用200点在[-3, 2]区间绘制二项式x^2 - 2x + 1

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-3, 2, 200)
Y = X ** 2 - 2 * X + 1.

plt.plot(X, Y)
plt.show()

运行前面的脚本将为我们提供如下图所示的结果:

There's more...

同样,我们可以用纯 Python 进行绘制,但是可以说它不那么容易阅读。 尽管可以在不使用 NumPy 的情况下使用 matplotlib,但这两者构成了强大的组合。

绘制多条曲线

我们绘制曲线的原因之一是比较那些曲线。 他们匹配吗? 它们在哪里匹配? 他们在哪里不匹配? 它们相关吗? 图形可以帮助您快速做出判断,以便进行更彻底的调查。

操作步骤

让我们以[0, 2pi]间隔显示sin(x)cos(x),如下所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(0, 2 * np.pi, 100)
Ya = np.sin(X)
Yb = np.cos(X)

plt.plot(X, Ya)
plt.plot(X, Yb)
plt.show()

前面的脚本将为我们提供如下图所示的结果:

How to do it...

工作原理

两条曲线以不同的颜色显示,由 matplotlib 自动拾取。 我们对一条曲线使用一个函数call plt.plot(); 因此,我们必须在这里两次调用plt.plot()。 但是,我们仍然只需要调用一次plt.show()。 函数calls plt.plot(X, Ya)plt.plot(X, Yb)可以看作是意图的声明。 我们想将这两套点链接在一起,并为每套点分别绘制一条曲线。

matplotlib 将仅记录此意图,但不会进行任何绘制。 但是,plt.show()曲线将发出信号,表明我们要绘制到目前为止已描述的内容。

更多

这种延迟渲染机制对于 matplotlib 至关重要。 您可以声明渲染的时间以及适合的时间。 仅当您调用 plt.show()时,图形才会呈现。 为了说明这一点,让我们看下面的脚本,该脚本呈现一个钟形曲线,以及该曲线在每个点的斜率:

import numpy as np
import matplotlib.pyplot as plt

def plot_slope(X, Y):
  Xs = X[1:] - X[:-1]
  Ys = Y[1:] - Y[:-1]
  plt.plot(X[1:], Ys / Xs)

X = np.linspace(-3, 3, 100)
Y = np.exp(-X ** 2)

plt.plot(X, Y)
plot_slope(X, Y)

plt.show()

上面的脚本将产生以下图形:

There's more...

其中一个函数plt.plot()是在plot_slope函数内部完成的,该函数对图形的呈现没有任何影响,因为plt.plot()只是声明了我们要呈现的内容,但尚未执行呈现 。 当编写具有很多曲线的复杂图形的脚本时,这非常有用。 您可以使用适当的编程语言的所有功能(循环,函数调用等)来组成图形。

根据文件数据绘制曲线

如前面所述,matplotlib 仅处理绘图。 如果要绘制存储在文件中的数据,则必须使用 Python 代码读取文件并提取所需的数据。

操作步骤

假设我们将时间序列存储在名为my_data.txt的纯文本文件中,如下所示:

0  0
1  1
2  4
4 16
5 25
6 36

一种用于读取和绘制数据的极简纯 Python 方法如下:

import matplotlib.pyplot as plt

X, Y = [], []
for line in open('my_data.txt', 'r'):
  values = [float(s) for s in line.split()]
  X.append(values[0])
  Y.append(values[1])

plt.plot(X, Y)
plt.show()

该脚本与my_data.txt中存储的数据一起,将产生以下图形:

How to do it...

工作原理

以下是有关的上述脚本工作原理的一些解释:

  • X, Y = [], []行将坐标XY的列表初始化为空列表。
  • for line in open('my_data.txt', 'r')行定义了一个循环,该循环将迭代文本文件my_data.txt的每一行。 每次迭代时,将从文本文件中提取的当前行作为字符串存储在变量行中。
  • values = [float(s) for s in line.split()]行将当前行分隔为空字符以形成令牌字符串。 然后将这些标记解释为浮点值。 这些值存储在列表值中。
  • 然后,在接下来的两行X.append(values[0])Y.append(values[1])中,values中存储的值将添加到列表XY中。

下面的等价于的单行读取文本文件可能会给熟悉 Python 的人带来微笑:

import matplotlib.pyplot as plt

with open('my_data.txt', 'r') as f:
  X, Y = zip(*[[float(s) for s in line.split()] for line in f])

plt.plot(X, Y)
plt.show()

更多

在我们的数据加载代码中,请注意,没有进行任何认真的检查或错误处理。 无论如何,一个人可能还记得一个好的程序员就是一个懒惰的程序员。 确实,由于 NumPy 经常与 matplotlib 一起使用,为什么不在这里使用它呢? 运行以下脚本以启用 NumPy:

import numpy as np
import matplotlib.pyplot as plt

data = np.loadtxt('my_data.txt')

plt.plot(data[:,0], data[:,1])
plt.show()

这与上一节中所示的单行代码一样短,但更易于阅读,它将处理许多纯 Python 代码无法处理的错误情况。 以下几点描述了前面的脚本:

  • numpy.loadtxt()函数读取文本文件并返回 2D 数组。 对于 NumPy,二维数组不是列表列表,它们是真实的,成熟的矩阵。
  • 变量data是 NumPy 2D 数组,它给我们带来的好处是能够将矩阵的行和列作为 1D 数组进行操作。 实际上,在plt.plot(data[:,0], data[:,1])行中,我们将第一列数据作为 x 坐标,将第二列数据作为 y 坐标。 此符号特定于 NumPy。

除了使代码更短,更简单之外,使用 NumPy 还带来了其他优势。 对于大文件,使用 NumPy 会明显更快(NumPy 模块主要用 C 编写),并且将整个数据集存储为 NumPy 数组也可以节省内存。 最后,使用 NumPy 可以轻松支持数字数据的其他常见文件格式(CVS 和 Matlab)。

作为演示到目前为止所看到的所有内容的一种方式,让我们考虑以下任务。 一个文件包含 N 列值,描述 N-1 条曲线。 第一列包含 x 坐标,第二列包含第一条曲线的 y 坐标,第三列包含第二条曲线的 y 坐标,依此类推。 我们要显示这些 N–1 曲线。 我们将使用以下代码来做到这一点:

import numpy as np
import matplotlib.pyplot as plt

data = np.loadtxt('my_data.txt')
for column in data.T:
  plt.plot(data[:,0], column)

plt.show()

文件my_data.txt应包含以下内容:

0 0 6
1 1 5
2 4 4
4 16 3
5 25 2
6 36 1

然后我们得到下图:

There's more...

我们通过两个技巧毫不费力地完成了这项工作。 在 NumPy 表示法中,data.T是 2D 数组数据的转置视图—行被视为列,列被视为行。 同样,我们可以通过执行for row in data遍历多维数组的行。 因此,执行for column in data.T将遍历数组的列。 用几行代码,我们得到了一个相当通用的绘图通用脚本。

绘制点

显示曲线时,我们隐含地假设一个点紧随另一个点-我们的数据是时间序列。 当然,并非总是如此。 数据的一个点可以彼此独立。 表示此类数据的一种简单方法是简单地显示这些点而无需链接它们。

操作步骤

以下脚本显示 1024 个点,其坐标是从[0, 1]间隔中随机绘制的:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.rand(1024, 2)

plt.scatter(data[:,0], data[:,1])
plt.show()

前面的脚本将产生以下图形:

How to do it...

工作原理

函数plt.scatter()的工作原理与plt.plot()完全相同,将点的 x 和 y 坐标作为输入参数。 但是,每个点仅用一个标记显示。 不要被这种简单性所迷惑-plt.scatter()是一个丰富的命令。 通过使用其许多可选参数,我们可以实现许多不同的效果。 我们将在第 2 章,“自定义颜色和样式”和第 3 章,“处理标注”中进行介绍。

绘制条形图

条形图是绘图包的常见主食,甚至 matplotlib 也有。

操作步骤

条形图的专用函数是pyplot.bar()。 我们将通过执行以下脚本来启用此函数:

import matplotlib.pyplot as plt

data = [5., 25., 50., 20.]

plt.bar(range(len(data)), data)
plt.show()

上面的脚本将产生以下图形:

How to do it...

工作原理

对于列表数据中的每个值,均显示一个垂直条。 pyplot.bar()函数接收两个参数-每个条形的 x 坐标和每个条形的高度。 在这里,我们为每个小节使用坐标 0、1、2 等,这是range(len(data))的目的。

更多

通过可选参数,pyplot.bar()提供了一种控制钢筋厚度的方法。 此外,我们还可以使用pyplot.bar()的双胞胎兄弟pyplot.barh()获得单杠。

条形的厚度

默认情况下,钢筋的厚度为 0.8 单位。 因为我们在每个单位长度上都放置了一个小节,所以它们之间的距离为 0.2。 当然,您可以摆弄这个厚度参数。 例如,通过将其设置为 1:

import matplotlib.pyplot as plt

data = [5., 25., 50., 20.]

plt.bar(range(len(data)), data, width = 1.)
plt.show()

前面的简约脚本将产生以下图形:

The thickness of a bar

现在,这些条之间没有缝隙。 matplotlib 条形图函数pyplot.bar()将无法处理条形的位置和厚度。 程序员负责。 这种灵活性使您可以在条形图上创建许多变体。

单杠

如果您更喜欢水平条,请使用 barh()函数,该函数与bar()严格等效,除了提供水平条而不是垂直条:

import matplotlib.pyplot as plt

data = [5., 25., 50., 20.]

plt.barh(range(len(data)), data)
plt.show()

上面的脚本将产生以下图形:

Horizontal bars

绘制多个条形图

比较多个数量和更改一个变量时,我们可能需要一个条形图,其中一个数量值具有一种颜色的条形。

操作步骤

我们可以通过玩这些条的粗细和位置来绘制多个条形图:

import numpy as np
import matplotlib.pyplot as plt

data = [[5., 25., 50., 20.],
  [4., 23., 51., 17.],
  [6., 22., 52., 19.]]

X = np.arange(4)
plt.bar(X + 0.00, data[0], color = 'b', width = 0.25)
plt.bar(X + 0.25, data[1], color = 'g', width = 0.25)
plt.bar(X + 0.50, data[2], color = 'r', width = 0.25)

plt.show()

上面的脚本将产生以下图形:

How to do it...

工作原理

data变量包含三个系列的四个值。 上面的脚本将显示四个条形图的三个条形图。 条的厚度为 0.25 个单位。 每个条形图将从上一个移位 0.25 个单位。 为了清楚起见,添加了颜色。 在第 2 章“自定义颜色和样式”中将详细介绍该主题。

更多

上一节中显示的代码非常繁琐,因为我们通过手动移动三个条形图来重复自己。 通过使用以下代码,我们可以做得更好:

import numpy as np
import matplotlib.pyplot as plt

data = [[5., 25., 50., 20.],
  [4., 23., 51., 17.],
  [6., 22., 52., 19.]]

color_list = ['b', 'g', 'r']
gap = .8 / len(data)
for i, row in enumerate(data):
  X = np.arange(len(row))
  plt.bar(X + i * gap, row,
    width = gap,
    color = color_list[i % len(color_list)])

plt.show()

在这里,我们使用循环for i, row in enumerate(data)遍历数据的每一行。 迭代器enumerate返回当前行及其索引。 通过列表推导完成为一个条形图生成每个条形图的位置。 该脚本将产生与前一个脚本相同的结果,但是如果我们添加数据的行或列,则不需要任何更改。

绘制堆叠的条形图

当然,可以通过使用pyplot.bar()函数中的特殊参数来堆叠条形图。

操作步骤

以下脚本相互堆叠两个条形图:

import matplotlib.pyplot as plt

A = [5., 30., 45., 22.]
B = [5., 25., 50., 20.]

X = range(4)

plt.bar(X, A, color = 'b')
plt.bar(X, B, color = 'r', bottom = A)
plt.show()

上面的脚本将产生以下图形:

How to do it...

工作原理

pyplot.bar()函数的可选bottom 参数允许您指定钢筋的起始值。 它不是从零到一个值,而是从下到上。 首次调用pyplot.bar()会绘制蓝色条形图。 对pyplot.bar()的第二次调用绘制了红色条,红色条的底部在蓝色条的顶部。

更多

当堆叠两个以上的值集时,代码会变得不那么漂亮,如下所示:

import numpy as np
import matplotlib.pyplot as plt

A = np.array([5., 30., 45., 22.])
B = np.array([5., 25., 50., 20.])
C = np.array([1.,  2.,  1.,  1.])
X = np.arange(4)

plt.bar(X, A, color = 'b')
plt.bar(X, B, color = 'g', bottom = A)
plt.bar(X, C, color = 'r', bottom = A + B)

plt.show()

对于第三个条形图,我们必须将底值计算为A + B,即AB的按系数求和。使用 NumPy 有助于保持代码紧凑但可读。 但是,此代码相当重复,并且仅适用于三个堆叠的条形图。 我们可以使用以下代码做得更好:

import numpy as np
import matplotlib.pyplot as plt

data = np.array([[5., 30., 45., 22.],
  [5., 25., 50., 20.],
  [1.,  2.,  1.,  1.]]

color_list = ['b', 'g', 'r']

X = np.arange(data.shape[1])
for i in range(data.shape[0]):
  plt.bar(X, data[i],
    bottom = np.sum(data[:i], axis = 0),
    color = color_list[i % len(color_list)])

plt.show()

在这里,我们将数据存储在 NumPy 数组中,一张条形图一行。 我们遍历每一行数据。 对于第i行,bottom参数接收第i行之前所有行的总和。 通过这种方式编写脚本,可以在更改输入数据时以最小的努力堆叠任意数量的条形图。

There's more...

绘制背对背条形图

一个简单但有用的技巧是同时背对背显示两个条形图。 想一想人口的年龄金字塔,它显示了不同年龄范围内的人数。 左侧显示男性人口,而右侧显示女性人口。

操作步骤

想法是使用一个简单的技巧来制作两个条形图,即一个条的长度/高度可以为负!

import numpy as np
import matplotlib.pyplot as plt

women_pop = np.array([5., 30., 45., 22.])
men_pop     = np.array( [5., 25., 50., 20.])
X = np.arange(4)

plt.barh(X, women_pop, color = 'r')
plt.barh(X, -men_pop, color = 'b')
plt.show()

上面的脚本将产生以下图形:

How to do it...

工作原理

照常绘制女性人群的条形图(红色)。 但是,男性人口的条形图(蓝色)的条形图向左延伸而不是向右延伸。 实际上,蓝色条形图的条形长度为负值。 而不是编辑输入值,我们使用列表推导来否定男性人口条形图的值。

绘制饼图

为了比较数量的相对重要性,没有什么比一个好的旧饼图饼图更好了。

操作步骤

专用的饼图函数pyplot.pie()将完成此工作。 我们将在以下代码中使用此函数:

import matplotlib.pyplot as plt

data = [5, 25, 50, 20]

  plt.pie(data)
plt.show()

前面的简单脚本将显示以下饼图:

How to do it...

工作原理

pyplot.pie()函数仅将值列表作为输入。 注意,输入数据是一个列表。 它可能是一个 NumPy 数组。 您不必调整数据,使其总计为 1 或 100。您只需为 matplolib 提供值,它将自动计算饼图的相对面积。

绘制直方图

直方图是概率分布的图形表示。 实际上,直方图只是条形图的一种。 我们可以轻松使用 matplotlib 的条形图函数并进行一些统计以生成直方图。 但是,直方图非常有用,以至于 matplotlib 为其提供了函数。 在本秘籍中,我们将了解如何使用此直方图函数。

操作步骤

以下脚本从正态分布中绘制1000值,然后生成具有 20 个桶的直方图:

import numpy as np
import matplotlib.pyplot as plt

X = np.random.randn(1000)

plt.hist(X, bins = 20)
plt.show()

每次我们运行脚本时,由于数据集是随机生成的,因此直方图会有所变化。 上面的脚本将显示以下图形:

How to do it...

工作原理

pyplot.hist()函数将值列表作为输入。 值的范围将分为相等大小的桶(默认为 10 个桶)。 pyplot.hist()函数将生成一个条形图,一个条带表示一个箱。 一格的高度是相应仓中跟随的值的数量。 箱的数量由可选参数箱确定。 通过将可选参数normed设置为True,可以对钢筋高度进行标准化,并且所有钢筋高度的总和等于 1。

绘制箱形图

箱形图允许您方便地显示一组值的中位数,四分位数,最大值和最小值,从而比较值的分布。

操作步骤

以下脚本显示了从正态分布中抽取的 100 个随机值的箱形图:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.randn(100)

plt.boxplot(data)
plt.show()

将会出现一个箱形图,代表我们从随机分布中提取的样本。 由于代码使用随机生成的数据集,因此每次运行脚本时,生成的图形都会略有变化。

前面的脚本将显示以下图形:

How to do it...

工作原理

data = [random.gauss(0., 1.) for i in range(100)]变量从正态分布中生成 100 个值。 出于演示目的,通常从文件中读取或从其他数据计算出这些值。 plot.boxplot()函数取一组值并自己计算平均值,中位数和其他统计量。 以下几点描述了前面的箱形图:

  • 红色条形是分布的中位数。
  • 蓝色框包含从下四分位数到上四分位数的 50% 的数据。 因此,该框位于数据中位数的中心。
  • 下胡须从下四分位数延伸到 1.5 IQR 内的最小值。
  • 上胡须从上四分位开始延伸到 1.5 IQR 以内的最大值。
  • 胡须以外的值用十字标记显示。

更多

要在单个图形中显示多个箱形图,对每个箱形图调用一次pyplot.boxplot()将不起作用。 它将简单地将箱形图相互绘制,从而制作出混乱的,不可读的图形。 但是,我们可以通过一次调用pyplot.boxplot()来绘制多个箱形图,如下所示:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.randn(100, 5)

plt.boxplot(data)
plt.show()

上面的脚本显示以下图形:

There's more...

pyplot.boxplot()函数接受列表列表作为输入,为每个子列表绘制一个箱形图。

绘制三角剖分

三角剖分在处理空间位置时出现。 除了显示点与邻域关系之间的距离之外,三角剖分图可以方便地表示地图。 matplotlib 为三角剖分提供了大量支持。

操作步骤

与前面的示例一样,以下几行代码就足够了:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri

data = np.random.rand(100, 2)

triangles = tri.Triangulation(data[:,0], data[:,1])

plt.triplot(triangles)
plt.show()

每次运行脚本时,您都会看到不同的三角剖分,因为三角剖分的点云是随机生成的。

前面的脚本显示以下图形:

How to do it...

工作原理

我们导入matplotlib.tri模块,该模块提供了一些辅助函数来计算点的三角剖分。 在此示例中,出于演示目的,我们使用以下代码生成随机的点云:

data = np.random.rand(100, 2)

我们使用以下代码来计算三角剖分并将其存储在三角形的变量中:

triangles = tri.Triangulation(data[:,0], data[:,1])

pyplot.triplot()函数仅将三角形作为输入并显示三角剖分结果。

二、自定义颜色和样式

在本章中,我们将介绍:

  • 定义自己的颜色
  • 对散点图使用自定义颜色
  • 对条形图使用自定义颜色
  • 对饼图使用自定义颜色
  • 对箱形图使用自定义颜色
  • 对散点图使用颜色表
  • 对条形图使用颜色表用
  • 控制线条图案和粗细
  • 控制填充图案
  • 控制标记的样式
  • 控制标记的大小
  • 创建自己的标记
  • 更好地控制标记
  • 创建自己的配色方案

简介

matplotlib 可用的所有绘图都带有其默认样式。 虽然这对于原型制作很方便,但我们的最终图形将需要与默认样式有所不同。 您可能只需要使用灰度级,或者遵循现有的配色方案,或更一般地说,遵循现有的可视化图表。 matplotlib 在设计时考虑了灵活性。 正如本章的秘籍将说明的那样,很容易适应 matplotlib 图形的样式。

定义自己的颜色

matplotlib 使用的默认颜色相当淡淡。 对于方便的颜色,我们可能会有自己的偏好。 我们可能希望使图形遵循预定义的配色方案,以便它们很好地适合文档或网页。 更加务实的是,我们可能只需要为将要在黑白打印机上打印的文档制作图形。 在本秘籍中,我们将了解如何定义自己的颜色。

准备

在 matplotlib 中定义颜色的方法有多种。 其中一些如下:

  • 三元组:这些颜色可以描述为实值三元组-颜色的红色,蓝色和绿色分量。 分量必须在[0, 1]间隔内。 因此,Python 语法(1.0, 0.0, 0.0)将编码纯净的鲜红色,而(1.0, 0.0, 1.0)则显示为强粉色。

  • 四元组:这些作为三元组,并且第四部分定义透明度值。 此值也应在[0, 1]间隔内。 将图形渲染到图片文件时,使用透明颜色可以使图形与背景融合。 当制作可在网页上滑动或结束的图形时,这特别有用。

  • 预定义名称:matplotlib 将标准 HTML 颜色名称解释为实际颜色。 例如,字符串red将被接受为一种颜色,并将被解释为亮红色。 几种颜色具有一个字母别名,如下表所示:

    别名颜色
    b蓝色
    g绿色
    r红色
    c青色
    m品红
    y黄色
    k黑色
    w白色
  • HTML 颜色字符串:matplotlib 可以将 HTML 颜色字符串解释为实际颜色。 这样的字符串定义为#RRGGBB,其中RRGGBB是十六进制的红色,绿色和蓝色分量的 8 位值。

  • 灰度字符串:matplotlib 将浮点值的字符串表示形式解释为灰色阴影,例如0.75用于中等浅灰色。

操作步骤

设置线形图的颜色是通过如下设置pyplot.plot()函数的参数颜色(或等效的快捷方式c)来完成的:

import numpy as np
import matplotlib.pyplot as plt

def pdf(X, mu, sigma):
  a = 1\. / (sigma * np.sqrt(2\. * np.pi))
  b = -1\. / (2\. * sigma ** 2)
  return a * np.exp(b * (X - mu) ** 2)

X = np.linspace(-6, 6, 1000)

for i in range(5):
  samples = np.random.standard_normal(50)
  mu, sigma = np.mean(samples), np.std(samples)
  plt.plot(X, pdf(X, mu, sigma), color = '.75')

plt.plot(X, pdf(X, 0., 1.), color = 'k')
plt.show()

上面的脚本将产生类似于下一个脚本的图形,其中显示五个浅灰色,钟形曲线和一个黑色曲线:

How to do it...

工作原理

在此示例中,我们从正态分布生成五组 50 个样本。 对于这五组中的每组,我们以浅灰色绘制估计的概率密度。 正态分布概率密度以黑色显示。 在那里,使用黑色的快捷方式k对颜色进行编码。

对散点图使用自定义颜色

就像控制线形图一样,我们可以控制用于散点图的颜色。 在本秘籍中,我们将看到如何使用两种方法来控制散点图的颜色。

准备

散点图函数pyplot.scatter() 提供以下两个选项,可通过其color参数或其快捷方式c控制点的颜色:

  • 所有点的通用颜色:如果颜色参数是有效的 matplotlib 颜色定义,则所有点将以该颜色显示。
  • 每个点的单独颜色:如果颜色参数是有效 matplotlib 颜色定义的序列,则第i个点将以第i种颜色出现。 当然,我们必须为每个点提供所需的颜色。

操作步骤

在以下脚本中,我们显示了从两个双变量高斯分布中得出的两组点AB。 每套都有自己的颜色。 我们两次调用pyplot.scatter(),每个点集调用一次,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt

A = np.random.standard_normal((100, 2))
A += np.array((-1, -1)) # Center the distrib. at <-1, -1>

B = np.random.standard_normal((100, 2))
B += np.array((1, 1)) # Center the distrib. at <1, 1>

plt.scatter(A[:,0], A[:,1], color = '.25')
plt.scatter(B[:,0], B[:,1], color = '.75')
plt.show()

上面的脚本将产生以下图形:

How to do it...

因此,在此示例中,完全像pyplot.plot()中那样使用自定义颜色。 在下面的脚本中,情况会有所不同。 我们从文本文件 Fisher 的鸢尾数据集加载数组,该文件可从这里获得。 其内容如下所示:

4.6,3.2,1.4,0.2,Iris-setosa
5.3,3.7,1.5,0.2,Iris-setosa
5.0,3.3,1.4,0.2,Iris-setosa
7.0,3.2,4.7,1.4,Iris-versicolor
6.4,3.2,4.5,1.5,Iris-versicolor

数据集的每个点都存储在以逗号分隔的值列表中。 给出每个点标签的最后一列是一个字符串,可以采用三个可能的值-Iris-virginicaIris-versicolorIris-Vertosa。 我们使用 NumPy 的numpy.loadtxt函数读取此文件。 点的颜色将取决于它们的标签,我们将仅通过一次调用pyplot.scatter()来显示它们,如下所示:

import numpy as np
import matplotlib.pyplot as plt

label_set = (
  b'Iris-setosa',
  b'Iris-versicolor',
  b'Iris-virginica',
)

def read_label(label):
  return label_set.index(label)

data = np.loadtxt('iris.data.txt',
                             delimiter = ',',
                             converters = { 4 : read_label })

color_set = ('.00', '.50', '.75')
color_list = [color_set[int(label)] for label in data[:,4]]

plt.scatter(data[:,0], data[:,1], color = color_list)
plt.show()

前面的脚本将产生以下图:

How to do it...

工作原理

对于的三个可能的标签,我们分配一种唯一的颜色。 颜色在color_set中定义,标签在label_set中定义。 label_set中的第i个标签与color_set中的第i个颜色相关联。

我们将标签列表label_list转换为颜色列表color_list,并使用列表推导特性。 然后,我们只需调用一次pyplot.scatter(),即可显示所有点及其颜色。 我们可以通过三个单独的调用来完成此操作,但是这将需要更多代码,而没有明显的收益。

两个点可能具有相同的坐标,但具有不同的标签。 在这种情况下,显示的颜色将是绘制的最新点的颜色。 使用透明颜色,重叠点的颜色将融合在一起。

更多

就像color参数控制点的颜色一样,edgecolor参数控制点的边缘的颜色。 它严格适用于color参数-您可以为每个点边缘设置相同的颜色,或分别控制边缘颜色,如下所示:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.standard_normal((100, 2))

plt.scatter(data[:,0], data[:,1], color = '1.0', edgecolor='0.0')
plt.show()

上面的脚本将产生以下图形:

There's more...

对条形图使用自定义颜色

条形图经常在网页和演示文稿中使用,其中人们通常必须遵循既定的配色方案。 因此,必须对它们的颜色进行良好的控制。 在本秘籍中,我们将看到如何用我们自己的颜色为条形图着色。

操作步骤

在第 1 章“第一步”中,我们已经了解了如何制作条形图。 控制使用哪种颜色的效果与用于线形图和散点图的方法相同,即通过一个可选参数。 在此示例中,我们从文件中加载国家人口的年龄金字塔,如下所示:

import numpy as np
import matplotlib.pyplot as plt

women_pop = np.array([5., 30., 45., 22.])
men_pop     = np.array([5., 25., 50., 20.])

X = np.arange(4)
plt.barh(X, women_pop, color = '.25')
plt.barh(X, -men_pop, color = '.75')

plt.show()

上面的脚本显示了一个条形图,其中有男性年龄划分,另一条形图是妇女。 女士显示为深灰色,而男士显示为浅灰色,如下图所示:

How to do it...

工作原理

pyplot.bar()pyplot.barh()函数的工作严格类似于pyplot.scatter()。 我们只需要设置可选参数color即可。 参数edgecolor也可用。

更多

在此示例中,我们显示条形图,并根据其表示的值对条形进行着色。 [0, 24][25, 49][50, 74][75, 100]范围内的值将以不同的灰色阴影显示。 颜色列表是使用列表理解来构建的,如下所示:

import numpy as np
import matplotlib.pyplot as plt

values = np.random.random_integers(99, size = 50)

color_set = ('.00', '.25', '.50', '.75')
color_list = [color_set[(len(color_set) * val) // 100] for val in values]
plt.bar(np.arange(len(values)), values, color = color_list)
plt.show()

条形图图表的条形图根据其高度着色,如下图所示:

There's more...

如果我们对值进行排序,则条形图将形成四个不同的带,如下图所示:

There's more...

对饼图使用自定义颜色

与条形图一样,饼图也用于配色方案可能非常重要的环境中。 饼图着色的工作原理与条形图中的类似。 在本秘籍中,我们将看到如何用我们自己的颜色给饼图上色。

操作步骤

函数pyplot.pie() 接受颜色列表作为可选参数,如以下脚本中的所示:

import numpy as np
import matplotlib.pyplot as plt

values = np.random.rand(8)
color_set = ('.00', '.25', '.50', '.75')

plt.pie(values, colors = color_set)
plt.show()

上面的脚本将产生以下饼图:

How to do it...

工作原理

饼图使用colors参数接受颜色列表(请注意,它是colors而不是color)。 但是,颜色列表没有输入值列表那么多的元素。 如果颜色少于值,则pyplot.pie()会简单地在颜色列表中循环显示。 在前面的示例中,我们给出了四种颜色的列表,以对由八个值组成的饼图上色。 因此,每种颜色将使用两次。

对箱形图使用自定义颜色

箱形图是科学出版物的常见主要特征。 彩色的箱形图没有问题。 但是,您可能只需要使用黑白。 在本秘籍中,我们将了解如何在箱图中使用自定义颜色。

操作步骤

每个创建特定图形的函数都会返回一些值-它们是构成图形的低级图形基元。 大多数时候,我们不会费心去获取那些返回值。 但是,操作这些低级绘图基元可以进行一些微调,例如对箱形图的自定义配色方案。

使箱形图显示为全黑比应该的要复杂一些,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt
values = np.random.randn(100)

b = plt.boxplot(values)
for name, line_list in b.iteritems():
  for line in line_list:
    line.set_color('k')

plt.show()

上面的脚本生成以下图形:

How to do it...

工作原理

绘图函数返回一个字典。 字典的关键字是图形元素的名称。 对于箱形图,此类元素将是中位数,传单,胡须,盒子和盖子。 与这些键中的每个键相关联的值是一系列低级图形图元(线,形状等)。 在脚本中,我们迭代作为箱形图一部分的每个图形基元,并将其颜色设置为黑色。 使用相同的方法,您可以使用自己的配色方案渲染箱形图。

对散点图使用颜色表

当使用多种颜色时,一个一个定义一个颜色是很麻烦的。 而且,建立一套好的色彩本身就是一个问题。 在某些情况下,颜色表 可以解决这些问题。 颜色表使用一种变量到一个值(对应一种颜色)的连续函数来定义颜色。 matplotlib 提供了几种常见的颜色表; 它们大多数是连续的色带。 在本秘籍中,我们将了解如何使用颜色表对散点图进行颜色着色。

操作步骤

颜色表在,,matplotib.cm模块中定义。 该模块提供函数来创建和使用颜色表。 它还提供了预定义颜色表的详尽选择。

函数pyplot.scatter()接受color参数的值列表。 提供颜色表(带有cmap参数)时,这些值将被解释为颜色表索引,如下所示:

import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt

N = 256
angle  = np.linspace(0, 8 * 2 * np.pi, N)
radius = np.linspace(.5, 1., N)

X = radius * np.cos(angle)
Y = radius * np.sin(angle)

plt.scatter(X, Y, c = angle, cmap = cm.hsv)
plt.show()

前面的脚本将生成点的彩色螺旋,如下图所示:

How to do it...

工作原理

在此脚本中,我们绘制了点的螺旋线。 点的颜色是角度变量的函数,从颜色表中获取颜色。 matplotlib.cm模块中提供了大量颜色表。 hsv贴图包含所有光谱,这使得花哨的彩虹主题更加丰富。 对于科学的可视化,考虑到感知到的颜色强度,其他颜色表更合适,例如PuOr图。 与PuOr映射相同的脚本将为我们提供以下结果:

How it works...

对条形图使用颜色表

pyplot.scatter()函数具有对颜色表的内置支持。 我们稍后将发现的其他一些绘图函数也具有这种支持。 但是,某些函数(例如 pyplot.bar())不会将颜色表用作绘图条形图的输入。 在本秘籍中,我们将了解如何使用颜色表为条形图着色。

matplotlib 具有辅助函数,可从颜色表显式生成颜色。 例如,我们可以使用条形所代表的值的函数为条形图的条形着色。

操作步骤

我们将在本秘籍的中使用matplotlib.cm模块,就像在先前的秘籍中一样。 这一次,我们将直接使用颜色表对象,而不是让渲染函数自动使用它。 我们还将需要matplotlib.colors模块,其中包含与颜色相关的工具函数,如以下脚本所示:

import numpy as np
import matplotlib.cm as cm
import matplotlib.colors as col
import matplotlib.pyplot as plt

values = np.random.random_integers(99, size = 50)

cmap = cm.ScalarMappable(col.Normalize(0, 99), cm.binary)

plt.bar(np.arange(len(values)), values, color = cmap.to_rgba(values))
plt.show()

上面的脚本将生成一个条形图,其中条形的颜色取决于其高度,如下图所示:

How to do it...

工作原理

我们首先创建颜色表cmap,以便将[0, 99]范围范围内的值映射到matplotlib.cm.binary颜色表的颜色。 然后,函数cmap.to_rgba将值列表转换为颜色列表。 因此,尽管pyplot.bar不支持颜色表,但是使用颜色表不涉及复杂的代码; 有一些功能可以简化这一过程。

请注意,如果对值列表进行了排序,则此处使用的颜色表的连续方面将变得显而易见,如下图所示:

How it works...

控制线条图案和粗细

在为黑白文档创建图形时,我们仅限于灰度级。 在实践中,通常我们可以合理使用最多三个灰度等级。 但是,使用不同的线型可以实现一些多样性。 在本秘籍中,我们将了解如何控制线条图案和粗细。

操作步骤

与颜色一样,线条样式由pyplot.plot()的可选参数控制,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt

def pdf(X, mu, sigma):
  a = 1\. / (sigma * np.sqrt(2\. * np.pi))
  b = -1\. / (2\. * sigma ** 2)
  return a * np.exp(b * (X - mu) ** 2)

X = np.linspace(-6, 6, 1024)

plt.plot(X, pdf(X, 0., 1.),   color = 'k', linestyle = 'solid')
plt.plot(X, pdf(X, 0.,  .5),  color = 'k', linestyle = 'dashed')
plt.plot(X, pdf(X, 0.,  .25), color = 'k', linestyle = 'dashdot')

plt.show()

前面的脚本将产生以下图形:

How to do it...

工作原理

在此示例中,我们使用pyplot.plot()linestyle参数控制三个不同曲线的线型。 可以使用以下线条样式:

  • 实线
  • 虚线
  • 点线
  • 点划线

更多

线条样式设置不限于限于pyplot.plot(); 实际上,任何由线条组成的图形都可以进行此类设置。 此外,您还可以控制线的粗细。

其他图类型的线型

linestyle参数可用于所有涉及线渲染的命令。 例如,我们可以修改用于条形图的折线图,如下所示:

import numpy as np
import matplotlib.pyplot as plt

N = 8
A = np.random.random(N)
B = np.random.random(N)
X = np.arange(N)

plt.bar(X, A, color = '.75')
plt.bar(X, A + B, bottom = A, color = 'w', linestyle = 'dashed')

plt.show()

上面的脚本将产生以下图形:

The line style with other plot types

线宽

同样,linewidth参数将更改线的粗细。 默认情况下,厚度设置为 1 个单位。 玩弄线条的粗细可以帮助强调一条特定的曲线。 以下是使用linewidth参数设置线宽的脚本:

import numpy as np
import matplotlib.pyplot as plt

def pdf(X, mu, sigma):
  a = 1\. / (sigma * np.sqrt(2\. * np.pi))
  b = -1\. / (2\. * sigma ** 2)
  return a * np.exp(b * (X - mu) ** 2)

X = np.linspace(-6, 6, 1024)
for i in range(64):
  samples = np.random.standard_normal(50)
  mu, sigma = np.mean(samples), np.std(samples)
  plt.plot(X, pdf(X, mu, sigma), color = '.75', linewidth = .5)

plt.plot(X, pdf(X, 0., 1.), color = 'y', linewidth = 3.)
plt.show()

下图是上述脚本的结果,从 50 个样本中估计出 64 个估计的高斯 PDF概率密度函数),并显示为细灰色曲线 。 用于绘制样本的高斯分布显示为粗黑曲线。

The line width

控制填充样式

matplotlib 提供相当有限的支持,以用图案填充表面。 对于线条图案,为黑白打印准备图形时可能会有所帮助。 在本秘籍中,我们将研究如何用图案填充表面。

操作步骤

让我们用条形图演示填充模式的用法,如下所示:

import numpy as np
import matplotlib.pyplot as plt

N = 8
A = np.random.random(N)
B = np.random.random(N)
X = np.arange(N)

plt.bar(X, A, color = 'w', hatch = 'x')
plt.bar(X, A + B, bottom = A, color = 'w', hatch = '/')

plt.show()

上面的脚本生成以下图形:

How to do it...

工作原理

填充体积的渲染函数(例如pyplot.bar())接受可选参数hatch。 此参数可以采用以下值:

  • /
  • \
  • |
  • -
  • +
  • x
  • o
  • O
  • .
  • *

每个值对应于不同的阴影图案。 color参数将控制图案的背景颜色,而edgecolor参数将控制阴影线的颜色。

控制标记的样式

在第 1 章“第一步”中,我们看到了如何将曲线的点显示为点。 此外,散点图表示数据集的每个点。 事实证明,matplotlib 提供了多种形状以用其他种类的标记替换点。 在本秘籍中,我们将了解如何设置标记的样式。

准备

可以通过以下各种方式将标记指定为:

  • 预定义标记:它们可以是预定义形状,可以将表示为[0, 8]范围内的数字,也可以包含一些字符串
  • 顶点列表:这是值对的列表,用作形状的路径的坐标
  • 正多边形:它将正 N 边形表示为带有旋转角度的三元组(N, 0, 角度)
  • 正多角星:它将正 N 角星表示为带有旋转角度的三元组(N, 1, 角度)

操作步骤

让我们以一个脚本显示两个具有两种不同颜色的点集。 现在,我们将所有点显示为黑色,但标记不同,如下所示:

import numpy as np
import matplotlib.pyplot as plt

A = np.random.standard_normal((100, 2))
A += np.array((-1, -1))
B = np.random.standard_normal((100, 2))
B += np.array((1, 1))

plt.scatter(A[:,0], A[:,1], color = 'k', marker = 'x')
plt.scatter(B[:,0], B[:,1], color = 'k', marker = '^')

plt.show()

将会出现两个高斯点云,每个云使用不同的标记,如下图所示:

How to do it...

工作原理

在此脚本中,我们将的两个散点图的颜色都设置为黑色。 使用marker参数,我们为每个集合指定一个不同的标记。

color参数不同,marker参数不接受标记规范列表作为输入。 因此,我们不能使用单个调用pyplot.scatter()来显示带有不同标记的几组点。 我们需要区分每种标记类型的点,并对每个标记使用单独的pyplot.scatter()调用,如下所示:

import numpy as np
import matplotlib.pyplot as plt

label_list = (
  b'Iris-setosa',
  b'Iris-versicolor',
  b'Iris-virginica',
)

def read_label(label):
  return label_list.index(label)

data = np.loadtxt('iris.data.txt',
  delimiter = ',',
  converters = { 4 : read_label })

marker_set = ('^', 'x', '.')
for i, marker in enumerate(marker_set):
  data_subset = numpy.asarray([x for x in data if x[4] == i])
  plt.scatter(data_subset[:,0], data_subset[:,1],
    color = 'k',
    marker = marker)

plt.show()

数据集中的每个簇都有其自己的标记,如下图所示:

How it works...

此示例与之前的示例相似,在该示例中,我们加载数据集,然后根据标签显示每个点。 但是,在这里,我们将每个标签的点分开。 然后,我们遍历地图的每个条目,并为每个点子集调用pyplot.scatter()

更多

也可以使用相同的marker参数为pyplot.plot()访问标记样式。 对每个数据点使用一个标记可能是一个问题,因为它将显示比我们想要的更多的点。 markevery参数允许您为每个 N 点仅显示一个标记,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-6, 6, 1024)
Y1 = np.sinc(X)
Y2 = np.sinc(X) + 1
plt.plot(X, Y1, marker = 'o', color = '.75')
plt.plot(X, Y2, marker = 'o', color = 'k', markevery = 32)

plt.show()

上面的脚本生成以下图形:

There's more...

控制标记的大小

从先前的秘籍中可以看出,我们可以控制标记的样式; 控制它们的大小也遵循相同的原则。 在本秘籍中,我们将了解如何控制标记大小。

操作步骤

标记的大小与其他标记属性的控制方式相同,具有专用的可选参数,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt
A = np.random.standard_normal((100, 2))
A += np.array((-1, -1))
B = np.random.standard_normal((100, 2))
B += np.array((1, 1))

plt.scatter(B[:,0], B[:,1], c = 'k', s = 100.)
plt.scatter(A[:,0], A[:,1], c = 'w', s = 25.)

plt.show()

前面的脚本产生以下图形:

How to do it...

在此示例中,我们显示两组不同大小的点。 标记的大小由pyplot.scatter()的参数s设置的。 奇怪的是,它设置标记的表面积而不是其半径。

因为大小是实际表面积而不是半径,所以它们遵循二次方的变化-较大四倍的标记将具有两倍大的半径。

更多

pyplot.scatter()函数还将列表作为s参数的输入-每个点的大小,如以下脚本所示:

import numpy as np
import matplotlib.pyplot as plt

M = np.random.standard_normal((1000, 2))
R = np.sum(M ** 2, axis = 1)

plt.scatter(M[:, 0], M[:, 1], c = 'w', marker = 's', s = 32\. * R)
plt.show()

上面的脚本生成以下图形:

There's more...

在此脚本中,我们根据双变量高斯分布绘制了随机点。 点的半径取决于其距原点的距离。

pyplot.plot()函数还可以借助markersize(或其快捷方式ms)参数来更改标记的大小。 此参数不接受值列表作为输入。

创建自己的标记

matplotlib 提供了多种标记形状。 但是您可能找不到适合您的特定需求的东西。 例如,您可能希望使用动物剪影,公司徽标等。 在本秘籍中,我们将看到如何定义自己的标记形状。

操作步骤

matplotlib 将形状描述为路径-链接在一起的点序列。 因此,要定义我们自己的标记形状,我们必须提供一系列点。 在以下脚本示例中,我们将定义一个十字形形状:

import numpy as np
import matplotlib.path as mpath
from matplotlib import pyplot as plt

shape_description = [
  ( 1.,  2., mpath.Path.MOVETO),
  ( 1.,  1., mpath.Path.LINETO),
  ( 2.,  1., mpath.Path.LINETO),
  ( 2., -1., mpath.Path.LINETO),
  ( 1., -1., mpath.Path.LINETO),
  ( 1., -2., mpath.Path.LINETO),
  (-1., -2., mpath.Path.LINETO),
  (-1., -1., mpath.Path.LINETO),
  (-2., -1., mpath.Path.LINETO),
  (-2.,  1., mpath.Path.LINETO),
  (-1.,  1., mpath.Path.LINETO),
  (-1.,  2., mpath.Path.LINETO),
  ( 0.,  0., mpath.Path.CLOSEPOLY),
]

u, v, codes = zip(*shape_description)
my_marker = mpath.Path(np.asarray((u, v)).T, codes)
data = np.random.rand(8, 8)
plt.scatter(data[:,0], data[:, 1], c = '.75', marker = my_marker, s = 64)
plt.show()

上面的脚本生成以下图形:

How to do it...

工作原理

使用标记渲染图形的所有pyplot函数都有一个可选参数,即marker。 我们在前面的秘籍中已经看到,参数可以是用于选择预定义的 matplotlib 标记之一的字符串。 但是marker参数也可以是Path的实例。 Path对象在matplotlib.path模块中定义。

Path对象的构造器将坐标列表和指令列表作为输入; 每个坐标一个指令。 我们没有使用两个单独的坐标和指令列表,而是使用单个列表shape_description,将坐标和指令融合在一起。 一点点代码用于操纵shape_description并将坐标和指令的单独列表馈送到Path构造器,如下所示:

u, v, codes = zip(*shape_description)
my_marker = mpath.Path(np.asarray((u, v)).T, codes)

形状由光标的移动来描述。 我们使用以下三种类型的指令:

  • MOVETO:该指令将光标移动到指定坐标; 没有画线。
  • LINETO:在画一条线的同时将光标移动到指定的坐标。
  • CLOSEPOLY:它不会执行任何操作,它将关闭路径。 此指令将结束您的路径。

从理论上讲,任何形状都是可能的,您只需要描述其路径即可。 实际上,如果您希望使用复杂的形状(例如,公司的徽标),则必须进行一些转换工作。 matplotlib 不提供从流行的向量文件格式(例如 SVG)到Path对象的转换例程。

更好地控制标记

标记上可以进行精细控制,例如边缘颜色,内部颜色等。 例如,可以使用与曲线颜色不同颜色的标记来绘制曲线。 在本秘籍中,我们将研究如何对标记的外观进行精细控制。

操作步骤

我们已经了解了有关设置标记的形状,颜色和大小的可选参数。 如以下脚本所示,还有很多其他的玩法:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-6, 6, 1024)
Y = np.sinc(X)

plt.plot(X, Y,
  linewidth = 3.,
  color = 'k',
  markersize = 9,
  markeredgewidth = 1.5,
  markerfacecolor = '.75',
  markeredgecolor = 'k',
  marker = 'o',
  markevery = 32)
plt.show()

出于可读性考虑,对pyplot.plot()的调用分为几行-每个可选参数一行。 上面的脚本将产生以下图形:

How to do it...

工作原理

此示例演示了markeredgecolormarkerfacecolormarkeredgewidth参数的使用,它们分别控制边缘颜色,内部颜色和标记的线宽。 所有可以使用标记的渲染函数(例如pyplot.plot)都接受这些可选参数。

创建您自己的配色方案

matplotlib 使用的默认颜色是指对于印刷文档而言,它适合合理地发布。 因此,默认情况下背景为白色,而标签,轴和其他标注显示为黑色。 在不同的使用上下文中,您可能希望使用不同的配色方案。 例如,将图形的背景变为黑色,标注为白色。 在本秘籍中,我们将展示如何更改 matplotlib 的默认设置。

操作步骤

在 matplotlib 中,可以分别处理各种对象,例如轴域,图形和标签。 一件一件地更改所有这些对象的颜色设置将非常麻烦。 幸运的是,所有 matplotlib 对象都从集中式配置对象中选择其默认颜色。

在以下脚本中,我们使用 matplotlib 的集中式配置来具有黑色背景和白色标注:

import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt

mpl.rc('lines', linewidth = 2.)
mpl.rc('axes', facecolor = 'k', edgecolor = 'w')
mpl.rc('xtick', color = 'w')
mpl.rc('ytick', color = 'w')
mpl.rc('text', color = 'w')
mpl.rc('figure', facecolor = 'k', edgecolor ='w')
mpl.rc('axes', color_cycle = ('w', '.5', '.75'))

X = np.linspace(0, 7, 1024)

plt.plot(X, np.sin(X))
plt.plot(X, np.cos(X))
plt.show()

上面的脚本生成以下图形:

How to do it...

工作原理

matplotlib模块具有用作集中配置的rc对象。 每个 matplotlib 对象都将从该rc对象中选择其默认设置。 rc对象包含一组属性和关联的值。 例如,mpl.rc('lines'linewidth = 2.)会将属性lines.linewidth设置为 2; 默认情况下,线条的宽度现在为 2。 在这里,我们将图形的背景设置为黑色(使用figure.facecoloraxes.facecolor属性),而将所有标注设置为白色(使用figure.edgecoloraxes.edgecolortext.colorxtick.colorytick.color属性)。 我们还使用axes.color_cycle属性重新定义了 matplotlib 自动选择的颜色。 有关 matplotlib 属性的很好参考,请访问这里

更多

现在,我们知道如何更改 matplotlib 的默认设置以适合我们的口味。 但是,如果我们希望所有脚本都使用这些设置,则必须复制并粘贴它们。 这很不方便。 幸运的是,默认设置可以保存在matplotlibrc文件中。 maptplotlibrc文件是纯文本文件,其中包含属性及其相应的值; 每行一个属性。 以下是此秘籍的matplotlibrc格式设置:

lines.linewidth : 2
axes.facecolor : black
axes.edgecolor : white
xtick.color : white
ytick.color : white
text.color : white
figure.facecolor : black
figure.edgecolor : white
axes.color_cycle : white, #808080, #b0b0b0

如果在当前目录(即从中启动脚本的目录)中找到了matplotlibrc文件,它将覆盖 matplotlib 的默认设置。

您也可以将matplotlibrc文件保存在特定位置以进行自己的默认设置。 在交互式 Python Shell 中,运行以下命令:

import matplotlib
mpl.get_configdir()

此命令将显示可放置matplotlibrc文件的位置,以便那些设置将是您自己的默认设置。

三、处理标注

在本章中,我们将介绍以下主题:

  • 添加标题
  • 使用 LaTeX 样式的符号
  • 在每个轴上添加标签
  • 添加文本
  • 添加箭头
  • 添加图例
  • 添加网格
  • 添加线条
  • 添加形状
  • 控制刻度线间距
  • 控制刻度标签

简介

使您的图表不言自明是一种很好的做法。 但是,很难在没有任何标注的情况下使一些曲线和点不言自明。 人们应该如何读取垂直和水平轴? 该框和该曲线代表哪个数量? matplotlib 提供了很多标注图形的可能性,我们将在本章中进行探讨。

添加标题

让我们从简单的事情开始:为图形添加标题。

操作步骤

以下代码将添加到图形标题:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.title('A polynomial')
plt.plot(X, Y, c = 'k')
plt.show()

在这里,我们绘制一条简单的曲线,并在图形的顶部添加一个标题,该标题显示在图形的顶部:

How to do it...

工作原理

简单地通过 pyplot.title()函数完成,该函数将一个字符串作为参数并设置整个图形的标题。

使用 LaTeX 样式的符号

现在我们可以标注数字。 但是,在科学和工程方面,以前演示的解决方案受到一个令人讨厌的限制。 我们不能使用数学符号! 或者,可以吗? 在本秘籍中,我们将了解如何使用 LaTeX 在图中显示和数学脚本。

准备

您需要在计算机上安装可运行的 LaTeX 设置,以便 matplotlib 可以解释 LaTeX 样式的表示法以呈现数学文本。 否则,您将无法尝试此秘籍。 您可以在 LaTeX Wikibook 上找到有关安装 LaTeX 的有用说明。

提示

LaTeX

LaTeX 是学术界广泛使用的文档准备系统。 与 Microsoft Word 或 LibreOffice Writer 等文档编辑器不同,LaTeX 用户无法看到最终文档在编辑时的外观。 文档被描述为文本和存储在纯文本文件中的命令的混合。 然后,LaTeX 将解释文档描述以呈现文档。 LaTeX 是一个相当大的环境。 LaTeX 具有用于描述数学文本的特定语言。 这种语言非常流行,以至于简单地编写公式而不是呈现它们已成为事实上的标准。 例如,在科学和工程界,LaTeX 的公式语言通常用于在电子邮件和论坛中编写数学文本。

操作步骤

使用 LaTeX 渲染一些文本非常简单:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.title('$f(x)=\\frac{1}{4}(x+4)(x+1)(x-2)$')
plt.plot(X, Y, c = 'k')
plt.show()

该脚本完全按照我们之前的秘籍进行操作:在顶部显示一个带有标题的图形。 但是,正如秘籍的标题可能暗示的那样,该标题使用 LaTeX 渲染,使我们可以使用数学表示法。

How to do it...

工作原理

与通常设置标题的方式的唯一区别是pyplot.title()提供的字符串。 字符串以$字符开头和结尾; 这是为了通知 matplotlib 将文本解释和呈现为 LaTeX 样式的数学文本。 然后,字符串内容只是数学文本的标准 LaTeX 语言。

LaTeX 语言严重依赖转义字符\,该字符也恰好是 Python 的字符串转义字符。 因此,在 LaTeX 文本中使用一个\字符的地方,请在 Python 字符串中放入两个。 为避免弄乱转义字符,您可以在字符串前面添加r,并且不需要任何转义字符。 因此,'$f(x)=\\frac{1}{4}(x+4)(x+1)(x-2)$'r'$f(x)=\frac{1}{4}(x+4)(x+1)(x-2)$'是等效的。

注意

您不懂数学文字的 LaTeX 语言吗? 不用担心,您可以快速学习! 在 matplotlib 上下文中,您可以在这个页面中找到权威指南。 可以在这个页面上找到相当完整的教程。

此 LaTeX 标注函数不限于标题。 它可以用于任何标注。 在这里,我们仅在标题文本上进行演示。

在每个轴上添加标签

除了标题,图形轴的正确描述有助于用户理解图形。 在本秘籍中,我们将向您展示如何在图形的每个轴旁边获取标签。

操作步骤

添加此类标注非常简单,如以下示例所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.title('Power curve for airfoil KV873')
plt.xlabel('Air speed')
plt.ylabel('Total drag')

plt.plot(X, Y, c = 'k')
plt.show()

该图将与本章第一个秘籍中获得的图相同。 但是,两个轴域都具有图例。

How to do it...

工作原理

我们使用 pyplot.xlabel()pyplot.ylabel()函数分别为的水平轴和的垂直轴添加描述。 至于pyplot.title()函数,该函数接受 LaTeX 表示法。 这些函数可用于任何图形。 您将使用相同的函数来标注散点图,直方图等。

添加文本

到目前为止,我们已经了解了如何在预设位置(例如标题和轴)设置文本。 在本秘籍中,我们将了解如何使用文本框在任何位置添加文本。

操作步骤

matplotlib 具有灵活的函数,称为 pyplot.text(),该函数显示文本:

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.text(-0.5, -0.25, 'Brackmard minimum')

plt.plot(X, Y, c = 'k')
plt.show()

该脚本在曲线旁边显示文本:

How to do it...

工作原理

我们使用pyplot.text()函数来获取位置和要显示的文本。 位置在图形坐标中给出,指定文本的左边框和垂直基线的位置。

更多

matplotlib 的文本呈现非常灵活。 让我们探索可用的重要选项。

对齐控制

文本由框限制。 此框用于使文本与传递给pyplot.text()的坐标相对对齐。 使用verticalalignmenthorizontalalignment参数(相应的快捷方式分别为vaha),我们可以控制对齐方式。

垂直对齐选项如下:

  • 'center':相对于文本框的中心

  • 'top':相对于文本框的上侧

  • 'bottom':相对于文本框的下侧

  • 'baseline':相对于文本的基线

    Alignment control

水平对齐选项如下:

  • 'center':相对于文本框的中心

  • 'left':相对于文本框的左侧

  • 'right':相对于文本框的右侧

    Alignment control

边界框控件

pyplot.text()函数支持bbox参数,其中将字典作为输入。 该词典定义了文本框的各种设置。 这是一个例子:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

box = {
  'facecolor'  : '.75',
  'edgecolor' : 'k',
  'boxstyle'    : 'round'
}

plt.text(-0.5, -0.20, 'Brackmard minimum', bbox = box)

plt.plot(X, Y, c='k')
plt.show()

前面的代码将给出以下输出:

Bounding box control

将传递给bbox参数的字典定义了以下键值对:

  • 'facecolor':这是用于包装盒的颜色。 它将用于设置背景和边缘颜色
  • 'edgecolor':这是用于盒子形状边缘的颜色
  • 'alpha':用于设置透明度级别,以使框与背景融合
  • 'boxstyle':设置框的样式,可以是'round''square'
  • 'pad':如果'boxstyle'设置为'square',则定义文本和框的两边之间的填充量

添加箭头

添加文本框可以帮助您标注图形。 但是,要显示图片的特定部分,使用箭头没有什么可比的。 在本秘籍中,我们将向您展示如何在图形上添加箭头。

操作步骤

matplotlib 具有使用pyplot.annotate()函数绘制箭头的功能,如以下代码片段所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.annotate('Brackmard minimum',
ha = 'center', va = 'bottom',
xytext = (-1.5, 3.),
xy = (0.75, -2.7),
arrowprops = { 'facecolor' : 'black', 'shrink' : 0.05 })

plt.plot(X, Y)
plt.show()

该脚本用文本和箭头标注一条曲线,如下图所示:

How to do it...

工作原理

pyplot.annotate()函数显示与pyplot.text()相同行的文本。 但是,也会显示一个箭头。 要显示的文本是第一个参数。 xy参数指定箭头的目的地。 xytext参数指定文本位置。 与pyplot.text()相似,可以通过horizontalalignmentverticalalignment参数进行文本对齐。 shrink参数控制箭头的端点和箭头本身之间的间隙。

箭头的方向由传递给 arrowprops参数的字典控制:

  • 'arrowstyle':参数''<-''''<''''-''''wedge''''simple''"fancy"控制箭头的样式

  • 'facecolor':这是箭头所使用的颜色。 它将用于设置背景和边缘颜色

  • 'edgecolor':这是箭头形状边缘使用的颜色

  • 'alpha': 这用于设置透明度,以便箭头与背景融合

    How it works...

添加图例

没有自己的传说,一个合适的图表是不完整的。 matplotlib 提供了一种以最少的精力生成图例的方法。 在本秘籍中,我们将看到如何在图上添加图例。

操作步骤

对于此秘籍,我们使用pyplot.legend()函数以及label可选参数:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(0, 6, 1024)
Y1 = np.sin(X)
Y2 = np.cos(X)

plt.xlabel('X')
plt.ylabel('Y')

plt.plot(X, Y1, c = 'k',  lw = 3.,              label = 'sin(X)')
plt.plot(X, Y2, c = '.5', lw = 3., ls = '--', label = 'cos(X)')

plt.legend()
plt.show()

上面的代码提供以下输出:

How to do it...

工作原理

每个pyplot函数都有可选的label参数,以命名元素,例如图形的曲线,直方图等。 matplotlib 跟踪这些标签。 pyplot.legend()函数将渲染图例。 图例是从标签自动生成的。

更多

pyplot.legend函数具有几个有趣的参数来控制图例方面:

  • 'loc':这是图例的位置。 默认值为'best',它将自动放置它。 其他有效值是'upper left''lower left''lower right''right''center left''center right''lower center''upper center''center'
  • 'shadow':可以是TrueFalse,并使用阴影效果渲染图例。
  • 'fancybox':可以是TrueFalse,并用圆角框显示图例。
  • 'title':这将通过带有作为参数传递的标题的图例进行渲染。
  • 'ncol':强制传递的值是图例的列数。

添加网格

在准备图形时,我们可能需要快速猜测图形任何部分的坐标。 在图形上添加网格是提高图形可读性的自然方法。 在本秘籍中,我们将看到如何在图形上添加网格。

操作步骤

matplotlib 的网格功能由 pyplot.grid()函数控制。

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-4, 4, 1024)
Y = .25 * (X + 4.) * (X + 1.) * (X - 2.)

plt.plot(X, Y, c = 'k')
plt.grid(True, lw = 2, ls = '--', c = '.75')
plt.show()

该脚本将显示在背景中带有网格的曲线。 网格与坐标轴图例的刻度对齐,如下图所示:

How to do it...

工作原理

添加网格就像一样简单,就像用True作为参数调用pyplot.grid()函数一样。 网格由线条组成,因此pyplot.grid()接受线条样式参数,例如linewidthlinestylecolor。 这些参数将应用于绘制网格的线。

添加线条

当您有非常具体的需求时,matplotlib 提供的数据可能对您没有太大帮助。 matplotlib 制作的所有图形均由基本图元组成。 在演示如何更改箱形图的颜色时,我们提到大多数 matplotlib 绘图函数都会返回线条和形状的集合。 现在,我们将演示如何直接使用基本图元。

操作步骤

以下脚本将显示由独立行构成的简单但美观的模式:

import matplotlib.pyplot as plt

N = 16
for i in range(N):
  plt.gca().add_line(plt.Line2D((0, i), (N - i, 0), color = '.75'))

plt.grid(True)
plt.axis('scaled')
plt.show()

上面的代码提供以下输出:

How to do it...

工作原理

在此脚本中,我们绘制了 16 条独立的线。 pyplot.Line2D()函数创建一个新的Line2D对象。 强制性参数是该行的端点。 可选参数是我们之前针对基于线的图形所见的所有参数。 因此,您可以使用linestylelinewidthmarkermarkersizecolor等。

pyplot.Line2D()函数创建了该行,但是除非您明确要求,否则不会渲染该行; 这是使用pyplot.gca().add_line()完成的。 pyplot.gca()函数返回负责跟踪渲染内容的对象。 调用gca().add_line()只是表示我们要渲染一条线。

需要使用pyplot.axis('scaled')函数以确保图形使用统一的比例尺:与 xy 轴上使用的比例尺相同。 这与默认行为'tight'形成对比,其中默认值 matplotlib 将为 xy 轴赋予不同的比例,以使图形尽可能紧密地适合显示表面。 此函数将在第 4 章,“处理图形”中介绍。

添加形状

要使用基本图元制作自己的图形,线条是很好的起点,但是您很可能需要更多形状。 渲染形状的工作方式与渲染线相同。 在本秘籍中,我们将向您展示如何在图形中添加形状。

操作步骤

在以下脚本中,我们创建并渲染几个形状。 标注指示哪个部分呈现哪种形状:

import matplotlib.patches as patches
import matplotlib.pyplot as plt

## Circle
shape = patches.Circle((0, 0), radius = 1., color = '.75')
plt.gca().add_patch(shape)

## Rectangle
shape = patches.Rectangle((2.5, -.5), 2., 1., color = '.75')
plt.gca().add_patch(shape)

## Ellipse
shape = patches.Ellipse((0, -2.), 2., 1., angle = 45., color = '.75')
plt.gca().add_patch(shape)

## Fancy box
shape = patches.FancyBboxPatch((2.5, -2.5), 2., 1., boxstyle = 'sawtooth', color = '.75')
plt.gca().add_patch(shape)

## Display all
plt.grid(True)
plt.axis('scaled')
plt.show()

输出中显示了四种不同的形状,如以下屏幕截图所示:

How to do it...

工作原理

无论显示哪种形状,原理都相同。 在内部,形状被描述为在 matplotlib API 中称为“补丁”的路径。 matplotlib.patches模块中提供了几种形状的路径。 实际上,该模块包含用于所有附图的补丁。 与线条一样,创建路径不足以渲染它。 您将必须表示要渲染它。 这是通过pyplot.gca().add_patch()完成的。

许多路径构造器都可用。 让我们回顾一下示例中使用的那些:

  • Circle:将其中心坐标和半径作为参数
  • Ractangle:将其左下角的坐标及其大小作为参数
  • Ellipse:将其中心坐标和两个轴的半长作为参数
  • FancyBox :这就像一个矩形,但带有一个附加的boxstyle参数('larrow''rarrow''round''round4''roundtooth''sawtooth''square'

更多

除了预定义的形状,我们还可以使用多边形定义任意形状。

使用多边形

多边形仅比路径复杂,并且由点列表定义:

import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt

theta = np.linspace(0, 2 * np.pi, 8)
points = np.vstack((np.cos(theta), np.sin(theta))).transpose()

plt.gca().add_patch(patches.Polygon(points, color = '.75'))

plt.grid(True)
plt.axis('scaled')
plt.show()

前面的代码提供以下多边形作为输出:

Working with polygons

matplotlib.patches.Polygon()构造器将坐标列表作为输入,即多边形的顶点。

使用路径属性

所有路径都有我们先前已经探讨过的几个属性:linewidthlinestyleedgecolorfacecolorhatch等,如下所示:

import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt

theta = np.linspace(0, 2 * np.pi, 6)
points = np.vstack((np.cos(theta), np.sin(theta))).transpose()

plt.gca().add_patch(plt.Circle((0, 0), radius = 1., color = '.75'))
plt.gca().add_patch(plt.Polygon(points, closed=None, fill=None, lw = 3., ls = 'dashed', edgecolor = 'k'))

plt.grid(True)
plt.axis('scaled')
plt.show()

下图是上述代码的输出:

Working with path attributes

在这里,我们使用具有虚线边缘(ls = 'dashed')的非填充(fill = None)多边形绘制多边形轮廓,而不必创建多个线对象。 仅通过使用路径的属性就可以实现许多效果。

控制刻度线间距

在 matplotlib 中,刻度在图形的两个轴上都是小标记。 到目前为止,我们让 matplotlib 处理轴域图例上刻度线的位置。 正如我们将在本秘籍中看到的那样,我们可以手动覆盖此机制。

操作步骤

在此脚本中,我们将操纵 x 轴上的刻度线之间的间隙:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

X = np.linspace(-15, 15, 1024)
Y = np.sinc(X)

ax = plt.axes()
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))

plt.plot(X, Y, c = 'k')
plt.show()

现在,在通常的刻度之间可以看到较小的刻度:

How to do it...

工作原理

我们强制水平刻度线以 5 个单位显示。 此外,我们还添加了小刻度,以 1 个单位的步长出现。 为此,我们执行以下步骤:

  1. 我们获得了Axes对象的实例:管理图形轴域的对象。 这是ax = plot.axes()的目的。
  2. 对于 x 轴(ax.xaxis),我们为主要和次要刻度线设置了一个Locator实例。

更多

如果我们希望添加网格,可以考虑较小的刻度,如下所示:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

X = np.linspace(-15, 15, 1024)
Y = np.sinc(X)
ax = plt.axes()
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))

plt.grid(True, which='both')
plt.plot(X, Y)
plt.show()

前面的代码代码段给出以下输出:

There's more...

如前所示,我们可以使用pyplot.grid()添加一个网格。 此函数采用可选参数which。 它可以接受三个值:'minor''major''both'。 它确定应在哪个刻度上显示网格。

控制刻度标签

刻度标签是图形空间中的坐标。 尽管在很多情况下都有意义,但这并不总是足够的。 例如,让我们想象一个条形图,该条形图显示 10 个国家的中位数收入。 我们希望看到每个条形下的国家名称,而不是条形的坐标。 对于时间序列,我们希望看到日期,而不是一些抽象坐标。 matplotlib 为此提供了一个全面的 API。 在本秘籍中,我们将了解如何控制刻度标签。

操作步骤

使用标准的 matplotlib 刻度 API,可以如下设置条形图(或任何其他类型的图形)的刻度:

import numpy as np
import matplotlib.ticker as ticker
import matplotlib.pyplot as plt

name_list = ('Omar', 'Serguey', 'Max', 'Zhou', 'Abidin')
value_list = np.random.randint(0, 99, size = len(name_list))
pos_list = np.arange(len(name_list))

ax = plt.axes()
ax.xaxis.set_major_locator(ticker.FixedLocator((pos_list)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter((name_list)))

plt.bar(pos_list, value_list, color = '.75', align = 'center')
plt.show()

条形图的每个条形都有自己的刻度和图例:

How to do it...

工作原理

我们已经看到了ticker.Locator来生成刻度线的位置。 ticker.Formatter对象实例将为刻度生成标签。 我们在这里使用的Formatter实例是FixedFormatter,它将从字符串列表中获取标签。 然后,使用Formatter实例设置 x 轴。 对于此特定示例,我们还使用FixedLocator来确保每个小节位于一个刻度的中间。

更多

我们几乎没有触及这个话题的表面。 关于刻度的更多信息。

一种创建带有固定标签的条形图的更简单方法

对于条形图固定标签的特殊情况,我们可以利用快捷方式的优势:

import numpy as np
import matplotlib.pyplot as plt

name_list = ('Omar', 'Serguey', 'Max', 'Zhou', 'Abidin')
value_list = np.random.randint(0, 99, size = len(name_list))
pos_list = np.arange(len(name_list))

plt.bar(pos_list, value_list, color = '.75', align = 'center')
plt.xticks(pos_list, name_list)
plt.show()

前面的代码代码段给出了以下条形图:

A simpler way to create bar charts with fixed labels

而不是使用股票代号 API,我们使用pyplot.xticks()函数为一组固定的代号提供了修复标签。 该函数将位置列表和名称列表作为参数。 结果与前面的示例相同; 它更短,更容易记住。

高级标签生成

如果代码 API 的重点是我们周围有快捷方式怎么办? 报价器 API 的效果要好于,而不是为每个报价显示固定标签,如下所示:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker

def make_label(value, pos):
  return '%0.1f%%' % (100\. * value)

ax = plt.axes()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(make_label))

X = np.linspace(0, 1, 256)
plt.plot(X, np.exp(-10 * X), c ='k')
plt.plot(X, np.exp(-5 * X), c= 'k', ls = '--')

plt.show()

上面的代码提供以下输出:

Advanced label generation

在此示例中,滴答是由自定义函数make_label生成的。 此函数将刻度的坐标作为输入并生成字符串。 在这里,一个百分比。 无论 matplotlib 决定显示多少滴答声,我们都可以为其生成正确的标签。 这比给出固定的字符串列表更加灵活。 这里唯一的新东西是FuncFormatter,它是将函数作为参数的格式化程序。

将生成标签的实际任务委派给函数的这种方法称为委托 。 我们的代表是make_label。 这是一种美丽的编程技术。 假设我们要显示每个刻度的日期。 这可以使用标准的 Python 时间和日期函数来完成:

import numpy as np
import datetime
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
start_date = datetime.datetime(1998, 1, 1)

def make_label(value, pos):
  time = start_date + datetime.timedelta(days = 365 * value)
  return time.strftime('%b %y')

ax = plt.axes()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(make_label))

X = np.linspace(0, 1, 256)
plt.plot(X, np.exp(-10 * X), c = 'k')
plt.plot(X, np.exp(-5 * X), c = 'k', ls = '--')

labels = ax.get_xticklabels()
plt.setp(labels, rotation = 30.)
plt.show()

前面的代码提供以下输出:

Advanced label generation

现在,每个刻度显示为以人类可读的格式设置的日期。 该方法与我们之前使用的方法相同:我们使用FuncFormatter。 在标签生成函数中,借助datetime标准模块,我们将刻度的位置转换为日期。 在这里,我们将[0, 1]范围内的值映射到 1998 年。datetime模块还提供了强大的格式化函数strftime,我们可以使用它来生成标签本身。

四、处理图形

在本章中,我们将介绍:

  • 合并多个图形
  • 均等缩放两个轴
  • 设定轴范围
  • 设定长宽比
  • 插入子图
  • 使用对数刻度
  • 使用极坐标

简介

设计科学的绘图包是一项艰巨的任务-涉及的需求极为多样化。 一方面,理想情况下,只需很少的编码和摆弄就可以创建任何一种图形。 另一方面,我们希望能够自定义图形的任何方面。 这两个目标是截然相反的。 matplotlib 在这两个目标之间提供了罕见的平衡。 在本章中,我们将探讨修改库存数据基本方面的方法,例如更改所使用的坐标系。

合并多个图形

在检查某些数据时,我们可能希望同时查看它的多个方面。 例如,利用来自一个国家的人口统计数据,我们希望看到男性/女性年龄金字塔,财富分配和每年的人口规模是三个不同的图形。 matplotlib 提供了将多个图形组合在一起的可能性。 从 1.2 版开始,用于此的 API 确实非常方便。 在本秘籍中,我们将了解如何将多个图形组合在一起。

操作步骤

将使用和pyplot.subplot2grid()函数,如下所示:

import numpy as np
from matplotlib import pyplot as plt

T = np.linspace(-np.pi, np.pi, 1024)

grid_size = (4, 2)

plt.subplot2grid(grid_size, (0, 0), rowspan = 3, colspan = 1)
plt.plot(np.sin(2 * T), np.cos(0.5 * T), c = 'k')

plt.subplot2grid(grid_size, (0, 1), rowspan = 3, colspan = 1)
plt.plot(np.cos(3 * T), np.sin(T), c = 'k')

plt.subplot2grid(grid_size, (3, 0), rowspan=1, colspan=3)

plt.plot(np.cos(5 * T), np.sin(7 * T), c= 'k')

plt.tight_layout()
plt.show()

绘制了三个图形,将图形分为三个区域,如下所示:

How to do it...

工作原理

pyplot.subplot2grid()之后的想法是定义 R 行和 C 列的网格。 然后,我们可以将图形渲染到该网格的矩形补丁。

pyplot.subplot2grid()函数具有四个参数:

  • 第一个参数是作为元组传递的网格的行数和列数。 如果我们想要一个由R行和C列组成的网格,我们将传递(R, C)
  • 第二个参数是网格中的行和列坐标,也作为元组传递。
  • 可选参数rowspan定义图形将跨越多少行。
  • 可选参数colspan定义图形将跨越多少列。

一旦调用pyplot.subplot2grid(),对pyplot的进一步调用将在指定的矩形区域内定义图形。 为了在另一个区域渲染另一个图形,我们再次调用pyplot.subplot2grid()

在示例脚本中,我们定义了2 x 4的网格。 前两个数字跨越 1 列和 3 行,因此每个填充几乎一整列。 第三个数字跨越 2 列,但只有 1 行,填充了底行。 描述完所有附图后,我们将其称为pyplot.tight_layout()。 此命令要求 matplotlib 打包所有图形,以使它们彼此不重叠。

更多

我们已经看到pyplot.title()在图形上添加了标题。 在下面的示例中,我们使用pyplot.title()为每个子图赋予标题:

import numpy as np
from matplotlib import pyplot as plt

def get_radius(T, params):
  m, n_1, n_2, n_3 = params
  U = (m * T) / 4

  return (np.fabs(np.cos(U)) ** n_2 + np.fabs(np.sin(U)) ** n_3) ** (-1\. / n_1)

grid_size = (3, 4)
T = np.linspace(0, 2 * np.pi, 1024)

for i in range(grid_size[0]):
  for j in range(grid_size[1]):
    params = np.random.random_integers(1, 20, size = 4)
    R = get_radius(T, params)

    axes = plt.subplot2grid(grid_size, (i, j), rowspan=1, colspan=1)
    axes.get_xaxis().set_visible(False)
    axes.get_yaxis().set_visible(False)

    plt.plot(R * np.cos(T), R * np.sin(T), c = 'k')
    plt.title('%d, %d, %d, %d' % tuple(params), fontsize = 'small')

plt.tight_layout()
plt.show()

下图包含 12 个图形,每个图形都有自己的标题:

There's more...

pyplot.title()函数为一个子图提供标题。 如果整个图形需要一个标题,则应使用pyplot.suptitle(),其中suptitle代表超级标题。

合并图形的另一种方法

这里介绍的子图机制相当笼统。 它使我们可以创建复杂的布局。 如果我们只需要在一行或一列中包含几个数字,则可以使用更简单的代码,如下所示:

import numpy as np
from matplotlib import pyplot as plt

T = np.linspace(-np.pi, np.pi, 1024)

fig, (ax0, ax1) = plt.subplots(ncols =2)
ax0.plot(np.sin(2 * T), np.cos(0.5 * T), c = 'k')
ax1.plot(np.cos(3 * T), np.sin(T), c = 'k')

plt.show()

只需调用一次pyplot.subplots(),我们就创建了两个彼此相邻的子图,如下图所示:

An alternative way to composite figures

pyplot.subplot()函数具有两个可选参数ncolsnrows,并将返回带有ncols * nrows实例的AxesFigure对象。 Axes实例通过nrows行布置在ncols列的网格中。 这使得网格布局非常容易创建。

均等缩放两个轴

默认情况下,matplotlib 将对图形的两个轴使用不同的比例。 在本秘籍中,我们将了解如何对图形的两个轴使用相同的比例。

操作步骤

要完成,我们需要使用pyplot API 和Axes对象,如以下代码所示:

import numpy as np
import matplotlib.pyplot as plt
T = np.linspace(0, 2 * np.pi, 1024)

plt.plot(2\. * np.cos(T), np.sin(T), c = 'k', lw = 3.)
plt.axes().set_aspect('equal')

plt.show()

前面的脚本用其实际的长宽比绘制了一个椭圆,如下所示:

How to do it...

工作原理

在此示例中,我们显示一个椭圆,其中长轴是短轴长度的两倍。 实际上,渲染的椭圆遵循这些比例。

pyplot.axes()函数返回Axes对象的实例,该对象负责轴域。 Axes实例具有set_aspect方法,我们将其设置为'equal'。 现在,两个轴使用相同的比例。 如果我们未设置相同的方面,则该图看起来会有所不同。

How it works...

上图仍是椭圆形,但长宽比变形。

设置轴范围

默认情况下,matplotlib 将在两个轴上查找数据的最小值和最大值,并将其用作绘制数据的范围。 但是,有时最好手动设置此范围,以更好地了解数据的极值。 在本秘籍中,我们将了解如何设置轴范围。

操作步骤

pyplot API 提供了直接设置一个轴范围的函数,如下所示:

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-6, 6, 1024)

plt.ylim(-.5, 1.5)
plt.plot(X, np.sinc(X), c = 'k')
plt.show()

前面的脚本绘制了曲线。 与默认设置相反,该图形不能完美地拟合曲线。 我们在曲线的上部有一些空间,如下图所示:

How to do it...

工作原理

pyplot.xlim()pyplot.ylim()参数允许我们分别控制 x 轴和 y 轴的范围。 这些参数是最大值和最小值。

设置长宽比

在为期刊出版物或网站准备图形时,可能需要一个具有特定长宽比的图形。 在本秘籍中,我们将看到如何控制图形的长宽比。

操作步骤

pyplot API 提供了一种设置自定义长宽比的简单方法,如下所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-6, 6, 1024)
Y1, Y2 = np.sinc(X), np.cos(X)

plt.figure(figsize=(10.24, 2.56))
plt.plot(X, Y1, c='k', lw = 3.)
plt.plot(X, Y2, c='.75', lw = 3.)

plt.show()

下图的长宽比与我们默认情况下的长宽比有很大不同:

How to do it...

工作原理

我们使用pyplot.figure()函数,该函数创建一个新的Figure实例。 Figure对象整体上代表图形。 通常,该对象是在幕后隐式创建的。 但是,通过显式创建对象,我们可以控制图形的各个方面,包括其长宽比。 figsize参数允许我们指定其大小。 在此示例中,我们将水平尺寸设置为垂直尺寸的四倍,使其长宽比为 4:1。

插入子图

插入一个小的嵌入式图形可以帮助显示图形的细节,或更一般而言,可以强调图形的特定部分。 在本秘籍中,我们将看到如何在图形中插入子图形。

操作步骤

matplotlib 允许我们在图形的任何部分中创建子区域,并将图形分配给该子区域。 在以下示例中,创建了一个子区域以显示曲线的详细信息:

import numpy as np
from matplotlib import pyplot as plt

X = np.linspace(-6, 6, 1024)
Y = np.sinc(X)

X_detail = np.linspace(-3, 3, 1024)
Y_detail = np.sinc(X_detail)

plt.plot(X, Y, c = 'k')

sub_axes = plt.axes([.6, .6, .25, .25])
sub_axes.plot(X_detail, Y_detail, c = 'k')
plt.setp(sub_axes)

plt.show()

该子区域显示在该图的右上方。

How to do it...

工作原理

我们首先从在图上创建一个子区域,如下所示:

sub_axes = plt.axes([.6, .6, .25, .25])

该区域以图形坐标表示; 也就是说,(0, 0)是整个图形的左下角,(1, 1)是整个图形的右上角。 该子区域由四个值定义:区域左下角的坐标及其尺寸。

定义子区域后,我们将在其中创建图形的Axes实例。 然后,我们需要在上调用实例上的pyplot.setp(),如下所示:

plt.setp(sub_axes)

请注意,可以创建多少个子区域没有限制。

使用对数刻度

当可视化很大范围内变化的数据时,对数刻度使我们能够可视化否则很难看到的变化。 在本秘籍中,我们将向您展示如何操纵图形的缩放系统。

操作步骤

有几种方法可以将设置为对数刻度。 此处完成的方式适用于任何类型的图形,而不仅适用于线形图。 在下面的示例中,我们设置了对数刻度,该刻度将应用于所有绘图元素:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(1, 10, 1024)

plt.yscale('log')
plt.plot(X, X, c = 'k', lw = 2., label = r'$f(x)=x$')
plt.plot(X, 10 ** X, c = '.75', ls = '--', lw = 2., label = r'$f(x)=e^x$')
plt.plot(X, np.log(X), c = '.75', lw = 2., label = r'$f(x)=\log(x)$')

plt.legend()
plt.show()

下图显示了几条曲线,垂直轴使用对数刻度:

How to do it...

工作原理

在此示例中,显示三个函数, y 轴遵循对数刻度。 所有工作都由pyplot.yscale()完成,我们在其中传递'log'来指定我们想要的比例尺类型。 同样,我们将使用plot.xscale()至在 x 轴上获得相同的结果。 可以很简单地创建对数-对数图,如下所示:

plt.xscale('log')
plt.yscale('log')

对数底数默认为 10,但可以使用可选参数basexbasey进行更改。

更多

使用对数刻度在放大很大范围数据上的一个小范围上也很有用,如以下示例所示:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-100, 100, 4096)

plt.xscale('symlog', linthreshx=6.)
plt.plot(X, np.sinc(X), c = 'k')

plt.show()

曲线的中心部分([-6, 6]范围)以线性标尺显示,而其他部分以对数标尺显示在下图中:

There's more...

在这里,我们将'symlog'作为参数pyplot.xscale()的参数,该参数是以 0 为中心的对称对数刻度。通过设置'linthreshx=6.',我们指定在[-6, 6]范围内,我们希望线性和对数刻度在这个范围。 这样,我们就可以在一个范围内获得详细的视图,同时仍然可以查看很大范围的剩余数据。

使用极坐标

一些现象具有角性质。 一个例子就是扬声器的功率,具体取决于我们从中测量扬声器的角度。 极坐标是表示此类数据的自然选择。 此外,可以方便地在极坐标中绘制诸如年度或每日统计数据之类的循环数据。 在本秘籍中,我们将了解如何使用极坐标。

操作步骤

让我们绘制一个简单的极坐标曲线,如下所示:

import numpy as np
import matplotlib.pyplot as plt

T = np.linspace(0 , 2 * np.pi, 1024)
plt.axes(polar = True)
plt.plot(T, 1\. + .25 * np.sin(16 * T), c= 'k')

plt.show()

下图显示了极坐标图的特殊布局:

How to do it...

工作原理

正如我们之前看到的,pyplot.axes() 显式创建一个Axes实例,该实例允许进行一些自定义设置。 只需使用可选的polar参数即可设置极坐标投影。 请注意图例如何适应投影。

更多

绘制曲线可能是极投影的最常见用法。 但是,我们可以使用其他任何类型的图,例如条形图和显示形状。 例如,使用极坐标投影和多边形,您可以绘制雷达图。 使用以下代码执行此操作:

import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt
ax = plt.axes(polar = True)

theta = np.linspace(0, 2 * np.pi, 8, endpoint = False)
radius = .25 + .75 * np.random.random(size = len(theta))
points = np.vstack((theta, radius)).transpose()

plt.gca().add_patch(patches.Polygon(points, color = '.75'))
plt.show()

下图显示了我们用极坐标定义的多边形:

There's more...

注意,多边形的坐标是到原点的角度和距离。 我们不需要执行从极坐标到直角坐标的显式转换。