source

모든 서브플롯에 대해 하나의 색상 막대를 갖는 방법

nicesource 2022. 11. 14. 21:37
반응형

모든 서브플롯에 대해 하나의 색상 막대를 갖는 방법

Matplotlib에서는 두 개의 서브플롯이 동일한 Y축을 공유하는 단일 색상 막대를 사용하는 방법에 대해 오랜 시간을 연구했습니다.

무슨 일이 있었냐면요 제가 전화했을 때colorbar()어느쪽이든 기능하다subplot1또는subplot2색상 막대와 플롯이 '하위 그림' 경계 상자 안에 들어가도록 플롯의 크기를 자동 조정하여 두 개의 나란히 있는 플롯의 크기가 서로 매우 다르게 됩니다.

이를 피하기 위해 세 번째 서브플롯을 작성하려고 했습니다.그것을 해킹해서 컬러바만 있어도 플롯을 렌더링하지 않도록 했습니다.유일한 문제는 이제 두 플롯의 높이와 폭이 고르지 않고 어떻게 하면 괜찮아 보일지 모르겠다는 것이다.

코드는 다음과 같습니다.

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()

색상 막대를 자체 축에 배치하여 사용subplots_adjust공간을 마련하기 위해서요

예를 들어 다음과 같습니다.

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=2, ncols=2)
for ax in axes.flat:
    im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)

fig.subplots_adjust(right=0.8)
cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
fig.colorbar(im, cax=cbar_ax)

plt.show()

여기에 이미지 설명 입력

색상 범위는 (를 발생시킨) 마지막 그림에 의해 설정됩니다.im값의 범위가 다음과 같이 설정되어 있는 경우에서도,vmin그리고.vmax예를 들어 다른 플롯의 최대값이 최대값보다 클 경우 최대값보다 높은 값을 가진 점:im균일한 색상으로 표시됩니다.

Joe Kington의 코드를 간단하게 할 수 있습니다.ax파라미터figure.colorbar()축 목록과 함께.매뉴얼에서 다음 항목을 참조하십시오.

도끼

[None] | 새로운 컬러바 축의 공간을 빼앗기는 부모 축 오브젝트축 목록이 제공된 경우 색상 막대 축을 위한 공간을 확보하기 위해 축의 크기가 모두 조정됩니다.

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=2, ncols=2)
for ax in axes.flat:
    im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)

fig.colorbar(im, ax=axes.ravel().tolist())

plt.show()

1

이 솔루션에서는 축 위치나 색상 막대 크기를 수동으로 조정할 필요가 없으며 다중 행 단일 행 레이아웃과 함께 작동하며tight_layout()갤러리의 예에서 개조한 것입니다.ImageGridmatplotlib의 AxesGrid 도구 상자에서 찾을 수 있습니다.

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

# Set up figure and image grid
fig = plt.figure(figsize=(9.75, 3))

grid = ImageGrid(fig, 111,          # as in plt.subplot(111)
                 nrows_ncols=(1,3),
                 axes_pad=0.15,
                 share_all=True,
                 cbar_location="right",
                 cbar_mode="single",
                 cbar_size="7%",
                 cbar_pad=0.15,
                 )

# Add data to image grid
for ax in grid:
    im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)

# Colorbar
ax.cax.colorbar(im)
ax.cax.toggle_label(True)

#plt.tight_layout()    # Works, but may still require rect paramater to keep colorbar labels visible
plt.show()

이미지 그리드

사용.make_axes더 쉽고 더 좋은 결과를 얻을 수 있습니다.또한 색상 막대의 배치를 맞춤화할 수도 있습니다.또, 다음의 옵션에 주의해 주세요.subplotsx축과 y축을 공유합니다.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
for ax in axes.flat:
    im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)

cax,kw = mpl.colorbar.make_axes([ax for ax in axes.flat])
plt.colorbar(im, cax=cax, **kw)

plt.show()

우연히 이 스레드를 접한 초보자로서, 나는 abieiramota의 매우 깔끔한 답변을 파이썬-for-dummies로 각색하고 싶다(그들의 코드가 무엇을 하고 있는지 알아내기 위해 '레벨'을 찾아봐야 하는 수준이기 때문이다).

import numpy as np
import matplotlib.pyplot as plt

fig, ((ax1,ax2,ax3),(ax4,ax5,ax6)) = plt.subplots(2,3)

axlist = [ax1,ax2,ax3,ax4,ax5,ax6]

first = ax1.imshow(np.random.random((10,10)), vmin=0, vmax=1)
third = ax3.imshow(np.random.random((12,12)), vmin=0, vmax=1)

fig.colorbar(first, ax=axlist)

plt.show()

비단뱀이 아니라 나 같은 남자애들이 여기서 무슨 일이 벌어지는지 알기 훨씬 쉽죠

다른 답변에서 지적된 바와 같이 일반적으로 색상 막대가 상주하는 축을 정의하는 것이 기본입니다.에는 여러 되지 않은 시 을 직접 할 수 . 아직 언급되지 않은 방법 중 하나는 다음과 같이 하위 구를 만들 때 색상 막대 축을 직접 지정하는 것입니다.plt.subplots()장점은 축 위치를 수동으로 설정할 필요가 없으며 자동 애스펙트에서는 모든 경우 컬러바가 서브플롯과 정확히 같은 높이가 된다는 것입니다.화상을 사용하는 경우도, 이하와 같이 만족스러운 결과를 얻을 수 있습니다.

「」를 사용하고 plt.subplots()의, " " " "gridspec_kw인수를 사용하면 색상 막대 축을 다른 축보다 훨씬 작게 만들 수 있습니다.

fig, (ax, ax2, cax) = plt.subplots(ncols=3,figsize=(5.5,3), 
                  gridspec_kw={"width_ratios":[1,1, 0.05]})

예를 들어:

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

fig, (ax, ax2, cax) = plt.subplots(ncols=3,figsize=(5.5,3), 
                  gridspec_kw={"width_ratios":[1,1, 0.05]})
fig.subplots_adjust(wspace=0.3)
im  = ax.imshow(np.random.rand(11,8), vmin=0, vmax=1)
im2 = ax2.imshow(np.random.rand(11,8), vmin=0, vmax=1)
ax.set_ylabel("y label")

fig.colorbar(im, cax=cax)

plt.show()

여기에 이미지 설명 입력

플롯의 애스펙트가 자동 스케일링되거나 (위와 같이) 폭 방향의 애스펙트로 인해 이미지가 축소되는 경우 이 기능은 잘 작동합니다.다만, 화상의 폭이 큰 경우는, 다음과 같이 되어, 바람직하지 않을 가능성이 있습니다.

여기에 이미지 설명 입력

색상 막대 높이를 하위구 높이로 고정하는 방법은 다음과 같습니다.mpl_toolkits.axes_grid1.inset_locator.InsetPosition이미지 하위구 축에 상대적인 색상 막대 축을 설정합니다.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition

fig, (ax, ax2, cax) = plt.subplots(ncols=3,figsize=(7,3), 
                  gridspec_kw={"width_ratios":[1,1, 0.05]})
fig.subplots_adjust(wspace=0.3)
im  = ax.imshow(np.random.rand(11,16), vmin=0, vmax=1)
im2 = ax2.imshow(np.random.rand(11,16), vmin=0, vmax=1)
ax.set_ylabel("y label")

ip = InsetPosition(ax2, [1.05,0,0.05,1]) 
cax.set_axes_locator(ip)

fig.colorbar(im, cax=cax, ax=[ax,ax2])

plt.show()

여기에 이미지 설명 입력

공유 컬러맵 및 컬러바

이는 값이 0과 1 사이뿐만 아니라 마지막 값만 사용하는 것이 아니라 cmap을 공유할 필요가 있는 보다 복잡한 경우입니다.

import numpy as np
from matplotlib.colors import Normalize
import matplotlib.pyplot as plt
import matplotlib.cm as cm
fig, axes = plt.subplots(nrows=2, ncols=2)
cmap=cm.get_cmap('viridis')
normalizer=Normalize(0,4)
im=cm.ScalarMappable(norm=normalizer)
for i,ax in enumerate(axes.flat):
    ax.imshow(i+np.random.random((10,10)),cmap=cmap,norm=normalizer)
    ax.set_title(str(i))
fig.colorbar(im, ax=axes.ravel().tolist())
plt.show()

matplotlib 3.4.0의 새로운 기능

공유 색상 막대는 다음 하위 구성을 사용하여 구현할 수 있습니다.

새로 만들기 및 허용... 서브픽처에만 관련된 현지화된 피규어 아티스트(컬러바 및 서플티클 등)

matplotlib 갤러리에는 하위 구성을 표시하는 방법에 대한 데모가 포함되어 있습니다.

다음으로 각각 공유 컬러바가 있는2개의 서브구성을 가진 최소한의 예를 나타냅니다.

서브픽처 컬러바

fig = plt.figure(constrained_layout=True)
(subfig_l, subfig_r) = fig.subfigures(nrows=1, ncols=2)

axes_l = subfig_l.subplots(nrows=1, ncols=2, sharey=True)
for ax in axes_l:
    im = ax.imshow(np.random.random((10, 10)), vmin=0, vmax=1)

# shared colorbar for left subfigure
subfig_l.colorbar(im, ax=axes_l, location='bottom')

axes_r = subfig_r.subplots(nrows=3, ncols=1, sharex=True)
for ax in axes_r:
    mesh = ax.pcolormesh(np.random.randn(30, 30), vmin=-2.5, vmax=2.5)

# shared colorbar for right subfigure
subfig_r.colorbar(mesh, ax=axes_r)

Abevieiramota별로 축 목록을 사용하는 솔루션은 댓글에서 지적한 것처럼 이미지를 한 줄만 사용할 때까지 매우 잘 작동합니다.적절한 석면비 사용figsize도움이 되긴 하지만 아직 완벽과는 거리가 멀다.예를 들어 다음과 같습니다.

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(9.75, 3))
for ax in axes.flat:
    im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)

fig.colorbar(im, ax=axes.ravel().tolist())

plt.show()

1 x 3 이미지 어레이

컬러바 기능은shrink색상 막대 축의 크기에 대한 스케일링 팩터인 파라미터.수동으로 시행착오를 해야 합니다.예를 들어 다음과 같습니다.

fig.colorbar(im, ax=axes.ravel().tolist(), shrink=0.75)

3 x 1 이미지 어레이 (컬러바 축소)

@abevieiramota ab_ __ __ _ tight _ 과ted qq qq q q q q qq q q qq qq q 。사용 시 수평 간격이 커집니다.imshowpcolormesh되기 때문에imshow

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows=2, ncols=2, constrained_layout=True)
for ax in axes.flat:
    im = ax.pcolormesh(np.random.random((10,10)), vmin=0, vmax=1)

fig.colorbar(im, ax=axes.flat)
plt.show()

여기에 이미지 설명 입력

게시된 거의 모든 솔루션에는ax.imshow(im, ...)여러 서브구성에 대해 컬러바에 표시되는 색상을 정규화하지 않았습니다.im만, multiple 이 multiple이면 ?im는요? 는요? -s는요? -s는요? -s는요? -s는요?아래 3D 표면도를 사용하여 2x2 하위구에 대해 두 개의 색상 막대를 만드는 예제가 있습니다(한 행당 하나의 색상 막대).이 질문에는 분명히 다른 배치가 요구되지만, 이 예시는 몇 가지 사항을 명확히 하는 데 도움이 된다고 생각합니다. 할 수 있는 없어요.plt.subplots(...)3D로 제작되었습니다.

플롯 예시

색상 막대를 더 잘 배치할 수만 있다면...(아마도 훨씬 더 좋은 방법이 있을 것입니다만, 적어도 그것을 따르는 것은 그다지 어렵지 않을 것입니다.)

import matplotlib
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

cmap = 'plasma'
ncontours = 5

def get_data(row, col):
    """ get X, Y, Z, and plot number of subplot
        Z > 0 for top row, Z < 0 for bottom row """
    if row == 0:
        x = np.linspace(1, 10, 10, dtype=int)
        X, Y = np.meshgrid(x, x)
        Z = np.sqrt(X**2 + Y**2)
        if col == 0:
            pnum = 1
        else:
            pnum = 2
    elif row == 1:
        x = np.linspace(1, 10, 10, dtype=int)
        X, Y = np.meshgrid(x, x)
        Z = -np.sqrt(X**2 + Y**2)
        if col == 0:
            pnum = 3
        else:
            pnum = 4
    print("\nPNUM: {}, Zmin = {}, Zmax = {}\n".format(pnum, np.min(Z), np.max(Z)))
    return X, Y, Z, pnum

fig = plt.figure()
nrows, ncols = 2, 2
zz = []
axes = []
for row in range(nrows):
    for col in range(ncols):
        X, Y, Z, pnum = get_data(row, col)
        ax = fig.add_subplot(nrows, ncols, pnum, projection='3d')
        ax.set_title('row = {}, col = {}'.format(row, col))
        fhandle = ax.plot_surface(X, Y, Z, cmap=cmap)
        zz.append(Z)
        axes.append(ax)

## get full range of Z data as flat list for top and bottom rows
zz_top = zz[0].reshape(-1).tolist() + zz[1].reshape(-1).tolist()
zz_btm = zz[2].reshape(-1).tolist() + zz[3].reshape(-1).tolist()
## get top and bottom axes
ax_top = [axes[0], axes[1]]
ax_btm = [axes[2], axes[3]]
## normalize colors to minimum and maximum values of dataset
norm_top = matplotlib.colors.Normalize(vmin=min(zz_top), vmax=max(zz_top))
norm_btm = matplotlib.colors.Normalize(vmin=min(zz_btm), vmax=max(zz_btm))
cmap = cm.get_cmap(cmap, ncontours) # number of colors on colorbar
mtop = cm.ScalarMappable(cmap=cmap, norm=norm_top)
mbtm = cm.ScalarMappable(cmap=cmap, norm=norm_btm)
for m in (mtop, mbtm):
    m.set_array([])

# ## create cax to draw colorbar in
# cax_top = fig.add_axes([0.9, 0.55, 0.05, 0.4])
# cax_btm = fig.add_axes([0.9, 0.05, 0.05, 0.4])
cbar_top = fig.colorbar(mtop, ax=ax_top, orientation='vertical', shrink=0.75, pad=0.2) #, cax=cax_top)
cbar_top.set_ticks(np.linspace(min(zz_top), max(zz_top), ncontours))
cbar_btm = fig.colorbar(mbtm, ax=ax_btm, orientation='vertical', shrink=0.75, pad=0.2) #, cax=cax_btm)
cbar_btm.set_ticks(np.linspace(min(zz_btm), max(zz_btm), ncontours))

plt.show()
plt.close(fig)
## orientation of colorbar = 'horizontal' if done by column

이 주제는 잘 다루어져 있지만, 나는 여전히 조금 다른 철학의 다른 접근법을 제안하고 싶다.

셋업이 좀 더 복잡하지만 (내 생각에) 좀 더 유연성이 있다.예를 들어, 각 서브플롯/컬러바의 각각의 비율로 재생할 수 있습니다.

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec

# Define number of rows and columns you want in your figure
nrow = 2
ncol = 3

# Make a new figure
fig = plt.figure(constrained_layout=True)

# Design your figure properties
widths = [3,4,5,1]
gs = GridSpec(nrow, ncol + 1, figure=fig, width_ratios=widths)

# Fill your figure with desired plots
axes = []
for i in range(nrow):
    for j in range(ncol):
        axes.append(fig.add_subplot(gs[i, j]))
        im = axes[-1].pcolormesh(np.random.random((10,10)))

# Shared colorbar    
axes.append(fig.add_subplot(gs[:, ncol]))
fig.colorbar(im, cax=axes[-1])

plt.show()

여기에 이미지 설명 입력

, 은 '이것'을.fig.colobar() fig 는 '먹다'를 사용하는 을 보여 줍니다.plt.colobar(), 기능pyplot:

def shared_colorbar_example():
    fig, axs = plt.subplots(nrows=3, ncols=3)
    for ax in axs.flat:
        plt.sca(ax)
        color = np.random.random((10))
        plt.scatter(range(10), range(10), c=color, cmap='viridis', vmin=0, vmax=1)
    plt.colorbar(ax=axs.ravel().tolist(), shrink=0.6)
    plt.show()

shared_colorbar_example()

위의 대부분의 답변이 2D 매트릭스에서의 사용법을 보여주었기 때문에 간단한 산점도로 진행했습니다.shrink키워드는 옵션이며 컬러바의 크기를 조정합니다.

ifvmin ★★★★★★★★★★★★★★★★★」vmax지정되지 않은 경우 이 접근법은 모든 서브플롯을 자동으로 분석하여 색상 막대에서 사용되는 최소값과 최대값을 확인합니다.는, 「」를 사용하는 입니다.fig.colorbar(im)컬러바의 최소값과 최대값 인수로 전달된 이미지만 스캔합니다.

결과:

위의 코드 스니펫을 실행한 결과

언급URL : https://stackoverflow.com/questions/13784201/how-to-have-one-colorbar-for-all-subplots

반응형