leon82
leon82

Reputation: 29

Labels of the axis from overlapping each other

I'm generating a bar-chart with matplotlib. It all works well but I can't figure out how to prevent the labels of the axis from overlapping each other. Here an example:

#!/usr/bin/env python
import matplotlib.pyplot as plt
import matplotlib.ticker as tic
import csv
from numpy import *
import matplotlib.pyplot as plt
from numpy.random import normal
import numpy as np



target_LandQ=['CHEMBL1293235', 'CHEMBL220', 'CHEMBL289', 'CHEMBL2903', 'CHEMBL311', 'CHEMBL3199', 'CHEMBL3356', 'CHEMBL3397', 'CHEMBL340', 'CHEMBL3622', 'CHEMBL4078', 'CHEMBL5501', 'CHEMBL1075216', 'CHEMBL1075280', 'CHEMBL1075282', 'CHEMBL1798', 'CHEMBL1821', 'CHEMBL1824', 'CHEMBL1827', 'CHEMBL1832', 'CHEMBL1833', 'CHEMBL1835', 'CHEMBL1841', 'CHEMBL1867', 'CHEMBL1868', 'CHEMBL1889', 'CHEMBL1901', 'CHEMBL1909043', 'CHEMBL1909044', 'CHEMBL1914', 'CHEMBL1916', 'CHEMBL1941', 'CHEMBL1942', 'CHEMBL1951', 'CHEMBL1977', 'CHEMBL203', 'CHEMBL2034', 'CHEMBL2035', 'CHEMBL205', 'CHEMBL2056', 'CHEMBL206', 'CHEMBL210', 'CHEMBL211', 'CHEMBL213', 'CHEMBL216', 'CHEMBL217', 'CHEMBL218', 'CHEMBL219', 'CHEMBL221', 'CHEMBL222', 'CHEMBL223', 'CHEMBL224', 'CHEMBL225', 'CHEMBL226', 'CHEMBL228', 'CHEMBL2292', 'CHEMBL230', 'CHEMBL231', 'CHEMBL2327', 'CHEMBL233', 'CHEMBL234', 'CHEMBL236', 'CHEMBL237', 'CHEMBL238', 'CHEMBL240', 'CHEMBL2414', 'CHEMBL242', 'CHEMBL2434', 'CHEMBL245', 'CHEMBL246', 'CHEMBL248', 'CHEMBL2487', 'CHEMBL249', 'CHEMBL250', 'CHEMBL251', 'CHEMBL252', 'CHEMBL256', 'CHEMBL258', 'CHEMBL259', 'CHEMBL260', 'CHEMBL2622', 'CHEMBL273', 'CHEMBL274', 'CHEMBL287', 'CHEMBL299', 'CHEMBL3048', 'CHEMBL3072', 'CHEMBL315', 'CHEMBL3157', 'CHEMBL3198', 'CHEMBL321', 'CHEMBL3243', 'CHEMBL326', 'CHEMBL332', 'CHEMBL3371', 'CHEMBL3385', 'CHEMBL3403', 'CHEMBL3459', 'CHEMBL3464', 'CHEMBL3577', 'CHEMBL4015', 'CHEMBL4018', 'CHEMBL402', 'CHEMBL4029', 'CHEMBL4040', 'CHEMBL4071', 'CHEMBL4074', 'CHEMBL4358', 'CHEMBL4376', 'CHEMBL4445', 'CHEMBL4607', 'CHEMBL4608', 'CHEMBL4644', 'CHEMBL4768', 'CHEMBL4777', 'CHEMBL4780', 'CHEMBL4801', 'CHEMBL4822', 'CHEMBL5017', 'CHEMBL5077', 'CHEMBL5144', 'CHEMBL5281', 'CHEMBL5282', 'CHEMBL5486', 'CHEMBL5763']
hist_q=[1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]


y_pos = np.arange(len(hist_q))
plt.barh(y_pos, hist_q, align='center', alpha=0.4)
plt.yticks(y_pos, target_LandQ)
plt.figure(1, [20, 20])
plt.xlabel('Target Presence')
plt.title('Query Molecule')
fig="s_Q"
plt.savefig(fig,bbox_inches='tight')
plt.show()
fig = plt.figure()
fig.clf()

ax = fig.add_subplot(111)
ax.yaxis.grid(True, linestyle='-', which='major', color='grey', alpha=0.5)
ind = range(len(hist_q))
rects = ax.bar(ind, hist_q, width=0.4444, align='center', color='thistle')
ax.set_xticks(ind)
ax.set_xticklabels(target_LandQ)

fig = plt.figure(1, [20, 8])
ax.set_xlim(-1,100)
plt.setp(ax.get_xticklabels(), fontsize=7, rotation='vertical')
fig.autofmt_xdate()
plt.savefig('test2.png',  dpi = 300,  pad_inches = 0)
plt.show()

Upvotes: 1

Views: 2772

Answers (1)

J Richard Snape
J Richard Snape

Reputation: 20344

You need to do a few different bits here. Your overlapping is basically due to the fact that the labels are written in a font that, at the scale of your plot, is too large to fit within the height of the bars. Things you can do:

  1. Put your call to plt.figure() right up front before you call plt.barh() - that way the display size of the figure will be applied before you plot. In your case, you want a tall but not wide figure, try using size [5,20]
  2. Add a ylim to your plot and set it to only the y values you use so that you don't get white space above and below your bars
  3. Change the tick label font to something appropriately small. You are trying to display a lot of bars, so it will be potentially really small - e.g. 6 point.

Applying all these - your code would look like (e.g.):

... Your existing code up to...

y_pos = np.arange(len(hist_q))
plt.figure(1, [5, 20]) # this line moved and figure size changed to suit data
plt.ylim(0,max(y_pos)+1) # this gets rid of whitespace
plt.tick_params(axis='both', which='major', labelsize=6) # makes axis labels smaller

... Carry on existing code from plt.barh(y_pos, hist_q, align='center', alpha=0.4) ...

You can do the same for the x axis on your second plot. These settings often take a bit of fiddling around to get the plot looking exactly how you want.

P.S.

I wouldn't use fig for the variable name to contain the string name of your figure to call savefig. It will work fine, but makes your code hard to read, because fig nearly always refers to a Figure object in code using matplotlib. Just a convention - your code is not wrong.

Upvotes: 1

Related Questions