Skip to content

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:

python
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.

Solution 1: Use tick_params() for Rotation

For simple formatting like label rotation, use tick_params() instead of manually setting tick labels:

python
# 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:

python
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:

python
# 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:

python
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

python
heatmap = sb.heatmap(data, annot=True)
cbar = heatmap.collections[0].colorbar
cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), rotation=90)  # Warning
python
heatmap = sb.heatmap(data, annot=True)
cbar = heatmap.collections[0].colorbar
cbar.ax.tick_params(axis='y', labelrotation=90)  # No warning

For Date Ticks

python
import matplotlib.dates as dates
ax.xaxis.set_major_locator(dates.DayLocator())
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)  # Warning
python
import matplotlib.dates as dates
ax.xaxis.set_major_locator(dates.DayLocator())
ax.tick_params(axis='x', labelrotation=45)  # No warning

Timing Matters

Ensure you format ticks after plotting your data. Setting tick labels before plotting can cause issues:

python
# Plot your data first
plt.boxplot(data)

# Then format ticks (after the plot call)
ax.set_xticklabels(['Label1', 'Label2'])  # Correct timing

WARNING

Avoid suppressing warnings globally with warnings.filterwarnings("ignore") as this may hide other important issues in your code.

Complete Working Example

python
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.