Python数据可视化matplotlib:第四回:文字图例尽眉目

Python数据可视化matplotlib:第四回:文字图例尽眉目

1. Figure和Axes上的文本

大家可以看到有些论文或者博客上都有绘制的很漂亮的图,其中大部分都在图形绘制上进行一定的注释说明,以增强图像的可读性。在matplotlib里面支持广泛的文本支持,包括对数学表达式的支持(一般是LaTeX数学公式)、对栅格和矢量输出的TrueType支持、具有任意旋转的换行分隔文本以及Unicode支持。

1.1 文本API示例

下面的命令是介绍了通过pyplot API和objected-oriented API分别创建文本的方式。大家可以轻松看到其中的不同点,OO模式的一般比pyploy模式前面需要多加一个set,当然这只是方法上的命名不同。可以看见其方法效果都是一致的。

pyplot APIOO APIdescription
texttext在子图axes的任意位置添加文本
annotateannotate在子图axes的任意位置添加注解,包含指向性的箭头
xlabelset_xlabel为子图axes添加x轴标签
ylabelset_ylabel为子图axes添加y轴标签
titleset_title为子图axes添加标题
figtexttext在画布figure的任意位置添加文本
suptitlesuptitle为画布figure添加标题

教程中的示例使用的是OO模式,由于使用pyplot模块也可以达到相同的效果,所以我自己使用pyplot的API写了一遍。
code:

plt.figure()

# 创建子图
plt.subplot(111)
# 设置子图title
plt.title("axes title")

# 设置x和y轴标签
plt.xlabel('xlabel')
plt.ylabel('ylabel')

# 设置x和y轴显示范围均为0到10
plt.xlim(0, 10)
plt.ylim(0, 10)

# 在子图添加文本
plt.text(3, 8, 'boxed italics text in data coords', style='italic',
        bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})

# 在画布上添加文本,一般在子图上添加文本是更常见的操作,这种方法很少用
plt.figtext(0.4,0.8,'This is text for figure')

plt.plot([2], [1], '*')
# 添加注解
plt.annotate('annotate', xy=(2, 1), xytext=(3, 4),arrowprops=dict(facecolor='black', shrink=0.05))

plt.suptitle('bold figure suptitle BY PYPLOT', fontsize=14, fontweight='bold')
plt.show()

原图和效果图如下:
在这里插入图片描述

在这里插入图片描述
可以看见达到的效果都是一样的,大家在学习过程中也可以多多使用不同的方法来尝试,可能有些仅仅只是部分参数不同,但是也会很有意思。下面就从不同方面详细介绍一下这些API的用法和参数。

1.2 text - 子图上的文本

当你去官方文档搜索text的时候会有很多搜索结果这篇教程就是下面两种结果,一种是Axes对象下的text,一种是pyplot下的一种API

在这里插入图片描述在这里插入图片描述
text的主要参数就是x, y, sx和y代表了文本出现的坐标位置,s即为文本的内容。然后就是可选参数** kwargsfontdict。在设置文本样式的时候可以分别使用这两种方法。
下面是使用pyplot的API绘制的代码
code:

plt.figure(figsize = (10, 3))

# 给第一幅子图添加文本, 使用关键字参数修改文本样式
plt.subplot(1, 2, 1)
plt.text(0.3, 0.8, 'modify by **kwargs', style='italic',
        bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})
plt.title("First")

# 给第二幅子图添加文本,使用fontdict参数修改文本样式
plt.subplot(1, 2, 2)
font = {'bbox':{'facecolor': 'red', 'alpha': 0.5, 'pad': 10}, 'style':'italic'}
plt.text(0.3, 0.8, 'modify by fontdict', fontdict=font)
plt.title("Second")
plt.suptitle("text style", fontsize = 15)
plt.show()

效果图如下:
在这里插入图片描述
matplotlib中所有支持的样式参数请参考官网文档说明,大多数时候需要用到的时候再查询即可。一般情况下能掌握下面常用的一些参数即可。

PropertyDescription
alphafloat or None 透明度,越接近0越透明,越接近1越不透明
backgroundcolorcolor 文本的背景颜色
bboxdict with properties for patches.FancyBboxPatch 用来设置text周围的box外框
color or ccolor 字体的颜色
fontfamily or family{FONTNAME, ‘serif’, ‘sans-serif’, ‘cursive’, ‘fantasy’, ‘monospace’} 字体的类型
fontsize or sizefloat or {‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’} 字体大小
fontstyle or style{‘normal’, ‘italic’, ‘oblique’} 字体的样式是否倾斜等
fontweight or weight{a numeric value in range 0-1000, ‘ultralight’, ‘light’, ‘normal’, ‘regular’, ‘book’, ‘medium’, ‘roman’, ‘semibold’, ‘demibold’, ‘demi’, ‘bold’, ‘heavy’, ‘extra bold’, ‘black’} 文本粗细
horizontalalignment or ha{‘center’, ‘right’, ‘left’} 选择文本左对齐右对齐还是居中对齐
linespacingfloat (multiple of font size) 文本间距
rotationfloat or {‘vertical’, ‘horizontal’} 指text逆时针旋转的角度,“horizontal”等于0,“vertical”等于90
verticalalignment or va{‘center’, ‘top’, ‘bottom’, ‘baseline’, ‘center_baseline’} 文本在垂直角度的对齐方式

1.3 xlabel和ylabel 子图的x,y轴标签

在OO模式中调用方法为Axes.set_xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
在pyplot里的方法为pyplot.xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
其中xlabel即为标签内容, labelpad为标签和坐标轴的距离(竖直方向),loc为标签位置,默认居中。
code:

# 观察labelpad和loc参数的使用效果
plt.figure(figsize=(10,3))
plt.subplot(1, 2, 1)
plt.xlabel('xlabel',labelpad=20,loc='left', fontsize = 15)

# loc参数仅能提供粗略的位置调整,如果想要更精确的设置标签的位置,可以使用position参数+horizontalalignment参数来定位
# position由一个元组过程,第一个元素0.2表示x轴标签在x轴的位置,第二个元素对于xlabel其实是无意义的,随便填一个数都可以
# horizontalalignment='left'表示左对齐,这样设置后x轴标签就能精确定位在x=0.2的位置处
plt.subplot(1, 2, 2)
plt.xlabel('xlabel', position=(0.2, _), fontsize = 15, horizontalalignment='left')
plt.show()

在这里插入图片描述
可以发现上图xlabel的位置和我们日常见到的不同,但是一般情况下都是居中显示,除非是有要求坐标的位置,或者当你绘制的子图显示有重合的部分,可以单独设置一下,也可以使用前面学到的tight_layout()方法。

1.4 title 和 suptitle - 子图和画布的标题

其实以上这些方法在第三回中就有使用过,只是没有单独拿出来详细介绍一下,在设置子图标签时,不管是OO模式还是使用pyplot模块,suptitle都是设置画布标题,title设置子图标题。
其中title的调用方式为Axes.set_title(label, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)
其中label为子图标签的内容,fontdict,loc,**kwargs和上面都是一样的。
pad是指标题偏离图表顶部的距离,默认为6
y是title所在子图垂向的位置。默认值为1,即title位于子图的顶部。

suptitle的调用方式为figure.suptitle(t, **kwargs)
其中t为画布的标题内容

code:

plt.figure(figsize = (10, 3))
plt.suptitle('This is figure title by pyplot', y = 1.2) #通过参数y设置高度

# 添加子图,并未子图设置标题
plt.subplot(1, 2, 1)
plt.title('This is title', pad = 15)

plt.subplot(1, 2, 2)
plt.title('This is title', pad = 8, loc = 'left')
plt.show()

在这里插入图片描述

1.5 annotate - 子图的注解

annotate的使用方法,格式设置是很多元化的,在不同的图表中所需要的注解形式不一样。接下来介绍一下使用方法,然后我们再用pyplot模块来尝试着对例子的内容进行一定的修改,来多多熟悉其内容。

annotate的调用方式为Axes.annotate(text, xy, *args, **kwargs)
其中text为注解的内容,
xy为注解箭头指向的坐标,
其他常用的参数包括:
xytext为注解文字的坐标,
xycoords用来定义xy参数的坐标系,
textcoords用来定义xytext参数的坐标系,
arrowprops用来定义指向箭头的样式
annotate的参数非常复杂,这里仅仅展示一个简单的例子,更多参数可以查看官方文档中的annotate介绍

code:

# 设置画布
plt.figure()

# 创建数据
x = np.arange(-5.0, 5.0, 0.01)
y = np.cos(2*np.pi*x)

# 绘制图像
plt.plot(x, y, linewidth = 3)
plt.annotate('local max', xy=(3, 1),  xycoords='data',
            xytext=(0.8, 0.95), textcoords='axes fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='right', verticalalignment='top',
            )
plt.annotate('(0,1)', xy = (170,165), xycoords = 'axes points',
            xytext = (0.5, 0.9),textcoords='axes fraction',
             arrowprops=dict(arrowstyle = "wedge", facecolor='orange', shrinkA = 1, shrinkB = 1))


plt.ylim(-2, 2)
plt.xlim(-x[-1] - 1, x[-1] + 1)
plt.show()

在这里插入图片描述

这里要说一下arrowprops里的shrink参数,在matplotlib中的介绍是move the tip and base some percent away from the annotated point and text',在设置过程中发现箭头的样式有很多种,但是并非所有的都可以用,有部分参数是支持shrinkA 和shrinkB这两个参数的,具体的大家可以使用的时候去查阅一下。
同时我们知道matplotlib也是可以绘制极坐标图的,下面为大家展示一下matplotlib官网上的一个给极坐标加注解的例子。
code:

# 绘制一个极地坐标,再以0.001为步长,画一条螺旋曲线
fig = plt.figure()
ax = fig.add_subplot(111, polar=True)
r = np.arange(0,1,0.001)
theta = 2 * 2*np.pi * r
line, = ax.plot(theta, r, color='#ee8d18', lw=3)
 
# 对索引为800处画一个圆点,并做注释
ind = 800
thisr, thistheta = r[ind], theta[ind]
ax.plot([thistheta], [thisr], 'o')
ax.annotate('a polar annotation',
            xy=(thistheta, thisr),  # 被注释点遵循极坐标系,坐标为角度和半径
            xytext=(0.05, 0.05),    # 注释文本放在绘图区的0.05百分比处
            textcoords='figure fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),# 箭头线为黑色,两端缩进5%
            horizontalalignment='left',# 注释文本的左端和低端对齐到指定位置
            verticalalignment='bottom',
            )
plt.show()

在这里插入图片描述

1.6 字体的属性设置

大家都知道一般字体设置大概有字体的选择,大小,格式等。matplotlib内字体的设置分为全局字体和局部字体两种,全局字体最常见以及最常用的就是下面代码:

#该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) ;   # 小示例图的字体设置

2. Tick上的文本

Tick容器在第二回中有介绍,他是用来细化坐标轴的一些设置的,这也是绘图多样性所在的原因之一。很多条件,格式都可以由作者自己来设置完成。

2.1 简单模式设置

code:

# 创建画布
plt.figure(figsize = (10, 4))

# 创建数据
x1 = np.linspace(0.0, 5.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
                                     
# 绘图对比
plt.subplot(1, 2, 1)
plt.plot(x1, y1)

# 第二个子图
plt.subplot(1, 2, 2)
plt.plot(x1, y1)
plt.xticks(np.arange(0., 10.1, 2.))
plt.tight_layout()
plt.show()

在这里插入图片描述
可以看到虽然我们确实设置好了对应的坐标刻度,但是图形并没有原来那么好看,我们需要的是等比扩大,并不是显示后面的空白部分。所以一般不用此方式设置tick。下面放出教程中所给的例子来给大家一个参考:

#一般绘图时会自动创建刻度,而如果通过上面的例子使用set_ticks创建刻度可能会导致tick的范围与所绘制图形的范围不一致的问题。
#所以在下面的案例中,axs[1]中set_xtick的设置要与数据范围所对应,然后再通过set_xticklabels设置刻度所对应的标签
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 1, figsize=(6, 4), tight_layout=True)
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
axs[0].plot(x1, y1)
axs[0].set_xticks([0,1,2,3,4,5,6])

axs[1].plot(x1, y1)
axs[1].set_xticks([0,1,2,3,4,5,6])#要将x轴的刻度放在数据范围中的哪些位置
axs[1].set_xticklabels(['zero','one', 'two', 'three', 'four', 'five','six'],#设置刻度对应的标签
                   rotation=30, fontsize='small')#rotation选项设定x刻度标签倾斜30度。
axs[1].xaxis.set_ticks_position('bottom')#set_ticks_position()方法是用来设置刻度所在的位置,常用的参数有bottom、top、both、none
print(axs[1].xaxis.get_ticklines());

在这里插入图片描述

2.2 Tick Locators and Formatters

除了上述的简单模式,还可以使用Tick Locators and Formatters完成对于刻度位置和刻度标签的设置。
其中Axis.set_major_locatorAxis.set_minor_locator方法用来设置标签的位置,Axis.set_major_formatterAxis.set_minor_formatter方法用来设置标签的格式。这种方式的好处是不用显式地列举出刻度值列表。这两种方法是Axis下特有的所以就不使用pyplot来绘制。

2.2.1 Tick Formatters

Formatters用于设置标签格式,set_major_formatter方法接收参数为formatter,类型为Formatter类,str或者一个function,所以在使用前获取一个f相应参数,具体代码如下:

# 接收字符串格式的例子
fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
    ax.plot(x1*10., y1)

formatter = matplotlib.ticker.FormatStrFormatter('%1.1f')
axs[0, 1].xaxis.set_major_formatter(formatter)

formatter = matplotlib.ticker.FormatStrFormatter('-%1.1f')
axs[1, 0].xaxis.set_major_formatter(formatter)

formatter = matplotlib.ticker.FormatStrFormatter('%1.5f')
axs[1, 1].xaxis.set_major_formatter(formatter);

# 接收函数的例子
def formatoddticks(x, pos):
    """Format odd tick positions."""
    if x % 2:
        return f'{x:1.2f}'
    else:
        return ''

fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)
ax.plot(x1, y1)
ax.xaxis.set_major_formatter(formatoddticks);

在这里插入图片描述

2.2.2 Tick Locators

Locators用于对刻度的位置进行修改,在普通的绘图中,我们可以直接通过上图的set_ticks进行设置刻度的位置,缺点是需要自己指定或者接受matplotlib默认给定的刻度。当需要更改刻度的位置时,matplotlib给了常用的几种locator的类型。如果要绘制更复杂的图,可以先设置locator的类型,然后通过axs.xaxis.set_major_locator(locator)绘制即可。和Formatters不同的是,Locators所需要的参数仅支持locator类参数。具体代码如下:

# 接收各种locator的例子
fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
    ax.plot(x1*10., y1)

locator = matplotlib.ticker.AutoLocator()
axs[0, 0].xaxis.set_major_locator(locator)

locator = matplotlib.ticker.MaxNLocator(nbins=10)
axs[0, 1].xaxis.set_major_locator(locator)


locator = matplotlib.ticker.MultipleLocator(5)
axs[1, 0].xaxis.set_major_locator(locator)


locator = matplotlib.ticker.FixedLocator([0,7,14,21,28])
axs[1, 1].xaxis.set_major_locator(locator);

在这里插入图片描述

3. legend - 图例

图例说明在绘图过程中尤为重要,我们知道一幅图中很有可能不会只有一条线,多组数据进行对比是很重要的一个部分。教程中解释的几个术语都是我之前没有学习到的,和大家share一下:
在具体学习图例之前,首先解释几个术语:
legend entry(图例条目)
每个图例由一个或多个legend entries组成。一个entry包含一个key和其对应的label。
legend key(图例键)
每个 legend label左面的colored/patterned marker(彩色/图案标记)
legend label(图例标签)
描述由key来表示的handle的文本
legend handle(图例句柄)
用于在图例中生成适当图例条目的原始对象

legend方法的几个常用参数介绍:
labels: 对应的图例标签
loc: loc参数接收一个字符串或数字表示图例的位置,数字和字符串对应关系如下:

Location StringLocation 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

frameon, edgecolor, facecolor: 这些是一些格式设置参数,分别对饮图例边框, 图例边框颜色和图例背景颜色, 当frameon为false时,facecolor参数就无效了。
title: 设置图例标题。
下面用几个子图来看一下这些参数设置后的展示效果:

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'])

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

结果如下:

第一种, 使用text绘制

# 设置随机数种子
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 = np.random.rand(1, 5).round(2)[0]
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')

在这里插入图片描述
第二种,使用bar_label绘制:

# 设置随机数种子
np.random.seed(325)

# 创建数据
names = ['Jim', 'Slim', 'Harry', 'Dick', 'Tom']
idx = np.arange(5)

# 创建画布
plt.figure(figsize = (16, 10))

# 提前准备部分参数
values = 8 + 8*np.random.rand(1,5)
bias = np.random.rand(1, 5).round(2)[0]
values = values.round(1)[0]


# 设置画布标题
plt.title("How fast do you want to go today?", fontsize = 16)
# 绘制柱状图
plt.barh(names, values, xerr = bias)

# 设置坐标轴格式
plt.xlim(0,18)
plt.xlabel('Performance', fontsize=16)
plt.yticks(fontsize = 16)
plt.xticks(fontsize = 16)
for i in range(5):
    plt.text(values[i] + bias[i] + 1, names[i], '±' + str(bias[i]), c = 'b', fontsize = 13, horizontalalignment = 'center')

在这里插入图片描述

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值