Los subplots permiten mostrar varios gráficos en una misma figura. La forma recomendada de crearlos en matplotlib es plt.subplots, que devuelve la figura y un array con un objeto de ejes para cada subplot.
plt.subplots
Los argumentos nrows y ncols establecen el número de filas y columnas de la cuadrícula. Con una sola fila o columna los ejes se devuelven como un array unidimensional, por lo que puedes desempaquetarlos directamente.

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, (ax1, ax2) = plt.subplots(nrows = 1, ncols = 2, figsize = (8, 3.5))
ax1.plot(x, np.sin(x))
ax2.plot(x, np.cos(x), color = "tab:orange")
# plt.show()
Cuadrícula de subplots
Con varias filas y columnas los ejes se devuelven como un array bidimensional. Accede a cada subplot con axs[fila, columna] o recórrelos todos con axs.flat.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(1)
fig, axs = plt.subplots(2, 2)
axs[0, 0].plot(rng.normal(size = 20).cumsum())
axs[0, 1].bar(["A", "B", "C"], [3, 5, 2])
axs[1, 0].hist(rng.normal(size = 200))
axs[1, 1].scatter(rng.normal(size = 30), rng.normal(size = 30))
# plt.show()

Recorrer los subplots
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, axs = plt.subplots(2, 3)
for i, ax in enumerate(axs.flat):
ax.plot(x, np.sin(x + i))
ax.set_title(f"Gráfico {i + 1}")
plt.tight_layout()
# plt.show()

El tamaño de toda la figura se establece en pulgadas con figsize = (ancho, alto). El espacio se reparte entre todos los subplots.

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, axs = plt.subplots(1, 3, figsize = (8, 3))
for ax in axs:
ax.plot(x, np.sin(x))
# plt.show()
Los títulos y las etiquetas de los ejes suelen solaparse cuando hay varios subplots. La solución más sencilla es llamar a plt.tight_layout() o crear la figura con layout = "constrained", que ajustan el espaciado automáticamente.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, axs = plt.subplots(2, 2, layout = "constrained")
for ax in axs.flat:
ax.plot(x, np.sin(x))
ax.set_title("Título")
ax.set_xlabel("Etiqueta del eje X")
# plt.show()

Espaciado personalizado
Para establecer el espacio manualmente utiliza subplots_adjust, donde wspace y hspace son el espacio horizontal y vertical entre subplots como fracción del ancho y el alto medio de los ejes.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, axs = plt.subplots(2, 2)
for ax in axs.flat:
ax.plot(x, np.sin(x))
plt.subplots_adjust(wspace = 0.5, hspace = 0.5)
# plt.show()

Establece sharex = True o sharey = True para usar los mismos límites en todos los subplots. Las etiquetas de los ejes solo se muestran en los subplots exteriores, lo que ahorra espacio y facilita las comparaciones.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(2)
fig, axs = plt.subplots(2, 2, sharex = True, sharey = True)
for ax in axs.flat:
ax.hist(rng.normal(size = 200))
# plt.show()

Los argumentos width_ratios y height_ratios establecen el tamaño relativo de las columnas y las filas de la cuadrícula.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(3)
y = rng.normal(size = 300)
fig, (ax1, ax2) = plt.subplots(1, 2, sharey = True,
width_ratios = [3, 1])
ax1.plot(y)
ax2.hist(y, orientation = "horizontal")
# plt.show()

Diseños complejos con subplot_mosaic
Para diseños en los que un subplot ocupa varias filas o columnas utiliza subplot_mosaic. Cada letra del diseño es un subplot y repetir una letra hace que el subplot sea más grande. Los ejes se devuelven en un diccionario.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(4)
fig, axd = plt.subplot_mosaic([["A", "A"],
["B", "C"]],
layout = "constrained")
axd["A"].plot(rng.normal(size = 50).cumsum())
axd["B"].hist(rng.normal(size = 200))
axd["C"].scatter(rng.normal(size = 30), rng.normal(size = 30))
# plt.show()

Utiliza set_title en cada eje para agregar un título a cada subplot y fig.suptitle para agregar un título principal a la figura. Lee más sobre los títulos en matplotlib.

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (8, 3.5))
ax1.plot(x, np.sin(x))
ax1.set_title("Seno")
ax2.plot(x, np.cos(x))
ax2.set_title("Coseno")
fig.suptitle("Funciones trigonométricas")
# plt.show()
Si la cuadrícula tiene más celdas que gráficos, elimina las vacías con fig.delaxes u ocúltalas con ax.axis("off").
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig, axs = plt.subplots(2, 2)
for i, ax in enumerate(axs.flat[:3]):
ax.plot(x, np.sin(x + i))
fig.delaxes(axs[1, 1])
# plt.show()

Para agregar una sola leyenda para todos los subplots consulta el tutorial sobre la leyenda en matplotlib.
También te puede interesar