用户警告: FixedFormatter 只能与 FixedLocator 一起使用

长期以来,我一直使用小的子程序来格式化我正在绘制的图表轴:

def format_y_label_thousands(): # format y-axis tick labels formats
ax = plt.gca()
label_format = '{:,.0f}'
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])


def format_y_label_percent(): # format y-axis tick labels formats
ax = plt.gca()
label_format = '{:.1%}'
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])

然而,在昨天对 matplotlib 进行了更新之后,当我调用这两个函数中的任何一个时,都会收到以下警告:

UserWarning: FixedFormatter should only be used together with FixedLocator
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])

为什么会有这样的警告呢? 我无法理解为什么要查看 matplotlib 的文档。

87685 次浏览

解决办法:

避免警告的方法是使用 FixedLocator (这是 matplotlib.ticker 的一部分)。下面我展示了绘制三个图表的代码。我用不同的方式格式化它们的轴。注意,“ set _ ticks”消除了警告,但是它改变了实际的刻度位置/标签(我花了一些时间才弄明白,FixedLocator 使用了相同的信息,但是保持了刻度位置的完整性)。您可以使用 x/y 来查看每个解决方案对输出的影响。

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker


mpl.rcParams['font.size'] = 6.5


x = np.array(range(1000, 5000, 500))
y = 37*x


fig, [ax1, ax2, ax3] = plt.subplots(1,3)


ax1.plot(x,y, linewidth=5, color='green')
ax2.plot(x,y, linewidth=5, color='red')
ax3.plot(x,y, linewidth=5, color='blue')


label_format = '{:,.0f}'


# nothing done to ax1 as it is a "control chart."


# fixing yticks with "set_yticks"
ticks_loc = ax2.get_yticks().tolist()
ax2.set_yticks(ax1.get_yticks().tolist())
ax2.set_yticklabels([label_format.format(x) for x in ticks_loc])


# fixing yticks with matplotlib.ticker "FixedLocator"
ticks_loc = ax3.get_yticks().tolist()
ax3.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax3.set_yticklabels([label_format.format(x) for x in ticks_loc])


# fixing xticks with FixedLocator but also using MaxNLocator to avoid cramped x-labels
ax3.xaxis.set_major_locator(mticker.MaxNLocator(3))
ticks_loc = ax3.get_xticks().tolist()
ax3.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax3.set_xticklabels([label_format.format(x) for x in ticks_loc])


fig.tight_layout()
plt.show()

输出图表:

Sample charts

显然,像上面这样有几行空闲代码(我基本上得到了 yticks 或 xticks 并重新设置它们)只会给我的程序增加噪音。我更希望警告消失。然而,看看一些“ bug 报告”(来自上面/下面评论的链接; 这个问题实际上不是 bug: 它是一个更新,正在产生一些问题) ,管理 matplotlib 的贡献者有他们的理由保留这个警告。

老版本的 MATPLOTLIB: 如果您使用控制台来控制代码的关键输出(正如我所做的) ,那么警告消息可能是有问题的。因此,推迟必须处理这个问题的一种方法是将 matplotlib 降级到3.2.2版。我使用 Anaconda 来管理我的 Python 包,下面是用于降级 matplotlib 的命令:

conda install matplotlib=3.2.2

并非所有列出的版本都可用。例如,无法安装 matplotlib 3.3.0,尽管它列在 matplotlib 的发布页面 https://github.com/matplotlib/matplotlib/releases

axis.set_xticks([labels])

如果有人在这里使用函数 axes.xaxis.set_ticklabels()(或等效的 yax) ,您不需要使用 FixedLocator,您可以使用 axes.xaxis.set_ticks(values_list) 之前 axes.xaxis.set_ticklabels(labels_list)避免此警告。

根据这个 matplotlib 呼叫

# FixedFormatter should only be used together with FixedLocator.
# Otherwise, one cannot be sure where the labels will end up.

这意味着一个人应该这样做

positions = [0, 1, 2, 3, 4, 5]
labels = ['A', 'B', 'C', 'D', 'E', 'F']
ax.xaxis.set_major_locator(ticker.FixedLocator(positions))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(labels))

但是,即使标签被传递给 ticker.FixedFormatter,这个问题仍然存在于 ticker.LogLocator中。 所以这个案子的解决办法是

  1. 定义一个格式化程序函数

    # FuncFormatter can be used as a decorator
    @ticker.FuncFormatter
    def major_formatter(x, pos):
    return f'{x:.2f}'
    
  2. 并将格式化程序函数传递给 FixedFormatter

    ax.xaxis.set_major_locator(ticker.LogLocator(base=10, numticks=5))
    ax.xaxis.set_major_formatter(major_formatter)
    

有关详细信息,请参阅上面的链接。

最简单的解决方案是禁止显示警告(包括用户警告) :

import warnings
warnings.filterwarnings("ignore")

这个用例是,如果你不想让你的 jupyter 笔记本在 github 上看起来像是被警告消息弄得一团糟。与大多数警告不同,如果处于循环中,此警告将不断重复(python 3.7)。

当我试图旋转 X 轴上的刻度标签时,我也遇到了同样的问题:

ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
ax.xaxis.set_major_locator(dates.DayLocator())

它使用的是‘ tick _ params ()’方法:

ax.tick_params(axis='x', labelrotation = 45)

我只要加上这句话就解决了:

ax.set_xticks([1,2,3])
ax.set_xtickslabels(['Label1', 'Label2', 'Label3'])