Defina o tamanho da barra de cores do Matplotlib para corresponder ao gráfico


161

Não consigo fazer com que a barra de cores em gráficos de exibição como esta tenha a mesma altura do gráfico, sem usar o Photoshop depois do fato. Como faço para combinar as alturas?Exemplo de incompatibilidade de tamanho da barra de cores


Você já tentou as sugestões de stackoverflow.com/questions/16702479/...
— lmjohns3

@ imjohns3 Nada nesse post parece fazer nada na barra de cores. Ele permanece do mesmo tamanho, não importa o que eu defina. Se eu definir fração e diminuir, o tamanho do gráfico mudará enquanto a barra de cores permanecerá a mesma, até voltarmos ao que já tenho, e eles pararão de fazer qualquer coisa.
— Elliot

Confira os documentos - matplotlib.org/api/colorbar_api.html - e use fractionou shrinkargs.
— BoltzmannBrain

Respostas:


194

Você pode fazer isso facilmente com um AxisDivider matplotlib .

O exemplo da página vinculada também funciona sem o uso de subtramas:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))

# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

plt.colorbar(im, cax=cax)

insira a descrição da imagem aqui


1
Como não estou trabalhando dentro de uma subtrama, isso não é aplicável.
— 22413 Elliot

Depois de muito mexer, consegui que funcionasse. Tem muitos problemas para interagir com o subplot_adjust, você precisa receber as chamadas nos lugares certos em relação uma à outra.
— 22413 Elliot

11
Isso está alterando levemente o tamanho dos gráficos. Eu tenho 4 em uma grade 2x2, mas só quero que os dois à direita tenham barras (a escala se aplica por linha). No entanto, isso não os torna do mesmo tamanho. Tentei simplesmente não ter a chamada da barra de cores (com a chamada do divisor), mas é claro que isso deixa uma caixa branca vazia e números ao lado. Como faço para que eles tenham um tamanho consistente sem colocar barras em todos eles?
— Elliot

@bogatron Infelizmente, isso não funciona com eixos projetados
— Bogdan

Se você deseja adicionar um título usando plt.title, ele será exibido trocado para a direita. Existe uma maneira de superar isso?
— user2820579

224

Essa combinação (e valores próximos a esses) parece funcionar "magicamente" para manter a barra de cores dimensionada para o gráfico, independentemente do tamanho da exibição.

plt.colorbar(im,fraction=0.046, pad=0.04)

Também não requer o compartilhamento do eixo que pode obter o gráfico fora do quadrado.


4
Isso pode funcionar em alguns casos, mas em geral não. Tente, por exemplo, traçar algo como na pergunta original, que tem uma largura duas vezes a altura.
— Matthias

A opção de fração ainda parece funcionar no caso mencionado, se dimensionada para corresponder à altura da plotagem. (mpl v1.4.3)
— skytaker 4/15

6
Esta é a única maneira universal de fazê-lo. As soluções com axex_grid1 não funcionarão para eixos projetados, como GeoAxes.
— Bogdan

OMG isso é incrível. Muito obrigado pela solução
— 2D_

3
Em resposta ao comentário @Matthias. Você pode corrigir o caso em que a imagem é muito larga usando este truque: im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)onde dataestá sua imagem.
— eindzl

30

O @bogatron já deu a resposta sugerida pelos documentos do matplotlib , que produz a altura certa, mas apresenta um problema diferente. Agora, a largura da barra de cores (assim como o espaço entre a barra de cores e a plotagem) muda com a largura da plotagem. Em outras palavras, a proporção da barra de cores não é mais fixa.

Para obter a altura correta e uma determinada proporção, você precisa se aprofundar um pouco no misterioso axes_grid1módulo.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
import numpy as np

aspect = 20
pad_fraction = 0.5

ax = plt.gca()
im = ax.imshow(np.arange(200).reshape((20, 10)))
divider = make_axes_locatable(ax)
width = axes_size.AxesY(ax, aspect=1./aspect)
pad = axes_size.Fraction(pad_fraction, width)
cax = divider.append_axes("right", size=width, pad=pad)
plt.colorbar(im, cax=cax)

Observe que isso especifica a largura da barra de cores e a altura do gráfico (em contraste com a largura da figura, como era antes).

O espaçamento entre a barra de cores e o gráfico agora pode ser especificado como uma fração da largura da barra de cores, que é um número muito mais significativo do que uma fração da largura da figura.

plotagem de imagem com barra de cores

ATUALIZAR:

Criei um bloco de notas IPython sobre o tópico , onde agrupei o código acima em uma função facilmente reutilizável:

import matplotlib.pyplot as plt
from mpl_toolkits import axes_grid1

def add_colorbar(im, aspect=20, pad_fraction=0.5, **kwargs):
    """Add a vertical color bar to an image plot."""
    divider = axes_grid1.make_axes_locatable(im.axes)
    width = axes_grid1.axes_size.AxesY(im.axes, aspect=1./aspect)
    pad = axes_grid1.axes_size.Fraction(pad_fraction, width)
    current_ax = plt.gca()
    cax = divider.append_axes("right", size=width, pad=pad)
    plt.sca(current_ax)
    return im.axes.figure.colorbar(im, cax=cax, **kwargs)

Pode ser usado assim:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)

1
Esta é uma pequena função realmente útil! Uma palavra de aviso é que ele não funciona quando você deseja adicionar várias barras de cores, porque elas aparecem umas sobre as outras.
— David Hall

22

Agradeço todas as respostas acima. No entanto, como algumas respostas e comentários apontou, o axes_grid1módulo pode não GeoAxes de endereços, enquanto ajustando fraction, pad, shrink, e outros parâmetros semelhantes podem não necessariamente dar a ordem muito precisa, o que realmente me incomoda. Acredito que dar o que é colorbarseu axespode ser uma solução melhor para resolver todos os problemas mencionados.

Código

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()
ax = plt.axes()
im = ax.imshow(np.arange(100).reshape((10,10)))

# Create an axes for colorbar. The position of the axes is calculated based on the position of ax.
# You can change 0.01 to adjust the distance between the main image and the colorbar.
# You can change 0.02 to adjust the width of the colorbar.
# This practice is universal for both subplots and GeoAxes.

cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])
plt.colorbar(im, cax=cax) # Similar to fig.colorbar(im, cax = cax)

Resultado

insira a descrição da imagem aqui

Mais tarde, acho que matplotlib.pyplot.colorbara documentação oficial também oferece a axopção, que são eixos existentes que fornecerão espaço para a barra de cores. Portanto, é útil para várias subparcelas, veja a seguir.

Código

fig, ax = plt.subplots(2,1,figsize=(12,8)) # Caution, figsize will also influence positions.
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
fig.colorbar(im1, ax=ax)

Resultado

insira a descrição da imagem aqui

Novamente, você também pode obter efeitos semelhantes especificando cax, uma maneira mais precisa da minha perspectiva.

Código

fig, ax = plt.subplots(2,1,figsize=(12,8))
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
cax = fig.add_axes([ax[1].get_position().x1-0.25,ax[1].get_position().y0,0.02,ax[0].get_position().y1-ax[1].get_position().y0])
fig.colorbar(im1, cax=cax)

Resultado

insira a descrição da imagem aqui


@ HS-nebula Obrigado por seus comentários e estou feliz que você goste. :)
— Fei Yao

Resposta realmente incrível. Obrigado!!
— episodeyang

11

Quando você cria a colorbartentativa usando os parâmetros de fração e / ou contração.

Dos documentos:

fração 0,15; fração dos eixos originais a serem usados ​​na barra de cores

encolher 1,0; fração pela qual diminuir a barra de cores


1
Se eu definir shrink 1.0 e fração para qualquer coisa, ele reduzirá o gráfico, sem afetar o tamanho da barra de cores, até que a alteração da fração faça com que seja exatamente o que eu já tenho; nesse momento, alterá-los para de fazer qualquer coisa.
— Elliot

Onde exatamente você os especifica, eles devem ser parâmetros para a colorbar()função ou método.
— 22613 Steve Barnes

Obrigado. só precisa especificar o parâmetro shrink e funciona como mágica!
— CodingNow

11

Todas as soluções acima são boas, mas eu gosto da @ Steve e da @ bejota as melhores, pois não envolvem chamadas sofisticadas e são universais.

Por universal, quero dizer que funciona com qualquer tipo de eixo, inclusive GeoAxes. Por exemplo, você projetou eixos para mapeamento:

projection = cartopy.crs.UTM(zone='17N')
ax = plt.axes(projection=projection)
im = ax.imshow(np.arange(200).reshape((20, 10)))

uma chamada para

cax = divider.append_axes("right", size=width, pad=pad)

falhará com: KeyException: map_projection

Portanto, a única maneira universal de lidar com o tamanho da barra de cores com todos os tipos de eixos é:

ax.colorbar(im, fraction=0.046, pad=0.04)

Trabalhe com fração de 0,035 a 0,046 para obter o melhor tamanho. No entanto, os valores para a fração e o paddig precisarão ser ajustados para obter o melhor ajuste para sua plotagem e variarão dependendo se a orientação da barra de cores estiver na posição vertical ou horizontal.


1
Também podemos adicionar shrinkparâmetros quando, em fractionconjunto pad, não produzem os resultados desejados o suficiente.
— Fei Yao
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.