FixedFormatter 与 FixedLocator 警告解决方案
问题描述
在使用 matplotlib 绘制图表时,许多开发者会遇到以下警告信息:
UserWarning: FixedFormatter should only be used together with FixedLocator
这个警告通常出现在使用 set_xticklabels()
或 set_yticklabels()
方法设置坐标轴标签时。例如,下面的代码会触发此警告:
def format_y_label_thousands():
ax = plt.gca()
label_format = '{:,.0f}'
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])
警告原因
这个警告出现的原因是:在 matplotlib 3.3.0 及更高版本中,开发团队加强了对标签设置的安全检查。FixedFormatter
应该与 FixedLocator
配合使用,否则无法确保标签会正确对应到指定的刻度位置。
重要说明
直接使用 set_xticklabels()
或 set_yticklabels()
可能会导致标签与刻度位置不匹配,特别是在动态调整图表大小或交互式环境中。
解决方案
方法一:使用 FixedLocator(推荐)
最规范的解决方法是明确使用 FixedLocator
来固定刻度位置:
import matplotlib.ticker as mticker
def format_y_label_thousands():
ax = plt.gca()
label_format = '{:,.0f}'
# 获取当前刻度位置
ticks_loc = ax.get_yticks().tolist()
# 使用 FixedLocator 固定刻度位置
ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
# 设置标签格式
ax.set_yticklabels([label_format.format(x) for x in ticks_loc])
方法二:先设置刻度位置再设置标签
另一种简单有效的方法是在设置标签前先明确设置刻度位置:
def format_y_label_thousands():
ax = plt.gca()
label_format = '{:,.0f}'
# 先设置刻度位置
ax.set_yticks(ax.get_yticks().tolist())
# 再设置标签
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])
方法三:使用 tick_params 方法
对于简单的标签旋转等操作,可以使用 tick_params
方法替代:
# 不推荐的方式(会触发警告)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
# 推荐的方式(无警告)
ax.tick_params(axis='x', labelrotation=45)
方法四:使用 FuncFormatter
对于更复杂的格式化需求,可以使用 FuncFormatter
:
import matplotlib.ticker as ticker
# 创建格式化函数
@ticker.FuncFormatter
def custom_formatter(x, pos):
return f'{x:,.0f}'
# 应用格式化器
ax.yaxis.set_major_formatter(custom_formatter)
常见场景解决方案
1. seaborn 热力图中的颜色条标签
# 不推荐的方式
cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), rotation=90, va='center')
# 推荐的方式
cbar.ax.tick_params(axis='y', labelrotation=90)
2. 日期刻度标签
# 不推荐的方式
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
ax.xaxis.set_major_locator(dates.DayLocator())
# 推荐的方式
ax.xaxis.set_major_locator(dates.DayLocator())
ax.tick_params(axis='x', labelrotation=45)
3. 确保在绘图后设置标签
重要提示
确保在绘制数据后再设置刻度标签,避免因为尚未生成刻度而导致的问题。
# 正确的顺序
plt.boxplot(data)
ax.set_xticklabels(labels) # 在绘图后设置标签
# 错误的顺序
ax.set_xticklabels(labels) # 在绘图前设置标签(可能出错)
plt.boxplot(data)
代码示例对比
def format_y_label_percent():
ax = plt.gca()
label_format = '{:.1%}'
# 会触发警告
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])
def format_y_label_percent():
ax = plt.gca()
label_format = '{:.1%}'
ticks_loc = ax.get_yticks().tolist()
# 使用 FixedLocator
ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax.set_yticklabels([label_format.format(x) for x in ticks_loc])
def format_y_label_percent():
ax = plt.gca()
label_format = '{:.1%}'
# 先设置刻度再设置标签
ax.set_yticks(ax.get_yticks().tolist())
ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])
总结
FixedFormatter should only be used together with FixedLocator
警告是 matplotlib 为了防止标签与刻度位置不匹配而引入的安全检查。虽然可以通过降级 matplotlib 或忽略警告来暂时解决问题,但推荐使用本文提供的解决方案来确保代码的长期兼容性和正确性。
最佳实践是:
- 明确使用
FixedLocator
固定刻度位置 - 或者先设置刻度位置再设置标签
- 对于简单操作,使用
tick_params
方法 - 确保在绘图完成后再设置标签
这些方法不仅能消除警告,还能确保你的图表在各种环境下都能正确显示。