Home > Mobile >  matplotlib: How to use adjust space between individual rows of a figure without applying it to all r
matplotlib: How to use adjust space between individual rows of a figure without applying it to all r

Time:09-27

I am trying to create a figure using matplotlib that contains 12 plots in total. The plots are distributed as follows: There are 3 columns, and 4 rows. I want the first two rows to be "sticking" together along the y axis/vertically, i.e. there shall be no axis labels, and no figure title of the lower row in between them. The same goes for rows 3 and 4. However, I want some space between the two "row-groups" So basically rows 1 and 2 stick together, and row 3 and 4 stick together, but some space between row 2 and 3.

I was only able to find parameters that influence all heigh space between subplots, but none that let me modify the height space individually. In this MWE, I'm using the "figure.subplot.hspace" rcParam to modify the hspace.

#!/usr/bin/env python3

import matplotlib as mpl
from matplotlib import pyplot as plt
import numpy as np

params = {
    "xtick.labelsize": 12,
    "ytick.labelsize": 12,
    "xtick.direction": "in",
    "ytick.direction": "in",
    "xtick.top": True,
    "ytick.right": True,
    "figure.subplot.left": 0.045,
    "figure.subplot.right": 0.99,
    "figure.subplot.bottom": 0.05,
    "figure.subplot.top": 0.93,
    "figure.subplot.wspace": 0.15,
    "figure.subplot.hspace": 0.0,
}
mpl.rcParams.update(params)


if __name__ == "__main__":

    # invent some data
    x = np.linspace(0, 2*np.pi, 100)
    y_main = np.sin(x)
    y_diff = 1. - y_main


    fig = plt.figure(figsize=(18, 22))
    ax1 = fig.add_subplot(4,3,1,)
    ax2 = fig.add_subplot(4,3,2,)
    ax3 = fig.add_subplot(4,3,3,)
    ax1_sub = fig.add_subplot(4,3,4)
    ax2_sub = fig.add_subplot(4,3,5)
    ax3_sub = fig.add_subplot(4,3,6)
    ax4 = fig.add_subplot(4,3,7,)
    ax5 = fig.add_subplot(4,3,8,)
    ax6 = fig.add_subplot(4,3,9,)
    ax4_sub = fig.add_subplot(4,3,10)
    ax5_sub = fig.add_subplot(4,3,11)
    ax6_sub = fig.add_subplot(4,3,12)


    subaxes = [ax1_sub, ax2_sub, ax3_sub, ax4_sub, ax5_sub, ax6_sub]
    mainaxes = [ax1, ax2, ax3, ax4, ax5, ax6]

    for ax in mainaxes:
        ax.set_title("Title")
        ax.plot(x, y_main)
        ax.set_ylabel("y(x)")
        ax.tick_params(labelbottom=False)

    for ax in subaxes:
        ax.plot(x, y_diff)
        ax.set_xlabel("xlabel")
        ax.set_ylabel("1 - y(x)")


    #  plt.tight_layout()
    plt.savefig("mwe.png", dpi=200)
    plt.close()

The resulting figure is as follows:

enter image description here

This is exactly how I want rows 1&2 and 3&4 to "stick together". But as you can see, the axis labels and figure titles are now missing and inside other figures, respectively.

How can I add some space between two specific rows only?

CodePudding user response:

For such 'special' plot arrangements I like to use enter image description here

Code:

import matplotlib as mpl
from matplotlib import pyplot as plt
import numpy as np

params = {
    "xtick.labelsize": 12,
    "ytick.labelsize": 12,
    "xtick.direction": "in",
    "ytick.direction": "in",
    "xtick.top": True,
    "ytick.right": True,
    "figure.subplot.left": 0.045,
    "figure.subplot.right": 0.99,
    "figure.subplot.bottom": 0.05,
    "figure.subplot.top": 0.93,
    "figure.subplot.wspace": 0.15,
    # "figure.subplot.hspace": 0.0,  # done within gridspec
}
mpl.rcParams.update(params)

# invent some data
x = np.linspace(0, 2*np.pi, 100)
y_main = np.sin(x)
y_diff = 1. - y_main

fig = plt.figure(figsize=(18, 22), facecolor=(1, 1, 1))
    
gs = fig.add_gridspec(2, 1, hspace=0.15)  # spacing between the two groups
# print(gs)
    
gs0 = gs[0].subgridspec(2, 3, hspace=0, wspace=0.2)  # spacing within the groups
gs1 = gs[1].subgridspec(2, 3, hspace=0, wspace=0.2)
# print(gs0)

set1, set1_sub = gs0.subplots()
# print(set1)
set1[0].text(0.5, 0.5, "set1[0]")
set1[1].text(0.5, 0.5, "set1[1]")
set1[2].text(0.5, 0.5, "set1[2]")
set1_sub[0].text(0.5, 0.5, "set1_sub[0]")
set1_sub[1].text(0.5, 0.5, "set1_sub[1]")
set1_sub[2].text(0.5, 0.5, "set1_sub[2]")
    
set2 = gs1.subplots()
# print(set2)
set2[0,0].text(0.5, 0.5, "set2[0]")
set2[0,1].text(0.5, 0.5, "set2[1]")
set2[0,2].text(0.5, 0.5, "set2[2]")
set2[1,0].text(0.5, 0.5, "set2_sub[0]")
set2[1,1].text(0.5, 0.5, "set2_sub[1]")
set2[1,2].text(0.5, 0.5, "set2_sub[2]")

mainaxes = [set1[0], set1[1], set1[2], set2[0,0], set2[0,1], set2[0,2]]
subaxes = [set1_sub[0], set1_sub[1], set1_sub[2], set2[1,0], set2[1,1], set2[1,2]]

for ax in mainaxes:
    ax.set_title("Title")
    ax.plot(x, y_main)
    ax.set_ylabel("y(x)")
    ax.tick_params(labelbottom=False)

for ax in subaxes:
    ax.plot(x, y_diff)
    ax.set_xlabel("xlabel")
    ax.set_ylabel("1 - y(x)")

#plt.savefig("mwe.png", dpi=200)
plt.show()

Notes:

  • The .text are included as a help to identify the positions, just remove them when you've got the overview.
  • set1/2 (groups) are build slightly different to show how gridspec works
    • both ways have the same result
    • activate the # print statements for further insight
  • fig.add_gridspec(2, 1) 'main' grid with 2 rows and 1 column
  • gs[0].subgridspec(2, 3) subgrid within the 1st main row, with 2 rows and 3 columns
  • Related