Matplotlib masking - 根据当前颜色值重置像素的 zorder?

Posted

技术标签:

【中文标题】Matplotlib masking - 根据当前颜色值重置像素的 zorder?【英文标题】:Matplotlib masking - Resetting the zorder of pixels depending on their current color value? 【发布时间】:2020-01-22 23:12:44 【问题描述】:

1) 我需要一个在 Matplotlib 中似乎不存在的屏蔽功能。 (如果不是这种情况,请告诉我)。

2) Matplotlib 具有裁剪功能,但“裁剪”出的区域使用相同的 zorder, 因此渲染几个重叠的多边形形状,应该根据它们的 zorder 看到 在使用剪裁来渲染其中一个的区域失败,因为我们之前在剪裁区域下方渲染的任何东西都被抹掉了(可以说是全白)。

3) 如果可以在渲染时随时“重置”给定像素颜色(我们的背景颜色)的 zorder,那么我们将解决裁剪问题。我们甚至不需要剪裁,因为我们可以对定义所需蒙版区域的部分使用给定的 zorder 值,为要剪裁的部分使用较低的 zorder,在渲染有问题的部分之后,我们更改所有的 zorder将“白色”像素设置为非常低的 zorder 值,并且我们的遮罩功能正在发挥作用!

这是一个非常简单的示例代码来说明需求:

'''Example of two overlapping squares having arbitrary openings in them.
In this example the opening is just two smaller overlapping square, but it can be anything.
We want to paint the green and red squares so that we see what is behind the opening(s)'''
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))

# This is to test if a well ordered polygon with slits (to define holes) can be rendered
quad_small = [(-0.2, -0.2), (-0.2, 0.2), (0.2, 0.2), (0.2, -0.2), (-0.2, -0.2)]
quad1x1 = [(-1, 1.), (-1, -1.), (1, -1.), (1., 1.), (-1, 1.)]

#Fill quad1x1 with green
x11 = [coord[0] for coord in quad1x1]
y11 = [coord[1] for coord in quad1x1]
plt.fill(x11, y11, facecolor='green', zorder=5)

'''Now make one or more holes, possibly overlapping holes, 
NOTE: if we use clipping to define the holes, Matplotlib sets the same zorder over all the clippped areas 
which was used. Also clipping does not work well with overlapping small squares. Would only work with nonoverlapping
squares.'''
xsq = [coord[0] for coord in quad_small]
ysq = [coord[1] for coord in quad_small]
plt.fill(xsq, ysq, facecolor='white', zorder=5)
xsq = [coord[0]+0.2 for coord in quad_small]
ysq = [coord[1]+0.2 for coord in quad_small]
plt.fill(xsq, ysq, facecolor='white', zorder=5)

'''At this point green and white openings have the same zorder=5.
We would need a call to change the zorder of all the 'white' pixels to a lower value, say 3'''

'''Now we want to render another polygon (red) with holes, but ONLY on areas not covered by the previous rendering,
we use a lower zorder so that we do not paint on the green part'''
x11 = [coord[0]+0.3 for coord in quad1x1]
y11 = [coord[1]+0.3 for coord in quad1x1]
plt.fill(x11, y11, facecolor='red', zorder=4)
xsq = [coord[0]+0.3 for coord in quad_small]
ysq = [coord[1]+0.3 for coord in quad_small]
plt.fill(xsq, ysq, facecolor='white', zorder=4)
xsq = [coord[0]+0.5 for coord in quad_small]
ysq = [coord[1]+0.5 for coord in quad_small]
plt.fill(xsq, ysq, facecolor='white', zorder=4)

'''The hole (white area) of the green square is not painted in red because the zorder of the white area is higher'''

plt.show()

Snapshot of the rendering produced by the code above

【问题讨论】:

我不明白这个问题。是否可以使用一些代码来展示您想要实现的目标,让每个人都能看到您面临的问题? 感谢您的兴趣/愿意提供帮助:如果我们有一个 10x10 的正方形,上面有多个可以重叠的任意孔。我们可以渲染 10x10 正方形,然后使用 zorder 制作任意孔,但是这样做时我们需要使用更高的 zorder,这会消除我们之前在 10x10 正方形以下渲染的所有内容。 如果您有一个 10 x 10 形状的图像,则其中的任何区域都可以显示或不显示。 Zorder 与此无关。所以我担心我仍然不明白这个问题。 对不起,按时间顺序的更好例子:如果我们有一个 10x10 的正方形,上面有多个任意孔,可能是重叠的孔。我们可以渲染 10x10 的正方形,然后使用更高的 zorder 来制作任意孔,或者使用相同的 zorder 和 Plotlib 裁剪。然而,现在我们有效地在(白色)区域(孔)中有一个 zorder,我们需要用渲染的下一部分覆盖它,但是我们不能为下一部分使用更高的 zorder,因为这样做会覆盖部分第一个带孔的 10x10 正方形。 为什么孔会有zorder?它们只是孔。我将重申,以代码的形式展示问题的示例可能是在这里推进的唯一方法。 【参考方案1】:

似乎甚至不需要剪辑;因为所有表面都是封闭的。

import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))


xi, yi = np.array([(-0.2, -0.2), (-0.2, 0.2), (0.2, 0.2), (0.2, -0.2), (-0.2, -0.2)]).T
xo, yo = np.array([(-1, 1.), (-1, -1.), (1, -1.), (1., 1.), (-1, 1.)]).T

plt.fill(list(xo)+list(xi), list(yo)+list(yi), facecolor='green', zorder=5)
plt.fill(list(xo+.3)+list(xi+.3), list(yo+.3)+list(yi+.3), facecolor='red', zorder=4)

plt.show()

【讨论】:

您使用了一个正方形来定义开口!尝试使用我在原始示例中使用的“重叠四边形”定义的孔,看看重叠的小四边形定义的区域会发生什么。 您需要帮助来定义两个重叠方块的路径吗?如果你想自动做,你也可以使用shapely并计算.union【参考方案2】:

上面提出的解决方案不起作用,因为它适用于单个不重叠的小四边形。当我们使用两个重叠的四边形时(对您的示例稍作修改):

import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))

xi, yi = np.array([(-0.2, -0.2), (-0.2, 0.2), (0.2, 0.2), (0.2, -0.2), (-0.2, -0.2)]).T
xo, yo = np.array([(-1, 1.), (-1, -1.), (1, -1.), (1., 1.), (-1, 1.)]).T

plt.fill(list(xo)+list(xi)+list(xi+0.1), list(yo)+list(yi)+list(yi+0.1), facecolor='green', zorder=5)
plt.fill(list(xo+.3)+list(xi+.3), list(yo+.3)+list(yi+.3), facecolor='red', zorder=4)

plt.show()

结果如图in this snapshot

此外,即使在您的示例中只有一个不重叠的小正方形,如果该正方形不完全“在”较大的多边形“内部”,则会出现如下所示的渲染问题:

mport numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))

xi, yi = np.array([(-0.2, -0.2), (-0.2, 0.2), (0.2, 0.2), (0.2, -0.2), (-0.2, -0.2)]).T
#xo, yo = np.array([(-1, 1.), (-1, -1.), (1, -1.), (1., 1.), (-1, 1.)]).T
xo, yo = np.array([(-.1, .1), (-1, -1.), (1, -1.), (1., 1.), (-.1, .1)]).T

#plt.fill(list(xo)+list(xi)+list(xi+0.1), list(yo)+list(yi)+list(yi+0.1), facecolor='green', zorder=5)
plt.fill(list(xo)+list(xi), list(yo)+list(yi), facecolor='green', zorder=5)
plt.fill(list(xo+.3)+list(xi+.3), list(yo+.3)+list(yi+.3), facecolor='red', zorder=4)

plt.show()

这是结果:Bad rendering when little square is partially outside

也许使用 Shapely union's 可以解决重叠小四边形的第一个问题,但是我们如何解决小四边形部分在外面的问题? 请告诉我什么最适合这种情况。

【讨论】:

以上是关于Matplotlib masking - 根据当前颜色值重置像素的 zorder?的主要内容,如果未能解决你的问题,请参考以下文章

图像语义分割出的json文件和原图,用plt绘制图像mask

一次绘制多条线,但都根据当前的循环器状态

Matplotlib:如何设置当前图形?

当我在 jupyter notebook 中使用 matplotlib 时,它总是引发“matplotlib 当前正在使用非 GUI 后端”错误?

Mask属性介绍

快速搭建部署网络PXE shell 脚本