Xlabel / ylabel común para subplots matplotlib

Tengo la siguiente plot:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) 

y ahora me gustaría darle a esta gráfica las tags comunes del eje xy las tags del eje y. Con “común”, quiero decir que debería haber una etiqueta grande del eje x debajo de toda la cuadrícula de subplots, y una etiqueta grande del eje y a la derecha. No puedo encontrar nada sobre esto en la documentación de plt.subplots , y mis googlings sugieren que necesito hacer un plt.subplot(111) grande plt.subplot(111) para comenzar, pero ¿cómo puedo poner mis plt.subplot(111) 5 * 2 en eso? utilizando plt.subplots ?

Esto parece lo que realmente quieres. Se aplica el mismo enfoque de esta respuesta a su caso específico:

 import matplotlib.pyplot as plt fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6)) fig.text(0.5, 0.04, 'common X', ha='center') fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical') 

Parcelas multiples con etiqueta de ejes comunes.

Sin sharex=True, sharey=True obtienes:

introduzca la descripción de la imagen aquí

Con él deberías hacerlo más bonito:

 fig, axes2d = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6,6)) for i, row in enumerate(axes2d): for j, cell in enumerate(row): cell.imshow(np.random.rand(32,32)) plt.tight_layout() 

introduzca la descripción de la imagen aquí

Pero si desea agregar tags adicionales, debe agregarlas solo a los gráficos de borde:

 fig, axes2d = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6,6)) for i, row in enumerate(axes2d): for j, cell in enumerate(row): cell.imshow(np.random.rand(32,32)) if i == len(axes2d) - 1: cell.set_xlabel("noise column: {0:d}".format(j + 1)) if j == 0: cell.set_ylabel("noise row: {0:d}".format(i + 1)) plt.tight_layout() 

introduzca la descripción de la imagen aquí

Agregar tags a cada gráfico podría estropearlo (tal vez haya una manera de detectar automáticamente las tags repetidas, pero no conozco una).

Desde el comando:

 fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) 

Usado devuelve una tupla que consta de la figura y una lista de las instancias de los ejes, ya es suficiente para hacer algo como (tenga en cuenta que he cambiado fig,ax to fig,axes ):

 fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size) for ax in axes: ax.set_xlabel('Common x-label') ax.set_ylabel('Common y-label') 

Si desea cambiar algunos detalles en una subplot específica, puede acceder a ella a través de los axes[i] donde itera sobre sus subplots.

También podría ser muy útil incluir un

 fig.tight_layout() 

al final del archivo, antes de plt.show() , para evitar la superposición de tags.

Como lo considero lo suficientemente relevante y elegante (no es necesario especificar las coordenadas para colocar el texto), copio (con una ligera adaptación) una respuesta a otra pregunta relacionada .

 import matplotlib.pyplot as plt fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15)) # add a big axis, hide frame fig.add_subplot(111, frameon=False) # hide tick and tick label of the big axis plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False) plt.xlabel("common X") plt.ylabel("common Y") 

Esto resulta en lo siguiente (con matplotlib versión 2.2.0):

Subplotaciones de 5 filas y 2 columnas con etiquetas comunes de ejes x e y

Me encontré con un problema similar al trazar una cuadrícula de gráficos. Los gráficos constaban de dos partes (superior e inferior). Se suponía que la etiqueta y estaba centrada en ambas partes.

No quería utilizar una solución que dependa de conocer la posición en la figura exterior (como fig.text ()), así que manipulé la posición y de la función set_ylabel (). Por lo general es 0.5, la mitad de la ttwig a la que se agrega. Como el relleno entre las partes (hspace) en mi código era cero, pude calcular la mitad de las dos partes en relación con la parte superior.

 import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec # Create outer and inner grid outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1]) somePlot = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0) # Add two partial plots partA = plt.subplot(somePlot[0]) partB = plt.subplot(somePlot[1]) # No x-ticks for the upper plot plt.setp(partA.get_xticklabels(), visible=False) # The center is (height(top)-height(bottom))/(2*height(top)) # Simplified to 0.5 - height(bottom)/(2*height(top)) mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0]) # Place the y-label partA.set_ylabel('shared label', y = mid) plt.show() 

imagen

Desventajas:

  • La distancia horizontal a la gráfica se basa en la parte superior, las marcas de abajo pueden extenderse a la etiqueta.

  • La fórmula no tiene en cuenta el espacio entre las partes.

  • Lanza una excepción cuando la altura de la parte superior es 0.

Probablemente hay una solución general que toma en cuenta el relleno entre las figuras.

Descubrí un método más robusto:

Si conoce los kwargs bottom y top que entraron en una inicialización de GridSpec , o si no conoce las posiciones de los bordes de sus ejes en las coordenadas de la Figure , también puede especificar la posición de ylabel en las coordenadas de la Figure con un poco de magia de “transformación” de fantasía. Por ejemplo:

 import matplotlib.transforms as mtransforms bottom, top = .1, .9 f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top) avepos = (bottom+top)/2 a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory( mtransforms.IdentityTransform(), f.transFigure # specify x, y transform )) # changed from default blend (IdentityTransform(), a[0].transAxes) a[0].yaxis.label.set_position((0, avepos)) a[0].set_ylabel('Hello, world!') 

… y debería ver que la etiqueta aún se ajusta correctamente de izquierda a derecha para evitar que se superponga con las marcas de verificación, como de costumbre, pero ahora se ajustará para estar siempre exactamente entre las subplots deseadas.

Además, si ni siquiera usa set_position , el ylabel se mostrará por defecto exactamente en la mitad de la figura . Supongo que esto se debe a que cuando la etiqueta se dibuja finalmente, matplotlib usa 0.5 para la coordenada y sin verificar si la transformación de coordenadas subyacente ha cambiado.

Se verá mejor si reserva espacio para las tags comunes haciendo tags invisibles para la ttwig secundaria en la esquina inferior izquierda. También es bueno pasar el tamaño de fuente de rcParams. De esta manera, las tags comunes cambiarán de tamaño con su configuración de rc, y los ejes también se ajustarán para dejar espacio para las tags comunes.

 fig_size = [8, 6] fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size) # Reserve space for axis labels ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0)) ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0)) # Make common axis labels fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize']) fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize']) 

introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí