pythonmatplotlibsubplot

Subplots of different heights in matplotlib?


I would like to create three figures showing how a quantity varies with z in three different simulations. The different simulations have different domains, the first extends from z=0 to 1.4, the next 1.1, and the next 1.0. I would like to have three side by side graphs displaying the quantity on the x-axis and z on the y-axis, all scaled in the same way, but with the axes stopping at the maximum z-value, so that the graphs get progressively shorter.

The below is how I'm currently plotting them, and I'd like to lose the blank space in the second and third axis.

fig, axes = plt.subplots(1, 3, sharey=True)
z1 = np.linspace(0, 1.4, 20)
z2 = np.linspace(0, 1.1, 20)
z3 = np.linspace(0, 1.0, 20)
axes[0].plot(np.exp(-z1), z1, c='k')
axes[1].plot(np.exp(-z2), z2, c='k')
axes[2].plot(np.exp(-z3), z3, c='k')

Result of the MWE, with blank space within the axes above the z-extent

I've attempted using gridspec and subplots_mosaic, but both seem to insist on keeping the axes the same relative size. I suppose there's a solution using subplots_mosaic where the mosaic is something like

"""
A..
A..
A..
AB.
ABC
ABC
ABC
ABC
ABC
ABC
ABC
ABC
ABC
"""

to get the right relative heights, but this seems very clunky, and I am hoping there is an easier solution.


Solution

  • i hope its what is required.

    import matplotlib.pyplot as plt
    import numpy as np
    
    z1 = np.linspace(0, 1.4, 20)
    z2 = np.linspace(0, 1.1, 20)
    z3 = np.linspace(0, 1.0, 20)
    
    fig, axes = plt.subplots(1, 3)
    
    axes[0].plot(np.exp(-z1), z1, c='k')
    axes[1].plot(np.exp(-z2), z2, c='k')
    axes[2].plot(np.exp(-z3), z3, c='k')
    
    orig_pos = [ax.get_position() for ax in axes]
    
    max_y_vals = [np.max(z1),np.max(z2),np.max(z3)]
    max_y = max(max_y_vals)
    height_ratios = [v / max_y for v in max_y_vals]
    
    # Align bottoms
    for ax, pos, h in zip(axes, orig_pos, height_ratios):
        new_height = (pos.y1 - pos.y0) * h
        new_y0 = pos.y0  # keep bottom fixed
        new_y1 = new_y0 + new_height
        ax.set_position([pos.x0, new_y0, pos.width, new_height])
        ax.set_ylim(0, max_y*h) # inaccuracy scaling fix and cut exactly by max value
    
    plt.show()
    

    subplots align bottom