Matplotlib - Horizontal Bar Chart Timeline With Dates - Xticks not showing date

Viewed 411

Trying to make a graph that looks like the first image here.

However when I try and implement it, I can't work out how to get the dates to print on the X axis, the scale seems about right, just the xticks seem not to be dates, but some basically random number. The typical output is visible in figure 2.

How can I get the dates to show on the xticks. I would like it to show every month, or quarter between 2019-12-01 and 2021-03-01 (march 1st).

Bonus points for any formatting that makes it look more like the first picture.

import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
event = np.array(['Groupone','Grouptwo','Group3','Group4','Group5','Group6'])
begin = np.array([datetime(year=2019,month=12,day=1),datetime(year=2020,month=2,day=1),datetime(year=2020,month=5,day=1),datetime(year=2020,month=11,day=1),datetime(year=2019,month=12,day=1),datetime(year=2020,month=5,day=1)])
end = np.array([datetime(year=2019,month=12,day=30),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2020,month=7,day=3)])

beg_sort = np.sort(begin)
end_sort = end[np.argsort(begin)]
evt_sort = event[np.argsort(begin)]

plt.barh(range(len(beg_sort)), end_sort-beg_sort, left=beg_sort, align='center')
plt.yticks(range(len(beg_sort)), evt_sort)

plt.yticks(range(len(beg_sort)), evt_sort)

plt.show()(begin)
end_sort = end[np.argsort(begin)]
evt_sort = event[np.argsort(begin)]

plt.barh(range(len(beg_sort)), end_sort-beg_sort, left=beg_sort, align='center')

plt.yticks(range(len(beg_sort)), evt_sort)

plt.show()

enter image description here

enter image description here

2 Answers

You can plot each bar as line, choosing the width of the line (lw) you prefer:

# Set the color of the grid lines
mpl.rcParams['grid.color'] = "w"

fig, ax = plt.subplots(1, 1)
# Plot eac item as a line
for i, (b, e, l) in enumerate(zip(beg_sort, end_sort, evt_sort)):
    ax.plot_date([b, e], [i + 1] * 2, ls='-', marker=None, lw=10)  # 10 for the line width

# Set ticks and labels on y axis
ax.set_yticks(range(1, len(evt_sort) + 1))
ax.set_yticklabels(evt_sort)

# Set color and transparency of the grid
ax.patch.set_facecolor('gray')
ax.patch.set_alpha(0.3)
# activate grid
ax.grid(True)

enter image description here

Moreover, you can play with the background grid, customizing it according to your needs.

Hacked something together that works, posting for curiosity, however go with PieCot's answer above:

import matplotlib.pyplot as plt
import numpy as np
from datetime import date
from datetime import datetime
import matplotlib.dates as mdates
#https://stackoverflow.com/questions/58387731/plotting-month-year-as-x-ticks-in-matplotlib
fig, ax = plt.subplots(ncols=2, nrows=1, figsize=(15, 4.18))

#fig, ax = plt.figure( figsize=(15, 4.18))

event = np.array(['Groupone','Grouptwo','Group3','Group4','Group5','Group6'])
begin = np.array([datetime(year=2019,month=12,day=1),datetime(year=2020,month=2,day=1),datetime(year=2020,month=5,day=1),datetime(year=2020,month=11,day=1),datetime(year=2019,month=12,day=1),datetime(year=2020,month=5,day=1)])
end = np.array([datetime(year=2019,month=12,day=30),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2021,month=2,day=1),datetime(year=2020,month=7,day=3)])

beg_sort = np.sort(begin)
end_sort = end[np.argsort(begin)]
evt_sort = event[np.argsort(begin)]
#start_m     = click.prompt('Start month', type=int)
#start_y     = click.prompt('Start year', type=int)
#end_m       = click.prompt('End month', type=int)
#end_y       = click.prompt('End year', type=int)
start_m     = 12
start_y     = 2019
end_m       = 3
end_y       = 2021
months = mdates.MonthLocator()          # Add tick every month
#days = mdates.DayLocator(range(1,32,5)) # Add tick every 5th day in a month
#monthFmt = mdates.DateFormatter('%b')   # Use abbreviated month name
ax[1].xaxis.set_major_locator(months)
#ax[1].xaxis.set_major_formatter(mdates.DateFormatter('%m-%Y')) 
ax[1].xaxis.set_major_formatter(mdates.DateFormatter('%b-%Y')) 

ax[1].xaxis.set_tick_params(rotation=90)
#ax.xaxis.set_tick_params(rotation=30)
#ax[1].xaxis.set_major_formatter(monthFmt)
#ax[0].xaxis.set_minor_locator(days)
start       = date(year=start_y,month=start_m,day=1)
print(start)
end         = date(year=end_y,month=end_m,day=1)
print(end)
Nticks      = 6
delta       = (end-start)/Nticks
tick_dates  = [start + i*delta for i in range(Nticks)]
x_ticks     = ['{}/{}'.format(d.month,d.year) for d in tick_dates]
print(x_ticks)
plt.barh(range(len(beg_sort)), end_sort-beg_sort, left=beg_sort, align='center')
plt.yticks(range(len(beg_sort)), evt_sort)

plt.yticks(range(len(beg_sort)), evt_sort)
#plt.xticks = x_ticks
#plt.set_xticks(x_ticks)

#plt.show()
fig.delaxes(ax[0])

plt.savefig('gwern.pdf',bbox_inches='tight')
Related