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的Collections模块中counter结构的用法
Jul 07 Python
Python爬虫实例_城市公交网络站点数据的爬取方法
Jan 10 Python
基于pycharm导入模块显示不存在的解决方法
Oct 13 Python
基于Python安装pyecharts所遇的问题及解决方法
Aug 12 Python
django 使用 PIL 压缩图片的例子
Aug 16 Python
Django学习之文件上传与下载
Oct 06 Python
pytorch绘制并显示loss曲线和acc曲线,LeNet5识别图像准确率
Jan 02 Python
Pytorch在dataloader类中设置shuffle的随机数种子方式
Jan 14 Python
PyTorch笔记之scatter()函数的使用
Feb 12 Python
django queryset相加和筛选教程
May 18 Python
Python中常见的反爬机制及其破解方法总结
Jun 10 Python
Python Django / Flask如何使用Elasticsearch
Apr 19 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
基于Windows下Apache PHP5.3.1安装教程
2010/01/08 PHP
[原创]php简单隔行变色功能实现代码
2016/07/09 PHP
php常用的工具开发整理
2019/09/26 PHP
jQuery '行 4954 错误: 不支持该属性或方法' 的问题解决方法
2011/01/19 Javascript
js 判断脚本加载完毕的代码
2011/07/13 Javascript
jQuery中的height innerHeight outerHeight区别示例介绍
2014/06/15 Javascript
jQuery拖拽插件gridster使用指南
2015/04/21 Javascript
JQuery.Ajax()的data参数类型实例详解
2015/11/20 Javascript
jQuery模拟物体自由落体运动(附演示与demo源码下载)
2016/01/21 Javascript
JavaScript是如何实现继承的(六种方式)
2016/03/31 Javascript
jQuery插件cxSelect多级联动下拉菜单实例解析
2016/06/24 Javascript
JS实现鼠标移上去显示图片或微信二维码
2016/12/14 Javascript
JQuery实现动态操作表格
2017/01/11 Javascript
js实现日历与定时器
2017/02/22 Javascript
使用InstantClick.js让页面提前加载200ms
2017/09/12 Javascript
js实现动态改变radio状态的方法
2018/02/28 Javascript
解决vue-cli脚手架打包后vendor文件过大的问题
2018/09/27 Javascript
详解vue项目中使用token的身份验证的简单实践
2019/03/08 Javascript
vue v-for 点击当前行,获取当前行数据及event当前事件对象的操作
2020/09/10 Javascript
[09:23]国际邀请赛采访专栏:iG战队VK,Tongfu战队Cu
2013/08/05 DOTA
跟老齐学Python之再深点,更懂list
2014/09/20 Python
python 内置函数filter
2017/06/01 Python
Python实现扣除个人税后的工资计算器示例
2018/03/26 Python
python 正确保留多位小数的实例
2018/07/16 Python
Django用户认证系统 组与权限解析
2019/08/02 Python
PyQt5 QDockWidget控件应用详解
2020/08/12 Python
opencv+pyQt5实现图片阈值编辑器/寻色块阈值利器
2020/11/13 Python
编写html5时调试发现脚本php等网页js、css等失效
2013/12/31 HTML / CSS
加拿大便宜的隐形眼镜商店:Clearly
2016/09/15 全球购物
LODI女鞋在线商店:阿利坎特的鞋类品牌
2019/02/15 全球购物
Elizabeth Gage官网:英国最好的珠宝设计之一
2020/09/26 全球购物
巴西最大的巴士票务门户:Quero Passagem
2020/11/21 全球购物
怎样从/向数据文件读/写结构
2014/11/23 面试题
贸易经济专业自荐书
2014/06/29 职场文书
中学生的1000字检讨书
2014/10/11 职场文书
党章党规党纪学习心得体会
2016/01/14 职场文书