2

I've found a way to draw a line (not necessary vertical or horizontal) in a matplotlib plot: This recommends using

plt.plot([2, 3], [25, 10])

However that does not work with plot with datetimes on the x axis.

I'm getting "ValueError: ordinal must be >= 1" with all the attempts in the following code.

import matplotlib.pyplot as plt
from calendar import monthrange
import datetime

def get_datetime_range(year, month): # Create a list with all days in a month
    nb_days = monthrange(year, month)[1]
    return [datetime.date(year, month, day) for day in range(1, nb_days+1)]    

# Create sample data
date = get_datetime_range(2017, 9)
value = [d.day % 12 for d in date]

# Draw
plt.plot(date, value)

plt.axvline(date[10], color='r', zorder=0) # Vertical line works

m = len(date)-1
print("Draw line from [%s, %s] to [%s, %s]." % (date[0], value[0], date[m], value[m]))

# The following does NOT work

plt.plot_date([date[0], value[0]], 
              [date[m], value[m]]) # Gives ValueError: ordinal must be >= 1

#plt.plot([date[10], 1], 
#         [date[25], 20])


#plt.plot_date([date2num(date[0]), value[0]], 
#              [date2num(date[m]), value[m]])

#plt.plot([2, 3], [25, 10])

plt.plot()

I also tried converting the datetimes to number with date2num without success (the same error):

from matplotlib.dates import date2num

dateNum = [date2num(d) for d in date]
plt.plot(dateNum, value) # Works

plt.axvline(date[10], color='r', zorder=0) # Works

plt.plot_date([date2num(date[0]), value[0]],  
              [date2num(date[m]), value[m]]) # Gives ValueError: ordinal must be >= 1

Any help?

DavidG
  • 24,279
  • 14
  • 89
  • 82

2 Answers2

0

The format is plot([x1, x2, x3, ...], [y1, y2, y3, ...]). In your code you have plot_date([x1, y1], [x2, y2]), which is incorrect.

replacing your code with:

plt.plot_date([date[0], date[m]], 
              [value[0], value[m]])

solves the problem.

Note, however, that the default behavior of plot_date() is to plot points (fmt='o') and not a line. If you want a line, as your code implies, you need to change the format argument:

plt.plot_date([date[0], date[m]], 
              [value[0], value[m]], fmt='-')
Diziet Asahi
  • 38,379
  • 7
  • 60
  • 75
0

The problem arises because you have got the order of your coordinates slightly wrong. With:

plt.plot_date([date[0], value[0]], 
              [date[m], value[m]])

You are saying that your x coordinates are date[0] and value[0]. Whereas your x coordinates are actually date[0] and date[m]. Therefore, you should use:

plt.plot_date([date[0],date[m]],
              [value[0], value[m]])

The full code:

def get_datetime_range(year, month): # Create a list with all days in a month
    nb_days = monthrange(year, month)[1]
    return [datetime.date(year, month, day) for day in range(1, nb_days+1)]

# Create sample data
date = get_datetime_range(2017, 9)
value = [d.day % 12 for d in date]

# Draw
plt.plot(date, value)

plt.axvline(date[10], color='r', zorder=0) # Vertical line works

m = len(date)-1
print("Draw line from [%s, %s] to [%s, %s]." % (date[0], value[0], date[m], value[m]))

# changes were made here
plt.plot_date([date[0], date[m]], [value[0], value[m]], fmt='-', color='r')

plt.show()

Gives the following graph:

enter image description here

DavidG
  • 24,279
  • 14
  • 89
  • 82