He pasado demasiado tiempo investigando cómo obtener dos subtramas para compartir el mismo eje y con una sola barra de colores compartida entre los dos en Matplotlib.
Lo que estaba sucediendo era que cuando llamaba a la colorbar()
función en uno subplot1
o en otro subplot2
, escalaba automáticamente el gráfico de manera que la barra de color más el gráfico encajaría dentro del cuadro delimitador 'subplot', haciendo que los dos gráficos de lado a lado fueran dos muy diferentes Tamaños.
Para evitar esto, intenté crear una tercera subtrama que luego pirateé para no representar ninguna trama con solo una barra de colores presente. El único problema es que ahora las alturas y los anchos de las dos parcelas son desiguales, y no puedo entender cómo hacer que se vea bien.
Aquí está mi código:
from __future__ import division
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import patches
from matplotlib.ticker import NullFormatter
# SIS Functions
TE = 1 # Einstein radius
g1 = lambda x,y: (TE/2) * (y**2-x**2)/((x**2+y**2)**(3/2))
g2 = lambda x,y: -1*TE*x*y / ((x**2+y**2)**(3/2))
kappa = lambda x,y: TE / (2*np.sqrt(x**2+y**2))
coords = np.linspace(-2,2,400)
X,Y = np.meshgrid(coords,coords)
g1out = g1(X,Y)
g2out = g2(X,Y)
kappaout = kappa(X,Y)
for i in range(len(coords)):
for j in range(len(coords)):
if np.sqrt(coords[i]**2+coords[j]**2) <= TE:
g1out[i][j]=0
g2out[i][j]=0
fig = plt.figure()
fig.subplots_adjust(wspace=0,hspace=0)
# subplot number 1
ax1 = fig.add_subplot(1,2,1,aspect='equal',xlim=[-2,2],ylim=[-2,2])
plt.title(r"$\gamma_{1}$",fontsize="18")
plt.xlabel(r"x ($\theta_{E}$)",fontsize="15")
plt.ylabel(r"y ($\theta_{E}$)",rotation='horizontal',fontsize="15")
plt.xticks([-2.0,-1.5,-1.0,-0.5,0,0.5,1.0,1.5])
plt.xticks([-2.0,-1.5,-1.0,-0.5,0,0.5,1.0,1.5])
plt.imshow(g1out,extent=(-2,2,-2,2))
plt.axhline(y=0,linewidth=2,color='k',linestyle="--")
plt.axvline(x=0,linewidth=2,color='k',linestyle="--")
e1 = patches.Ellipse((0,0),2,2,color='white')
ax1.add_patch(e1)
# subplot number 2
ax2 = fig.add_subplot(1,2,2,sharey=ax1,xlim=[-2,2],ylim=[-2,2])
plt.title(r"$\gamma_{2}$",fontsize="18")
plt.xlabel(r"x ($\theta_{E}$)",fontsize="15")
ax2.yaxis.set_major_formatter( NullFormatter() )
plt.axhline(y=0,linewidth=2,color='k',linestyle="--")
plt.axvline(x=0,linewidth=2,color='k',linestyle="--")
plt.imshow(g2out,extent=(-2,2,-2,2))
e2 = patches.Ellipse((0,0),2,2,color='white')
ax2.add_patch(e2)
# subplot for colorbar
ax3 = fig.add_subplot(1,1,1)
ax3.axis('off')
cbar = plt.colorbar(ax=ax2)
plt.show()
fuente
vmin
yvmax
son críticos. Controlan la gama de colores de cada subtrama. Si tiene datos reales, es posible que tenga que pasar por esto para encontrar primero los valores mínimo y máximo.Puede simplificar el código de Joe Kington usando el
ax
parámetro defigure.colorbar()
con una lista de ejes. De la documentación :fuente
fig.colorbar(im, ax=axes.ravel().tolist())
. Si omiteax=axes.ravel().tolist()
, la barra de colores se colocará dentro de una subtrama.Esta solución no requiere ajustes manuales de las ubicaciones de los ejes o el tamaño de la barra de colores, funciona con diseños de varias filas y una sola fila, y funciona con
tight_layout()
. Está adaptado a partir de un ejemplo galería , con elImageGrid
de de matplotlib AxesGrid Caja de herramientas .fuente
thecb = ax.cax.colorbar(im)
. Entonces puedes hacerlothecb.set_label_text("foo")
Usar
make_axes
es aún más fácil y ofrece un mejor resultado. También ofrece posibilidades para personalizar el posicionamiento de la barra de colores. También tenga en cuenta la opción desubplots
compartir los ejes x e y.fuente
nrows=1
, la barra de colores se vuelve más grande que las subtramas.Como principiante que tropezó con este hilo, me gustaría agregar una adaptación de python-for-dummies de la muy clara respuesta de abevieiramota (porque estoy en el nivel en el que tuve que buscar 'ravel' para averiguar qué su código estaba haciendo):
Mucho menos pitónico, mucho más fácil para novatos como yo para ver lo que realmente está sucediendo aquí.
fuente
Como se señaló en otras respuestas, la idea suele ser definir un eje para que resida la barra de colores. Hay varias formas de hacerlo; uno que no ha sido mencionado todavía habría que especificar directamente los ejes de barra de colores en la creación trama secundaria con
plt.subplots()
. La ventaja es que no es necesario establecer manualmente la posición de los ejes y, en todos los casos con aspecto automático, la barra de colores tendrá exactamente la misma altura que las subtramas. Incluso en muchos casos donde se usan imágenes, el resultado será satisfactorio como se muestra a continuación.Cuando se usa
plt.subplots()
, el uso delgridspec_kw
argumento permite hacer que los ejes de la barra de colores sean mucho más pequeños que los otros ejes.Ejemplo:
Esto funciona bien, si el aspecto de los gráficos se escala automáticamente o las imágenes se reducen debido a su aspecto en la dirección del ancho (como en el anterior). Sin embargo, si las imágenes son más anchas que altas, el resultado sería el siguiente, que podría no ser deseado.
Una solución para fijar la altura de la barra de colores a la altura de la subtrama sería utilizar
mpl_toolkits.axes_grid1.inset_locator.InsetPosition
para establecer los ejes de la barra de colores en relación con los ejes de la subtrama de la imagen.fuente
ax = fig.add_subplot()
? Lo pregunto porque no puedo entender cómo usarlo con el mapa base.GridSpec
aadd_subplot()
en ese caso.La solución de usar una lista de ejes por abevieiramota funciona muy bien hasta que use solo una fila de imágenes, como se señala en los comentarios. Usar una relación de aspecto razonable para obtener
figsize
ayuda, pero aún está lejos de ser perfecto. Por ejemplo:La función de barra de colores proporciona el
shrink
parámetro que es un factor de escala para el tamaño de los ejes de la barra de colores. Requiere algún tipo de prueba y error manual. Por ejemplo:fuente
Para agregar a la excelente respuesta de @ abevieiramota, puede obtener el euqivalente de tight_layout con restrictined_layout. Todavía obtendrá grandes espacios horizontales si lo usa en
imshow
lugar depcolormesh
debido a la relación de aspecto 1: 1 impuesta porimshow
.fuente
Noté que casi todas las soluciones publicadas involucraban
ax.imshow(im, ...)
y no normalizaban los colores mostrados en la barra de colores para las múltiples subfiguras. Elim
mapeable se toma de la última instancia, pero ¿qué pasa si los valores de los múltiplesim
-s son diferentes? (Supongo que estos mapas se tratan de la misma manera que se tratan los conjuntos de contorno y los conjuntos de superficie). Tengo un ejemplo que usa un diagrama de superficie en 3D a continuación que crea dos barras de colores para una subtrama de 2x2 (una barra de colores por una fila ) Aunque la pregunta pide explícitamente un arreglo diferente, creo que el ejemplo ayuda a aclarar algunas cosas.plt.subplots(...)
Aún no he encontrado una manera de hacerlo usando los ejes 3D, desafortunadamente.Si tan solo pudiera posicionar las barras de color de una mejor manera ... (Probablemente haya una forma mucho mejor de hacer esto, pero al menos no debería ser demasiado difícil de seguir).
fuente
im
s son diferentes, deben no utilizan la misma barra de colores, por lo que la pregunta original no sería realmente apliqueEste tema está bien cubierto, pero aún me gustaría proponer otro enfoque en una filosofía ligeramente diferente.
Es un poco más complejo de configurar, pero permite (en mi opinión) un poco más de flexibilidad. Por ejemplo, uno puede jugar con las proporciones respectivas de cada subtrama / barra de colores:
fuente