【课程介绍】
Datawhale开源教程链接: https://github.com/datawhalechina/fantastic-matplotlib
本项目重点在两个层面帮助读者构建matplotlib的知识体系:
从图形,布局,文本,样式等多维度系统梳理matplotlib的绘图方法,构建对于绘图方法的整体理解。
从绘图API层级,接口等方面阐明matplotlib的设计理念,摆脱只会复制粘贴的尴尬处境。
目录
2.Tick Locators and Formatters
头文件:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
import datetime
一、Figure和Axes上的文本
Matplotlib具有广泛的文本支持,包括对数学表达式的支持、对栅格和矢量输出的TrueType支持、具有任意旋转的换行分隔文本以及Unicode支持。
1.文本API示例
下面的命令是介绍了通过pyplot API和objected-oriented API分别创建文本的方式。
pyplot API | OO API | description |
---|---|---|
|
| 在子图axes的任意位置添加文本 |
|
| 在子图axes的任意位置添加注解,包含指向性的箭头 |
|
| 为子图axes添加x轴标签 |
|
| 为子图axes添加y轴标签 |
|
| 为子图axes添加标题 |
|
| 在画布figure的任意位置添加文本 |
|
| 为画布figure添加标题 |
一个综合例子,以OO模式展示这些API是如何控制一个图像中各部分的文本: | |
| fig.suptitle()画布标题; ax.axis([0,10,0,10])设置x轴y轴范围; ax.text()中可添加背景框bbox={}; ax.annotate()先文本,再设置箭头指向点,文本点;shrink箭头两端收缩的百分比(占总长),一般都是0.05。 |
fig = plt.figure()
ax = fig.add_subplot()
# 分别为figure和ax设置标题,注意两者的位置是不同的
fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold')
ax.set_title('axes title')
# 设置x和y轴标签
ax.set_xlabel('xlabel')
ax.set_ylabel('ylabel')
# 设置x和y轴显示范围均为0到10
ax.axis([0, 10, 0, 10])
# 在子图上添加文本
ax.text(3, 8, 'boxed italics text in data coords', style='italic',
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})
# 在画布上添加文本,一般在子图上添加文本是更常见的操作,这种方法很少用
fig.text(0.4,0.8,'This is text for figure')
ax.plot([2], [1], 'o')
# 添加注解
ax.annotate('annotate', xy=(2, 1), xytext=(3, 4),arrowprops=dict(facecolor='black', shrink=0.05));
2.text - 子图上的文本
text的调用方式为Axes.text(
x, y,
s,
fontdict=None,
**kwargs)
其中x
,y
为文本出现的位置,默认状态下即为当前坐标系下的坐标值,s
为文本的内容,fontdict
是可选参数,用于覆盖默认的文本属性,**kwargs
为关键字参数,也可以用于传入文本样式参数
重点解释下fontdict和**kwargs参数,这两种方式都可以用于调整呈现的文本样式,最终效果是一样的,不仅text方法,其他文本方法如set_xlabel,set_title等同样适用这两种方式修改样式。通过一个例子演示这两种方法是如何使用的。
fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,2)
# 使用关键字参数修改文本样式
axes[0].text(0.3, 0.8, 'modify by **kwargs', style='italic',
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10});
# 使用fontdict参数修改文本样式
font = {'bbox':{'facecolor': 'red', 'alpha': 0.5, 'pad': 10}, 'style':'italic'}
axes[1].text(0.3, 0.8, 'modify by fontdict', fontdict=font);
matplotlib中所有支持的样式参数请参考官网文档说明,大多数时候需要用到的时候再查询即可。
下表列举了一些常用的参数供参考。
Property | Description |
---|---|
| float or None 透明度,越接近0越透明,越接近1越不透明 |
| color 文本的背景颜色 |
| dict with properties for patches.FancyBboxPatch 用来设置text周围的box外框 |
| color 字体的颜色 |
| {FONTNAME, 'serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'} 字体的类型 |
| float or {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'} 字体大小 |
| {'normal', 'italic', 'oblique'} 字体的样式是否倾斜等 |
| {a numeric value in range 0-1000, 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'} 文本粗细 |
| {'center', 'right', 'left'} 选择文本左对齐右对齐还是居中对齐 |
| float (multiple of font size) 文本间距 |
| float or {'vertical', 'horizontal'} 指text逆时针旋转的角度,“horizontal”等于0,“vertical”等于90 |
| {'center', 'top', 'bottom', 'baseline', 'center_baseline'} 文本在垂直角度的对齐方式 |
3.xlabel和ylabel - 子图的x,y轴标签
xlabel的调用方式为Axes.set_xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
ylabel方式类似,这里不重复写出。
其中xlabel
即为标签内容,fontdict
和**kwargs
用来修改样式,上一小节已介绍,labelpad
为标签和坐标轴的距离,默认为4,loc
为标签位置,可选的值为'left', 'center', 'right'之一,默认为居中
# 观察labelpad和loc参数的使用效果
fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,2)
axes[0].set_xlabel('xlabel',labelpad=20,loc='left')
# loc参数仅能提供粗略的位置调整,如果想要更精确的设置标签的位置,可以使用position参数+horizontalalignment参数来定位
# position由一个元组过程,第一个元素0.2表示x轴标签在x轴的位置,第二个元素对于xlabel其实是无意义的,随便填一个数都可以
# horizontalalignment='left'表示左对齐,这样设置后x轴标签就能精确定位在x=0.2的位置处
axes[1].set_xlabel('xlabel', position=(0.2, _), horizontalalignment='left');
4.title和suptitle - 子图和画布的标题
title的调用方式为Axes.set_title(label, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)
其中label为子图标签的内容,fontdict
,loc
,**kwargs
和之前小节相同不重复介绍pad
是指标题偏离图表顶部的距离,默认为6y
是title所在子图垂向的位置。默认值为1,即title位于子图的顶部。
suptitle的调用方式为figure.suptitle(t, **kwargs)
其中t
为画布的标题内容
# 观察pad参数的使用效果
fig = plt.figure(figsize=(10,3))
fig.suptitle('This is figure title',y=1.2) # 通过参数y设置高度
axes = fig.subplots(1,2)
axes[0].set_title('This is title',pad=15)
axes[1].set_title('This is title',pad=6);
5.annotate - 子图的注解
annotate的调用方式为Axes.annotate(text, xy, *args, **kwargs)
其中text
为注解的内容,xy
为注解箭头指向的坐标,
其他常用的参数包括:xytext
为注解文字的坐标,xycoords
用来定义xy参数的坐标系,textcoords
用来定义xytext参数的坐标系,arrowprops
用来定义指向箭头的样式
annotate的参数非常复杂,这里仅仅展示一个简单的例子,更多参数可以查看官方文档中的annotate介绍
fig = plt.figure()
ax = fig.add_subplot()
ax.annotate("",
xy=(0.2, 0.2), xycoords='data',
xytext=(0.8, 0.8), textcoords='data',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=0.2")
);
6.字体的属性设置
字体设置一般有全局字体设置和自定义局部字体设置两种方法。
为方便在图中加入合适的字体,可以尝试了解中文字体的英文名称,该链接告诉了常用中文的英文名称
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
#局部字体的修改方法1
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(x, label='小示例图标签')
# 直接用字体的名字
plt.xlabel('x 轴名称参数', fontproperties='Microsoft YaHei', fontsize=16) # 设置x轴名称,采用微软雅黑字体
plt.ylabel('y 轴名称参数', fontproperties='Microsoft YaHei', fontsize=14) # 设置Y轴名称
plt.title('坐标系的标题', fontproperties='Microsoft YaHei', fontsize=20) # 设置坐标系标题的字体
plt.legend(loc='lower right', prop={"family": 'Microsoft YaHei'}, fontsize=10) ; # 小示例图的字体设置
二、Tick上的文本
设置tick(刻度)和ticklabel(刻度标签)也是可视化中经常需要操作的步骤,matplotlib既提供了自动生成刻度和刻度标签的模式(默认状态),同时也提供了许多让使用者灵活设置的方式。
1.简单模式 可以使用axis的 | ![]() ![]() ![]() |
2.Tick Locators and Formatters除了上述的简单模式,还可以使用 set_major_formatter和set_minor_formatter这两个formatter格式命令可以接收字符串格式(matplotlib.ticker.StrMethodFormatter)或函数参数(matplotlib.ticker.FuncFormatter)来设置刻度值的格式 。 | a) Tick Formatters
b) Tick Locators 在普通的绘图中,我们可以直接通过上图的set_ticks进行设置刻度的位置,缺点是需要自己指定或者接受matplotlib默认给定的刻度。当需要更改刻度的位置时,matplotlib给了常用的几种locator的类型。如果要绘制更复杂的图,可以先设置locator的类型,然后通过axs.xaxis.set_major_locator(locator)绘制即可
|
此外matplotlib.dates 模块还提供了特殊的设置日期型刻度格式和位置的方式 | ![]() |
三、legend(图例)
在具体学习图例之前,首先解释几个术语:
legend entry(图例条目)
每个图例由一个或多个legend entries组成。一个entry包含一个key和其对应的label。
legend key(图例键)
每个legend label左面的colored/patterned marker(彩色/图案标记)
legend label(图例标签)
描述由key来表示的handle的文本
legend handle(图例句柄)
用于在图例中生成适当图例条目的原始对象
以下面这个图为例,右侧的方框中的共有两个legend entry;两个legend key,分别是一个蓝色和一个黄色的legend key;两个legend label,一个名为‘Line up’和一个名为‘Line Down’的legend label
图例的绘制同样有OO模式和pyplot模式两种方式,写法都是一样的,使用legend()即可调用。
以下面的代码为例,在使用legend方法时,我们可以手动传入两个变量,句柄和标签,用以指定条目中的特定绘图对象和显示的标签值。
当然通常更简单的操作是不传入任何参数,此时matplotlib会自动寻找合适的图例条目。
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles = [line_up, line_down], labels = ['Line Up', 'Line Down']);
legend其他常用的几个参数如下:
设置图例位置
loc参数接收一个字符串或数字表示图例出现的位置
ax.legend(loc='upper center') 等同于ax.legend(loc=9)
Location String | Location Code |
---|---|
'best' | 0 |
'upper right' | 1 |
'upper left' | 2 |
'lower left' | 3 |
'lower right' | 4 |
'right' | 5 |
'center left' | 6 |
'center right' | 7 |
'lower center' | 8 |
'upper center' | 9 |
'center' | 10 |
fig,axes = plt.subplots(1,4,figsize=(10,4))
for i in range(4):
axes[i].plot([0.5],[0.5])
axes[i].legend(labels='a',loc=i) # 观察loc参数传入不同值时图例的位置
fig.tight_layout()
设置图例边框及背景
fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,3)
for i, ax in enumerate(axes):
ax.plot([1,2,3],label=f'ax {i}')
axes[0].legend(frameon=False) #去掉图例边框
axes[1].legend(edgecolor='blue') #设置图例边框颜色
axes[2].legend(facecolor='gray'); #设置图例背景颜色,若无边框,参数无效
设置图例标题
fig,ax =plt.subplots()
ax.plot([1,2,3],label='label')
ax.legend(title='legend title');
思考题
-
请尝试使用两种方式模仿画出下面的图表(重点是柱状图上的标签),本文学习的text方法和matplotlib自带的柱状图标签方法bar_label
# 设置随机数种子
np.random.seed(325)
# 创建数据
names = ['Jim', 'Slim', 'Harry', 'Dick', 'Tom']
idx = np.arange(5)
# 创建画布
fig = plt.figure(figsize = (16, 10))
# 提前准备部分参数
values = 8 + 8*np.random.rand(1,5)
bias = [0.71, 0.25, 0.16, 0.70, 0.72]
values = values.round(1)[0]
# 创建子图
ax = fig.add_subplot(111)
# 设置子图画布标题
ax.set_title("How fast do you want to go today?", fontsize = 20)
# 绘制水平柱状图
ax.barh(names, values, xerr = bias)
# 设置坐标轴格式
ax.set_xticks(np.arange(0, 20, 2))
ax.set_xticklabels(np.arange(0, 20, 2), fontsize = 16)
ax.set_yticklabels(names, fontsize = 16)
ax.set_xlabel('Performance', fontsize = 16, labelpad = 4)
for i in range(5):
ax.text(values[i] + bias[i] + 1, names[i], '±' + str(bias[i]), c = 'b', fontsize = 13, horizontalalignment = 'center')