2012-12-09 97 views
130

我花了太長時間研究如何讓兩個subplots共享同一個y軸,Matplotlib中的兩個共享一個顏色條。Matplotlib 2 Subplots,1 Colorbar

發生了什麼事是,當我在任何subplot1subplot2colorbar()功能,它會自動縮放的情節使得彩條加的情節會適合進入「插曲」包圍盒內部,造成兩個並排側面情節是兩個非常不同的大小。

爲了解決這個問題,我嘗試創建第三個子區塊,然後我只用一個顏色條呈現沒有繪製的圖形。 唯一的問題是,現在兩塊地塊的高度和寬度不均勻,我無法弄清楚如何使它看起來沒問題。

這裏是我的代碼:

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

回答

198

剛剛發生的彩條在其自身的軸線,並使用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() 

enter image description here

+0

真棒!非常感謝幫忙。 – astromax

+4

ImageGrid對於這個確切的目的也非常有用。 –

+4

如果您需要使用tight_layout(),您將希望在緊張後的subplots_adjust之後執行所有操作,然後手動調整subplots_adjust和add_axes的座標。 – user1748155

34

使用make_axes變得更加容易,並給出一個更好的結果。它還提供了自定義色條位置的可能性。 還要注意subplots的選項以共享x和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() 

+5

當子圖不是正方形時,此方法不起作用。如果更改'nrows = 1',則顏色條會再次大於子圖。 –

+0

你的matplotlib默認值是什麼?看起來不錯! – rafaelvalle

68

可以使用的figure.colorbar()ax參數與軸的清單簡化喬金頓的代碼。 從the documentation

斧頭

無|父軸對象,新的顏色條軸的空間將被盜用。如果給出了一系列軸,它們將全部被調整大小以爲色條軸騰出空間。

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

+2

這個解決方案在這裏工作得很好,似乎是最簡單的一個。 – Kknd

+4

如果將nrows更改爲1,則兩個圖都比colorbar更快。那麼,如何解決這個問題呢? – Jin

+0

可惜它不適用於tight_layout,但仍然是一個很好的解決方案。 – Mark

7

使用軸的列表中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 image array

colorbar function提供shrink參數這對於顏色條軸的尺寸的比例因子。它確實需要一些手動試驗和錯誤。例如:

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

1 x 3 image array with shrunk colorbar

25

此解決方案不要求的座標軸的位置或彩條的大小手動調整,可與多排單排的佈局,以及與tight_layout()工作。它從gallery example改編而來,使用來自matplotlib的AxesGrid ToolboxImageGrid

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

image grid

+0

Double +1,這是一個很好的方法 – bizzy

+0

確實可以與tight_layout一起使用,但我不知道如何將標籤添加到該顏色條。它不接受kws標籤,標題,文字......任何東西!而文檔沒有多大幫助。 – TomCho

+1

@TomCho要設置標籤,您可以在實例化顏色條時抓住它,如:thecb = ax.cax.colorbar(im)'。那麼你可以做'thecb.set_label_text(「foo」)' – spinup

6

至於誰碰到這個線程絆倒初學者,我想補充的蟒換假人適應abevieiramota的很整齊的答案(因爲我在我不得不尋找「拉威爾」制定出了他們的代碼在做什麼)級別:

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

更何況Python的,對於很多像我這樣的菜鳥,看看有什麼實際發生在這裏更容易。

+0

萬歲!我偶然發現了這個答案,我認爲這對SO社區是一個寶貴的貢獻。謝謝你,@RChapman! – ericmjl

4

正如在其他答案中指出的那樣,這個想法通常是定義一個彩色條所在的座標軸。尚未提及的一種方法是直接在子圖創建時使用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() 

enter image description here

這種運作良好,如果情節方面是在上述自動定標的或圖像被在寬度方向上,由於收縮到它們的縱橫(如)。但是,如果圖像較寬而較高,則結果如下所示,這可能是不希望的。

enter image description here

的溶液到固定彩條高度與副區高度將是使用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() 

enter image description here