How to render subfigures with even sizes

61 views Asked by At

I have been trying to make a figure like the one below. enter image description here

It contains 5 barh subplots and I want to place the legend in the last slot. There is also an annotation line and a suptitle.

The issue that I am facing is that the subplots are not even in size. The second row subplots have a different height than the others. Also, the third row subplot (subplot 5) have a different width.

The code that I am using below is looking like this:

import numpy as np

import matplotlib
import matplotlib.pyplot as plt

fig = plt.figure(constrained_layout=True)

temps = ['1', '2', '3']
colour=['#ffffff','#29d639']

subfigs = fig.subfigures(nrows=3, ncols=1)
subfigs[1].suptitle('Open defects')


[ax14, ax9] = subfigs[0].subplots(nrows=1, ncols=2)


d14_4= [15000000,15000000,15000000]
b14 = ax14.barh(temps, d14_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax14.set_xscale('log')
ax14.set_xlim(1,15000000)
ax14.margins(x=0,y=0)


d9_4= [1500000,1500000,1500000]
b9_4 = ax9.barh(temps, d9_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax9.set_xscale('log')
ax9.set_xlim(1,1500000)
ax9.margins(x=0,y=0)

ax14.annotate('', xy=(0, -0.32), xycoords='axes fraction', xytext=(2.07, -0.32), arrowprops=dict(arrowstyle="-", linestyle='-', linewidth=1.5, color='grey'))


[ax1, ax8] = subfigs[1].subplots(nrows=1, ncols=2)

d1_5= [4000,4000,4000]
b1_5 = ax1.barh(temps, d1_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax1.set_xscale('log')
ax1.set_xlim(1,4000)
ax1.margins(x=0,y=0)

d8_3= [60000000, 60000000, 0]
b8_3 = ax8.barh(temps, d8_3,height= 1, linewidth=0.5,edgecolor='black', color=colour[1])
ax8.set_xscale('log')
ax8.set_xlim(1,60000000)
ax8.margins(x=0,y=0)

[ax15, ax18] = subfigs[2].subplots(nrows=1, ncols=2)

d15_5= [0, 0, 5000000]
b15 = ax15.barh(temps, d15_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax15.set_xscale('log')
ax15.set_xlim(1,5000000)
ax15.margins(x=0,y=0)

ax18.remove()

labels=["1","2"]
lines=[b15,b14]

leg=fig.legend(lines, labels, loc = (0.7, 0.035), ncol=3,frameon=False)

# plt.savefig('output1.pdf', format='pdf')
plt.show()

I tried to make the subplots even by changing the contrained layout parameters and the subplot_adjust() method but nothing worked.

It would really helpful if someone can guide me what could be done here. Thanks a lot

I tried changing the parameters of the constrained layout method and the subplot_adjust method but nothing worked.

When I change the contrained_layout to tight_layout and then manually adjust the layout sizes, the figure does not render correctly.

1

There are 1 answers

1
HMH1013 On BEST ANSWER

Here is a solution with plt.tight_layout, the part which I have changed, I added a comment.

fig = plt.figure(constrained_layout=True)

temps = ['1', '2', '3']
colour=['#ffffff','#29d639']

subfigs = fig.subfigures(nrows=3, ncols=1)
subfigs[1].suptitle('Open defects')


[ax14, ax9] = subfigs[0].subplots(nrows=1, ncols=2)


d14_4= [15000000,15000000,15000000]
b14 = ax14.barh(temps, d14_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax14.set_xscale('log')
ax14.set_xlim(1,15000000)
ax14.margins(x=0,y=0)


d9_4= [1500000,1500000,1500000]
b9_4 = ax9.barh(temps, d9_4,height= 1, linewidth=0.5,edgecolor='black', color=colour[0])
ax9.set_xscale('log')
ax9.set_xlim(1,1500000)
ax9.margins(x=0,y=0)

# Change to xytext=(2.2, -0.32), because after tight_layout the layout is changed
ax14.annotate('', xy=(0, -0.32), xycoords='axes fraction', xytext=(2.2, -0.32), arrowprops=dict(arrowstyle="-", linestyle='-', linewidth=1.5, color='grey'))


[ax1, ax8] = subfigs[1].subplots(nrows=1, ncols=2)

d1_5= [4000,4000,4000]
b1_5 = ax1.barh(temps, d1_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax1.set_xscale('log')
ax1.set_xlim(1,4000)
ax1.margins(x=0,y=0)

d8_3= [60000000, 60000000, 0]
b8_3 = ax8.barh(temps, d8_3,height= 1, linewidth=0.5,edgecolor='black', color=colour[1])
ax8.set_xscale('log')
ax8.set_xlim(1,60000000)
ax8.margins(x=0,y=0)

[ax15, ax18] = subfigs[2].subplots(nrows=1, ncols=2)

d15_5= [0, 0, 5000000]
b15 = ax15.barh(temps, d15_5,height= 1, linewidth=0.5,edgecolor='black',color=colour[1])
ax15.set_xscale('log')
ax15.set_xlim(1,5000000)
ax15.margins(x=0,y=0)

ax18.remove()

# Add tight_layout 
plt.tight_layout(rect=[0, 0.2, 1, 0.9])

labels=["1","2"]
lines=[b15,b14]

# Change location of the legend
leg=plt.legend(lines, labels, loc = (1.5, 0.035), ncol=3,frameon=False)

plt.show()

Which gives you the result:

result