# 绘制固定区域的子图
# matplotlib 可以将整个画布规划成等分布局的 m×n(行 x 列)的矩阵区域,并按照先行后列的方式对每个区域进行编号(编号从 1 开始),之后在选中的某个或某些区域中绘制单个或多个子图。例如,画布被规划成等分布局的 3x2 的矩阵区域及编号示意图如图 5-1 所示。
# 下面将对在等分区域中绘制单子图或多子图的相关内容进行详细介绍。
# 绘制单子图
# 使用 pyplot的 subplot() 函数可以在规划好的某个区域中绘制单个子图,suBplot() 函数的语法格式如下 :
subplo(nrows, ncols, index, projection, polar, sharex, sharey,
label, **kwargs)
# 该函数的常用参数含义如下。
# · nrows :表示规划区域的行数。
· ncols :表示规划区域的列数。
· index :表示选择区域的索引,默认从 1 开始编号。
· projection :表示子图的投影类型,可以为 None、'hammer'、'lambert'、'mollweide'、'polar'、'rectilinear',中任一取值,其中默认值 None 代表使用 'rectilinear',直线投影。
· polar : 表示是否使用极坐标,默认值为 False。若参数 polar 设为 True, 则作用等同于projection'polar'。
· sharex, sharey:表示是否共享子图的 x 轴或 y 轴。
# 参数 nrows、ncols、index 既支持单独传参,也支持以一个 3 位整数 (每位整数必须小于10)的形式传参。例如,subplot(235)与 subplot(2,3,5) 是等价的。
subplot() 函数会返回一个 Axes 类的子类 SubplotBase 对象。
需要说明的是,Figure 类对象可以使用 add_subplot() 方法绘制单子图,此方式与 subplot() 函数的作用是等价的。
例如,将画布规划成 3x2 的矩阵区域,并在索引为 6 的区域中绘制子图;再次将画布规划成 3x1 的矩阵区域,并在索引为 2 的区域中绘制子图,代码如下。
In [1]:
# 通过窗口的形式显示./image/ ,很好地体现子图与整个画布的位置关系
%matplotlib auto
import matplotlib.pyplot as plt
# 画布被规划为 3x2 的矩阵区域,之后在索引为 6 的区域中绘制子图
ax_ne = plt.subplot(326)
ax_one.plot([1, 2, 3, 4, 5])
# 面布被标划为 3x1 的矩阵区域,之后在索引为 2 的区域中绘制子图
ax_two = plt.subplot(312)
ax_two.plot([1, 2, 3, 4, 5])
plt.show()
# 运行程序,效果如图 5-2 所示。
# 多学一招:Jupyter Notebook 的绘图模式
# 当 Jupyter Notebook 工具运行 matplotlib 程序时,默认会以静态./image/的形式显示运行结果。此时的./image/不支持放大或缩小等交互操作。实际上,Jupyter Notebook 支持两种绘图模式,分别为控制台绘图和弹出窗绘图。
1. 控制台绘图
控制台绘图是默认模式,该模式是将绘制的图表以静态./image/的形式显示,具有便于存储./image/、不支持用户交互的特点。开发者可以在 matplotlib 程序中添加 “%matplotlib inline” 语句,通过控制台来显示./image/,示例代码及运行结果如图 5-3 所示。
# 2. 弹出窗绘图
弹出窗绘图模式是将绘制的图表以弹出窗口的形式显示,具有支持用户交互、支持多种./image/存储格式的特点。开发者可以在 matplotlib 程序中添加“%matplotlib auto” 或 “%matplotlib notebook” 语句,通过弹出窗口来显示./image/,示例代码及运行结果分别如图 5-4 和图 5-5 所示。
# 需要注意的是,matplotlib 程序添加完设置绘图模式的语句后,很有可能出现延迟设置绘图模式的现象。因此这里建议大家重启服务,即在 Jupyter Notebook 工具的菜单栏中选择【Kernel】 -> 【Restart】,之后在弹出的“重启服务?”窗口中选择【重启】即可。
# 实例1:某工厂产品 A 与产品 B 去年的销售额分析
# 已知某工厂有两种爆款产品:产品 A 和产品 B。 公司在 2020 年年初分别对产品 A 和产品 B 去年的销售额进行了统计,并将统计后的结果进行整合,如表 5-1 所示。
# 根据表 5-1 的数据,将“月份”一列的数据作为 x 轴的数据,将“产品 A 的销售额”和“产品 B 的销售额”两列的数据作为 y 轴的数据,将画布规划成 2x1 的矩阵区域,并在索引为 1 的区域中绘制反映产品 A 和产品 B 销售额趋势的折线图;将画布规划成2x2的矩阵区域,并在索引为 3 的区域中绘制反映产品 A 销售额占比的饼图;再次将画布规划成 2x2 的矩阵区域,并在索引为 4 的区域中绘制反映产品 B 销售额占比的饼图,具体代码如下。
In [2]:
# 01_product_sales
%matplotlib auto
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ["SimHei”]
x = [x for x in range(1, 13)]
y1 = [20, 28, 23, 16, 29, 36, 39, 33, 31, 19, 21, 25]
y2 = [17, 22, 39, 26, 35, 23, 25, 27, 29, 38, 28, 20]
labels = ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月']
# 将画布规划成等分布局的 2×1 的矩阵区域,之后在索引为 1 的区域中绘制子图
ax1 = plt.subplot(211)
ax1.plot(x, y1, 'm--o', lw=2, ms=5, label='产品 A')
ax1.plot(x, y2, 'g--o', lw=2, ms=5, label='产品 B')
ax1.set_title(" 产品 A 与产品 B 的销售额趋势", fontsize=11)
ax1.set_ylim(10, 45)
ax1.set_ylabel('销售额(亿元)')
ax1.set_xlabel('月份')
for xy1 in zip(x, y1):
ax1.annotate("%s" % xy1[1], xy=xy1, xytext=(-5, 5),
textcoords='offset points')
for xy2 in zip(x, y2):
ax1.annotate("%s" % xy2[1], xy=xy2, xytext=(-5, 5),
textcoords='offset points')
ax1.legend()
# 将画布规划成等分布局的 2x2 的矩阵区域,之后在索引为 3 的区域中绘制子图
ax2 = plt.subplot(223)
ax2.pie(y1, radius=1, wedgeprops={'width': 0.5}, labels=labels,
autopct='%3.1f%%', pctdistance=0.75)
ax2.set_title('产品 A 的销售额')
# 将画布规划成等分布局的 2x2 的矩阵区域,之后在索引为 4 的区域中绘制子图
ax3 = plt.subplot(224)
ax3.pie(y2, radius=1, wedgeprops={'width': 0.5}, labels=labels,
autopct='%3.1f%%', pctdistance=0.75)
ax3.set__title('产品 B 的销售额')
# 调整子图之间的距离
plt.tight_layout()
plt.show()
# 运行程序,效果如图 5-6 所示。
# 图 5-6中,整个窗口同时显示了 3 个图表,其中上方的折线图展示了去年产品 A 与产品B 的销售额趋势,左下方的圆环图展示了产品 A 的销售额的占比,右下方的圆环图展示了产品 B 的销售额的占比。由图 5-6 可知,上方的折线图反映了产品 A 与产品 B 去年销售额的整体变化情况,下方的圆环图分别反映了去年每月产品 A 与产品 B 的销售额占比情况,同一个画布的多个子图从多个角度反映了数据呈现的多条信息。
# 绘制多子图
# 使用 pyplot 的 subplots() 函数可以在规划好的所有区域中一次绘制多个子图。subplot() 函数的语法格式如下:
subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True,
subplot_kw=None, gridspec_kw=None, **fig_kw)
# 该函数常用参数的含义如下。
# · nrows:表示规划区域的行数,默认为 1。
· ncols :表示规划区域的列数,默认为 1。
· sharex, sharey :表示是否共享子图的 x 轴或 y 轴。
· squeeze :表示是否返回压缩的 Axes 对象数组,默认为 True。当 squeeze 为 True 时,若 nrows 和 ncols 均为 1 , 则 subplots() 函数会返回一个 Axes 对象;若 nrows 和 ncols 均大于 1 ,则 subplots() 函数会返回一个 Axes 对象数组。当参数 squeeze 为 False 时,subplotsO 函数会返回一个包含 Axes 对象的二维数组。
· gridspec_kw :表示用于控制区域结构属性的字典。
# subplots() 函数会返回一个包含两个元素的元组,其中元组的第一个元素为 Figure 对象,第二个元素为 Axes 对象或 Axes 对象数组。
例如,将画布规划成 2x2 的矩阵区域,之后在第 3 个区域中绘制子图,代码如下。
In [3]:
%matplotlib auto
import matplotlib.pyplot as plt
# 将画布划分为 2x2 的等分区域
fig, ax arr = plt.subplots (2, 2)
# 获取品_arr 数组第 1 行第 0 列的元索 ,也就是第 3 个区域
ax_thr = ax_arr[1, 0]
ax_thr.plot([1, 2, 3, 4, 5])
# 运行程序,效果如图 5-7 所示。
# 实例2:部分国家养猫人群比例与养狗人群比例分析
# 随着人们生活水平的提高,许多人都会在家里养一些萌宠,有时还会在抖音上分享萌宠日常的可爱视频。据某数据平台统计,部分国家养猫人群比例和养狗人群比例的情况如表 5-2 所示。
# 根据表 5-2 的数据,将 “国家” 一列的数据作为 y 轴的刻度,将 “养猫人群比例” 和 “养狗人群比例” 两列的数据作为 x 轴的数据,将整个画布规划成 1x2 的矩阵区域,并在索引为 1 和索引为 2 的区域中分别绘制反映养猫人群比例与养狗人群比例的条形图,具体代码如下。
In [4]:
# 02_people_with_dogs_and_cats
%matplotlib auto
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ["SimHei"]
# 添加无指向型注释文本
def autolabel(ax, rects):
"""在每个矩形条的上方附加一个文本标签,以显示其高度"""
for rect in rects:
width = rect.get_width() # 获取每个矩形条的高度
ax.text(width + 3, rect.get_y() , s='()'.format(width),
ha='center', va='bottom')
y = np.arange(12)
x1 = np.array([19, 33, 28, 29, 14, 24, 57, 6, 26, 15, 27, 39])
x2 = np.array([25, 33, 58, 39, 15, 64, 29, 23, 22, 11, 27, 50])
labels = np.array (['中国', '加拿大', '巴西', '澳大利亚', '日本', '墨西哥',
'俄罗斯', '韩国', '瑞士', '土耳其', '英国', '美国'])
# 将画布规划为 1×2 的矩阵区域 ,依次在每个区域中绘制子图
fig, (ax1, ax2) = plt.subplots (1, 2)
barh1_rects = ax1.barh(y, x1, height=0.5, tick_label=labels, color='#FFA500')
ax1.set_xlabel ('人群比例(%)')
ax1.set_title('部分国家养猫人群的比例')
ax1.set_xlim((0, x1.max()+10)
autolabel(ax1, barh1__rects)
barh2_rects = ax2.barh(y, x2, height=0.5, tick_label=labels, color='#20B2AA')
ax2.set_xlabel('人群比例(%))')
ax2.set_title('部分国家养狗人群的比例')
ax2.set_xlim(0, x2.max()+10)
autolabel(ax2, barh2_rects)
# 调整子图之间的距离
plt.tight_layout()
plt.show()
# 运行程序,效果如图 5-8 所示。
# 图 5-8 中,整个窗口同时显示了两个图表,其中左侧的图表展示了部分国家养猫人群的比例,右侧的图表展示了部分国家养狗人群的比例。由图 5-8 可知,俄罗斯养猫人群的比例最高,墨西哥养狗人群的比例最高。
← 填充区域 绘制自定义区域的子图 →