pythonmatplotlibmatplotlib-gridspec

Adjusting space between gridspec subplots for better alignment


I'm using matplotlib.gridspec to create a grid for 3 axes.

My current code looks like:

from matplotlib import pyplot as plt
from matplotlib.gridspec import GridSpec
import pandas as pd

df = pd.DataFrame({'d1': [20,30,40], 'd2': [10,20,30]}, index=['a', 'b', 'c']) #  Dataset to emulate real data structure
df = df.apply(lambda l: l / l.sum() * 100).T
df.index = ['Some dataset', 'Some dataset 2']

fig = plt.figure(figsize=(6.25, 4.0))
gs = GridSpec(3, 2, figure=fig)

ax1 = fig.add_subplot(gs[:2, 0])
ax2 = fig.add_subplot(gs[:2, 1])
hbar_ax = fig.add_subplot(gs[2, :])

df.plot(ax=hbar_ax, kind='barh', stacked=True, width=0.5, color=['#FF3B3B', '#F4B083', '#9CD5A4'], legend=None)
hbar_ax.invert_yaxis()
hbar_ax.set_xlim(-1, 101)

for n in df:
    for i, (cs, ab, pc) in enumerate(zip(df.iloc[:, 0:].cumsum(1)[n], 
                                         df[n], df[n])):
        hbar_ax.text(cs - ab / 2, i, str(np.round(pc, 1)) + '%', 
                 va = 'center', ha = 'center', fontsize='medium')


hbar_ax.tick_params(axis='both', which='both', length=0)
hbar_ax.tick_params(
    axis='x',
    which='both',
    bottom=False,
    top=False,
    labelbottom=False)

plt.tight_layout()

Which produces this figure:

enter image description here

But i cant figure out how to adjust the top plots to space out to look like this:

enter image description here


Solution

  • You can use subfigures:

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib.gridspec import GridSpec
    import pandas as pd
    
    df = pd.DataFrame({'d1': [20,30,40], 'd2': [10,20,30]}, index=['a', 'b', 'c']) #  Dataset to emulate real data structure
    df = df.apply(lambda l: l / l.sum() * 100).T
    df.index = ['Some dataset', 'Some dataset 2']
    
    # create subplot grid (using wpace to set space between top two plots)
    fig, axs = plt.subplots(3, 2, layout="constrained", figsize=(6.25, 4.0), gridspec_kw={"wspace": 0.2})
    gridspec = axs[0, 0].get_subplotspec().get_gridspec()
    
    # add in top two plots (first removing existing axes)
    for ax in axs[:2, 0]:
        ax.remove()
    for ax in axs[:2, 1]:
        ax.remove()
    ax1 = fig.add_subplot(gridspec[:2, 0])
    ax2 = fig.add_subplot(gridspec[:2, 1])
    
    # create subfigure for bottom plot
    for ax in axs[2, :]:
        ax.remove()
    
    subfig = fig.add_subfigure(gridspec[2, :])
    
    # bottom axis
    hbar_ax = subfig.subplots(1)
    
    df.plot(ax=hbar_ax, kind='barh', stacked=True, width=0.5, color=['#FF3B3B', '#F4B083', '#9CD5A4'], legend=None)
    hbar_ax.invert_yaxis()
    hbar_ax.set_xlim(-1, 101)
    
    for n in df:
        for i, (cs, ab, pc) in enumerate(zip(df.iloc[:, 0:].cumsum(1)[n],
                                             df[n], df[n])):
            hbar_ax.text(cs - ab / 2, i, str(np.round(pc, 1)) + '%',
                     va = 'center', ha = 'center', fontsize='medium')
    
    hbar_ax.tick_params(axis='both', which='both', length=0)
    hbar_ax.tick_params(
        axis='x',
        which='both',
        bottom=False,
        top=False,
        labelbottom=False)
    
    fig.show()
    

    This gives:

    enter image description here