2

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

dipl0
  • 1,017
  • 2
  • 13
  • 36

2 Answers2

3

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.

PieCot
  • 3,564
  • 1
  • 12
  • 20
  • 1
    Thanks PieCot, awesome work. Thanks! Found my own solution posted below but yours is far more elegant. – dipl0 Feb 21 '21 at 17:52
0

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')
dipl0
  • 1,017
  • 2
  • 13
  • 36