设置Matplotlib颜色条大小以匹配图形


161

我无法在像这样的imshow图上获得与该图相同的高度的色条,但事后没有使用Photoshop。如何获得与之匹配的高度?颜色条大小不匹配的示例



@ imjohns3该帖子似乎对色条没有任何作用。无论我设置什么,它都保持相同的大小。但是,如果我设置了分数并缩小,则图形的大小将改变,而颜色条保持不变,直到我们回到我已经拥有的位置,然后它们停止执行任何操作。
艾略特

查看文档-matplotlib.org/api/colorbar_api.html-并使用fractionshrinkargs。
BoltzmannBrain

Answers:


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
我不在子图内工作,因此这不适用。
Elliot

经过大量修补后,它开始工作。与subplot_adjust交互时会遇到很多麻烦,您必须将调用放在相对正确的位置。
艾略特

11
这会稍微改变图形的大小。我在2x2网格中有4个,但只希望右边的两个具有条形(按行应用比例)。但是,这使它们的大小不同。我试过不使用colorbar调用(使用除法器调用),但是当然这会在侧面留下一个空白的白色框和数字。如何使它们具有一致的大小而又不对所有条都加条呢?
Elliot

@bogatron不幸的是,这不适用于投影轴
Bogdan

如果您想使用添加标题plt.title,则会在右侧交换显示。有办法克服吗?
user2820579 '17

224

这种组合(以及接近这些值的组合)似乎“神奇地”对我起作用,无论显示大小如何,都可以将颜色条缩放到绘图。

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

它也不需要共享轴,这可以使绘图不成正方形。


4
在某些情况下,这可能会起作用,但通常不会。尝试,例如,绘制类似原始问题的内容,其宽度是高度的两倍。
马提亚斯(Matthias)2015年

如果缩放比例以匹配图的高度,那么分数选项在您提到的情况下似乎仍然有效。(mpl v1.4.3)
2015年

6
这是唯一的通用方法。使用axex_grid1的解决方案不适用于诸如GeoAxes的投影轴。
Bogdan

天哪,这太棒了。非常感谢您的解决方案
2D_ '18

3
回应@Matthias评论。您可以使用以下技巧纠正图像过宽的情况:图像im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)在哪里data
eindzl

29

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

请注意,这指定了颜色条的宽度与绘图高度(与宽度相反)之前的图形)。

现在可以将颜色条和图形之间的间距指定为颜色条宽度的一部分,恕我直言,IMHO比图形宽度的一部分有意义得多。

带有颜色条的图像图

更新:

我在主题上创建了一个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
这是一个非常有用的小功能!一个警告词是,当您要添加多个颜色条时,它不起作用,因为它们相互重叠。
David Hall

22

我感谢上述所有答案。然而,像一些答案和评论中指出,该axes_grid1模块不能地址GeoAxes,而调整fractionpadshrink,和其他类似参数不一定能给出非常精确的顺序,这真的令我烦恼。我认为,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感谢您的评论,我很高兴您喜欢它。:)
费飞

真的很棒的答案。谢谢!!
episodeyang

11

当您创建 colorbar分数和/或收缩参数尝试。

从文件:

分数0.15; 用于颜色条的原始轴的比例

缩小1.0;缩小颜色条的分数


1
如果我将收缩率1.0和分数设置为任何值,它将收缩图形,完全不影响颜色条的大小,直到改变分数使之完全等于我已经拥有的值为止,此时更改它们将停止执行任何操作。
Elliot

您确切在哪里指定它们,它们必须是colorbar()函数或方法的参数。
史蒂夫·巴恩斯

谢谢。只需指定收缩参数即可使用,就像魔术一样!
CodingNow19年

11

以上所有解决方案都是好的,但是我最喜欢@Steve和@bejota的解决方案,因为它们不涉及花哨的调用并且具有通用性。

通用的意思是适用于任何类型的轴,包括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之间的分数以获得最佳尺寸。但是,必须调整小数和paddig的值,以使其最适合您的绘图,并且根据颜色条的方向是垂直位置还是水平位置,它们的值将有所不同。


1
shrinkfraction与一起pad产生的效果不够理想时,我们也可以添加参数。
Fei Yao
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.