Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: get UserWarning about FixedFormatter/FixedLocator in series.plot() #35684

Closed
3 tasks done
WestXu opened this issue Aug 12, 2020 · 18 comments · Fixed by #36145
Closed
3 tasks done

BUG: get UserWarning about FixedFormatter/FixedLocator in series.plot() #35684

WestXu opened this issue Aug 12, 2020 · 18 comments · Fixed by #36145
Labels
Bug Compat pandas objects compatability with Numpy or Python functions Visualization plotting
Milestone

Comments

@WestXu
Copy link

WestXu commented Aug 12, 2020

  • I have checked that this issue has not already been reported.

  • I have confirmed this bug exists on the latest version of pandas.

  • (optional) I have confirmed this bug exists on the master branch of pandas.

Code Sample, a copy-pastable example

pd.Series({"20190102": 10, "20190103": 10}).plot()

Problem description

Got a UserWarning:

/home/.../miniconda3/lib/python3.8/site-packages/pandas/plotting/_matplotlib/core.py:1192: UserWarning: FixedFormatter should only be used together with FixedLocator

And to catch the Warning:

import warnings
with warnings.catch_warnings():
    warnings.filterwarnings("error")
    pd.Series({"20190102": 10, "20190103": 10}).plot()

Got

---------------------------------------------------------------------------
UserWarning                               Traceback (most recent call last)
<ipython-input-5-4339a8efd56e> in <module>
      2 with warnings.catch_warnings():
      3     warnings.filterwarnings("error")
----> 4     pd.Series({"20190102": 10, "20190103": 10}).plot()

~/miniconda3/lib/python3.8/site-packages/pandas/plotting/_core.py in __call__(self, *args, **kwargs)
    845                     data.columns = label_name
    846 
--> 847         return plot_backend.plot(data, kind=kind, **kwargs)
    848 
    849     __call__.__doc__ = __doc__

~/miniconda3/lib/python3.8/site-packages/pandas/plotting/_matplotlib/__init__.py in plot(data, kind, **kwargs)
     59             kwargs["ax"] = getattr(ax, "left_ax", ax)
     60     plot_obj = PLOT_CLASSES[kind](data, **kwargs)
---> 61     plot_obj.generate()
     62     plot_obj.draw()
     63     return plot_obj.result

~/miniconda3/lib/python3.8/site-packages/pandas/plotting/_matplotlib/core.py in generate(self)
    268         for ax in self.axes:
    269             self._post_plot_logic_common(ax, self.data)
--> 270             self._post_plot_logic(ax, self.data)
    271 
    272     def _args_adjust(self):

~/miniconda3/lib/python3.8/site-packages/pandas/plotting/_matplotlib/core.py in _post_plot_logic(self, ax, data)
   1190             xticks = ax.get_xticks()
   1191             xticklabels = [get_label(x) for x in xticks]
-> 1192             ax.set_xticklabels(xticklabels)
   1193             ax.xaxis.set_major_locator(FixedLocator(xticks))
   1194 

~/miniconda3/lib/python3.8/site-packages/matplotlib/axes/_base.py in wrapper(self, *args, **kwargs)
     61 
     62         def wrapper(self, *args, **kwargs):
---> 63             return get_method(self)(*args, **kwargs)
     64 
     65         wrapper.__module__ = owner.__module__

~/miniconda3/lib/python3.8/site-packages/matplotlib/cbook/deprecation.py in wrapper(*args, **kwargs)
    449                 "parameter will become keyword-only %(removal)s.",
    450                 name=name, obj_type=f"parameter of {func.__name__}()")
--> 451         return func(*args, **kwargs)
    452 
    453     return wrapper

~/miniconda3/lib/python3.8/site-packages/matplotlib/axis.py in _set_ticklabels(self, labels, fontdict, minor, **kwargs)
   1791         if fontdict is not None:
   1792             kwargs.update(fontdict)
-> 1793         return self.set_ticklabels(labels, minor=minor, **kwargs)
   1794 
   1795     @cbook._make_keyword_only("3.2", "minor")

~/miniconda3/lib/python3.8/site-packages/matplotlib/axis.py in set_ticklabels(self, ticklabels, minor, **kwargs)
   1728             ticks = self.get_minor_ticks(len(locs))
   1729         else:
-> 1730             self.set_major_formatter(formatter)
   1731             locs = self.get_majorticklocs()
   1732             ticks = self.get_major_ticks(len(locs))

~/miniconda3/lib/python3.8/site-packages/matplotlib/axis.py in set_major_formatter(self, formatter)
   1589         formatter : `~matplotlib.ticker.Formatter`, ``str``, or function
   1590         """
-> 1591         self._set_formatter(formatter, self.major)
   1592 
   1593     def set_minor_formatter(self, formatter):

~/miniconda3/lib/python3.8/site-packages/matplotlib/axis.py in _set_formatter(self, formatter, level)
   1619                 and len(formatter.seq) > 0
   1620                 and not isinstance(level.locator, mticker.FixedLocator)):
-> 1621             cbook._warn_external('FixedFormatter should only be used together '
   1622                                  'with FixedLocator')
   1623 

~/miniconda3/lib/python3.8/site-packages/matplotlib/cbook/__init__.py in _warn_external(message, category)
   2088             break
   2089         frame = frame.f_back
-> 2090     warnings.warn(message, category, stacklevel)
   2091 
   2092 

UserWarning: FixedFormatter should only be used together with FixedLocator

Output of pd.show_versions()

INSTALLED VERSIONS

commit : None
python : 3.8.5.final.0
python-bits : 64
OS : Linux
OS-release : 4.19.104-microsoft-standard
machine : x86_64
processor : x86_64
byteorder : little
LC_ALL : None
LANG : C.UTF-8
LOCALE : en_US.UTF-8

pandas : 1.0.5
numpy : 1.19.1
pytz : 2020.1
dateutil : 2.8.1
pip : 20.2.1
setuptools : 49.3.1.post20200810
Cython : None
pytest : 6.0.1
hypothesis : None
sphinx : 3.2.0
blosc : None
feather : None
xlsxwriter : None
lxml.etree : 4.5.2
html5lib : None
pymysql : 0.10.0
psycopg2 : None
jinja2 : 2.11.2
IPython : 7.17.0
pandas_datareader: None
bs4 : 4.9.1
bottleneck : None
fastparquet : None
gcsfs : None
lxml.etree : 4.5.2
matplotlib : 3.3.0
numexpr : 2.7.1
odfpy : None
openpyxl : 3.0.4
pandas_gbq : None
pyarrow : 1.0.0
pytables : None
pytest : 6.0.1
pyxlsb : None
s3fs : None
scipy : 1.5.2
sqlalchemy : 1.3.18
tables : 3.6.1
tabulate : 0.8.7
xarray : None
xlrd : 1.2.0
xlwt : None
xlsxwriter : None
numba : None

@WestXu WestXu added Bug Needs Triage Issue that has not been reviewed by a pandas team member labels Aug 12, 2020
@simonjayhawkins
Copy link
Member

Thanks @WestXu for the report. This appears to be for Matplotlib 3.3.0+ and persists on pandas master.

>>> pd.__version__
'1.2.0.dev0+100.ged1165575'
>>>
>>> pd.Series({"20190102": 10, "20190103": 10}).plot()
C:\Users\simon\pandas\pandas\plotting\_matplotlib\core.py:1235: UserWarning: FixedFormatter should only be used together with FixedLocator
  ax.set_xticklabels(xticklabels)
<AxesSubplot:>
>>> import matplotlib as mpl
>>> mpl.__version__
'3.3.1'
>>>
>>> import pandas as pd
>>>
>>> pd.__version__
'1.2.0.dev0+100.ged1165575'
>>>
>>> pd.Series({"20190102": 10, "20190103": 10}).plot()
<matplotlib.axes._subplots.AxesSubplot object at 0x0000029E1B3DA040>
>>>
>>> import matplotlib as mpl
>>> mpl.__version__
'3.2.1'
>>>

@simonjayhawkins simonjayhawkins added Compat pandas objects compatability with Numpy or Python functions Visualization plotting and removed Needs Triage Issue that has not been reviewed by a pandas team member labels Aug 17, 2020
@simonjayhawkins simonjayhawkins added this to the Contributions Welcome milestone Aug 17, 2020
@pythonic2020
Copy link

pythonic2020 commented Aug 25, 2020

I got the same error with this code that plots dataframe columns (Series):

fig, ax = plt.subplots(figsize=(8,6))

ax.bar(med2008_sub.index, med2008_sub['Gold'], label='Gold', color='gold')
ax.bar(med2008_sub.index, med2008_sub['Silver'], bottom=med2008_sub['Gold'], color='silver', label='Silver')
ax.bar(med2008_sub.index, med2008_sub['Bronze'], bottom=med2008_sub['Gold'] + med2008_sub['Silver'], 
       color='sandybrown', label='Bronze')
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")
ax.set_ylabel('Number of Gold medals - 2008')
ax.legend(title='Medal type:')

plt.show()

Result (note error at top):

Untitled

pd.show_versions() output:

INSTALLED VERSIONS

commit : f2ca0a2
python : 3.7.8.final.0
python-bits : 64
OS : Windows
OS-release : 10
Version : 10.0.19041
machine : AMD64
processor : Intel64 Family 6 Model 26 Stepping 4, GenuineIntel
byteorder : little
LC_ALL : None
LANG : None
LOCALE : None.None

pandas : 1.1.1
numpy : 1.19.1
pytz : 2020.1
dateutil : 2.8.1
pip : 20.2.2
setuptools : 49.6.0.post20200814
Cython : None
pytest : None
hypothesis : None
sphinx : 3.2.1
blosc : None
feather : None
xlsxwriter : None
lxml.etree : 4.5.2
html5lib : None
pymysql : None
psycopg2 : None
jinja2 : 2.11.2
IPython : 7.17.0
pandas_datareader: None
bs4 : 4.9.1
bottleneck : None
fsspec : None
fastparquet : None
gcsfs : None
matplotlib : 3.3.1
numexpr : 2.7.1
odfpy : None
openpyxl : None
pandas_gbq : None
pyarrow : None
pytables : None
pyxlsb : None
s3fs : None
scipy : 1.5.2
sqlalchemy : None
tables : 3.6.1
tabulate : None
xarray : None
xlrd : 1.2.0
xlwt : None
numba : None

@CatChenal
Copy link

The problem comes from Matplotlib: I can reproduce the problem without using Pandas.

  • Info:
Matplotlib: 3.3.1
Python: 3.7.6 | packaged by conda-forge | (default, Jun  1 2020, 18:11:50) [MSC v.1916 64 bit (AMD64)]
Platform: win32
  • Test data:
np.random.seed(123)
x = np.array(range(10))
y = np.random.random_sample(10)*4
  • Plot triggering the warning:
fig, ax = plt.subplots(1, figsize=(8,5))
ax.bar(x, y);

title1 = "UserWarning: FixedFormatter should only be used together with FixedLocator"
labels = [str(np.round(item.get_position()[1], 3))
              for item in ax.get_yticklabels()]

ax.set(xlim=None,
        xticks=[],
        xlabel='',
        yticklabels=labels,
        ylabel='Series values',
        title=title1)

plt.show();

user_warn_on

  • Amended code that removes the warning:
fig, ax = plt.subplots(1, figsize=(8,5))
ax.bar(x, y);

title2 = "No UserWarning using set_major_formatter"
ax.yaxis.set_major_formatter('{x:.1f}')
ax.set(xlim=None,
       xticks=[],
       xlabel='',
       ylabel='Series values',
       title=title2
      )
plt.show();

user_warn_off

@pythonic2020
Copy link

In my example above, if I add

ax.yaxis.set_major_formatter('{x:0.0f}')

the plot is the same as before, but I still get the UserWarning.

@CatChenal
Copy link

You did not provide the data in your example, so I cannot reproduce it, but it seems to me that the problem originates with the x axis.

  • Instead of
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")
  • Try first:
ax.figure.canvas.draw()
ax.xaxis.set_major_formatter('{x:0.0f}')
ax.tick_params(axis='x',which='major', rotation=45)
  • Then:
ax.figure.canvas.draw()
ax.tick_params(axis='x',which='major', rotation=45)

@pythonic2020
Copy link

Thanks! Your second idea works, with no Warning (!), but I need to get the

ha="right", rotation_mode="anchor"

code in there somehow so that the x axis labels are placed properly under the bars. I'm still trying various methods...

Is there a matplotlib bug filed for this issue? I couldn't find it...

@CatChenal
Copy link

There are many parameters to ax.tick_params: you need to check the documentation then experiment to find out which param can reproduce the previous behavior.

  • For help:
ax.tick_params?
  • Lastly, have you tried this:
ax.figure.canvas.draw()
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")

@pythonic2020
Copy link

pythonic2020 commented Aug 31, 2020

ax.tick_params appears to have no params for anchoring the axis labels. My solution is below. The canvas.draw appears to have no effect.

Your suggestion

ax.figure.canvas.draw()
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")

produces the correct plot (as my original code did), but this UserWarning is thrown:

C:\Users\Me\Miniconda3\envs\forge37\lib\site-packages\ipykernel_launcher.py:9: UserWarning: FixedFormatter should only be used together with FixedLocator
if name == 'main':

This code works, with no Warning:

fig, ax = plt.subplots(figsize=(8,6))

ax.bar(med2008_sub.index, med2008_sub['Gold'], label='Gold', color='gold')
ax.bar(med2008_sub.index, med2008_sub['Silver'], bottom=med2008_sub['Gold'], color='silver', label='Silver')
ax.bar(med2008_sub.index, med2008_sub['Bronze'], bottom=med2008_sub['Gold'] + med2008_sub['Silver'], 
       color='sandybrown', label='Bronze')

ax.set_xticks(med2008_sub.index)
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")

ax.set_ylabel('Number of Gold medals - 2008')
ax.legend(title='Medal type:')

plt.show()

All that was needed was the set_xticks.

@simonjayhawkins
Copy link
Member

I think this may have been fixed in #35946

code sample from #35684 (comment)

>>> import pandas as pd
>>>
>>> pd.__version__
'1.2.0.dev0+261.g9fea06cec'
>>>
>>> pd.Series({"20190102": 10, "20190103": 10}).plot()
<AxesSubplot:>
>>>
>>> import matplotlib as mpl
>>>
>>> mpl.__version__
'3.3.1'
>>>

maybe should add a release note and close

cc @VirosaLi

@Rational-IM
Copy link

The issue has not been fixed. I had to include an "idle" set_yticks() command on my code (see below) to make the error go away in a very simple subroutine I use to format y-axis for my charts. Needless to say I don't want my code with such "noise". I hope it gets fixed soon.

def format_y_label_thousands(): # format y-axis tick labels formats
    ax = plt.gca()
    label_format = '{:,.0f}'
    ax.set_yticks(ax.get_yticks().tolist()) # REMOVE IN THE FUTURE - PLACED TO AVOID WARNING - IT IS A BUG FROM MATPLOTLIB 3.3.1
    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_yticks(ax.get_yticks().tolist()) # REMOVE IN THE FUTURE - PLACED TO AVOID WARNING - IT IS A BUG FROM MATPLOTLIB 3.3.1
    ax.set_yticklabels([label_format.format(x) for x in ax.get_yticks().tolist()])

@TomAugspurger
Copy link
Contributor

@Rational-IM you're using pandas master? #35946 will be in 1.2

@Rational-IM
Copy link

@TomAugspurger pardon my lack of knowledge but what it means to "use pandas master"? I'm using pandas 1.1.1

In [5]: pd.version
Out[5]: '1.1.1'

@MarcoGorelli
Copy link
Member

MarcoGorelli commented Sep 5, 2020

@TomAugspurger pardon my lack of knowledge but what it means to "use pandas master"? I'm using pandas 1.1.1

In [5]: pd.version
Out[5]: '1.1.1'

It's the master branch from the git repository

@Rational-IM
Copy link

No - I'm using the latest version of pandas that I got from a regular anaconda update. When do you believe pandas 1.2.x will be released? The workaround is actually distorting the scale of some of my charts - therefore I will have to live with the warning until it is fixed.

@simonjayhawkins
Copy link
Member

#35946 was a relatively small change. maybe could be backported.

@jreback jreback modified the milestones: Contributions Welcome, 1.2 Sep 5, 2020
jbrockmendel pushed a commit to jbrockmendel/pandas that referenced this issue Sep 8, 2020
@stevenlis
Copy link

stevenlis commented Oct 1, 2020

I'm using 3.3.1 and set_major_foarmatter but still getting a UserWarning: FixedFormatter should only be used together with FixedLocator

Am I missing something?

import matplotlib.pyplot as plt
from matplotlib.ticker import FixedLocator, FixedFormatter

fig, ax = plt.subplots()
ax.scatter(0.5, 0.5)

x_formatter = FixedFormatter(['0', r'$T/2$', r'$T$'])
x_locator = FixedLocator([0, 0.5, 1])
ax.xaxis.set_major_formatter(x_formatter)
ax.xaxis.set_major_locator(x_locator)

ax.set_xlim(0, 1)

@fangchenli
Copy link
Member

I'm using 3.3.1 and set_major_foarmatter but still getting a UserWarning: FixedFormatter should only be used together with FixedLocator

Am I missing something?

import matplotlib.pyplot as plt
from matplotlib.ticker import FixedLocator, FixedFormatter

fig, ax = plt.subplots()
ax.scatter(0.5, 0.5)

x_formatter = FixedFormatter(['0', r'$T/2$', r'$T$'])
x_locator = FixedLocator([0, 0.5, 1])
ax.xaxis.set_major_formatter(x_formatter)
ax.xaxis.set_major_locator(x_locator)

ax.set_xlim(0, 1)

Switch those two statements would fix the warning.

ax.xaxis.set_major_locator(x_locator)
ax.xaxis.set_major_formatter(x_formatter)

@SamtheDeveloper91
Copy link

You did not provide the data in your example, so I cannot reproduce it, but it seems to me that the problem originates with the x axis.

  • Instead of
ax.set_xticklabels(med2008_sub.index, rotation=45, ha="right", rotation_mode="anchor")
  • Try first:
ax.figure.canvas.draw()
ax.xaxis.set_major_formatter('{x:0.0f}')
ax.tick_params(axis='x',which='major', rotation=45)
  • Then:
ax.figure.canvas.draw()
ax.tick_params(axis='x',which='major', rotation=45)

Wow, this was such an elegant solution. Using matplotlib to create simple bar charts, I kept receiving the 'FixedFormatter should only be used together with FixedLocator' error. using the canvas.draw() and tick_params() commands solved the issue immediately. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Compat pandas objects compatability with Numpy or Python functions Visualization plotting
Projects
None yet
Development

Successfully merging a pull request may close this issue.