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

Cannot use a timedelta Rectangle width with a datetime axis #4916

Closed
brandon-rhodes opened this issue Aug 13, 2015 · 5 comments

Comments

Projects
None yet
7 participants
@brandon-rhodes
Copy link

commented Aug 13, 2015

I would like to draw a rectangle to represent the weekend on a plot whose x-axis is time. In an IPython Notebook:

%pylab inline
dt = datetime.datetime
dates = [
    dt(2015, 1, 1),
    dt(2015, 1, 2),
    dt(2015, 1, 3),
    dt(2015, 1, 4),
    dt(2015, 1, 5),
    ]
data = [56.0, 53.2, 57.8, 59.1, 55.5]
gca().add_patch(Rectangle(
    xy=(dt(2015, 1, 3), 50.0),
    width=datetime.timedelta(days=2), 
    height=1.0,
    ))
plot(dates, data)

The big problem is that the above code dies with an exception.

AttributeError                            Traceback (most recent call last)
<ipython-input-13-b4545adc3ff2> in <module>()
     12     xy=(dt(2015, 1, 3), 50.0),
     13     width=datetime.timedelta(days=2),
---> 14     height=1.0,
     15     ))
     16 plot(dates, data)

...

/home/brhodes/.v/misc/lib/python2.7/site-packages/matplotlib/dates.pyc in _to_ordinalf(dt)
    202             dt -= delta
    203 
--> 204     base = float(dt.toordinal())
    205     if hasattr(dt, 'hour'):
    206         base += (dt.hour / HOURS_PER_DAY + dt.minute / MINUTES_PER_DAY +

AttributeError: 'datetime.timedelta' object has no attribute 'toordinal'

The other problem is that my backup plan, of replacing the timedelta() with the floating-point value 2.0, destroys the date-ness of the x axis. It reverts to being a float that does not display as a date.

Why is a timedelta not a valid increment or offset with which I can express width along a datetime x-axis?

Thanks for any help you can provide!

@tacaswell tacaswell added this to the proposed next point release milestone Aug 13, 2015

@tacaswell

This comment has been minimized.

Copy link
Member

commented Aug 13, 2015

As a work around I would try using ax.fill_betweenx or one of the lower-level polygons which lets you specify all of the vertex coordinates.

@liubenyuan

This comment has been minimized.

Copy link

commented Dec 23, 2016

@brandon-rhodes I faced the same problem as you, to annotate a graph using a rectangle.

My workaround is to define a function, it can automatically use timestamp as x axis.

# draw a rectangle
def annote_rect(ax, x, y, w, h):
    t = [x, x+w, x+w, x, x]
    d = [y, y, y+h, y+h, y]
    ax.plot(t, d, 'm--', lw=2)
@bennguvaye

This comment has been minimized.

Copy link

commented May 11, 2017

Another workaround is to subclass timezone.timedelta to implement a toordinal method
(which has no true meaning).
Basically I used

class OrdinalTimedelta(datetime.timedelta):
    _origin = datetime.date(1, 1, 1)
    def toordinal(self):
        return (self._origin + self).toordinal()
@WeatherGod

This comment has been minimized.

Copy link
Member

commented May 12, 2017

Clever! Would you like to make an example show-casing this?

@bennguvaye

This comment has been minimized.

Copy link

commented May 15, 2017

@dstansby dstansby modified the milestones: 2.2 (next next feature release), 2.1 (next point release) Aug 22, 2017

@QuLogic QuLogic modified the milestones: needs sorting, v2.2.0 Feb 12, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.