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
Closed

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

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

Comments

@brandon-rhodes
Copy link

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
Copy link
Member

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
Copy link

liubenyuan 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
Copy link

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
Copy link
Member

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

@bennguvaye
Copy link

bennguvaye commented May 15, 2017 via email

@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
Projects
None yet
Development

No branches or pull requests

7 participants