Rational-IM
Rational-IM

Reputation: 2682

UserWarning: FixedFormatter should only be used together with FixedLocator

I have used for a long time small subroutines to format axes of charts I'm plotting. A couple of examples:

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()])

However, after an update to matplotlib yesterday, I get the following warning when calling any of these two functions:

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

What is the reason for such a warning? I couldn't figure it out looking into matplotlib's documentation.

Upvotes: 119

Views: 154125

Answers (13)

vahndi
vahndi

Reputation: 1045

labels = ['your', 'labels', 'here']
ax.set_xticks(ax.get_xticks(), labels=labels)

Upvotes: 0

user110954
user110954

Reputation: 761

I know it's a silly answer, but maybe someone had the same problem... I was setting labels before plotting data (in a box plot) and got the warning, added set_xtikcs(range(len(data)) and warning disappeared but labels too, moving set_xticklabels after plot fixed everything, even without set_xticks call.

Upvotes: 0

pds
pds

Reputation: 2582

Code:

ax.set_xticks(ax.get_xticks())
ax.set_yticks(ax.get_yticks())

^ this removes the warning for every data/plot case I've encountered.

I keep bumping into this warning and to @dansarmo's answer. It is basically their answer. Thanks for correction by @als0052 and @Hampus Larsson's comment for noting the bug report and solution with set_*ticks.

Upvotes: 3

ermaure
ermaure

Reputation: 196

According to this matplotlib page

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

This means one should do

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))

But the issue also persisted with the ticker.LogLocator even if the labels were passed to ticker.FixedFormatter. So the solution in this case was

  1. Define a formatter function

    # FuncFormatter can be used as a decorator
    @ticker.FuncFormatter
    def major_formatter(x, pos):
        return f'{x:.2f}'
    
  2. and pass the formatter function to the FixedFormatter

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

See the above link for details.

Upvotes: 11

Diedre
Diedre

Reputation: 565

My case was a simple thing, I was customizing ticks before creating the plot itself, which resulted in trying to format something that had not been set to my expected number of ticks yet.

Make sure that if for example you are making a boxplot, edit the ticks AFTER the plt.boxplot() call.

Upvotes: 0

Laetis
Laetis

Reputation: 1357

I also have the UserWarning: FixedFormatter should only be used together with FixedLocator warning when doing:

 ax2.xaxis.set_major_locator(mdates.DayLocator(bymonthday=ttick_solar))
 ax2.set_xticklabels(label_solar)

I tried to encapsulate mdates.DayLocator(bymonthday=ttick_solar) in a mticker.FixedLocator but i must do it wrongly. What would be the correct syntax to do it?

Thanks

Upvotes: 0

gotnull
gotnull

Reputation: 27224

In my case I was using a seaborn heatmap and this is how I fixed it:

This was throwing the warning UserWarning: FixedFormatter should only be used together with FixedLocator cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), rotation=90, va='center')

heatmap = sb.heatmap(pd.DataFrame(full_dict).T.fillna(0), annot=True, linewidths=1, xticklabels=1, yticklabels=1, annot_kws={'rotation': 90})
cbar = heatmap.collections[0].colorbar
cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), rotation=90, va='center')

I changed it to the following in order to suppress the warning:

heatmap = sb.heatmap(pd.DataFrame(full_dict).T.fillna(0), annot=True, linewidths=1, xticklabels=1, yticklabels=1, annot_kws={'rotation': 90})
cbar = heatmap.collections[0].colorbar
cbar.ax.tick_params(axis='y', labelrotation=90)

Thanks to @Rami's answer: https://stackoverflow.com/a/72099702/264802

Upvotes: 1

Alfredo Vazquez
Alfredo Vazquez

Reputation: 71

I solved just adding this sentence:

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

Upvotes: 7

Rami
Rami

Reputation: 708

I had the same problem as I tried to rotate the tick labels on the X-axis with located date ticks:

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

It worked out using the 'tick_params()' method:

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

Upvotes: 32

russian_spy
russian_spy

Reputation: 6665

Simplest workaround is to suppress warnings (this includes UserWarning):

import warnings
warnings.filterwarnings("ignore")

The use-case would be if you don't want your jupyter notebook on github to look trashed with warning messages. Unlike most warnings, this warning keeps repeating if you're in a loop (python 3.7).

Upvotes: 2

dansarmo
dansarmo

Reputation: 1037

If someone comes here using the function axes.xaxis.set_ticklabels() (or yaxis equivalent), you don't need to use FixedLocator, you can avoid this warning using axes.xaxis.set_ticks(values_list) BEFORE axes.xaxis.set_ticklabels(labels_list).

Upvotes: 102

Ahmad Asmndr
Ahmad Asmndr

Reputation: 355

just use axis.set_xticks([labels])

Upvotes: -6

Rational-IM
Rational-IM

Reputation: 2682

WORKAROUND:

The way to avoid the warning is to use FixedLocator (that is part of matplotlib.ticker). Below I show a code to plot three charts. I format their axes in different ways. Note that the "set_ticks" silence the warning, but it changes the actual ticks locations/labels (it took me some time to figure out that FixedLocator uses the same info but keeps the ticks locations intact). You can play with the x/y's to see how each solution might affect the output.

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()

OUTPUT CHARTS:

Sample charts

Obviously, having a couple of idle lines of code like the one above (I'm basically getting the yticks or xticks and setting them again) only adds noise to my program. I would prefer that the warning was removed. However, look into some of the "bug reports" (from links on the comments above/below; the issue is not actually a bug: it is an update that is generating some issues), and the contributors that manage matplotlib have their reasons to keep the warning.

OLDER VERSION OF MATPLOTLIB: If you use your Console to control critical outputs of your code (as I do), the warning messages might be problematic. Therefore, a way to delay having to deal with the issue is to downgrade matplotlib to version 3.2.2. I use Anaconda to manage my Python packages, and here is the command used to downgrade matplotlib:

conda install matplotlib=3.2.2

Not all listed versions might be available. For instance, couldn't install matplotlib 3.3.0 although it is listed on matplotlib's releases page: https://github.com/matplotlib/matplotlib/releases

Upvotes: 79

Related Questions