Passei muito tempo pesquisando como obter duas subparcelas para compartilhar o mesmo eixo y com uma única barra de cores compartilhada entre as duas no Matplotlib.
O que estava acontecendo era que, quando eu chamei a colorbar()
função em um subplot1
ou outro subplot2
, ele dimensionaria automaticamente a plotagem de forma que a barra de cores mais a plotagem caíssem dentro da caixa delimitadora da 'subtrama', fazendo com que as duas plotagens lado a lado fossem duas muito diferentes. tamanhos.
Para contornar isso, tentei criar uma terceira subtrama que eu hackeei para renderizar nenhuma plotagem com apenas uma barra de cores presente. O único problema é que agora as alturas e larguras das duas parcelas são desiguais, e não consigo descobrir como fazê-la parecer correta.
Aqui está o meu 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()
fonte
vmin
evmax
são críticos. Eles controlam o intervalo de cores de cada subtrama. Se você tiver dados reais, pode ser necessário passar por isso para encontrar os valores mínimo e máximo primeiro.Você pode simplificar o código de Joe Kington usando o
ax
parâmetro defigure.colorbar()
com uma lista de eixos. A partir da documentação :fonte
fig.colorbar(im, ax=axes.ravel().tolist())
. Se você omitirax=axes.ravel().tolist()
, a barra de cores será colocada dentro de uma subtrama.Esta solução não requer ajustes manuais dos locais dos eixos ou do tamanho da barra de cores, trabalha com layouts de várias linhas e de uma linha e trabalha com
tight_layout()
. É adaptado de um exemplo da galeria , usandoImageGrid
a caixa de ferramentas AxesGrid do matplotlib .fonte
thecb = ax.cax.colorbar(im)
. Então você pode fazerthecb.set_label_text("foo")
O uso
make_axes
é ainda mais fácil e oferece um resultado melhor. Também oferece possibilidades de personalizar o posicionamento da barra de cores. Observe também a opção desubplots
compartilhar os eixos x e y.fonte
nrows=1
, a barra de cores se tornará maior que as subparcelas novamente.Como iniciante que tropeçou nesse tópico, eu gostaria de adicionar uma adaptação python-por-manequins da resposta muito legal de abevieiramota (porque estou no nível em que precisei procurar 'ravel' para descobrir o que o código deles estava funcionando):
Muito menos pitônico, muito mais fácil para noobs como eu ver o que realmente está acontecendo aqui.
fonte
Como apontado em outras respostas, a idéia é geralmente definir um eixo para a barra de cores residir. Existem várias maneiras de fazer isso; um que ainda não tenha sido mencionado seria especificar diretamente os eixos da barra de cores na criação da subtrama
plt.subplots()
. A vantagem é que a posição dos eixos não precisa ser definida manualmente e, em todos os casos com aspecto automático, a barra de cores terá exatamente a mesma altura das subparcelas. Mesmo em muitos casos em que as imagens são usadas, o resultado será satisfatório, como mostrado abaixo.Ao usar
plt.subplots()
, o uso dogridspec_kw
argumento permite tornar os eixos da barra de cores muito menores que os outros eixos.Exemplo:
Isso funciona bem, se o aspecto das plotagens for escalonado automaticamente ou as imagens forem reduzidas devido ao aspecto na direção da largura (como acima). Se, no entanto, as imagens forem mais amplas que altas, o resultado seria o seguinte, o que pode ser indesejável.
Uma solução para fixar a altura da barra de cores à altura da subparcela seria usar
mpl_toolkits.axes_grid1.inset_locator.InsetPosition
para definir os eixos da barra de cores em relação aos eixos da subparcela da imagem.fonte
ax = fig.add_subplot()
? Estou perguntando porque não consigo descobrir como usá-lo com o mapa base.GridSpec
paraadd_subplot()
nesse caso.A solução de usar uma lista de eixos por abevieiramota funciona muito bem até você usar apenas uma linha de imagens, conforme indicado nos comentários. Usando uma proporção razoável para obter
figsize
ajuda, mas ainda está longe de ser perfeito. Por exemplo:A função barra de cores fornece o
shrink
parâmetro que é um fator de escala para o tamanho dos eixos da barra de cores. Requer alguma tentativa e erro manual. Por exemplo:fonte
Para adicionar à excelente resposta de @ abevieiramota, você pode obter o euqivalente de tight_layout com constrained_layout. Você ainda terá grandes espaços horizontais se usar em
imshow
vez dapcolormesh
razão de aspecto de 1: 1 imposta porimshow
.fonte
Percebi que quase todas as soluções postadas envolviam
ax.imshow(im, ...)
e não normalizavam as cores exibidas na barra de cores para as várias sub-configurações. Oim
mapeável é extraído da última instância, mas e se os valores dos múltiplosim
-s forem diferentes? (Suponho que esses mapas mapeáveis sejam tratados da mesma maneira que os conjuntos de contorno e superfície). Eu tenho um exemplo usando um gráfico de superfície 3d abaixo que cria duas barras de cores para uma subparte 2x2 (uma barra de cores por uma linha) ) Embora a pergunta solicite explicitamente um arranjo diferente, acho que o exemplo ajuda a esclarecer algumas coisas.plt.subplots(...)
Infelizmente, ainda não encontrei uma maneira de fazer isso usando os eixos 3D.Se eu pudesse posicionar as barras de cores de uma maneira melhor ... (Provavelmente existe uma maneira muito melhor de fazer isso, mas pelo menos não deve ser muito difícil de seguir.)
fonte
im
s forem diferentes, eles não deverão usar a mesma barra de cores, para que a pergunta original não se aplique realmente.Este tópico é bem abordado, mas eu ainda gostaria de propor outra abordagem em uma filosofia um pouco diferente.
É um pouco mais complexo de configurar, mas permite (na minha opinião) um pouco mais de flexibilidade. Por exemplo, pode-se jogar com as respectivas proporções de cada subparcela / barra de cores:
fonte