Spędziłem całkowicie zbyt długo na badaniu, jak uzyskać dwa podploty, aby współdzielić tę samą oś Y z jednym paskiem kolorów współdzielonym między nimi w Matplotlib.
Co się dzieje, że kiedy zadzwoniłem do colorbar()
funkcji w jednej subplot1
lub subplot2
, byłoby AUTOSCALE fabułę tak, że colorbar plus działka pasowałby w polu „poletko” ograniczającej, powodując dwa side-by-side działek być dwa bardzo różne rozmiary.
Aby obejść ten problem, próbowałem utworzyć trzeci podplot, który następnie zhakowałem, aby nie wyświetlać żadnej fabuły z obecnym paskiem kolorów. Jedynym problemem jest to, że teraz wysokości i szerokości dwóch wykresów są nierówne i nie mogę wymyślić, jak sprawić, by wyglądało dobrze.
Oto mój kod:
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()
źródło
vmin
ivmax
są krytyczne. Kontrolują zakres kolorów każdej podploty. Jeśli masz prawdziwe dane, być może trzeba to zrobić, aby najpierw znaleźć wartości minimalną i maksymalną.Możesz uprościć kod Joe Kingtona za pomocą
ax
parametrufigure.colorbar()
z listą osi. Z dokumentacji :źródło
fig.colorbar(im, ax=axes.ravel().tolist())
. Jeśli pominieszax=axes.ravel().tolist()
, pasek kolorów zostanie umieszczony w jednym wątku podrzędnym.To rozwiązanie nie wymaga ręcznego dostosowywania lokalizacji osi lub rozmiaru paska kolorów, działa z układami wielorzędowymi i jednorzędowymi i działa z
tight_layout()
. Jest on przystosowany od przykładzie galerii , korzystającImageGrid
z matplotlib za AxesGrid Toolbox .źródło
thecb = ax.cax.colorbar(im)
. Potem możesz zrobićthecb.set_label_text("foo")
Korzystanie
make_axes
jest jeszcze łatwiejsze i daje lepszy wynik. Zapewnia również możliwość dostosowania położenia paska kolorów. Zwróć także uwagę na opcjęsubplots
współdzielenia osi xiy.źródło
nrows=1
, pasek kolorów ponownie stanie się większy niż podploty.Jako początkujący, który natknął się na ten wątek, chciałbym dodać adaptację python-for-dummies bardzo trafnej odpowiedzi abevieiramota (ponieważ jestem na poziomie, że musiałem poszukać „ravel”, aby dowiedzieć się, co ich kod działał):
O wiele mniej pytoniczny, dla noobów takich jak ja łatwiej jest zobaczyć, co się tutaj naprawdę dzieje.
źródło
Jak wskazano w innych odpowiedziach, zazwyczaj chodzi o zdefiniowanie osi, w których ma znajdować się pasek kolorów. Istnieją różne sposoby na to; jedną, o której jeszcze nie wspomniano, byłoby bezpośrednie określenie osi paska kolorów przy tworzeniu podplotu za pomocą
plt.subplots()
. Zaletą jest to, że położenie osi nie musi być ustawiane ręcznie i we wszystkich przypadkach z automatycznym aspektem pasek kolorów będzie miał dokładnie taką samą wysokość jak wykresy podrzędne. Nawet w wielu przypadkach, w których używane są obrazy, wynik będzie satysfakcjonujący, jak pokazano poniżej.Podczas używania
plt.subplots()
, użyciegridspec_kw
argumentu pozwala, aby osie colorbar znacznie mniejszy niż w innych osiach.Przykład:
Działa to dobrze, jeśli aspekt wykresów jest skalowany automatycznie lub obrazy są zmniejszane ze względu na ich proporcje w kierunku szerokości (jak powyżej). Jeśli jednak obrazy są szersze niż wysokie, wynik wyglądałby następująco, co może być niepożądane.
Rozwiązaniem, aby ustalić wysokość paska kolorów do wysokości podplotu, byłoby użycie go
mpl_toolkits.axes_grid1.inset_locator.InsetPosition
do ustawienia osi paska kolorów względem osi podplotu obrazu.źródło
ax = fig.add_subplot()
? Pytam, ponieważ nie mogę wymyślić, jak go używać z mapą bazową.GridSpec
doadd_subplot()
w tej sprawie.Rozwiązanie polegające na użyciu listy osi abevieiramota działa bardzo dobrze, dopóki nie użyje się tylko jednego wiersza obrazów, jak wskazano w komentarzach. Używanie rozsądnego współczynnika proporcji w celu uzyskania
figsize
pomocy, ale wciąż jest daleki od ideału. Na przykład:Funkcja paska kolorów zapewnia
shrink
parametr, który jest współczynnikiem skalowania dla wielkości osi paska kolorów. Wymaga ręcznej próby i błędu. Na przykład:źródło
Aby dodać do doskonałej odpowiedzi @ abevieiramota, możesz uzyskać równoważnik tight_layout z constrained_layout. Nadal będziesz otrzymywać duże poziome przerwy, jeśli użyjesz
imshow
zamiast tego zpcolormesh
powodu narzuconego przez ciebie współczynnika proporcji 1: 1imshow
.źródło
Zauważyłem, że prawie każde opublikowane rozwiązanie dotyczyło
ax.imshow(im, ...)
i nie znormalizowało kolorów wyświetlanych na pasku kolorów dla wielu podfigur.im
Odwzorowywalne pochodzi z ostatniej instancji, ale co, jeśli wartości wieluim
-s są różne? (Zakładam, że te odwzorowania są traktowane w taki sam sposób, jak traktowane są zestawy konturów i zestawy powierzchni.) Mam przykład wykorzystujący wykres powierzchni 3D poniżej, który tworzy dwa paski kolorów dla podplotu 2x2 (jeden pasek kolorów na jeden wiersz ). Chociaż pytanie wyraźnie wymaga innego rozwiązania, myślę, że przykład pomaga wyjaśnić niektóre rzeczy.plt.subplots(...)
Niestety nie znalazłem sposobu na zrobienie tego z powodu osi 3D.Gdybym tylko mógł lepiej ustawić paski kolorów ... (Prawdopodobnie jest na to znacznie lepszy sposób, ale przynajmniej nie powinno być zbyt trudne do naśladowania).
źródło
im
s są różne, powinny one nie używać tego samego colorbar, więc oryginalne pytanie nie naprawdę zastosowaćTen temat jest dobrze omówiony, ale nadal chciałbym nieco zaproponować inne podejście innej filozofii.
Konfiguracja jest nieco bardziej złożona, ale pozwala (moim zdaniem) na nieco większą elastyczność. Na przykład można grać z odpowiednimi proporcjami każdej podploty / paska kolorów:
źródło