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

Posted

技术标签:

【中文标题】设置 Matplotlib 颜色条大小以匹配图形【英文标题】:Set Matplotlib colorbar size to match graph 【发布时间】:2013-08-14 06:46:14 【问题描述】:

我无法让 imshow 图表上的颜色条与图表高度相同,事后没有使用 Photoshop。如何让高度匹配?

【问题讨论】:

你有没有尝试过***.com/questions/16702479/…的建议 @imjohns3 那篇文章似乎对彩条没有任何作用。无论我设置什么,它都保持相同的大小。但是,如果我设置分数并缩小,图表的大小会发生变化,而颜色条保持不变,直到我们回到我已经拥有的,然后他们停止做任何事情。 查看文档 -- matplotlib.org/api/colorbar_api.html -- 并使用 fractionshrink args。 【参考方案1】:

您可以使用 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)

【讨论】:

我不在子图内工作,所以这不适用。 这会稍微改变图表的大小。我在 2x2 网格中有 4 个,但只希望右边的两个有条(按行应用比例)。然而,这使得它们的大小不同。我尝试不使用颜色条调用(使用分隔符调用),但是当然这会在旁边留下一个空的白色框和数字。我如何让它们具有一致的尺寸而不在所有它们上放置条? @bogatron 不幸的是,这不适用于投影轴 如果你想用plt.title添加一个标题,它将显示在右边。有没有办法克服这个问题? @user2820579,您可以在添加颜色条之前调用plt.title。这将使标题至少以主要人物为中心......【参考方案2】:

当您创建 colorbar 时,请尝试使用分数和/或收缩参数。

来自文档:

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

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

【讨论】:

如果我将收缩 1.0 和分数设置为任何值,它会缩小图形,根本不会影响颜色条的大小,直到更改分数导致它完全是我已经拥有的,此时更改它们会停止做任何事。 您具体在哪里指定它们,它们必须是colorbar() 函数或方法的参数。 谢谢。只需要指定收缩参数,它就像魔术一样工作!【参考方案3】:

这种组合(以及接近这些的值)似乎“神奇地”让我保持颜色条按比例缩放到绘图,无论显示器大小。

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

它也不需要共享可以使绘图不方形的轴。

【讨论】:

这在某些情况下可能会起作用,但通常不会。例如,尝试绘制类似于原始问题中的内容,其宽度是高度的两倍。 分数选项在您提到的情况下似乎仍然有效,如果缩放以匹配绘图的高度。 (mpl v1.4.3) 这是唯一通用的方法。 axex_grid1 的解决方案不适用于 GeoAxes 等投影轴。 回应@Matthias 评论。您可以使用以下技巧纠正图像过宽的情况:im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04) 其中data 是您的图像。 shrink 关键字参数,默认为1.0,也可能对进一步微调有用。我发现shrink=0.9 在我有两个并排的方形子图时帮助得到了它。【参考方案4】:

@bogatron 已经给出了matplotlib docs 建议的答案,它产生了正确的高度,但它引入了一个不同的问题。 现在颜色条的宽度(以及颜色条和绘图之间的空间)随着绘图的宽度而变化。 也就是说,颜色条的纵横比不再是固定的了。

要获得正确的高度给定的纵横比,您必须深入挖掘神秘的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)

请注意,这指定了颜色条 w.r.t 的 宽度。图的 height(与之前的图的 width 形成对比)。

现在可以将颜色条和绘图之间的间距指定为颜色条宽度的一部分,恕我直言,这是一个比图形宽度的一部分更有意义的数字。

更新:

我创建了an IPython notebook on the topic,将上面的代码打包成一个易于重用的函数:

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)

【讨论】:

这是一个非常有用的小功能!一个警告是当你想添加多个颜色条时它不起作用,因为它们会出现在彼此的顶部。【参考方案5】:

上述所有解决方案都很好,但我最喜欢@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 的分数以获得最佳尺寸。但是,fraction 和 paddig 的值需要进行调整以最适合您的绘图,并且会根据颜色条的方向是垂直位置还是水平位置而有所不同。

【讨论】:

fractionpad 不能产生足够的结果时,我们也可以添加shrink 参数。 最简洁的答案。【参考方案6】:

感谢以上所有答案。但是,就像一些答案和 cmets 指出的那样,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 official documentation 也提供了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)

结果

【讨论】:

真的很棒的答案。谢谢!! 这是我发现的唯一有效的答案!我发现的所有其他问题似乎可以解决每个人的颜色条大小问题,但对我不起作用。在我的情况下,情节太长,颜色条太短。这解决了它。谢谢! 非常适合我,我只是想知道如何让它在全屏图像上正常工作。【参考方案7】:

另一种选择是

shrink=0.7, aspect=20*0.7

shrink 缩放高度和宽度,但 aspect 参数恢复原始宽度。默认纵横比为 20。0.7 是凭经验确定的。

【讨论】:

这是我的单曲最快的罗马之路,我很感激!

以上是关于设置 Matplotlib 颜色条大小以匹配图形的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 Matplotlib 中颜色条刻度标签的字体大小?

Matplotlib:quiver 和 imshow 叠加,如何设置两个颜色条?

从 matplotlib 中的图形中删除颜色条

如何从matplotlib中的图形中检索颜色条实例

在 matplotlib 中更改颜色条的字体大小

如何使用 Matplotlib 设置图形背景颜色的不透明度