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

ax.bar doesn't work correctly when width is a timedelta64 object · Issue #11290 · matplotlib/matplotlib · GitHub

Repository navigation

ax.bar doesn't work correctly when width is a timedelta64 object #11290

Closed

Description

The following example

In [1]: x = np.array(range(100), dtype='M8[D]')

In [2]: ax = plt.subplot(1,1,1)

In [3]: y = np.random.random(100)

In [4]: ax.bar(x, y)
Out[4]: <BarContainer object of 100 artists>

works fine, but if I set width to be the diff of the datetime64 array, which gives a timedelta64 array, things break:

In [7]: ax.bar(x[:-1], y[:-1], width=np.diff(x))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-f05692d600cb> in <module>()
----> 1 ax.bar(x[:-1], y[:-1], width=np.diff(x))

~/miniconda3/envs/dev/lib/python3.6/site-packages/matplotlib/__init__.py in inner(ax, *args, **kwargs)
   1853                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1854                         RuntimeWarning, stacklevel=2)
-> 1855             return func(ax, *args, **kwargs)
   1856 
   1857         inner.__doc__ = _add_data_doc(inner.__doc__,

~/miniconda3/envs/dev/lib/python3.6/site-packages/matplotlib/axes/_axes.py in bar(self, *args, **kwargs)
   2257         if align == 'center':
   2258             if orientation == 'vertical':
-> 2259                 left = x - width / 2
   2260                 bottom = y
   2261             elif orientation == 'horizontal':

TypeError: ufunc subtract cannot use operands with types dtype('float64') and dtype('<m8[D]')

This should however be unambiguous, so it would be nice if it worked.

Activity

  1. dstansby commented on May 25, 2018

    Member

    Can you provide the full example with the timedelta64 array that produces that error? I've encountered similar looking problems before, that depend on when we do our unit conversions, and this might actually be fixed in the master branch.

  2. astrofrog commented on May 25, 2018

    ContributorAuthor

    @dstansby - the full example is:

    import numpy as np
    import matplotlib.pyplot as plt
    x = np.array(range(100), dtype='M8[D]')
    ax = plt.subplot(1,1,1)
    y = np.random.random(100)
    ax.bar(x[:-1], y[:-1], width=np.diff(x))
  3. timhoffm commented on May 26, 2018

    Member

    The problem is our unit conversion. We do

    x = self.convert_xunits(x)
    width = self.convert_xunits(width)
    

    However, we don't have a conversion implemented for timedelta64. A result, x is our internal float-based date format while width is still a timedelta64, which cannot be subtracted from each other.

    The solution would be to implement a converter for timedelta64.

  4. dstansby commented on May 26, 2018

    Member

    Ah, so this would be fixed by something like #9120 I think.

  5. timhoffm commented on May 26, 2018

    Member

    Sort of. It needs a bit more infrastructure:

    • implement a converter analogously to DateConverter
    • add it to matplotlib.units.registry
  6. dstansby commented on Sep 18, 2018

    Member

    I'm having a look at this now, but having trouble with your example @astrofrog ; when I do

    import numpy as np
    x = np.array(range(100), dtype='M8[D]')
    print((x[:-1] + np.diff(x) / 2.0) - x[:-1])

    I just get a bunch of zeros; dividing np.diff(x) by a number seems to just zero it out. Do you know of a way to fix this? Internally Matplotlib has to divide the width by 2, which is why I can't get your example working.

  7. QuLogic commented on Sep 18, 2018

    Member

    'M8[D]' has a single day resolution, and your array goes up by one, so dividing by two rounds down to 0. You'd need to at least change it to hourly resolution.

  8. jklymak commented on Sep 18, 2018

    Member

    @dstansby, not sure of the approach you are taking here, but I think as @timhoffm says, we should add timedelta64 to dates.py, and register it. Then all the math can be done in floating point numbers...

  9. dstansby commented on Sep 18, 2018

    Member

    Trying to take that approach, but running into the problem that np.timedelta64 is a subclass of numbers.Number, so the conversion interface assumes it doesn't need converting:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.units as munits
    x = np.array(range(100), dtype='M8[D]')
    xdiff = np.diff(x)
    print(xdiff.dtype)
    print(munits.ConversionInterface.is_numlike(xdiff))

    prints

    timedelta64[D]
    True
  10. added this to the v3.1 milestone on Jan 13, 2019
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