Skip to content

broken_barh appears not to work with datetime/timedelta objects #12862

@pfmoore

Description

@pfmoore

Bug report

Bug summary

The Axis.broken_barh function takes an xranges parameter described as "The x-positions and extends of the rectangles". But if I'm plotting datetime values on the axis, it appears impossible to supply an extent value of a type that the function can deal with.

Using datetime.timedelta raises an exception AttributeError: 'datetime.timedelta' object has no attribute 'toordinal', as does using an integer. Using a datetime value causes the bar to extend too far (which I guess isn't surprising, as toordinal on a datetime will not give a duration).

Code for reproduction

import matplotlib.pyplot as plt
from datetime import datetime, timedelta

lo = datetime.fromisoformat("2018-11-09 20:00")
hi = datetime.fromisoformat("2018-11-09 22:00")

fig, ax = plt.subplots()

ax.set_xlim(lo, hi)
ax.set_ylim(0, 30)
ax.broken_barh([(lo, timedelta(hours=1))], (10, 20))

plt.show()

Actual outcome

Traceback (most recent call last):
  File ".\problem.py", line 11, in <module>
    ax.broken_barh([(lo, timedelta(hours=1))], (10, 20))
  File "C:\...\lib\site-packages\matplotlib\__init__.py", line 1810, in inner
    return func(ax, *args, **kwargs)
  File "C:\...\lib\site-packages\matplotlib\axes\_axes.py", line 2528, in broken_barh
    xranges = self.convert_xunits(xranges)
  File "C:\...\lib\site-packages\matplotlib\artist.py", line 186, in convert_xunits
    return ax.xaxis.convert_units(x)
  File "C:\...\lib\site-packages\matplotlib\axis.py", line 1530, in convert_units
    ret = self.converter.convert(x, self.units, self)
  File "C:\...\lib\site-packages\matplotlib\dates.py", line 1801, in convert
    return date2num(value)
  File "C:\...\lib\site-packages\matplotlib\dates.py", line 428, in date2num
    return _to_ordinalf_np_vectorized(d)
  File "C:\...\lib\site-packages\numpy\lib\function_base.py", line 1972, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "C:\...\lib\site-packages\numpy\lib\function_base.py", line 2048, in _vectorize_call
    outputs = ufunc(*inputs)
  File "C:\...\lib\site-packages\matplotlib\dates.py", line 229, in _to_ordinalf
    base = float(dt.toordinal())
AttributeError: 'datetime.timedelta' object has no attribute 'toordinal'

Expected outcome

A graph showing a single bar from 20:00 to 21:00.

If this is a limitation of the current version of matplotlib, I'd be perfectly happy with a workaround that gave the expected result by another means (but the approaches I've tried have resulted in the axis tick marks not being correctly formatted as times).

Matplotlib version

  • Operating system: Windows 7
  • Matplotlib version: 3.0.2
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg
  • Python version: 3.7.1
  • Jupyter version (if applicable): N/A
  • Other libraries: None

Python installed from the python.org Windows 64-bit installer. Matplotlib installed from the wheel on PyPI (pipenv install matplotlib).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions