FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Repeated plot calls with xunits=None throws exception · Issue #11095 · matplotlib/matplotlib · GitHub

Repository navigation

Repeated plot calls with xunits=None throws exception #11095

Closed

Description

Bug report

Calling plot with xunits=None or yunits=None more than once throws an exception.

Matplotlib version

  • Operating system: RedHat Enterprise 7
  • Matplotlib version: 2.2.2
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 2.7.14

Bug summary

Note that I know this looks weird - but this in an application library that where the user may or may not set units. So we always pass that info though to the kwarg and it may be None in some cases.

import pylab as P
from datetime import datetime

t0 = datetime( 2018, 3, 1 )
t1 = datetime( 2018, 3, 2 )
t2 = datetime( 2018, 3, 3 )
t3 = datetime( 2018, 3, 4 )

# First call works, second call throws.
P.plot( [t0, t1], ["V1", "V1"], xunits=None, yunits=None )
P.plot( [t2, t3], ["V1", "V1"], xunits=None, yunits=None )
P.show()

Actual outcome

Traceback (most recent call last):
  File "t.py", line 10, in <module>
    P.plot( [t2, t3], ["V1", "V1"], xunits=None, yunits=None )
  File "site-packages/matplotlib/pyplot.py", line 3358, in plot
    ret = ax.plot(*args, **kwargs)
  File "site-packages/matplotlib/__init__.py", line 1855, in inner
    return func(ax, *args, **kwargs)
  File "site-packages/matplotlib/axes/_axes.py", line 1527, in plot
    for line in self._get_lines(*args, **kwargs):
  File "site-packages/matplotlib/axes/_base.py", line 194, in __call__
    self.axes.yaxis.set_units(yunits)
  File "site-packages/matplotlib/axis.py", line 1544, in set_units
    self._update_axisinfo()
  File "site-packages/matplotlib/axis.py", line 1486, in _update_axisinfo
    info = self.converter.axisinfo(self.units, self)
  File "site-packages/matplotlib/category.py", line 93, in axisinfo
    majloc = StrCategoryLocator(unit._mapping)
AttributeError: 'NoneType' object has no attribute '_mapping'

The issue is in axes/_base.py:2130 in the _process_unit_info() method. If the xunits or yunits kwarg is set, it's used even if it's None. The question here is what is None in this context. Before 2.2.2, None meant "use the default units". But now that's not possible because it depends on what was plotted before that call whether that will work or not.

My suggestion is that None should mean "I'm not setting this" and behave the way it did before. I think that adding these lines to process_unit_info would fix this (repeat for yunits).

            xunits = kwargs.pop('xunits', self.xaxis.units)
            if xunits is None:
               xunits = self.axis.units

Activity

  1. story645 commented on Apr 23, 2018

    Member

    I think the problem is that string categorical is stashing a units mapping object unit. The information you're passing is a string, and so maybe it should be stashed as an attribute on the units object?

  2. TD22057 commented on Apr 24, 2018

    ContributorAuthor

    Sorry - I don't understand what you mean. What is "the information you're passing"? I think it's important to answer the question: what does passing xunits=None mean? Then we can talk about solutions and code. This is probably related to the changes that were made for locking units to an axis once they are set but I think None wasn't handled in that case.

  3. jklymak commented on Apr 24, 2018

    Member

    I don't think the units-locking PR ever got merged... (#9776), but a bunch of stuff was done to categoricals, which this issue would seem to touch because you are passing string arguments in...

  4. story645 commented on Apr 24, 2018

    Member

    @TD22057 sorry, I meant that the yaxis data is ["V1", "V1"], which means it hits the StrCategorical code path. In the StrCategorical code path, the axis.units attribute gets set to a UnitData object:

     if axis.units is None:
                axis.set_units(UnitData(data))
            else:
                axis.units.update(data)
    return axis.units

    So xunits or yunits = "None" now overwrites that object.

  5. added this to the v2.2.3 milestone on Apr 24, 2018
  6. tacaswell commented on Apr 24, 2018

    Member

    I think @TD22057 's suggestion is correct, we should ignore None when passed as xunit or yunit.

  7. story645 commented on Apr 24, 2018

    Member

    Probably, but I think it raises an issue of what happens when xunit or yunit isn't none but is a string. The JPL string implementation uses it to store sorting (which I think is a smart idea), but currently any use of it will clobber the object on strings.

  8. modified the milestones: v2.2.3, v2.2.4 on Jul 30, 2018
  9. modified the milestones: v2.2.4, v2.2.5 on Feb 11, 2019
  10. modified the milestones: v2.2.5, v3.2.1 on Oct 22, 2019
  11. modified the milestones: v3.2.1, v3.2.2 on Mar 13, 2020
  12. modified the milestones: v3.2.2, v3.4.0 on Jun 16, 2020
  13. dstansby commented on Jul 2, 2020

    Member

    I've added a nicer error message in #17824. It seems that unless we want to enforce None as a "do-nothing" unit in Matplotlib (which would be a big API change if external libraries have converters that take None as a valid unit), this isn't fixable.

  14. tacaswell commented on Jul 3, 2020

    Member

    @TD22057 Sorry this fell by the wayside for so long.

    @dstansby that is not quite what is being proposed. Axis.units is inited to None if we explicitly call axes.set_units(None) it would still be cleared, what @TD22057 is asking for is if you pass xuints=None to ax.plot it gets treated as "not really passed" / "do the the default thing" (which is this case is "do no change the units") which seems like the correct API (you can change but not clear) the units from ax.plot. I suspect that this has "worked" in most cases because most other converters are not storing useful / critical information in the units attribute.

    This first stopped working (but with a slightly different exception that may never have been released) in 34b8eb4 which changed from storing the string <-> float mapping in a second attribute to re-using the 'units` attribute (which seems to be a defend-able position, but I think we may have miss-understood how it was generally being used).

  15. added 5 commits that reference this issue on Jul 3, 2020
    2784df2
    8649ad9
    f0851fc
    810aa21
    444eaa4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL