farqwag25
tengo la siguiente trama:
import matplotlib.pyplot as plt
fig2 = plt.figure()
ax3 = fig2.add_subplot(2,1,1)
ax4 = fig2.add_subplot(2,1,2)
ax4.loglog(x1, y1)
ax3.loglog(x2, y2)
ax3.set_ylabel('hello')
Quiero poder crear etiquetas y títulos de ejes no solo para cada una de las dos subtramas, sino también etiquetas comunes que abarquen ambas subtramas. Por ejemplo, dado que ambos gráficos tienen ejes idénticos, solo necesito un conjunto de etiquetas de ejes x e y. Sin embargo, quiero títulos diferentes para cada trama secundaria.
Intenté algunas cosas pero ninguna funcionó bien.
wwliao
Puede crear una subparcela grande que cubra las dos subparcelas y luego establecer las etiquetas comunes.
import random
import matplotlib.pyplot as plt
x = range(1, 101)
y1 = [random.randint(1, 100) for _ in range(len(x))]
y2 = [random.randint(1, 100) for _ in range(len(x))]
fig = plt.figure()
ax = fig.add_subplot(111) # The big subplot
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
# Turn off axis lines and ticks of the big subplot
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['right'].set_color('none')
ax.tick_params(labelcolor="w", top=False, bottom=False, left=False, right=False)
ax1.loglog(x, y1)
ax2.loglog(x, y2)
# Set common labels
ax.set_xlabel('common xlabel')
ax.set_ylabel('common ylabel')
ax1.set_title('ax1 title')
ax2.set_title('ax2 title')
plt.savefig('common_labels.png', dpi=300)
Otra forma es usar fig.text() para establecer las ubicaciones de las etiquetas comunes directamente.
import random
import matplotlib.pyplot as plt
x = range(1, 101)
y1 = [random.randint(1, 100) for _ in range(len(x))]
y2 = [random.randint(1, 100) for _ in range(len(x))]
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax1.loglog(x, y1)
ax2.loglog(x, y2)
# Set common labels
fig.text(0.5, 0.04, 'common xlabel', ha="center", va="center")
fig.text(0.06, 0.5, 'common ylabel', ha="center", va="center", rotation='vertical')
ax1.set_title('ax1 title')
ax2.set_title('ax2 title')
plt.savefig('common_labels_text.png', dpi=300)
-
La función de subtítulos usa la versión fig.text(). Entonces, ¿esta podría ser la forma “oficial” de hacerlo?
– PhML
26 de marzo de 2013 a las 10:12
-
Vale la pena enfatizar que
ax
tiene que ser creado antesax1
yax2
de lo contrario, la parcela grande cubrirá las parcelas pequeñas.– 1”
29 de noviembre de 2014 a las 21:06
-
También se necesita ax.grid(False) o plt.grid(False) si los parámetros de trazado globales incluyen una cuadrícula (visible).
– Næreen
17/10/2017 a las 17:31
-
Parece que el primer enfoque ya no funciona con las versiones recientes de matplotplib (yo uso 2.0.2): las etiquetas agregadas al eje adjunto no son visibles.
– M.Toya
27 oct 2017 a las 9:50
-
¿Cómo agregar y_labels a cada subparcela individual?
– Fardín Abdi
24 de mayo de 2018 a las 1:43
Julián Chen
Una manera simple usando subplots
:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(3, 4, sharex=True, sharey=True)
# add a big axes, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor="none", top=False, bottom=False, left=False, right=False)
plt.grid(False)
plt.xlabel("common X")
plt.ylabel("common Y")
-
También se necesita ax.grid(False) o plt.grid(False) si los parámetros de trazado globales incluyen una cuadrícula (visible).
– Næreen
17/10/2017 a las 17:31
-
Estoy haciendo esto para una subparcela (5, 1) y mi ylabel está muy lejos en el borde izquierdo de la ventana en lugar de cerca de las subparcelas.
– Evidlo
10 de abril de 2019 a las 4:22
-
Tienes un voto a favor. pero siempre explique qué está haciendo el código, adjunte una imagen o muestre un ejemplo, porque definitivamente tomó un poco de tiempo obtenerlo.
– Kareem Jeiroudi
17 abr 2019 a las 22:08
-
Cambio
'off'
aFalse
con versiones más nuevas de Matplotlib (tengo 2.2.2)–Ted
7 de agosto de 2019 a las 11:17
-
Y luego, ¿cómo se agregan las parcelas?
for ax in axes: ax.plot(x, y)
no parece hacer ningún bien.– número de usuario
16 oct 2019 a las 14:44
plt.setp()
hará el trabajo:
# plot something
fig, axs = plt.subplots(3,3, figsize=(15, 8), sharex=True, sharey=True)
for i, ax in enumerate(axs.flat):
ax.scatter(*np.random.normal(size=(2,200)))
ax.set_title(f'Title {i}')
# set labels
plt.setp(axs[-1, :], xlabel="x axis label")
plt.setp(axs[:, 0], ylabel="y axis label")
-
¿Hay alguna manera de establecer también el tamaño/peso de la fuente con este método?
– pfabri
10 de julio de 2020 a las 14:26
-
@pfabri…
plt.setp(axs[-1, :], xlabel='x axis label')
solo modifica el texto de la etiqueta (aparentemente). si desea personalizar sus parámetros de texto, por ejemplo,ax.set_xlabel(None, size=12, weight='demibold', color='xkcd:lime green', labelpad=0.33)
dentro de por círculo. controlar matplotlib.texto.Texto para más**kwargs
.– Manuel F.
23 de enero de 2021 a las 0:37
tdy
Nuevo en matplotlib 3.4.0
Ahora hay métodos integrados para establecer etiquetas de ejes comunes:
Para reproducir OP loglog
tramas (etiquetas comunes pero títulos separados):
x = np.arange(0.01, 10.01, 0.01)
y = 2 ** x
fig, (ax1, ax2) = plt.subplots(2, 1, constrained_layout=True)
ax1.loglog(y, x)
ax2.loglog(x, y)
# separate subplot titles
ax1.set_title('ax1.title')
ax2.set_title('ax2.title')
# common axis labels
fig.supxlabel('fig.supxlabel')
fig.supylabel('fig.supylabel')
KYC
La respuesta de Wen-wei Liao es buena si no está tratando de exportar gráficos vectoriales o si ha configurado sus backends de matplotlib para ignorar los ejes incoloros; de lo contrario, los ejes ocultos se mostrarían en el gráfico exportado.
Mi respuesta suplabel
aquí es similar a la fig.suptitle
que utiliza el fig.text
función. Por lo tanto, no hay hachas de artista que se creen y se vuelvan incoloras. Sin embargo, si intenta llamarlo varias veces, se agregará texto uno encima del otro (como fig.suptitle
también lo hace). La respuesta de Wen-wei Liao no, porque fig.add_subplot(111)
devolverá el mismo objeto Axes si ya está creado.
Mi función también se puede llamar después de que se hayan creado las parcelas.
def suplabel(axis,label,label_prop=None,
labelpad=5,
ha="center",va="center"):
''' Add super ylabel or xlabel to the figure
Similar to matplotlib.suptitle
axis - string: "x" or "y"
label - string
label_prop - keyword dictionary for Text
labelpad - padding from the axis (default: 5)
ha - horizontal alignment (default: "center")
va - vertical alignment (default: "center")
'''
fig = pylab.gcf()
xmin = []
ymin = []
for ax in fig.axes:
xmin.append(ax.get_position().xmin)
ymin.append(ax.get_position().ymin)
xmin,ymin = min(xmin),min(ymin)
dpi = fig.dpi
if axis.lower() == "y":
rotation=90.
x = xmin-float(labelpad)/dpi
y = 0.5
elif axis.lower() == 'x':
rotation = 0.
x = 0.5
y = ymin - float(labelpad)/dpi
else:
raise Exception("Unexpected axis: x or y")
if label_prop is None:
label_prop = dict()
pylab.text(x,y,label,rotation=rotation,
transform=fig.transFigure,
ha=ha,va=va,
**label_prop)
-
Esta es la mejor respuesta imo. Es fácil de implementar y las etiquetas no se superponen gracias a la opción de rotulador.
– Arthur Dent
25 de junio de 2018 a las 20:23
Aquí hay una solución en la que configura la etiqueta y de una de las parcelas y ajusta la posición de la misma para que esté centrada verticalmente. De esta forma evitas los problemas mencionados por KYC.
import numpy as np
import matplotlib.pyplot as plt
def set_shared_ylabel(a, ylabel, labelpad = 0.01):
"""Set a y label shared by multiple axes
Parameters
----------
a: list of axes
ylabel: string
labelpad: float
Sets the padding between ticklabels and axis label"""
f = a[0].get_figure()
f.canvas.draw() #sets f.canvas.renderer needed below
# get the center position for all plots
top = a[0].get_position().y1
bottom = a[-1].get_position().y0
# get the coordinates of the left side of the tick labels
x0 = 1
for at in a:
at.set_ylabel('') # just to make sure we don't and up with multiple labels
bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
bboxes = bboxes.inverse_transformed(f.transFigure)
xt = bboxes.x0
if xt < x0:
x0 = xt
tick_label_left = x0
# set position of label
a[-1].set_ylabel(ylabel)
a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure)
length = 100
x = np.linspace(0,100, length)
y1 = np.random.random(length) * 1000
y2 = np.random.random(length)
f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0})
a[0].plot(x, y1)
a[1].plot(x, y2)
set_shared_ylabel(a, 'shared y label (a. u.)')
-
Esta es la mejor respuesta imo. Es fácil de implementar y las etiquetas no se superponen gracias a la opción de rotulador.
– Arthur Dent
25 de junio de 2018 a las 20:23
J. Zhao
# list loss and acc are your data
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.plot(iteration1, loss)
ax2.plot(iteration2, acc)
ax1.set_title('Training Loss')
ax2.set_title('Training Accuracy')
ax1.set_xlabel('Iteration')
ax1.set_ylabel('Loss')
ax2.set_xlabel('Iteration')
ax2.set_ylabel('Accuracy')