21

I tried to plot a rectangle on a graph with a datetime x-axis using the following code:

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

# Create new plot
fig = plt.figure()
ax = fig.add_subplot(111)

# Create rectangle
startTime = datetime.now()
width = timedelta(seconds = 1)
endTime = startTime + width
rect = Rectangle((startTime, 0), width, 1, color='yellow')

# Plot rectangle
ax.add_patch(rect)   ### ERROR HERE!!! ###
plt.xlim([startTime, endTime])
plt.ylim([0, 1])
plt.show()

However, I get the error:

TypeError: unsupported operand type(s) for +: 'float' and 'datetime.timedelta'

What's going wrong? (I'm using matplotlib version 1.0.1)

3 Answers 3

28

The problem is that matplotlib uses its own representation of dates/times (floating number of days), so you have to convert them first. Furthermore, you will have to tell the xaxis that it should have date/time ticks and labels. The code below does that:

from datetime import datetime, timedelta
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# Create new plot
fig = plt.figure()
ax = fig.add_subplot(111)

# Create rectangle x coordinates
startTime = datetime.now()
endTime = startTime + timedelta(seconds = 1)

# convert to matplotlib date representation
start = mdates.date2num(startTime)
end = mdates.date2num(endTime)
width = end - start

# Plot rectangle
rect = Rectangle((start, 0), width, 1, color='yellow')
ax.add_patch(rect)   

# assign date locator / formatter to the x-axis to get proper labels
locator = mdates.AutoDateLocator(minticks=3)
formatter = mdates.AutoDateFormatter(locator)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)

# set the limits
plt.xlim([start-width, end+width])
plt.ylim([-.5, 1.5])

# go
plt.show()

Result:

enter image description here

NOTE: Matplotlib 1.0.1 is very old. I can't guarantee that my example will work. You should try to update!

Sign up to request clarification or add additional context in comments.

1 Comment

Note that if the dates in the x-axis are from pandas, you need to convert to python date-time first. The line start = mdates.date2num( startTime ) would then be start = mdates.date2num( startTime.to_pydatetime() ). The same goes for the end.
-1

The issue is that the type(startTime) datetime.datetime isn't a valid type to pass into the rectangle. It needs to be typecast into a supported type in order to use the rectangle patch.

If all you really want is to make a yellow rectangle just make a normal plot with a yellow background:

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

# Create new plot
fig = plt.figure()
ax = fig.add_subplot(111, axisbg='yellow')
plt.xticks(rotation=15)
plt.tight_layout()
# Create rectangle
startTime = datetime.now()
width = timedelta(seconds = 1)
endTime = startTime + width

#rect = Rectangle((0, 0), 1, 1, color='yellow')

# Plot rectangle
#ax.add_patch(rect)   ### ERROR HERE!!! ###

plt.xlim([startTime, endTime])
plt.ylim([0, 1])
plt.show()

1 Comment

You seem to be missing some critical info here...
-1

Another error that you can see when trying to create a patches.Rectangle artist using the datetime values for x is:

TypeError: float() argument must be a string or a number.

The reason for this is that during Rectangle object initialization x argument is converted internally to float:

self._x = float(xy[0])

It doesn't work for datetime values. Solution proposed by @hitzg will solve this issue because matplotlib.dates.date2num() returns float.

1 Comment

This is a comment, not an answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.