Matplotlib自定义坐标轴刻度的实现示例


Posted in Python onJune 18, 2020

虽然 Matplotlib 默认的坐标轴定位器(locator)格式生成器(formatter)可以满足大部分需求,但是并非对每一幅图都合适。此次我将通过一些示例演示如何将坐标轴刻度调整为你需要的位置与格式。

在介绍示例之前,我们最好先对 Matplotlib 图形的对象层级有更深入的理解。Matplotlib 的目标是用 Python 对象表现任意图形元素。例如,想想前面介绍的 figure 对象,它其实就是一个盛放图形元素的包围盒(bounding box)。可以将每个 Matplotlib 对象都看成是子对象(sub-object)的容器,例如每个 figure 都会包含一个或多个 axes 对象,每个 axes 对象又会包含其他表示图形内容的对象。

坐标轴刻度线也不例外。每个 axes 都有 xaxis 和 yaxis 属性,每个属性同样包含构成坐标轴的线条、刻度和标签的全部属性。

1 主要刻度与次要刻度

每一个坐标轴都有主要刻度线与次要刻度线。顾名思义,主要刻度往往更大或更显著,而次要刻度往往更小。虽然一般情况下 Matplotlib 不会使用次要刻度,但是你会在对数图中看到它们

import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
ax = plt.axes(xscale='log', yscale='log')
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

我们发现每个主要刻度都显示为一个较大的刻度线和标签,而次要刻度都显示为一个较小的刻度线,且不显示标签。
可以通过设置每个坐标轴的 formatter 与 locator 对象,自定义这些刻度属性(包括刻度线的位置和标签)。来检查一下图形 x 轴的属性:

In[1]: 	print(ax.xaxis.get_major_locator())
		print(ax.xaxis.get_minor_locator())
<matplotlib.ticker.LogLocator object at 0x107530cc0>
<matplotlib.ticker.LogLocator object at 0x107530198>
In[2]: 	print(ax.xaxis.get_major_formatter())
		print(ax.xaxis.get_minor_formatter())
<matplotlib.ticker.LogFormatterMathtext object at 0x107512780>
<matplotlib.ticker.NullFormatter object at 0x10752dc18>

我们会发现,主要刻度标签和次要刻度标签的位置都是通过一个 LogLocator 对象(在对数图中可以看到)设置的。然而,次要刻度有一个 NullFormatter 对象处理标签,这样标签就不会在图上显示了。

下面来演示一些示例,看看不同图形的定位器与格式生成器是如何设置的。

2 隐藏刻度与标签

隐藏图形的 x 轴标签与 y 轴刻度

最常用的刻度 / 标签格式化操作可能就是隐藏刻度与标签了,可以通过 plt.NullLocator()plt.NullFormatter() 实现,如下所示

ax = plt.axes()
ax.plot(np.random.rand(50))
ax.yaxis.set_major_locator(plt.NullLocator())
ax.xaxis.set_major_formatter(plt.NullFormatter())
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
ax = plt.axes()
ax.plot(np.random.rand(50))
ax.yaxis.set_major_locator(plt.NullLocator())
ax.xaxis.set_major_formatter(plt.NullFormatter())
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

需要注意的是,我们移除了 x 轴的标签(但是保留了刻度线 / 网格线),以及 y 轴的刻度(标签也一并被移除)。

隐藏人脸图形的坐标轴

在许多场景中都不需要刻度线,比如当你想要显示一组图形时。举个例子,不同人脸的照片,就是经常用于研究有监督机器学习问题的示例:

fig, ax = plt.subplots(5, 5, figsize=(5, 5))
fig.subplots_adjust(hspace=0, wspace=0)
# 从scikit-learn获取一些人脸照片数据
from sklearn.datasets import fetch_olivetti_faces
faces = fetch_olivetti_faces().images
for i in range(5):
	for j in range(5):
		ax[i, j].xaxis.set_major_locator(plt.NullLocator())
		ax[i, j].yaxis.set_major_locator(plt.NullLocator())
		ax[i, j].imshow(faces[10 * i + j], cmap="bone")
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
fig, ax = plt.subplots(5, 5, figsize=(5, 5))
fig.subplots_adjust(hspace=0, wspace=0)
# 从scikit-learn获取一些人脸照片数据
from sklearn.datasets import fetch_olivetti_faces
faces = fetch_olivetti_faces().images
for i in range(5):
  for j in range(5):
    ax[i, j].xaxis.set_major_locator(plt.NullLocator())
    ax[i, j].yaxis.set_major_locator(plt.NullLocator())
    ax[i, j].imshow(faces[10 * i + j], cmap="bone")
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

需要注意的是,由于每幅人脸图形默认都有各自的坐标轴,然而在这个特殊的可视化场景中,刻度值(本例中是像素值)的存在并不能传达任何有用的信息,因此需要将定位器设置为空。

3 增减刻度数量

刻度拥挤的图形

默认刻度标签有一个问题,就是显示较小图形时,通常刻度显得十分拥挤。我们可以在下图的网格中看到类似的问题:

fig, ax = plt.subplots(4, 4, sharex=True, sharey=True)

Matplotlib自定义坐标轴刻度的实现示例

自定义刻度数量

尤其是 x 轴,数字几乎都重叠在一起,辨识起来非常困难。我们可以用 plt.MaxNLocator()来解决这个问题,通过它可以设置最多需要显示多少刻度。根据设置的最多刻度数量,Matplotlib 会自动为刻度安排恰当的位置:

# 为每个坐标轴设置主要刻度定位器
for axi in ax.flat:
axi.xaxis.set_major_locator(plt.MaxNLocator(3))
axi.yaxis.set_major_locator(plt.MaxNLocator(3))
fig
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
fig, ax = plt.subplots(4, 4, sharex=True, sharey=True)
# 为每个坐标轴设置主要刻度定位器
for axi in ax.flat:
  axi.xaxis.set_major_locator(plt.MaxNLocator(3))
  axi.yaxis.set_major_locator(plt.MaxNLocator(3))
fig
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

这样图形就显得更简洁了。如果你还想要获得更多的配置功能,那么可以试试 plt.MultipleLocator ,我们将在接下来的内容中介绍它。

4 花哨的刻度格式

默认带整数刻度的图

Matplotlib 默认的刻度格式可以满足大部分的需求。虽然默认配置已经很不错了,但是有时候你可能需要更多的功能,例如下图中的正弦曲线和余弦曲线:

# 画正弦曲线和余弦曲线
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 1000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')
# 设置网格、图例和坐标轴上下限
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
ax.set_xlim(0, 3 * np.pi);
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
# 画正弦曲线和余弦曲线
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 1000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')
# 设置网格、图例和坐标轴上下限
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
ax.set_xlim(0, 3 * np.pi);
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

在 π / 2 的倍数上显示刻度

我们可能想稍稍改变一下这幅图。首先,如果将刻度与网格线画在 π 的倍数上,图形会更加自然。可以通过设置一个 MultipleLocator 来实现,它可以将刻度放在你提供的数值的倍数上。为了更好地测量,在 π /4 的倍数上添加主要刻度和次要刻度

ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 4))
fig
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
# 画正弦曲线和余弦曲线
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 1000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')
# 设置网格、图例和坐标轴上下限
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 4))
fig
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

然而,这些刻度标签看起来有点奇怪:虽然我们知道它们是 π 的倍数,但是用小数表示圆周率不太直观。因此,我们可以用刻度格式生成器来修改。

自定义刻度标签

由于没有内置的格式生成器可以直接解决问题,因此需要用plt.FuncFormatter 来实现,用一个自定义的函数设置不同刻度标签的显示

def format_func(value, tick_number):
  # 找到 π /2的倍数刻度
  N = int(np.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)
ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))
fig
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
# 画正弦曲线和余弦曲线
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 1000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')
# 设置网格、图例和坐标轴上下限
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
def format_func(value, tick_number):
  # 找到 π /2的倍数刻度
  N = int(np.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)
ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))
fig
plt.show()

Matplotlib自定义坐标轴刻度的实现示例

这样就好看多啦!其实我们已经用了 Matplotlib 支持 LaTeX 的功能,在数学表达式两侧加上美元符号( $ ),这样可以非常方便地显示数学符号和数学公式。在这个示例中, " $ \pi $"就表示圆周率符合 π
当你准备展示或打印图形时, plt.FuncFormatter() 不仅可以为自定义图形刻度提供十分灵活的功能,而且用法非常简单。

5 格式生成器与定位器小结

前面已经介绍了一些格式生成器与定位器,下面用表格简单地总结一下内置的格式生成器与定位器选项。关于两者更详细的信息,请参考各自的程序文档或者 Matplotlib 的在线文档。以下的所有类都在 plt 命名空间内。

定位器类 描述
NullLocator 无刻度
FixedLocator 刻度位置固定
IndexLocator 用索引作为定位器(如 x = range(len(y)))
LinearLocator 从 min 到 max 均匀分布刻度
LogLocator 从 min 到 max 按对数分布刻度
MultipleLocator 刻度和范围都是基数(base)的倍数
MaxNLocator 为最大刻度找到最优位置
AutoLocator (默认)以 MaxNLocator 进行简单配置
AutoMinorLocator 次要刻度的定位器

格式生成器类 描述
NullFormatter 刻度上无标签
IndexFormatter 将一组标签设置为字符串
FixedFormatter 手动为刻度设置标签
FuncFormatter 用自定义函数设置标签
FormatStrFormatter 为每个刻度值设置字符串格式
ScalarFormatter (默认)为标量值设置标签
LogFormatter 对数坐标轴的默认格式生成器

到此这篇关于Matplotlib自定义坐标轴刻度的实现示例的文章就介绍到这了,更多相关Matplotlib自定义坐标轴刻度内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python 文件和路径操作函数小结
Nov 23 Python
python获取一组数据里最大值max函数用法实例
May 26 Python
使用Python解析JSON数据的基本方法
Oct 15 Python
Django 如何获取前端发送的头文件详解(推荐)
Aug 15 Python
PyQt5每天必学之事件与信号
Apr 20 Python
查看django执行的sql语句及消耗时间的两种方法
May 29 Python
python将控制台输出保存至文件的方法
Jan 07 Python
对Python中DataFrame选择某列值为XX的行实例详解
Jan 29 Python
使用python实现mqtt的发布和订阅
May 05 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
Sep 10 Python
Python requests模块基础使用方法实例及高级应用(自动登陆,抓取网页源码)实例详解
Feb 14 Python
python glom模块的使用简介
Apr 13 Python
浅谈keras中的batch_dot,dot方法和TensorFlow的matmul
Jun 18 #Python
PyCharm中配置PySide2的图文教程
Jun 18 #Python
python属于软件吗
Jun 18 #Python
python交互模式基础知识点学习
Jun 18 #Python
使用Keras实现Tensor的相乘和相加代码
Jun 18 #Python
python如何从键盘获取输入实例
Jun 18 #Python
Python计算信息熵实例
Jun 18 #Python
You might like
PHP的ASP防火墙
2006/10/09 PHP
PHP插入排序实现代码
2013/04/04 PHP
实测在class的function中include的文件中非php的global全局环境
2013/07/15 PHP
PHP Ajax JavaScript Json获取天气信息实现代码
2016/08/17 PHP
php正确输出json数据的实例讲解
2018/08/21 PHP
JavaScript 常见对象类创建代码与优缺点分析
2009/12/07 Javascript
将json当数据库一样操作的javascript lib
2013/10/28 Javascript
当鼠标移动时出现特效的JQuery代码
2013/11/08 Javascript
javascript实现回车键提交表单方法总结
2015/01/10 Javascript
jQuery实现复选框批量选择与反选的方法
2015/06/17 Javascript
详解JavaScript的回调函数
2015/11/20 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
2016/05/24 Javascript
jQuery获取select选中的option的value值实现方法
2016/08/29 Javascript
AngularJS $http模块POST请求实现
2017/04/08 Javascript
基于js文件加载优化(详解)
2018/01/03 Javascript
关于微信小程序bug记录与解决方法
2018/08/15 Javascript
Element输入框带历史查询记录的实现示例
2019/01/15 Javascript
JavaScript 作用域scope简单汇总
2019/10/23 Javascript
JavaScript实现多层颜色选项卡嵌套
2020/09/21 Javascript
springboot+vue+对接支付宝接口+二维码扫描支付功能(沙箱环境)
2020/10/15 Javascript
python字典多条件排序方法实例
2014/06/30 Python
收集的几个Python小技巧分享
2014/11/22 Python
把MySQL表结构映射为Python中的对象的教程
2015/04/07 Python
Python使用Srapy框架爬虫模拟登陆并抓取知乎内容
2016/07/02 Python
python爬虫实现POST request payload形式的请求
2020/04/30 Python
python else语句在循环中的运用详解
2020/07/06 Python
python实现代码审查自动回复消息
2021/02/01 Python
详解使用双缓存解决Canvas clearRect引起的闪屏问题
2019/04/29 HTML / CSS
Stuart Weitzman美国官网:美国奢华鞋履品牌
2016/08/18 全球购物
香港时尚女装购物网站:ZAFUL
2017/07/19 全球购物
DOUGLAS荷兰:购买香水和化妆品
2020/10/24 全球购物
快递业务员岗位职责
2014/01/06 职场文书
优秀驾驶员先进事迹材料
2014/05/04 职场文书
诉讼代理人授权委托书
2014/10/11 职场文书
《堡垒之夜》联动《刺客信条》 4月7日正式上线
2022/04/06 其他游戏
4种方法python批量修改替换列表中元素
2022/04/07 Python