FixedFormatter and FixedLocator Warning in Matplotlib
When working with matplotlib, you may encounter the warning: "UserWarning: FixedFormatter should only be used together with FixedLocator." This warning appears when trying to format axis labels without properly setting up the corresponding locator.
Problem Overview
The warning occurs when using set_xticklabels() or set_yticklabels() without ensuring the axis has a FixedLocator. Here's a typical problematic pattern:
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()])This approach triggers the warning because matplotlib can't guarantee proper label placement when the locator isn't fixed.
Recommended Solutions
Solution 1: Use tick_params() for Rotation
For simple formatting like label rotation, use tick_params() instead of manually setting tick labels:
# Instead of:
# ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
# Use:
ax.tick_params(axis='x', labelrotation=45)Solution 2: Pair FixedFormatter with FixedLocator
When you need custom labels, explicitly pair FixedFormatter with FixedLocator:
from matplotlib import ticker
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))Solution 3: Set Ticks Before Labels
Set the tick positions before setting their labels:
# For custom x-axis labels
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['Label1', 'Label2', 'Label3'])Solution 4: Use FuncFormatter for Dynamic Formatting
For more complex formatting, use FuncFormatter:
from matplotlib import ticker
@ticker.FuncFormatter
def major_formatter(x, pos):
return f'{x:.2f}'
ax.xaxis.set_major_locator(ticker.LogLocator(base=10, numticks=5))
ax.xaxis.set_major_formatter(major_formatter)Common Scenarios and Fixes
For Seaborn Heatmaps
heatmap = sb.heatmap(data, annot=True)
cbar = heatmap.collections[0].colorbar
cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), rotation=90) # Warningheatmap = sb.heatmap(data, annot=True)
cbar = heatmap.collections[0].colorbar
cbar.ax.tick_params(axis='y', labelrotation=90) # No warningFor Date Ticks
import matplotlib.dates as dates
ax.xaxis.set_major_locator(dates.DayLocator())
ax.set_xticklabels(ax.get_xticklabels(), rotation=45) # Warningimport matplotlib.dates as dates
ax.xaxis.set_major_locator(dates.DayLocator())
ax.tick_params(axis='x', labelrotation=45) # No warningTiming Matters
Ensure you format ticks after plotting your data. Setting tick labels before plotting can cause issues:
# Plot your data first
plt.boxplot(data)
# Then format ticks (after the plot call)
ax.set_xticklabels(['Label1', 'Label2']) # Correct timingWARNING
Avoid suppressing warnings globally with warnings.filterwarnings("ignore") as this may hide other important issues in your code.
Complete Working Example
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as mticker
# Create sample data
x = np.array(range(1000, 5000, 500))
y = 37 * x
fig, ax = plt.subplots()
ax.plot(x, y, linewidth=2, color='green')
# Format y-axis properly
ticks_loc = ax.get_yticks().tolist()
ax.yaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax.set_yticklabels([f'{x:,.0f}' for x in ticks_loc])
# Format x-axis with limited ticks
ax.xaxis.set_major_locator(mticker.MaxNLocator(3))
ticks_loc = ax.get_xticks().tolist()
ax.xaxis.set_major_locator(mticker.FixedLocator(ticks_loc))
ax.set_xticklabels([f'{x:,.0f}' for x in ticks_loc])
plt.show()Understanding the Warning
Matplotlib introduced this warning to prevent mismatches between tick positions and labels. When you use a FixedFormatter, matplotlib expects you to also use a FixedLocator to ensure each label corresponds exactly to a specific tick position.
By following the solutions above, you can format your matplotlib axes effectively while avoiding this common warning.