pythonmatplotlibsubfigurefigsize

One figure with two subplots and one with three do not have the same size


I am trying to create two figures with squared subfigures for an article. My problem is that when I do it for two subfigures I get one size and when I do it for three I get a different one, and I would like both to have the same overall size. Moreover, I would like to have all subfigures touching each other as in the examples below.

I am sharing the codes and the outputs for both cases.

Two subfigures:

fig, ax = plt.subplots(1,2, figsize=(13,7), sharey=True, facecolor='w')
fig.subplots_adjust(wspace=0, hspace=0)

ax[0].scatter(exp_list, yrel_slack_list, label='CCC; R$^2$ = 0.34, MUE = 1.01')
ax[0].scatter(exp_list, yrel_glm1_list, facecolors='none', edgecolors='#ff7f0e', label='CCC + cGLM1; R$^2$ = 0.81, MUE = 0.56')
ax[0].plot(np.linspace(-4,4), np.linspace(-4,4), color='red')

ax[1].scatter(exp_list, yrel_slack_list, label='CCC; R$^2$ = 0.34, MUE = 1.01')
ax[1].scatter(exp_list, yrel_slm1_list, facecolors='none', edgecolors='#8c564b', label='CCC + cSLM1; R$^2$ = 0.40, MUE = 0.77')
ax[1].plot(np.linspace(-4,4), np.linspace(-4,4), color='red')

ax[0].set_ylabel(r'Estimated $\Delta \Delta G$ (kcal/mol)', fontsize=14)
ax[0].set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
ax[0].legend(loc=0, frameon=False, fontsize=14, handletextpad=0.1)
ax[0].set_ylim([-4,1])
ax[0].set_xlim([-4,1])
ax[0].set_xticks([-4, -3, -2, -1, 0])
ax[0].tick_params(axis = 'both', which = 'major', labelsize=14)
ax[1].set_xlim([-4,1])
ax[1].legend(loc=0, frameon=False, fontsize=14, handletextpad=0.1)
ax[1].set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
ax[1].tick_params(axis = 'both', which = 'major', labelsize=14)

plt.savefig('inclusion_1h1q_correlation.eps', format='eps', bbox_inches='tight')
plt.show()

enter image description here

Three subfigures:

fig, ax = plt.subplots(1,3, figsize=(20,7), sharey=True, facecolor='w')
fig.subplots_adjust(wspace=0, hspace=0)

ax[0].scatter(exp_list, yrel_slack_list, marker='x', color='k', label='CCC; R$^2$ = 0.34, MUE = 1.01')
ax[0].scatter(exp_list, yrel_c1oiu1h1q_list, color='#1f77b4', label='CCC + cGLM1; R$^2$ = %.2f, MUE = %.2f'%(corr_node_c1oiu1h1q[0]**2,corr_node_c1oiu1h1q[1]))
ax[0].plot(np.linspace(-4,1), np.linspace(-4,1), color='red')

ax[1].scatter(exp_list, yrel_slack_list, marker='x', color='k', label='CCC; R$^2$ = 0.34, MUE = 1.01')
ax[1].scatter(exp_list, yrel_c1oiu1h1q_c1oiu1h1s_list, color='#ff7f0e', label='CCC + cGLM1-2; R$^2$ = %.2f, MUE = %.2f'%(corr_node_c1oiu1h1q_c1oiu1h1s[0]**2,corr_node_c1oiu1h1q_c1oiu1h1s[1]))
ax[1].plot(np.linspace(-4,1), np.linspace(-4,1), color='red')

ax[2].scatter(exp_list, yrel_slack_list, marker='x', color='k', label='CCC; R$^2$ = 0.34, MUE = 1.01')
ax[2].scatter(exp_list, yrel_c1h1q1oiu_i1oiu_list, color='#2ca02c', label='CCC + cGLM1 + iGLMI1; R$^2$ = %.2f, MUE = %.2f'%(corr_node_1oiu[0]**2,corr_node_1oiu[1]))
ax[2].plot(np.linspace(-4,1), np.linspace(-4,1), color='red')

ax[0].set_ylabel(r'Estimated $\Delta \Delta G$ (kcal/mol)', fontsize=18)
ax[0].set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=18)
ax[0].legend(loc=0, frameon=False, fontsize=12, handletextpad=0.1)
ax[0].set_ylim([-3.5,1])
ax[0].set_xlim([-3.5,1])
ax[0].tick_params(axis = 'both', which = 'major', labelsize=18)
ax[1].set_xlim([-3.5,1])
ax[1].legend(loc=0, frameon=False, fontsize=12, handletextpad=0.1)
ax[1].set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=18)
ax[1].tick_params(axis = 'both', which = 'major', labelsize=18)
ax[2].set_xlim([-3.5,1])
ax[2].legend(loc=0, frameon=False, fontsize=12, handletextpad=0.1)
ax[2].set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=18)
ax[2].tick_params(axis = 'both', which = 'major', labelsize=18)

plt.savefig('main_result_cdk2.eps', format='eps', bbox_inches='tight')
plt.show()

enter image description here


Solution

  • You can use gridspec to align subplots ratios for a given overall figure size incl. your required y-axis touching.

    I haven't adapted all your various individual plot settings, but tried to show how gridspec can be used for your general case and kept the respective parts like e.g. the axis ticks (to not overlap especially at the shared y-axis).

    from matplotlib import gridspec
    
    ### 2 subplots
    fig = plt.figure(figsize=(20,7), facecolor='w')
    fig.subplots_adjust(wspace=0, hspace=0)
    
    gs = gridspec.GridSpec(1, 2, width_ratios=[1,1]) 
    ax1 = fig.add_subplot(gs[0,:1])
    ax1.set_title('ax1')
    ax1.set_ylim([-4,1])
    ax1.set_xlim([-4,1])
    ax1.set_xticks([-4, -3, -2, -1, 0])
    
    xx, locs = plt.yticks()
    ll = ['%.1f' % a for a in xx]
    ax1.set_yticks(xx, ll)
    
    ax1.tick_params(axis = 'both', which = 'major', labelsize=14)
    ax2 = fig.add_subplot(gs[0,1:])
    ax2.set_title('ax2')
    ax2.get_yaxis().set_visible(False)
    ax2.set_xlim([-4,1])
    ax2.tick_params(axis = 'both', which = 'major', labelsize=14)
    
    ax1.set_ylabel(r'Estimated $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    ax1.set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    ax2.set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    
    plt.show()
    
    ### 3 subplots
    fig = plt.figure(figsize=(20,7), facecolor='w')
    fig.subplots_adjust(wspace=0, hspace=0)
    
    gs = gridspec.GridSpec(1, 3, width_ratios=[1,1,1]) 
    ax1 = fig.add_subplot(gs[0,:1])
    ax1.set_title('ax1')
    ax1.set_ylim([-3.5,1])
    ax1.set_xlim([-3.5,1])
    ax1.tick_params(axis = 'both', which = 'major', labelsize=14)
    ax2 = fig.add_subplot(gs[0,1])
    ax2.set_title('ax2')
    ax2.get_yaxis().set_visible(False)
    ax2.set_xlim([-3.5,1])
    ax2.tick_params(axis = 'both', which = 'major', labelsize=14)
    ax3 = fig.add_subplot(gs[0,2:])
    ax3.set_title('ax3')
    ax3.get_yaxis().set_visible(False)
    ax3.set_xlim([-3.5,1])
    ax3.tick_params(axis = 'both', which = 'major', labelsize=14)
    
    ax1.set_ylabel(r'Estimated $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    ax1.set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    ax2.set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    ax3.set_xlabel('Experimental $\Delta \Delta G$ (kcal/mol)', fontsize=14)
    
    plt.show()
    

    Notes:


    Here's a screenshot incl. some jupyter parts to show that both overall plots have the same size:

    enter image description here