Установите размер цветовой шкалы Matplotlib в соответствии с графиком


161

Я не могу сделать так, чтобы цветовая шкала на графиках imshow была такой же высоты, как и график, за исключением фактов использования Photoshop. Как мне получить высоту, чтобы соответствовать?Пример несоответствия размера цветовой шкалы


Вы пробовали предложения от stackoverflow.com/questions/16702479/...
— lmjohns3

@ imjohns3 Ничто в этом посте, похоже, никак не влияет на цветную полосу. Он остается одинаковым, независимо от того, что я установил. Если я установлю дробь и сжатие, размер графика изменится, а цветовая полоса останется прежней, пока мы не вернемся к тому, что у меня уже есть, тогда они перестанут что-либо делать.
— Эллиот

Проверьте документы - matplotlib.org/api/colorbar_api.html - и используйте fractionили shrinkаргументы.
— BoltzmannBrain

Ответы:


194

Вы можете сделать это легко с помощью matplotlib AxisDivider .

Пример со связанной страницы также работает без использования вспомогательных участков:

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)

введите описание изображения здесь


1
Я не работаю на участке, так что это не применимо.
— Эллиот

После долгих переделок получил его на работу. У вас много проблем с взаимодействием с subplot_adjust, вы должны получать вызовы только в правильных местах относительно друг друга.
— Эллиот

11
Это немного меняет размеры графиков. У меня есть 4 в сетке 2x2, но я хочу, чтобы только два справа имели столбцы (масштаб применяется по строкам). Однако это делает их не одинакового размера. Я попытался просто не иметь вызова цветовой панели (с вызовом делителя), но, конечно, это оставляет пустую белую коробку и цифры на стороне. Как я могу сделать так, чтобы они имели одинаковый размер, не ставя столбики на всех из них?
— Эллиот

@bogatron К сожалению, это не работает с проецируемыми осями
— Богдан

Если вы хотите добавить заголовок с помощью plt.title, он будет отображаться поменять местами справа. Есть ли способ преодолеть это?
— user2820579

225

Эта комбинация (и значения, близкие к этим), кажется, «волшебным образом» работает для меня, чтобы цветовая шкала соответствовала графику, независимо от размера дисплея.

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

Это также не требует разделения оси, которая может вывести график из квадрата.


4
Это может работать в некоторых случаях, но в целом это не так. Попробуйте, например, построить что-то похожее на исходный вопрос, ширина которого в два раза больше высоты.
— Матиас

Опция дроби все еще работает в том случае, если вы упомянули, если масштабируется в соответствии с высотой графика. (mpl v1.4.3)
— скайтакер

6
Это единственный универсальный способ сделать это. Решения с axex_grid1 не будут работать для проецируемых осей, таких как GeoAxes.
— Богдан

О боже, это круто. Большое спасибо за решение
— 2D_

3
В ответ на комментарий @Matthias. Вы можете исправить ситуацию, когда изображение слишком широкое, используя этот трюк: im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)где dataваше изображение.
— Эйндзл

30

@bogatron уже дал ответ, предложенный документами matplotlib , который выдает правильную высоту, но создает другую проблему. Теперь ширина цветовой шкалы (а также расстояние между цветовой шкалой и графиком) изменяется в зависимости от ширины графика. Другими словами, соотношение сторон цветовой шкалы больше не фиксируется.

Чтобы получить правильную высоту и заданное соотношение сторон, вам нужно немного глубже заглянуть в таинственный axes_grid1модуль.

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)

Обратите внимание, что это определяет ширину цветовой шкалы относительно высоты графика (в отличие от ширины рисунка, как это было раньше).

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

графическое изображение с цветовой шкалой

ОБНОВИТЬ:

Я создал блокнот IPython по этой теме , где я упаковал приведенный выше код в легко используемую функцию:

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)

Это можно использовать так:

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

1
Это действительно полезная маленькая функция! Одним из предупреждений является то, что он не работает, когда вы хотите добавить несколько цветовых полос, потому что они появляются друг над другом.
— Дэвид Холл

22

Я ценю все ответы выше. Однако, как и некоторые ответы и комментарии указали, axes_grid1модуль может не адрес GeoAxes, тогда как регулировка fraction, pad, shrinkи другие подобные параметры могут не обязательно дать очень точный порядок, который действительно беспокоит меня. Я считаю, что предоставление colorbarсвоего axesможет быть лучшим решением для решения всех вопросов, которые были упомянуты.

Код

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)

результат

введите описание изображения здесь

Позже я нахожу matplotlib.pyplot.colorbarофициальную документацию также даетax опцию, которая представляет собой существующие оси, которые предоставят место для цветовой шкалы. Следовательно, это полезно для нескольких подзаговоров, см. Следующее.

Код

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)

результат

введите описание изображения здесь

Опять же, вы также можете достичь аналогичных эффектов, указав cax, более точный способ с моей точки зрения.

Код

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)

результат

введите описание изображения здесь


@ HS-nebula Спасибо за ваши комментарии, и я рад, что вам понравилось. :)
— Фэй Яо

Действительно удивительный ответ. Спасибо!!
— эпизодян

11

Когда вы создаете colorbar попробуйте использовать параметры дроби и / или сжатия.

Из документов:

фракция 0,15; доля исходных осей для использования для цветовой шкалы

уменьшить 1,0; доля, на которую сжимается цветовая полоса


1
Если я установлю shrink 1.0 и fraction на что-либо, он сжимает график, не влияя на размер цветовой шкалы, пока изменение доли не приведет к тому, что оно уже будет, и в этот момент изменение их перестанет делать что-либо.
— Эллиот

Где именно вы указываете их, они должны быть параметрами для colorbar()функции или метода.
— Стив Барнс

Спасибо. просто нужно указать параметр сжатия, и он работает как по волшебству!
— CodingNow

11

Все вышеперечисленные решения хороши, но мне нравятся @ Steve's и @ bejota's лучше всего, поскольку они не включают в себя модные звонки и универсальны.

Под универсальным я подразумеваю, что работает с любым типом осей, включая GeoAxes. Например, если вы спроецировали оси для отображения:

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

вызов

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

потерпит неудачу с: KeyException: map_projection

Поэтому единственным универсальным способом определения размера цветовой шкалы для всех типов осей является:

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

Работайте с дробью от 0,035 до 0,046, чтобы получить лучший размер. Однако значения фракции и паддига необходимо будет отрегулировать так, чтобы они наилучшим образом подходили для вашего графика и будут различаться в зависимости от ориентации цветовой шкалы по вертикали или горизонтали.


1
Мы также можем добавить shrinkпараметр, когда fractionвместе с padне дают желаемых результатов достаточно.
— Фэй Яо
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.