4.Matplotlib多子图,文字和注释以及自定义坐标轴

Matplotlib绘制多子图,文字和注释以及自定义坐标轴刻度

本节将讲解Matplotlib绘制多子图,文字和注释以及自定义坐标轴刻度等内容

多子图

我们在一个Figure对象上创建Axes对象最基本的方法就是使用plt.axes()函数

这个函数默认配置将会创建一个标准的子图,将会填满整张图

plt.axes()
plt.show()

在这里插入图片描述

自定义子图位置

实际上,plt.axes()函数可以接受一个含有四个数字的数组,用于确定子图的四条边的位置,按照[left,bottom,width,height]的顺序排列

并且bottom和left的取值是以小数(百分比表示),左下角作为原点为0,右上角为1

下面我们将创建一个画中画

plt.axes()
plt.axes([0.65,0.65,0.2,0.2])
plt.show()

这里我们指定底边和左边在65%的位置,宽度和高度均为20%

得到图像

在这里插入图片描述

面向对象接口中Axes对象实际上作为Figure对象的底层对象(即Figure对象可以容纳Axes对象),我们只需要调用Figure对象的add_axes()方法来添加子图

Fig=plt.figure()
Fig.add_axes([0.1,0.1,0.8,0.8])
Fig.add_axes([0.65,0.65,0.2,0.2])
plt.show()

在这里插入图片描述

网格多子图

为了对比多个图像,我们通常在一个Figure对象中创建多个Axes对象,分别绘制不同的图线

为此,我们就需要创建网格多子图,创建网格多子图有两种方式,第一种是通过plt.subplot循环创建,另外一种就是通过plt.subplots直接创建

plt.subplot() / add_subplot方法循环创建

plt.subplot()函数和Figure对象的add_subplots方法一次只能创建一个网格子图,所以我们需要通过循环的方式来创建

for i in range(1,7):
    plt.subplot(2,3,i)
    plt.text(0.5,0.5,str((2,3,i)),fontsize=18,ha='center')

plt.show()

在这里插入图片描述

这里我们使用默认情况来创建完图像后,每个图像之间的分布其实并不是最佳的,为此我们可以调用plt.subplots_adjust来调整子图之间的间隔

我们指定plt.subplots_adjust的hspace和wspace来分别指定所有子图之间的纵向与横向间距

for i in range(1,7):
    plt.subplot(2,3,i)
    plt.text(0.5,0.5,str((2,3,i)),fontsize=18,ha='center')

plt.subplots_adjust(hspace=0.4,wspace=0.4)
plt.show()

在这里插入图片描述

plt.subplots()直接创建

实际上我们可以直接使用plt.subplots()一行代码来直接创建网格图

而且如果使用第一种方法来循环创建网格图的话,每个子图都会有独立的坐标刻度,这样我们想让多张子图之间共享坐标就会十分困难

因此,这种情况下使用plt.subplots()非常的方便,只需要指定sharex和sharey参数即可

Fig,Axes=plt.subplots(2,3,sharex='col',sharey='row')
plt.show()

在这里插入图片描述

我们通过plt.subplots()方式创建网格多子图后将会返回由子图作为元素的数组,该数组的形状和我们创建的子图形状一致

Fig,Axes=plt.subplots(2,3,sharex='col',sharey='row')
for i in range(2):
    for j in range(3):
        Axes[i,j].text(0.5,0.5,str((i,j)),fontsize=18,ha='center')
plt.show()

在这里插入图片描述

plt.GridSpec()创建不同形状多子图

无论是使用plt.subplot()还是plt.subplots()方法创建出来的,相互之间都是具有相同的规则形状

但是在实际情况下,我们可能需要不行形状的子图来显示不同的曲线

为此,我们可以使用plt.GridSpec()函数来创建不规则多子图

实际上plt.GridSpec()函数本身并不能创建子图,它是一个可以由plt.subplot来识别的接口.为了理解其作用,我们可以想象plt.GridSpec()创建了多个可以合并的子图(实际上并没有创建),接下来我们为plt.subplot()传入需要合并的子图,就能够成功创建不同形状的子图

Grid=plt.GridSpec(2,3,wspace=0.4,hspace=0.3)
plt.subplot(Grid[0,0])
plt.subplot(Grid[0,1:])
plt.subplot(Grid[1,:2])
plt.subplot(Grid[1,2])
plt.show()

在这里插入图片描述

不同形状子图表示多维数据

实际上我们通常使用不同形状的多子图用来表示多维数据

下面将以二维数据为例讲解如何使用不同形状子图来表示多维数据

mean=[0,0]
cov=[[1,1],[1,2]]
x,y=np.random.multivariate_normal(mean,cov,3000).T

Fig=plt.figure(figsize=(6,6))
Grid=plt.GridSpec(4,4,hspace=0.4,wspace=0.2)
main_axes=Fig.add_subplot(Grid[:-1,1:])
y_hist=Fig.add_subplot(Grid[:-1,0],xticklabels=[],sharey=main_axes)
x_hist=Fig.add_subplot(Grid[-1,1:],yticklabels=[],sharex=main_axes)

main_axes.plot(x,y,'ok',markersize=3,alpha=0.3)

x_hist.hist(x,bins=40,histtype='stepfilled',orientation='vertical',color='gray')
x_hist.invert_yaxis()

y_hist.hist(y,bins=40,histtype='stepfilled',orientation='horizontal',color='gray')
y_hist.invert_xaxis()

plt.show()

这里我们首先创建了正态分布的点作为后续需要显示的数据点,接下来我们创建了子图,并且设置了子图的格式,我们指定x轴子图和主子图之间共享x坐标值,y轴子图和主子图之间共享y坐标值

我们在主子图上绘制了二维分布的点,接下来在y轴子图上绘制了所有点的y值的频数直方分布图,在x轴子图上绘制了所有点的x值的频数直方分布图

我们所有的绘图都是使用的面向对象接口实现的

在这里插入图片描述

文字与注释

一个优秀的可视化作品就是给读者讲解一个精彩的故事.

而在一些场景中用少量的文字会起到画龙点睛的效果

下面我们讲解文字与注释将基于在Pandas数据透视表中讲解过的美国人生日数据

美国人生日数据

我们首先绘制一下一年中平均每天美国人的出生数量的图像,然后基于该图像进行逐步的添加文字与注释,数据集详见我的Pandas学习专栏

# 设置绘图风格
plt.style.use('seaborn-whitegrid')

# 读取数据
births=pd.read_csv('births.csv')

# 截取出生数据
quartiles=np.percentile(births['births'],[25,50,75])
mu,sig=quartiles[1],0.47*(quartiles[2]-quartiles[0])
births=births.query('(births>@mu-5*@sig)&(births < @mu +5*@sig)')

# 设置日期索引以便于绘图
births['day']=births['day'].astype(int)
births.index=pd.to_datetime(10000*births.year+100*births.month+births.day,format='%Y%m%d')
births_by_date=births.pivot_table('births',index=[births.index.month,births.index.day])
births_by_date.index=[pd.datetime(2012,month,day) for (month,day) in births_by_date.index]


# 绘制平均每日的出生人数
Fig,Axes=plt.subplots(figsize=(12,4))
births_by_date.plot(ax=Axes)

# 图像标签
plt.xlabel('Date')
plt.ylabel('Number')
plt.title('Number of Birth Per Day')
plt.show()

在这里插入图片描述

注意,这里在调用DataFrame对象的query方法时候,使用@表明这是查询字符串外的一个局部变量,和Python原生的放在函数名前的修饰器并不相同

plt.text() / text()方法在图像的指定位置添加文本

我们在图像的指定位置添加文本只需要指定文本添加的坐标即可

plt.text() / Axes对象的text()方法需要x轴坐标,y轴坐标,一个字符串作为显示的文本以及一些可选的参数

这些可选的参数包括文字的颜色,字号,风格,对齐方式(即下面的ha,设置水平对齐方式)

import matplotlib as mpl
plt.style.use('seaborn-whitegrid')

# 读取数据
births=pd.read_csv('births.csv')

# 截取出生数据
quartiles=np.percentile(births['births'],[25,50,75])
mu,sig=quartiles[1],0.47*(quartiles[2]-quartiles[0])
births=births.query('(births>@mu-5*@sig)&(births < @mu +5*@sig)')

# 设置日期索引以便于绘图
births['day']=births['day'].astype(int)
births.index=pd.to_datetime(10000*births.year+100*births.month+births.day,format='%Y%m%d')
births_by_date=births.pivot_table('births',index=[births.index.month,births.index.day])
births_by_date.index=[pd.datetime(2012,month,day) for (month,day) in births_by_date.index]


# 绘制平均每日的出生人数
Fig,Axes=plt.subplots(figsize=(12,4))
births_by_date.plot(ax=Axes)

# 添加文本
style=dict(size=10,color='gray')
Axes.text('2012-01-01',3950,"New Year's Day",**style)
Axes.text('2012-07-04',4250,"Independence Day",ha='center',**style)
Axes.text('2012-09-04',4850,"Labor Day",ha='center',**style)
Axes.text('2012-10-31',4600,"Halloween",ha='right',**style)
Axes.text('2012-11-25',4450,"Thanksgiving",ha='center',**style)
Axes.text('2012-12-25',3850,"Christmas",ha='right',**style)


# 图像标签
Axes.set(title='USA births by day of year ( 1969 - 1988 )',ylabel='Average Daily Birth')
Axes.xaxis.set_major_locator(mpl.dates.MonthLocator())
Axes.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
Axes.xaxis.set_major_formatter(plt.NullFormatter())
Axes.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'))


plt.show()

在这里插入图片描述

这里我们在设置图像标签的时候,我们还设置了图像的坐标轴刻度,关于坐标轴刻度我们将在后面进行讲解

坐标变换与文字位置

上面的例子,我们将文字放在了目标数据的位置,但实际上我们更常做的是把文字放在与数据无关的位置上,比如坐标轴或者空白部分,接下来我们再通过箭头来指出数据点

在Matplotlib中,我们通过调整坐标变换来实现改变文字的位置.

任何图形的显示框架都需要坐标变换的机制,例如,当一个位于(x,y)=(1,1)位置的点需要以某种方式显示在图像上的特定的位置时,就需要屏幕的像素来表示

通常我们都是用数学方法来表示坐标系的变换.Matplotlib中有一组非常好的工具可以实现坐标变换,他们位于Matplotlib中的transforms子模块中

虽然一般用户并不需要来关注这些坐标变换的细节,但是了解着这些知识对于我们在图上放置文字大有裨益

Matplotlib中具有三种预定义的变换方式

  1. Axes.transData():以数据为基准的坐标变换
  2. Axes.transAxes():以子图为基准的坐标变换(以子图维度为单位)
  3. Axes.transFigure():以图形为基准的坐标变换(以图形维度为单位)

下面我们将使用三种变换方式将文字显示在图像的不同位置上

plt.style.use('seaborn')

Fig,Axes=plt.subplots(facecolor='lightgray')

Axes.axis([0,10,0,10])
Axes.text(1,5,".  DataPoint : ( 1 , 5 )",transform=Axes.transData)
Axes.text(0.5,0.1,'.    AxesPoint : ( 0.5 , 0.1 )',transform=Axes.transAxes)
Axes.text(0.5,0.1,'.    FigurePoint : ( 0.5 , 0.1 )',transform=Fig.transFigure)

plt.show()

在这里插入图片描述

我们可以看到,以子图为基准进行的坐标变换是相对于当前子图进行的变换,而以图像为基准进行的坐标变换则是相对于当前图像进行的坐标变换,以数据为基准进行的坐标变换则是直接在当前子图的对应坐标上显示点

此外,transAxes和transFigure都是以左下角为原点

当我们改变坐标轴的上下限,那么只有transData坐标会受到影响

箭头与注释

我们在Matplotlib中添加箭头实际上比我们想象的要困难.

虽然有plt.arrow()函数可以直接绘制箭头,但通过这种方式绘制得到的箭头是SVG向量图对象,会随着图像分辨率的变化而变化,所以最终得到的结果可能完全不是我们希望的

因此更加推荐使用plt.annotate()函数,这个函数既可以创建文字,也可以创建箭头.而且它创建的箭头能够进行非常灵活的配置

plt.annotate()创建简单的箭头

我们为plt.annotate()函数指定文本的位置,箭头指向的位置,要显示的文本以及箭头的样式就能够创建一个箭头

注意,必须要为plt.annotate()指定箭头样式,否则plt.annotate只会创建一个简单的文本作为注释信息

Fig,Axes=plt.subplots(1)

x=np.linspace(start=-np.pi,stop=np.pi,num=100)
y=np.cos(x)

Axes.plot(x,y)
Axes.axis('equal')
Axes.annotate('local maximun',xy=(0,1),xytext=(2,2),arrowprops=dict(facecolor='black',shrink=0.05))

plt.show()

在这里插入图片描述

使用arrowprop字典指定箭头样式

下面我们将使用arrowprop字典来创建几种箭头样式

Fig,Axes=plt.subplots(1)

x=np.linspace(start=-np.pi,stop=np.pi,num=100)
y=np.cos(x)

Axes.plot(x,y)
Axes.axis('equal')
Axes.annotate('local maximun',xy=(0,1),xytext=(2,2),arrowprops=dict(facecolor='red',shrink=0.05))
Axes.annotate('local maximun',xy=(0,1),xytext=(2,-2),arrowprops=dict(facecolor='black',arrowstyle='->'))
Axes.annotate('local maximun',xy=(0,1),xytext=(-3,-2),arrowprops=dict(facecolor='](https://img-blog.csdnimg.cn/20200808135755832.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NDg4MjQy,size_16,color_FFFFFF,t_70)


我们这里只是演示了最简单的用法,关于arrowprop字典的选项和参数,在Matplotlib的官方文档中都有详细的介绍

## 美国人生日数据

在前面成功绘制了图像的基础上,下面我们将要为图像添加一系列箭头与注释

```python
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')

# 读取数据
births=pd.read_csv('births.csv')

# 截取出生数据
quartiles=np.percentile(births['births'],[25,50,75])
mu,sig=quartiles[1],0.47*(quartiles[2]-quartiles[0])
births=births.query('(births>@mu-5*@sig)&(births < @mu +5*@sig)')

# 设置日期索引以便于绘图
births['day']=births['day'].astype(int)
births.index=pd.to_datetime(10000*births.year+100*births.month+births.day,format='%Y%m%d')
births_by_date=births.pivot_table('births',index=[births.index.month,births.index.day])
births_by_date.index=[pd.datetime(2012,month,day) for (month,day) in births_by_date.index]


# 绘制平均每日的出生人数
Fig,Axes=plt.subplots(figsize=(12,4))
births_by_date.plot(ax=Axes)


# 添加文本与箭头
Axes.annotate("New Year's Day",xy=('2012-01-01',4100),xycoords='data',\
    xytext=(50,-30),textcoords='offset points',\
    arrowprops=dict(arrowstyle='->',connectionstyle='arc3,rad=-0.2'))

Axes.annotate("Independence Day",xy=('2012-07-04',4250),xycoords='data',\
    bbox=dict(boxstyle='round',fc='none',ec='gray'),\
    xytext=(10,-40),textcoords='offset points',ha='center',\
    arrowprops=dict(arrowstyle='->'))
   
Axes.annotate('Labor Day',xy=('2012-9-1',4850),\
    xytext=('2012-9-7',4850),xycoords='data',textcoords='data',\
    arrowprops=dict(arrowstyle='|-|,widthA=0.2,widthB=0.2'))

Axes.annotate('Halloween',xy=('2012-10-31',4600),xycoords='data',\
    xytext=(-80,-40),textcoords='offset points',\
 arrowprops=dict(arrowstyle='fancy',fc='0.6',ec='none',connectionstyle='angle3,angleA=0,angleB=-90'))

Axes.annotate('Thanksgiving',xy=('2012-11-25',4500),xycoords='data',\
    xytext=(-120,-60),textcoords='offset points',\
    bbox=dict(boxstyle='round4,pad=.5',fc='0.9'),\

    arrowprops=dict(arrowstyle='->',connectionstyle='angle,angleA=0,angleB=80,rad=20'))
Axes.annotate('Chrismas',xy=('2012-12-25',3850),xycoords='data',\
    xytext=(-30,0),textcoords='offset points',\
    size=13,ha='right',va='center',\
    bbox=dict(boxstyle='round',alpha=0.1),\
    arrowprops=dict(arrowstyle='wedge,tail_width=0.5',alpha=0.1))


# 图像标签
Axes.set(title='USA births by day of year ( 1969 - 1988 )',ylabel='Average Daily Birth')
Axes.xaxis.set_major_locator(mpl.dates.MonthLocator())
Axes.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15))
Axes.xaxis.set_major_formatter(plt.NullFormatter())
Axes.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'))


plt.show()

在这里插入图片描述

自定义坐标轴

虽然MAtplotlib默认的坐标轴定位器(locator)和格式生成器(formatter)能够满足大部分需求,但并非对每一幅图都合适,在一些场景中我们可能会需要自定义坐标轴.

本节将主要讲解如何将坐标轴刻度调整为我们需要的位置和格式

在正式开始讲解前,我们需要对matplotlib图形的对象层级有更深入的理解.
Matplotlib的目标是用Python对象来表现任意图形元素,而图形之间可能存在从属关系,例如Figure对象可以包含Axes对象和Colorbar对象,而Axes对象又能包含Line2D,Axis对象;图形之间也有可能不存在从属关系,例如Colorbar对象和Line2D对象

因此Matplotlib中所有的对象能够分成两类:

  1. 基础类:我们要绘制的标准对象,
    包含: 线(Line),点(Marker),文字(Text),图例(Legend),网格(Grid),标题(Title),图片(iamge)等
  2. 容器类:能够容纳基础类对象并将它们组织为一体
    包含: 图像(Figure),子图(Axes),坐标轴(Axis),刻度(Tick)

此外,容器类对象之间也能够根据层级结构从上向下包含,即: Figure > Axes > Axis > Tick

对于坐标轴对象而言,每个Axes对象包含两个坐标轴属性,即xaxis和yaixs,它们两个都是Axis对象下的子对象

Fig,Axes=plt.subplots(1)
print(type(Axes))
print(type(Axes.xaxis))
print(type(Axes.yaxis))
>>>
<class 'matplotlib.axes._subplots.AxesSubplot'>
<class 'matplotlib.axis.XAxis'>
<class 'matplotlib.axis.YAxis'>

所以我们下面讲解的对坐标轴进行修改,其实就是对这两个子类调用Axis类中的方法

主要刻度与次要刻度

每一个坐标轴都有主要刻度和次要刻度,顾名思义,主要刻度就是大格之间的刻度,次要刻度就是每个小格之间的刻度,类似于刻度尺上整厘米处的刻度就是主要刻度,每毫米的合度就是次要刻度

plt.style.use('seaborn-whitegrid')

Axes=plt.axes(xscale='log',yscale='log')
plt.show()

在这里插入图片描述

每个刻度(Tick)对象实际上都包含formatter和locator两个对象,分别用于定义刻度的样式和位置

由于每个轴又有主要刻度和次要刻度,因此一个轴实际上有四个对象

我们下面来查看x轴的属性

Fig,Axes=plt.subplots(1)
print(Axes.xaxis.get_major_locator())
print(Axes.xaxis.get_minor_locator())
print(Axes.xaxis.get_major_formatter())
print(Axes.xaxis.get_minor_formatter())
>>>
<matplotlib.ticker.AutoLocator object at 0x7fd9fd94b940>
<matplotlib.ticker.NullLocator object at 0x7fd9fd93ac18>
<matplotlib.ticker.ScalarFormatter object at 0x7fd9fd93a7f0>
<matplotlib.ticker.NullFormatter object at 0x7fd9fd93af60>

这里由于我们是直接创建的一个空白子图,因此主要刻度是通过AutoLocator来生成的,而在默认情况下没有指定次要刻度则不会生成,即由NullLocator来生成.主要刻度的格式就是正常的scalar,而次要刻度的格式就是null

隐藏刻度和标签

我们对刻度进行设置主要就是对主要刻度和次要刻度的Locator和Formatter进行设置.调用axis对象的set_major / minor_ locator / formatter()方法即可

有的时候我们想要隐藏图像的刻度和标签.受到上面的启发,我们只需要为set_major_locator()和set_major_formatter()设定为plt.NullLocator()和plt.NullFormatter()对象即可

Fig,Axes=plt.subplots(1)

Axes.plot(np.random.rand(50))

Axes.xaxis.set_major_locator(plt.NullLocator())
Axes.xaxis.set_major_formatter(plt.NullFormatter())
Axes.yaxis.set_major_locator(plt.NullLocator())
Axes.yaxis.set_major_formatter(plt.NullFormatter())

plt.show()

在这里插入图片描述

实际上我们只需要指定两个坐标轴的Locator为Null即可,因为Locator是Formatter的底层对象

通常我们省略掉x轴和y轴的刻度主要是为了用于显示图片,例如我们在机器学习人脸模型的时候,往往会首先使用Matplotlib显示出人脸,这个时候就需要省略所有的刻度

设置刻度数量

在创建一张子图的时候,Matplotlib默认会为其创建xaxis和yaxis对象,并为其添加刻度

但是默认创建的刻度有一个问题,就是当我们显示较小的图形的时候,刻度就会显得十分拥挤

Fig,Axes=plt.subplots(5,5,sharex=True,sharey=True)
plt.show()

在这里插入图片描述

为此,我们可以在创建Axes对象后对其所属的xaxis和yaxis对象调用set_major_locator()方法.

类似于隐藏刻度和标签时候我们指定其Locator为NullLocator,我们指定MaxLocator为我们需要的数量即可

plt.style.use('seaborn-whitegrid')
Fig,Axes=plt.subplots(4,4,sharex=True,sharey=True)

for Axe in Axes.flat:
    Axe.xaxis.set_major_locator(plt.MaxNLocator(2))
    Axe.yaxis.set_major_locator(plt.MaxNLocator(2))

plt.show()

注意我们这里使用plt.subplots()方法返回的是由Axes对象构成的数组,维度和子图的排列一样

这里我们需要遍历到每一个Axes对象,因此我们调用数组对象的flat方法,将其变为一维数组,然后这样直接进行一次遍历就能够设置所有的子图

花哨的刻度格式

Matplotlib默认的刻度格式是以整数为刻度,但在特殊情况下我们可能会需要特殊的刻度格式,例如对于正弦和余弦函数

默认情况下的整数刻度可能导致我们无法很好地查看极值

plt.style.use('seaborn-whitegrid')

Fig,Axes=plt.subplots(1)

x=np.linspace(start=0,stop=3*np.pi,num=500)
y_sin=np.sin(x)
y_cos=np.cos(x)

Axes.plot(x,y_sin,lw=3,label='Sine')
Axes.plot(x,y_cos,lw=3,label='Cosine')

Axes.grid(True)
Axes.legend(frameon=False)
Axes.axis('equal')
Axes.set_xlim(0,3*np.pi)

plt.show()

在这里插入图片描述

我们希望将刻度与网格线绘制在 π \pi π的整数倍上,这样就能够清晰直观的看到极值了

类似于上面,我们给set_major_locator()传入plt.MultiLocator()来指定要显示的刻度即可

plt.style.use('seaborn-whitegrid')

Fig,Axes=plt.subplots(1)

x=np.linspace(start=0,stop=3*np.pi,num=500)
y_sin=np.sin(x)
y_cos=np.cos(x)

Axes.plot(x,y_sin,lw=3,label='Sine')
Axes.plot(x,y_cos,lw=3,label='Cosine')

Axes.xaxis.set_major_locator(plt.MultipleLocator(np.pi/2))
Axes.xaxis.set_minor_locator(plt.MultipleLocator(np.pi/4))

Axes.grid(True)
Axes.legend(frameon=False)
Axes.axis('equal')
Axes.set_xlim(0,3*np.pi)

plt.show()

在这里插入图片描述

但是我们发现通过简单地传入np.pi这样的方式最终绘制到图形上却是数字

为此,我们想要绘制符号这个时候就需要使用Formatter来控制格式,我们可以为Formatter传入格式字符串,也可以传入我们自己定义生成格式的函数,具体根据我们调用的格式生成器不同而不同

def FormatFunc(value,tick_number):
    N=int(round(2*value/np.pi))
    if N == 0:
        return '0'
    elif N == 1:
        return r"$\pi/2$"
    elif N == 2:
        return r"$\pi$"
    elif N % 2 > 0:
        return r"${0}\pi/2$".format(N)
    else:
        return r"${0}\pi$".format(N//2)

plt.style.use('seaborn-whitegrid')

Fig,Axes=plt.subplots(1)

x=np.linspace(start=0,stop=3*np.pi,num=500)
y_sin=np.sin(x)
y_cos=np.cos(x)

Axes.plot(x,y_sin,lw=3,label='Sine')
Axes.plot(x,y_cos,lw=3,label='Cosine')

Axes.xaxis.set_major_locator(plt.MultipleLocator(np.pi/2))
Axes.xaxis.set_minor_locator(plt.MultipleLocator(np.pi/4))
Axes.xaxis.set_major_formatter(plt.FuncFormatter(FormatFunc))

Axes.grid(True)
Axes.legend(frameon=False)
Axes.axis('equal')
Axes.set_xlim(0,3*np.pi)

plt.show()

在这里插入图片描述

这里我们使用plt.FuncFormatter作为格式生成器,为其传入我们自己定义的生成格式函数即可

我们自己定义的格式生成函数要接受两个参数,第一个参数(上面的例子是value)是传入的坐标刻度的值,第二个参数则是必须的刻度的标记

刻度定位器与格式生成器小结

下面将列举Tick对象所有的定位器和格式生成器.具体的使用方法查看官方文档即可

定位器类描述
NullLocator无刻度
FixedLocator刻度位置固定
IndexLocator用索引作为定位器
LinearLocator从min到max均匀分布刻度
LogLocator从min到max按对数分布刻度
MultiplyeLocator刻度和范围都是基数的倍数
MaxNLocator为最大刻度有限找到最优位置
AutoLocator默认以MaxNLocator进行简单配置
AutoMinorLocator次要刻度的定位器
格式生成器类描述
NullFormatter刻度上无标签
IndexFormatter将一组标签值设置为字符串
FixedFormatter手动位刻度设置标签
FuncFormatter用字定义函数设置标签值
FormatStrFormatter为每个刻度值设置字符串格式
ScalarFormatter默认为标量值设置标签
LogFormatter对数坐标轴的默认格式生成器
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页