Вопрос-Ответ

How to have one colorbar for all subplots

Как иметь одну цветовую панель для всех вложенных графиков

Я потратил слишком много времени на изучение того, как заставить два вложенных графика использовать одну и ту же ось y с одной цветовой полосой, разделяемой между ними в Matplotlib.

Что происходило, так это то, что когда я вызывал 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()
Переведено автоматически
Ответ 1

Просто поместите цветовую панель на ее собственную ось и используйте 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, будут отображаться однородным цветом.

Ответ 2

Вы можете упростить код Джо Кингтона, используя axпараметр figure.colorbar() со списком осей. Из документации:


топор



Нет объекта (объектов) родительских осей, из которого будет украдено место для новых осей цветовой панели. Если указан список осей, все они будут изменены, чтобы освободить место для осей цветовой панели.



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

Ответ 3

Это решение не требует ручной настройки расположения осей или размера цветовой панели, работает с многорядными и однорядными макетами, а также работает с tight_layout(). Он адаптирован на основе примера из галереи с использованием ImageGrid из matplotlib AxesGrid Toolbox.

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

сетка изображений

Ответ 4

Использование 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()

2023-06-20 16:07 python matplotlib