颜色条框架和颜色不对齐

3
我有一个令人困扰的问题,与颜色条有关,即使经过了大量的研究,我也找不到相关问题。我有一个绘图,我在上面叠加了等高线和pcolormesh,并且我想要一个颜色条来指示值。这很好地工作,除了一件事: 颜色条框架和颜色偏移
颜色条框架和实际的条之间存在偏移,因此在下面有一个白色的部分在框架中,而在上面颜色则突出。虽然框架与轴对齐,但颜色条却偏移了。
以下是一个可以模拟我所遇到情况的工作示例,即具有插图的多个绘图。
import matplotlib.gridspec as gridspec
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

figheight = 4.2 - (2.1 - 49.519 / 25.4)
matplotlib.rcParams['figure.figsize'] = (5.25, figheight)
matplotlib.rcParams['axes.linewidth'] = 0.5

fig = plt.figure()
grid = gridspec.GridSpec(2, 1, height_ratios=[49.519 / 25.4 / figheight, 2.1 / figheight])
ax0 = plt.subplot(grid[0, 0])
ax1 = plt.subplot(grid[1, 0])

plt.tight_layout()

###############################################################################################
#
#           Define position of inset
#
    ###############################################################################################

ax1.axis('off')
pos1 = ax1.get_position()
pos2 = matplotlib.transforms.Bbox([[pos1.x0, pos1.y0],
                                    [.8*pos1.x1,
                                     0.8*pos1.height + pos1.y0]])
left, bottom, width, height = [pos2.x0, pos2.y0, pos2.width, pos2.height]

ax2 = fig.add_axes([left, bottom, width, height])

###############################################################################################
#
#           ax2 (inset) plot
#
###############################################################################################

pos2 = ax2.get_position()
ax2.axis('on')

x = np.linspace(0,5)
z = (np.outer(np.sin(x), np.cos(x))+1)*0.5

im = ax2.pcolormesh(z)
c  = ax2.contour(z, linewidths=7)

ax2pos = ax2.get_position()

cbar_axis = fig.add_axes([ax2pos.x1+0.05,ax2pos.y0, .02, ax2pos.height])
colorbar = fig.colorbar(im, ax = ax2,
                    cax = cbar_axis, ticks = [0.1, .5, .9])
colorbar.outline.set_visible(True)

plot = 'Minimal.pdf'

fig.savefig(plot)

plt.close()

如果选择“Inline”图形后端,则问题会在内联显示和保存的.pdf中持续存在。使用紧密布局或不使用取决于柱状图的大小,使用PyQT5而不是内联图形后端也是如此。我原以为在更改各种组合时已经解决了它,但我刚意识到它仍然存在。
我将感激任何建议。

根据ImportanceOfBeingErnest的建议,我尝试在figsize上使用np.round,但这并没有改变什么。虽然你可以调整大小使其看起来还不错,但它总是在某一侧或另一侧超出一定量。当我将Spyder 3的图形后端从“Inline”更改为“QT5”时,无论是否取整,问题都会变得不那么严重。这个问题的摘要在这张图片中Colorbar overlap cases。请注意,对于未取整和PyQT5,问题仍然存在,但不如之前严重。


尝试使用 tight_layout(),至少它可以简化色条的定位(参见最后一个例子)。不确定偏移量,但您可以尝试使用 更粗的线宽 来掩盖它(我知道这不是理想的解决方案)。 - berna1111
为了进一步帮助您,您需要提供一个 [mcve]。这种情况只发生在显示时还是只发生在保存时或两种情况都有?我怀疑可能是什么原因导致的,但由于我无法重现这个问题,所以我无法测试这个怀疑是否正确。 - ImportanceOfBeingErnest
由于我还没有足够的声望,无法上传超过2个链接:[3]: https://i.stack.imgur.com/Px5pB.png [4]: https://i.stack.imgur.com/xO8An.png - Christian
2个回答

2
检查后发现,颜色条不仅在其轴线上方溢出,而且还略微向左偏移。 原始问题,显示颜色条的溢出 因此,这里的问题似乎是当光栅化发生时,颜色条轴的位置与颜色条本身之间存在冲突。您可以在matplotlib的GitHub存储库中找到更多详细信息,但我会总结一下这里正在发生的事情。
颜色条在生成输出时进行光栅化,以避免渲染过程中的伪影问题。在光栅化过程中,颜色条的位置被捕捉到最近的整数像素,而轴保持在它应该在的位置。然后,当输出产生时,颜色条落在图像固定像素边界内,尽管图像本身是矢量化的。因此,有两种策略可用于避免这种意外事件。

使用更精细的DPI

将向量化坐标转换为光栅化坐标时,假定图像具有给定的DPI。默认情况下,此值设置为72。但是,通过使用更高的DPI,由光栅化过程引起的整体偏移将会更小,因为色条最接近的像素将更加接近。在这里,我们将输出更改为 fig.savefig(plot,dpi=4000),问题就解决了: A close look at the edge of the colorbar, showing that it is well contained within the axis bounds 但是请注意,在我的计算机上,由于这个更改,输出大小从62 KB变为78 KB(尽管DPI调整也是极端的)。如果您担心文件大小,应选择较低的DPI以解决问题。

使用不同的颜色映射

当色条中有超过50种颜色时,就会进行栅格化。因此,我们可以进行快速测试,通过将我们的色图设置为“Pastel1”来缓解颜色条/轴不匹配问题,即im = ax2.pcolormesh(z,cmap='Pastel1')

The colorbar with a colormap of Pastel1; despite no other changes, the mismatch has been rectified.

作为备选方案,采用少于50种颜色的色条应该可以减轻这个问题。
栅格化轴
为了完整起见,还有第三个选项。如果将色条轴栅格化,轴边界和颜色映射都会被栅格化,偏移量也会丢失。这也会栅格化您的标签,并且轴将作为一个整体移动,与附近的轴不对齐。为此,您只需要包括cbar_axis.set_rasterized(True)即可。色条已经被栅格化,解决了问题,但随后产生了栅格化问题。

1
可能还有第三种选择,使用“cbar_pos = cbar_axis.get_position()”获取轴位置值,“new_cbar_bbox = matplotlib.transforms.Bbox.from_extents([new_x0,new_y0,new_x1,new_y1])”创建一个新的Bbox,并使用“cbar_axis.set_position(new_cbar_bbox)”将颜色条轴Bbox重置为与整数捕捉更加协调的内容,但我无法完全使其正常工作。 - Tom

0

首先,将轮廓和pcolormesh叠加并创建一个色条的方法如下:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

x = np.linspace(0,5)
z = (np.outer(np.sin(x), np.cos(x))+1)*0.5

fig = plt.figure(figsize=(4, 4))
ax = fig.add_subplot(111)
im = ax.pcolormesh(z)
c  = ax.contour(z, linewidths=7)

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", "5%", pad="3%")
colorbar = fig.colorbar(im, cax=cax, ticks = [0.1, .5, .9])

plt.show()

enter image description here

现在来讨论一下问题。当然可以手动创建轴来放置色条。用问题中的代码替换创建色条的代码,仍然会生成一个很好的图像。
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0,5)
z = (np.outer(np.sin(x), np.cos(x))+1)*0.5

fig = plt.figure(figsize=(4, 4))
ax = fig.add_subplot(111)
plt.subplots_adjust(right=0.8)
im = ax.pcolormesh(z)
c  = ax.contour(z, linewidths=7)

ax2pos = ax.get_position()

cbar_axis = fig.add_axes([ax2pos.x1+0.05,ax2pos.y0, .05, ax2pos.height])
colorbar = fig.colorbar(im, ax = ax,
                    cax = cbar_axis, ticks = [0.1, .5, .9])
colorbar.outline.set_visible(True)
plt.show()

enter image description here

目前为止的结论是:这个问题无法重现,至少没有提供最小、完整和可验证的示例


我对问题中的行为原因感到不确定。然而,似乎可以通过将图形大小四舍五入到3个有效数字来克服这个问题。

matplotlib.rcParams['figure.figsize'] = (5.25, np.round(figheight,3))

我已经提供了示例并添加了更多细节。 - Christian
@Christian编辑了答案。你能确认一下吗? - ImportanceOfBeingErnest
不,还是一样的。你可能偶然找到一些颜色条大小值,使其看起来还好,但如果你改变它,我总能找到某个值,在其中一个或另一个侧面上超过了条 - 包括圆形图大小。 - Christian
你能举个它不起作用的值的例子吗? - ImportanceOfBeingErnest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接