【问题标题】:Colorbar frame and color not aligned颜色栏框架和颜色未对齐
【发布时间】:2017-03-14 23:23:47
【问题描述】:

我对颜色条有一个令人烦恼的问题,即使经过深入研究,我什至找不到问题。我有一个图,其中我覆盖了一个轮廓和一个 pcolormesh,我想要一个颜色条来指示值。这很好用,除了一件事: The colorbar frame and color are offset

颜色条框架和实际条是偏移的,因此在框架下方有一个白色位,在顶部颜色突出。当框架根据需要与轴对齐时,颜色条会发生偏移。

这是一个模拟我所处情况的工作示例,即带有插图的多个图。

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

如果选择了“内联”图形后端,则内联显示和保存的 .pdf 中仍然存在问题。是否使用紧密布局会根据条的大小改变偏移的严重程度——与使用 PyQT5 而不是内联图形后端相同。当我在各种组合之间切换时,我以为它已经消失了,但我才意识到它仍然存在。

如有任何意见,我将不胜感激。


正如 ImportanceOfBeingErnest 所建议的那样,我尝试在 figsize 上使用 np.round 并没有改变任何事情。虽然您可以摆弄尺寸以使其看起来不错,但它总是在某一侧或另一侧突出一些。当我将 Spyder 3 上的图形后端从“内联”更改为“QT5”时,无论是否舍入,问题都会变得不那么严重。这张图片Colorbar overlap cases对此进行了总结。请注意,在不四舍五入和 PyQT5 的情况下,问题仍然存在,但没有那么严重。

【问题讨论】:

标签: matplotlib alignment colorbar


【解决方案1】:

首先,一种覆盖轮廓和 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()

现在从问题开始。当然可以创建轴以手动放置颜色条。用问题中的代码替换颜色条创建仍然会产生漂亮的图像。

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

到目前为止的结论:这个问题是不可重现的,至少没有Minimal, Complete, and Verifiable example


我不确定问题示例中行为的原因。但是,似乎可以通过将数字大小四舍五入到 3 个有效数字来克服

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

【讨论】:

  • 我已经提供了上述示例并添加了更多细节。
  • @Christian 编辑了答案。你能验证一下吗?
  • 不,还是一样。您可能会偶然遇到一些使它看起来不错的颜色条大小值,但是如果您更改它,我总能找到一些值,它位于一侧或另一侧的条上方 - 包括圆形无花果大小。
  • 你能举个例子说明它不起作用的值吗?
【解决方案2】:

经过检查,很明显,颜色条不仅在其轴的顶部溢出,而且还略微位于左侧。 因此,这里的问题似乎是当光栅化发生时颜色条轴的位置和颜色条本身之间的冲突。您可以在此issue in matplotlib's github repository 上找到更多详细信息,但我将在这里总结一下发生了什么。

颜色条在生成输出时被光栅化,以避免在渲染过程中出现伪影问题。在光栅化过程中,颜色条的位置被捕捉到最近的整数像素,而轴保持在它应该在的位置。然后,当产生输出时,颜色条落在图像固定像素的边界内,尽管图像本身是矢量化的。因此,可以采用两种策略来避免这种事故。

使用更精细的 DPI

从矢量化坐标到光栅化坐标的转换是在假设图像上具有给定 DPI 的情况下进行的。默认情况下,该值设置为 72。但是,通过使用更多 DPI,由光栅化过程引起的整体偏移将更小,因为颜色条将捕捉到的最近像素将更接近。在这里,我们将输出更改为fig.savefig(plot,dpi=4000),问题就消失了: 但是请注意,在我的机器上,由于这种变化,输出大小从 62 KB 变为 78 KB(尽管 DPI 调整也是,无可否认,极端)。如果您担心文件大小,您应该选择一个较低的 DPI 来解决问题。

使用不同的颜色图

当颜色栏中的颜色超过 50 种时,就会发生这种光栅化。因此,我们可以做一个快速测试,将我们的颜色图设置为Pastel1 via im = ax2.pcolormesh(z,cmap='Pastel1')。在这里,颜色条/轴不匹配得到了缓解。

作为后备方案,采用少于 50 种颜色的颜色条应该可以缓解此问题。

光栅化轴

为了完整起见,还有第三种选择。如果您栅格化颜色条轴,轴边界和颜色图都将被栅格化,并且您将丢失偏移量。这也将光栅化您的标签,并且轴将移动为一个,从而破坏与附近轴的对齐。为此,您只需要包含cbar_axis.set_rasterized(True)

【讨论】:

  • 可能还有第三种选择,使用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 重置为播放更好的东西使用整数捕捉,但我无法完全解决。
猜你喜欢
  • 1970-01-01
  • 2013-09-06
  • 2017-09-12
  • 1970-01-01
  • 2015-09-18
  • 1970-01-01
  • 2016-02-11
  • 2017-01-22
  • 1970-01-01
相关资源
最近更新 更多