0

The closest post I found on SO is as follows (Date ticks and rotation in matplotlib), but still doesnt solve my issue. I need to align the years to appear directly below the red square boxes. I have tried autoformat and align keywords, but nothing works. Anyone can show what am I doing wrong?

dates = [df_filtered.release_date.min(),wm_director.release_date.min(),wd.loc[7283,'Year'],wd.loc[9125,'Year'],
     wd.loc[10127,'Year']]
texts = ['1st movie released','1st movie directed by woman','1st Best Director nomination','Best Director won',
     '2nd Best Director Nomination']

fig, ax = plt.subplots(figsize=(14,1))
ax.plot((dates[0],dates[-1]),(0,0),'k',alpha=0.3)

for i, (text,date) in enumerate(zip(texts,dates)):
    ax.scatter(date,0,marker='s', s=100,color='crimson')
    ax.text(date,0.01,text,rotation=45,va="bottom",fontsize=14)
    ax.set_xticklabels([i.year for i in dates])

ax.yaxis.set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.grid('off')
ax.patch.set_facecolor('white')
ax.get_yaxis().set_ticklabels([])
plt.show()

The list of dates are obtained by extracting the relevant rows from various dataframes, with values already converted to datatime format.

My timeline

Zoozoo
  • 240
  • 4
  • 13

1 Answers1

1

In your code you only set the xticklabels, but let matplotlib figure out the xtick positions itself. The default is to produce equally spaced xticks, which is not what you want. If you add the line ax.set_xticks(dates) before you set the xticklabels, you get what you want:

from matplotlib import pyplot as plt
import pandas as pd

dates = pd.to_datetime(pd.Series(['1916', '1938', '1993', '2009', '2017']),format='%Y')
dates = [d for d in dates]

texts = ['1st movie released','1st movie directed by woman','1st Best Director nomination','Best Director won',
     '2nd Best Director Nomination']

fig, ax = plt.subplots(figsize=(14,1))
ax.plot((dates[0],dates[-1]),(0,0),'k',alpha=0.3)

for i, (text,date) in enumerate(zip(texts,dates)):
    ax.scatter(date,0,marker='s', s=100,color='crimson')
    ax.text(date,0.01,text,rotation=45,va="bottom",fontsize=14)

ax.set_xticks(dates)
ax.set_xticklabels([i.year for i in dates])
ax.tick_params(axis='x', which='both',length=0)

ax.set_ylim([-0.01,0.01])

ax.yaxis.set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.grid('off')
ax.patch.set_facecolor('white')

fig.subplots_adjust(bottom=0.2,top=0.9)
ax.get_yaxis().set_ticklabels([])
plt.savefig('align_years.png', bbox_inches='tight')

The final image (after some code adjustments, and using savefig instead of show) now looks like this:

result of the above code

Hope this helps.

Community
  • 1
  • 1
Thomas Kühn
  • 9,412
  • 3
  • 47
  • 63
  • works wonderfully, thanks! For understanding the code, I tried to remove this line ax.tick_params(axis='x',which='both',lenght=0) and it's still aligned to the red squares. I guess there's no need for the 3rd line. – Zoozoo Jul 09 '18 at 07:29
  • 1
    @Zoozoo yes, you are right. The third line is only there because I was trying to reproduce your plot as closely as possible. If you leave out the third line, you get tick lines above the years, which I don't see in your example figure. – Thomas Kühn Jul 09 '18 at 08:31