第三章 图标辅助元素的定制
1.认识图表常用的辅助元素
图表的辅助元素是指除了根据数据绘制的图形之外的元素,常用的辅助元素包括坐标轴、标题、图例、网格、参考线、参考区域、注释文本和表格,它们都可以对图形进行补充说明。
上图中图表常用辅助元素的说明如下:
-
坐标轴:分为单坐标轴和双坐标轴,单坐标轴按不同的方向又可分为水平坐标轴(又称x轴)和垂直坐标轴(又称y轴)。
-
标题:表示图表的说明性文本。
-
图例:用于指出图表中各组图形采用的标识方式。
-
网格:从坐标轴刻度开始的、贯穿绘图区域的若干条线,用于作为估算图形所示值的标准。
-
参考线:标记坐标轴上特殊值的一条直线。
-
参考区域:标记坐标轴上特殊范围的一块区域。
-
注释文本:表示对图形的一些注释和说明。
-
表格:用于强调比较难理解数据的表格。
坐标轴是由刻度标签、刻度线(主刻度线和次刻度线)、轴脊和坐标轴标签组成。
“x轴”为坐标轴的标签,“0”“7”均为刻度标签,“0”“7”对应的短竖线为刻度线,且为主刻度线,刻度线上方的横线为轴脊。需要说明的是,matplotlib中的次刻度线默认是隐藏的。
需要注意的是:不同的图表具有不同的辅助元素,比如饼图是没有坐标轴的,而折线图是有坐标轴的,大家可根据实际需求进行定制。
2.设置坐标轴的标签、刻度范围和刻度标签
坐标轴对数据可视化效果有着直接的影响。坐标轴的刻度范围过大或过小、刻度标签过多或过少,都会导致图形显示的比例不够理想。我们可以使用下面的一些方法来进行设置。
2.1.设置坐标轴的标签
matplotlib提供了设置x轴和y轴标签的方式。
- 设置x轴的标签:直接使用pyplot的
xlabel()
函数设置x轴的标签,语法格式如下:
xlabel(xlabel, fontdict=None, labelpad=None, **kwargs)
-
xlabel
:表示x轴标签的文本。 -
fontdict
:表示控制标签文本样式的字典。 -
labelpad
:表示标签与x轴轴脊间的距离。2.设置y轴的标签:直接使用pyplot的
ylabel()
函数设置y轴的标签,语法格式如下:
ylabel(ylabel, fontdict=None, labelpad=None, **kwargs)
ylabel
:表示y轴标签的文本。fontdict
:表示控制标签文本样式的字典。labelpad
:表示标签与y轴轴脊的距离。
Axes对象使用set_xlabel()
方法可以设置x轴的标签,使用set_ylabel()
方法可以设置y轴的标签。set_xlabel()
、set_ylabel()
方法与xlabel()
、ylabel()
函数的参数用法相同。
假设现在有一个包含正弦曲线和余弦曲线的图表,该图表中设置x轴和y轴的标签,图标如下:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
x = np.linspace(-np.pi, np.pi, 256, endpoint=True)
y1, y2 = np.sin(x), np.cos(x)
plt.plot(x, y1, x, y2)
# 设置x轴和y轴的标签
plt.xlabel("x轴")
plt.ylabel("y轴")
plt.show()
2.2.设置刻度范围和刻度标签
当绘制图表时,坐标轴的刻度范围和刻度标签都与数据的分布有着直接的联系,即坐标轴的刻度范围取决于数据中的最大值和最小值。
- 若没有指定任何数据,x轴和y轴的刻度范围为0.05~1.05,刻度标签为[-0.2, 0. 0, 0.2, 0.4, 0.6, 0.8, 1. 0, 1.2];
- 若指定了数据,刻度范围和刻度标签会随着数据的变化而变化。
1.**设置刻度范围:**使用pyplot模块的xlim()
和ylim()
函数分别可以设置或获取x轴和y轴的刻度范围。
xlim(left=None, right=None, emit=True, auto=False, *, xmin=None, xmax=None)
-
left
:表示x轴刻度取值区间的左位数。 -
right
:表示x轴刻度取值区间的右位数。 -
emit
:表示是否通知限制变化的观察者,默认为True。 -
auto
:表示是否允许自动缩放x轴,默认为True。此外,Axes对象可以使用set_xlim()或set_ylim()方法设置x轴或y轴的刻度范围。
2.**设置刻度标签:**使用pyplot模块的xticks()
或yticks()
函数可以设置x轴或y轴的刻度线位置和刻度标签。
xticks(ticks=None, labels=None, **kwargs)
-
ticks
:表示刻度显示的位置列表,该参数可以设置为空列表,以此禁用x轴的刻度。 -
labels
:表示指定位置刻度的标签列表。此外,Axes对象可以使用set_xticks()或set_yticks()方法设置x轴或y轴的刻度线位置,使用set_xticklabels()或set_yticklabels()方法设置x轴或y轴的刻度标签。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
x = np.linspace(-np.pi, np.pi, 256, endpoint=True)
y1, y2 = np.sin(x), np.cos(x)
plt.plot(x, y1, x, y2)
# 设置x轴和y轴的标签
plt.xlabel("x轴")
plt.ylabel("y轴")
# 设置x轴的刻度范围和刻度标签
plt.xlim(x.min() * 1.5, x.max() * 1.5)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2,
np.pi], [r'$-\pi$', r'$-\pi/2$',
r'$0$', r'$\pi/2$', r'$\pi$'])
plt.show()
2.3.示例:2019年中国电影票房排行榜
假如你有一段闲暇时间,到影院观影会是个不错的选项。如今,看电影已经成为人们休闲娱乐的方式之一,它不仅是一种视觉享受,而且是一场精神盛宴,使人们放松身心。
本实例要求根据下表的数据,将电影名称列的数据作为y轴的刻度标签 ,将总票房(亿元)列的数据作为条形数据,使用barh()函数绘制下图所示的条形图,并设置坐标轴标签和刻度标签。
由图可知,电影《哪吒之魔童降世》的总票房最高,《流浪地球》的总票房排行第二,《复仇者联盟4:终局之战》的总票房排行第三。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
labels = ['哪吒之魔童降世', '流浪地球', '复仇者联盟4:终局之战',
'疯狂的外星人', '飞驰人生', '烈火英雄', '蜘蛛侠:英雄远征',
'速度与激情:特别行动', '扫毒2:天地对决', '大黄蜂',
'惊奇队长', '比悲伤更悲伤的故事', '哥斯拉2:怪兽之王',
'阿丽塔:战斗天使', '银河补习班']
bar_width = [48.57, 46.18, 42.05, 21.83, 17.03, 16.70, 14.01,
13.84, 12.85, 11.38, 10.25, 9.46, 9.27, 8.88, 8.64]
y_data = range(len(labels))
fig = plt.figure()
ax = fig.add_subplot(111)
ax.barh(y_data, bar_width, height=0.2, color='orange')
# 设置x轴和y轴的标签
ax.set_xlabel("总票房(亿元)")
ax.set_ylabel("电影名称")
# 设置y轴的刻度线位置、刻度标签
ax.set_yticks(y_data)
ax.set_yticklabels(labels)
plt.show()
3.添加标题和图例
3.1.添加标题
使用pyplot模块的title()
函数可以添加图表标题。其语法格式如下:
title(label, fontdict=None, loc=‘center’, pad=None, **kwargs)
label
:表示标题的文本。fontdict
:表示控制标题文本样式的字典。loc
:表示标题的对齐样式。pad
:表示标题与图表顶部的距离,默认为None。
Axes对象还可以使用set_title()方法为图表添加标题。
在2.1设置坐标轴的案例中,添加标题:
plt.title("正弦曲线和余弦曲线")
3.2.添加图例
图例是一个列举的各组图形数据标识方式的方框图,它由图例标识和图例项两部分构成,其中图例标识是代表各组图形的图案;图例项是与图例标识对应的名称。
当在使用matplotlib绘制包含多组图形的图表时,我们可以在图表中添加图例,帮助用户明确每组图形代表的含义。使用pyplot模块的legend()
函数可以为图表添加图例。其语法格式如下:
legend(handles, labels, loc, bbox_to_anchor, ncol, title, shadow, fancybox, *args, **kwargs)
handles
:表示由图形标识构成的列表。labels
:表示由图例项构成的列表。loc
:用于控制图例在图表中的位置。ncol
:表示图例的列数,默认值为1。title
:表示图例的标题,默认值为None。shadow
:表示是否在图例后面显示阴影,默认值为None。fancybox
:表示是否为图例设置圆角边框,默认值为None
在使用pyplot的绘图函数绘图时,若已经预先通过label参数指定了显示于图例的标签,则后续可以直接调用legend()函数添加图例。
若未预先指定应用于图例的标签,则后续在调用legend()函数时为handles和labels参数传值即可。
- 预先指定图例标签:
ax.plot([1, 2, 3], label='Inline label')
ax.legend()
- 预先未指定图例标签:
ax.legend((line1, line2, line3), ('label1', 'label2', 'label3'))
在3.1添加标题的案例中,添加图例:
# 添加图例
lines = plt.plot(x, y1, x, y2)
plt.legend(lines, ['正弦', '余弦'], shadow=True, fancybox=True)
3.3.实例:支付宝月账单报告
支付宝月账单报告的饼图中每个扇形的含义均标注到圆外,由于代表每个扇形含义的文字长短不一且数量偏多,导致图表显得比较杂乱。
本实例要求将原饼图中所有的标注文字移动到图例中,以图例的形式来标注每个扇形代表的含义,使饼图显得更加简洁。
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
# 饼状图外侧文字说明
kinds = ['购物', '人情往来', '餐饮美食', '通信物流', '生活日用',
'交通通行', '休闲娱乐', '其他']
# 饼状图数据
money_scale = [800/3000, 100/3000, 1000/3000, 200/3000,
300/3000, 200/3000, 200/3000, 200/3000]
dev_position = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
# 饼图绘制
plt.pie(money_scale, labels=kinds, autopct='%3.1f%%', shadow=True,
explode=dev_position, startangle=90)
# 添加标题
plt.title('支付宝月账单报告')
# 添加图例
plt.legend(kinds, loc='upper right', bbox_to_anchor=[1.3, 1.1])
plt.show()
4.显示网格
4.1.显示指定网格
网格是从刻度线开始延伸,贯穿至整个绘图区域的辅助线条,它能帮助人们轻松地查看图形的数值。网格可以分为垂直网格和水平网格,这两种网格既可以单独使用,也可以同时使用。
使用pyplot模块的grid()函数可以显示图表中的网格。其语法格式如下:
grid(b=None, which='major', axis='both', **kwargs)
-
b
:表示是否显示网格。 -
which
:表示显示网格的类型,默认为major。 -
axis
:表示显示哪个方向的网格,默认为both。 -
linewidth
或lw
:网格线的宽度。还可以使用Axes对象的grid()方法显示网格。
**注意:**若坐标轴没有刻度,则将无法显示网格。
在3.2的案例中,我们添加网格:
plt.grid(axis='y', linewidth=0.3)
4.2.实例:汽车速度与制动距离的关系(添加网格)
我们用散点图表示汽车速度与制动距离关系,很多圆点因距离坐标轴较远而无法准确的看出数值,因此我们需要将它们显示在网格中,并调整坐标轴刻度:
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 准备x轴和y轴数据
x_speed = np.arange(10, 210, 10)
y_distance = np.array([0.5, 2.0, 4.4, 7.9, 12.3, 17.7,
24.1, 31.5, 39.9, 49.2, 59.5, 70.8,
83.1, 96.4, 110.7, 126.0, 142.2,
159.4, 177.6, 196.8])
# 绘制散点图
plt.scatter(x_speed, y_distance, s=50, alpha=0.9)
# 设置x轴的标签、刻度标签
plt.xlabel('速度(km/h)')
plt.ylabel('制动距离(m)')
plt.xticks(x_speed)
# 显示网格
plt.grid(linewidth=0.3)
plt.show()
5.添加参考线和参考区域
5.1.添加参考线
参考线是一条或多条贯穿绘图区域的线条,用于为绘图区域中图形数据之间的比较提供参考依据,比如目标线、平均线、预算线等。参考线按方向的不同可分为水平参考线和垂直参考线。
1.使用axhline()绘制水平参考线
axhline(y=0, xmin=0, xmax=1, linestyle='-', **kwargs)
y
:表示水平参考线的纵坐标。xmin
:表示水平参考线的起始位置,默认为0。xmax
:表示水平参考线的终止位置,默认为1。linestyle
:表示水平参考线的类型,默认为实线。
2.使用axvline()绘制垂直参考线
axvline(x=0, ymin=0, ymax=1, linestyle='-', **kwargs)
x
:表示垂直参考线的横坐标。ymin
:表示垂直参考线的起始位置,默认为0。ymax
:表示垂直参考线的终止位置,默认为1。linestyle
:表示垂直参考线的类型,默认为实线。
在4.1的案例中添加参考线:
# 添加参考线
plt.axvline(x=0, linestyle='--')
plt.axhline(y=0, linestyle='--')
5.2.添加参考区域
1.使用axhspan()
添加水平参考区域:
axhspan(ymin, ymax, xmin=0, xmax=1, **kwargs)
ymin
:表示水平跨度的下限,以数据为单位。ymax
:表示水平跨度的上限,以数据为单位。xmin
:表示垂直跨度的下限,以轴为单位,默认为0。xmax
:表示垂直跨度的上限,以轴为单位,默认为1。
2.使用axvspan()
添加水平参考区域:
axvspan(xmin, xmax, ymin=0, ymax=1, **kwargs)
xmin
:表示垂直跨度的下限。xmax
:表示垂直跨度的上限。
在5.1的案例中添加参考区域:
# 添加参考区域
plt.axvspan(xmin=0.5, xmax=2.0, alpha=0.3)
plt.axhspan(ymin=0.5, ymax=1.0, alpha=0.3)
5.3.全校高二年级各班男女生英语成绩评估
某高中高二年级模拟考试后,学校对该年级各班各学科的平均成绩进行了统计,计算出全体高二年级的英语平均成绩为88.5。
本实例要求根据下表的数据,绘制展示各班男生、女生英语平均成绩的柱形图,并将全体高二年级的英语平均成绩绘制成参考线 。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
men_means = (90.5, 89.5, 88.7, 88.5, 85.2, 86.6)
women_means = (92.7, 87.0, 90.5, 85.0, 89.5, 89.8)
# 每组柱形的x位置
ind = np.arange(len(men_means))
# 各柱形的宽度
width = 0.2
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar(ind - width / 2, men_means, width, label='男生平均成绩')
ax.bar(ind + 0.2, women_means, width, label='女生平均成绩')
ax.set_title('高二各班男生、女生英语平均成绩')
ax.set_ylabel('分数')
ax.set_xticks(ind)
ax.set_xticklabels(['高二1班', '高二2班', '高二3班', '高二4班', '高二5班',
'高二6班'])
# 添加参考线
ax.axhline(88.5, ls='--', linewidth=1.0, label='全体平均成绩')
ax.legend(loc='lower right')
plt.show()
6.添加注释文本
注释文本是图表的重要组成部分,它能够对图形进行简短地描述,有助于用户理解图表。注释文本按注释对象的不同主要分为指向型注释文本和无指向型注释文本,其中指向型注释文本一般是针对图表某一部分的特定说明,无指向型注释文本一般是针对图表整体的特定说明。
6.1.添加指向型注释文本
指向型注释文本是指通过指示箭头的注释方式对绘图区域的图形进行解释的文本,它一般使用线条连接说明点和箭头指向的注释文字。
使用pyplot模块的annotate()函数可以为图表添加指向型注释文本。其语法格式如下:
annotate(s, xy, *args, **kwargs)
s
:表示注释文本的内容。xy
:表示被注释的点的坐标位置,接收元组(x,y)。xytext
:表示注释文本所在的坐标位置,接收元组(x,y)。arrowprops
:表示指示箭头的属性字典。bbox
:表示注释文本的边框属性字典。
参数说明:
arrowprops
参数接收一个包含若干键的字典,通过向字典中添加键值对以控制箭头的显示。常见的控制箭头的键包括width、headwidth、headlength、shrink、arrowstyle等。- 键
arrowstyle
代表箭头的类型,该键对应的值及其类型如下图所示。
在5.2的案例中,我们为正弦添加一个注释文本:
# 添加指向型注释文本
plt.annotate('最小值', xy=(-np.pi / 2, -1.0), xytext=(-(np.pi / 2), -0.5), arrowprops=dict(arrowstyle="->"))
6.2.添加无指向型注释文本
无指向型注解文本是指仅使用文字的注释方式对绘图区域的图形进行说明的文本。
使用pyplot模块的text()函数可以为图表添加无指向型注释文本。其语法格式如下:
text(x, y, s, fontdict=None, withdash=<deprecated parameter>, **kwargs)
x, y
:表示注释文本的位置。s
:表示注释文本的内容。horizontalalignment
或ha
:表示水平对齐的方式,可以取值为’center’、'right’或 ‘left’。verticalalignment
或va
:表示垂直对齐的方式,可以取值为’center’、‘top’、‘bottom’、‘baseline’或’center_baseline’
在6.1的案例中添加无指向型注释文本:
# 添加无指向型注释文本
plt.text(3.10, 0.10, "y=sin(x)", bbox=dict(alpha=0.2))
6.3.实例:2013—2019财年阿里巴巴淘宝和
天猫平台的GMV(添加注释文本)
柱形图经常会与注释文本配合使用,在柱形的顶部标注柱形代表的具体数值。2.2.2节实例中的柱形图描述了阿里巴巴淘宝和天猫平台的GMV,但图中的矩形条缺少具体的数值。
本实例要求对前面的柱形图进行调整,在每个柱形的顶部添加无指向型注释文本,并设置y轴的标签。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
x = np.arange(1, 8)
y = np.array([10770, 16780, 24440, 30920, 37670, 48200, 57270])
# 绘制柱形图
bar_rects = plt.bar(x, y, tick_label=['FY2013', 'FY2014', 'FY2015', 'FY2016',
'FY2017', 'FY2018', 'FY2019'], width=0.5)
# 添加无指向型注释文本
def autolabel(rects):
"""在每个矩形条的上方附加一个文本标签,以显示其高度"""
for rect in rects:
height = rect.get_height() # 获取每个矩形条的高度
plt.text(rect.get_x() + rect.get_width() / 2,
height + 300, s='{}'.format(height),
ha='center', va='bottom')
autolabel(bar_rects)
plt.ylabel('GMV(亿元)')
plt.show()
6.4.拓展:matplotlib编写数学表达式
matplotlib中自带mathtext引擎,通过该引擎可以自动识别使用annotate()或text()函数传入的数学字符串,并解析成对应的数学表达式。
数学字符串有着固定的格式,它要求字符串以美元符号“$”为首尾字符,且首尾字符中间包裹数学表达式。
'$数学表达式$'
为保证字符串中的所有字符能以字面的形式显示,数学字符串需要配合“r”使用。
r'$\alpha > \beta$'
\alpha”和“\beta”的后面还可以增加上标和下标,其中上标使用符号“^”表示,下标使用符号“_”表示。
r'$\alpha_i > \beta_i$'
matplotlib中使用“ \frac{}{}”可以编写分数形式的数字字符串,“\frac”的后面的两个中括号分别代表分数的分子和分母。
r'$\frac{3}{4}$'
还可以编写分数嵌套的数学字符串。
r'$\frac{5 - \frac{1}{x}}{4}$'
7.添加表格
7.1.用table()添加表格
使用pyplot模块的table()函数可以为图表添加数据表格。其语法格式如下:
table(cellText=None, cellColours=None, cellLoc='right', colWidths=None, …, **kwargs)
cellText
:表示表格单元格中的数据,可以是一个二维列表。cellColours
:表示单元格的背景颜色。cellLoc
:表示单元格文本的对齐方式,支持’left’、‘center’、‘right’三种取值,默认值为’right’。colWidths
:表示每列的宽度。rowLabels
:表示行标题的文本。rowLoc
:表示行标题的对齐方式。colLabels
:表示列标题的文本。colColours
:表示列标题所在单元格的背景颜色。colLoc
:表示列标题的对齐方式。loc
:表示表格对于绘图区域的对齐方式。
在6.2中添加表格:
# 添加表格
plt.table(cellText=[[6, 6, 6], [8, 8, 8]], colWidths=[0.1] * 3, rowLabels=['第1行', '第2行'], colLabels=['第1列', '第2列', '第3列'], loc='lower right')
7.2.果酱面包配料比例
美好的一天从早餐开始,果酱面包是一道深受大家喜爱的美食,无论是大人还是小孩,都对果酱面包赞不绝口。
本实例要求根据下表的数据,将配料名称列的数据作为图例项,将重量列的数据与总重量的比例作为数据,使用pie()
绘制果酱面包配料比例的饼图,并将各种配料的重量以数据表格的形式添加到图表中,方便用户了解各种配料的占比和重量。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
kinds = ['面粉', '全麦面', '酵母', '苹果酱', '鸡蛋', '黄油', '盐', '白糖']
weight = [250, 150, 4, 250, 50, 30, 4, 20]
total_weight = 0
for i in weight:
total_weight += 1
batching_scale = [i / total_weight for i in weight]
plt.pie(batching_scale, autopct='%3.1f%%')
plt.legend(kinds, loc='upper right', bbox_to_anchor=[1.1, 1.1])
# 添加表格
plt.table(cellText=[weight],
cellLoc='center',
rowLabels=['重量(g)'],
colLabels=kinds,
loc='lower center')
plt.show()
ms[‘axes.unicode_minus’] = False
kinds = [‘面粉’, ‘全麦面’, ‘酵母’, ‘苹果酱’, ‘鸡蛋’, ‘黄油’, ‘盐’, ‘白糖’]
weight = [250, 150, 4, 250, 50, 30, 4, 20]
total_weight = 0
for i in weight:
total_weight += 1
batching_scale = [i / total_weight for i in weight]
plt.pie(batching_scale, autopct=‘%3.1f%%’)
plt.legend(kinds, loc=‘upper right’, bbox_to_anchor=[1.1, 1.1])
添加表格
plt.table(cellText=[weight],
cellLoc=‘center’,
rowLabels=[‘重量(g)’],
colLabels=kinds,
loc=‘lower center’)
plt.show()
<img src="https://img-blog.csdnimg.cn/img_convert/3d0ff7bfae600328d8bd513c382ad711.png" alt="image-20230925154504163" style="zoom:50%;" />