Matplotlib 3.0 秘籍(四)
五、使用高级功能的绘图
在本章中,我们将学习以下秘籍:
- 使用属性循环器
- 绘制路径效果
- 使用转换
- 控制轴域位置
- 使用
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)
- 使用宽度和高度比率参数定义第二个
GridSpecgs2:
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处开始以及在处结束的位置rightwspace控制各图之间的行间隔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}指定要以罗马字体打印dx将按原样打印
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和上标为jhspace{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()
- 使用
300DPI 将图形保存为 PNG 格式,并将其显示在屏幕上:
plt.savefig('histogram_300.png', dpi=300)
plt.show()
- 定义另一个更大的图形,绘制直方图,并使用
100DPI 将其保存为 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 文档。 如果您打开文档,您应该看到以下三个图为三页。 正如我们在代码中定义的那样,它们每个都有不同的大小: