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中编写并发程序
Feb 27 Python
python安装numpy&amp;安装matplotlib&amp; scipy的教程
Nov 02 Python
Python爬虫实例爬取网站搞笑段子
Nov 08 Python
Python开发最牛逼的IDE——pycharm
Aug 01 Python
python获取url的返回信息方法
Dec 17 Python
详解pandas库pd.read_excel操作读取excel文件参数整理与实例
Feb 17 Python
Python利用lxml模块爬取豆瓣读书排行榜的方法与分析
Apr 15 Python
python机器人运动范围问题的解答
Apr 29 Python
在windows下使用python进行串口通讯的方法
Jul 02 Python
Python调用C语言的实现
Jul 26 Python
python tkinter 设置窗口大小不可缩放实例
Mar 04 Python
pyqt5蒙版遮罩mask,setmask的使用
Jun 11 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过滤危险html代码的函数
2008/07/22 PHP
php图片缩放实现方法
2014/02/20 PHP
ThinkPHP CURD方法之order方法详解
2014/06/18 PHP
destoon整合UCenter图文教程
2014/06/21 PHP
smarty中post用法实例
2014/11/28 PHP
PHP中遇到的时区问题解决方法
2015/07/23 PHP
PHP MySql增删改查的简单实例
2016/06/21 PHP
利用PHP_XLSXWriter代替PHPExcel的方法示例
2017/07/16 PHP
php创建类并调用的实例方法
2019/09/25 PHP
使用documentElement正确取得当前可见区域的大小
2014/07/25 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
BootStrap modal模态弹窗使用小结
2016/10/26 Javascript
node.js中cluster的使用教程
2017/06/09 Javascript
简单谈谈require模块化jquery和angular的问题
2017/06/23 jQuery
原生JS实现萤火虫效果
2020/03/07 Javascript
Nodejs环境实现socket通信过程解析
2020/07/03 NodeJs
微信小程序实现列表滚动头部吸顶的示例代码
2020/07/12 Javascript
在Echarts图中给坐标轴加一个标识线markLine
2020/07/20 Javascript
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
C#返回当前系统所有可用驱动器符号的方法
2015/04/18 Python
python使用htmllib分析网页内容的方法
2015/05/08 Python
python实现猜数字游戏
2020/03/25 Python
python调用函数、类和文件操作简单实例总结
2019/11/29 Python
django ORM之values和annotate使用详解
2020/05/19 Python
Python基于httpx模块实现发送请求
2020/07/07 Python
Python实现JS解密并爬取某音漫客网站
2020/10/23 Python
浅析python实现动态规划背包问题
2020/12/31 Python
行政内勤岗位职责
2014/04/07 职场文书
阳光体育活动总结
2014/04/30 职场文书
常务副总经理任命书
2014/06/05 职场文书
企业读书活动总结
2014/06/30 职场文书
九一八事变演讲稿
2014/09/05 职场文书
银行柜员与客户起冲突检讨书
2014/09/27 职场文书
CSS3 天气图标动画效果
2021/04/06 HTML / CSS
redis限流的实际应用
2021/04/24 Redis
使用Python通过企业微信应用给企业成员发消息
2022/04/18 Python