matplotlib具有Alpha的圆形补丁会产生边缘和面色的重叠

时间:2018-12-16 15:16:12

标签: python matplotlib

我通常对matplotlib和python还是陌生的,而我想做的是相当基本的。但是,即使经过了一段时间的搜寻,我仍然找不到解决方案:

问题出在这里

我想绘制一个边框和脸部颜色不同的圆,即分别设置edgecolorfacecolor。我还想拥有一个Alpha通道,即alpha=0.5。现在,尽管所有这些工作都很好,但是生成的圆圈确实没有使用单个边框颜色,但是绘制了2个边框。一种颜色是我为edgecolor指定的颜色,另一种颜色是我假设是edgecolor和facecolor之间的组合。

这是我的代码:

from matplotlib import pyplot as plt
point = (1.0, 1.0)
c = plt.Circle(point, 1, facecolor='green', edgecolor='orange', linewidth=15.0, alpha=0.5)
fig, ax = plt.subplots()
ax.add_artist(c)
plt.show()

这是一个例子:

circle with 2 border colors

好的,这可能是一件小事,但是第二个边界让我发疯了!

我做错什么了吗?就是这样吗?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

在某种程度上,是的,这就是事实。 关键是该边缘实际上是在圆的边缘上绘制的。 这意味着边缘宽度的一半绘制在圆的表面顶部,另一半绘制在外部。如果现在设置alpha<1.0,则可以正确地得出结论,即会看到面部颜色和边缘颜色的重叠。

但是,您可以摆脱“额外边界” 。以下是两种方法,哪种方法最适合您取决于您​​要做什么。

第一个建议

最简单的恕我直言,是仅为facecolor 设置Alpha。这可以通过直接设置facecolor的alpha通道并在调用alpha时省略Circle自变量来完成。您可以使用colorConverter设置Alpha通道:

from matplotlib.colors import colorConverter
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(8, 8))
ax.axis('equal')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
# Here you set alpha for the faceolor
fc = colorConverter.to_rgba('green', alpha=0.5)
point = (1.0, 1.0)
r = 1.0
lw = 15.0
ec = 'orange'
# NOTE: do not set alpha when calling Circle!
c = plt.Circle(point, r,fc=fc, ec=ec, lw=lw)
ax.add_artist(c)
plt.show()

enter image description here

第二个建议

更详细的选择是在仅绘制面部之后,仅绘制边缘,然后用白色边缘“擦拭”圆形的边缘。 通过这种方法,两种颜色都会在alpha通道中出现。但是请注意,在这种情况下,位于“边缘”下方的任何对象都将被边缘完全遮盖:

import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection

point = (1.0, 1.0)
r = 1.0
alpha = 0.5
lw = 15.0
fc = 'green'
ec = 'orange'
# First only draw the facecolor
c_face = plt.Circle(point, r, alpha=alpha, fc=fc, lw=0.0)
# Draw a non-transparent white edge to wipe the facecolor where they overlap
c_wipe = plt.Circle(point, r, alpha=1.0, ec='white', fc='none', lw=lw)
# Now draw only the edge
c_edge = plt.Circle(point, r, alpha=alpha, fc='none', ec=ec, lw=lw)
circle_patch = PatchCollection([c_face, c_wipe, c_edge], match_original=True)
fig, ax = plt.subplots(figsize=(8, 8))
ax.axis('equal')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax.add_artist(circle_patch)
plt.show()

enter image description here


Here is a gist根据第二个建议处理此问题。只需下载mod_patch.py文件就可以了。

这里是如何使用它:

import matplotlib.pyplot as plt
from mod_patch import get_Patch
fig, ax = plt.subplots(figsize=(8,8))
c = get_Patch(plt.Circle, (0,0.5), 0.5, facecolor='green', edgecolor='orange', alpha=0.5, lw=15)
ax.add_artist(c)
r = get_Patch(plt.Rectangle, (0.5,0), 0.5, 0.5, facecolor='green', edgecolor='orange', alpha=0.5, lw=15)
ax.add_artist(r)
plt.show()

enter image description here

为完整起见,这里get_Patch的定义:

from matplotlib.collections import PatchCollection


def get_Patch(a_Patch, *args, **kwargs):
    background_color = kwargs.pop(
        'bgc',
        kwargs.pop('background_color', 'white')
    )
    alpha = kwargs.get('alpha', 1.0)
    patches = []
    lw = kwargs.get('lw', kwargs.get('linewidth', 0.0))
    if alpha < 1.0 and lw:
        color = kwargs.get('c', kwargs.get('color', None))
        fc = kwargs.get('facecolor', kwargs.get('fc', None))
        ec = kwargs.get('edgecolor', kwargs.get('ec', None))
        face_kwargs = dict(kwargs)
        face_kwargs['fc'] = fc if fc is not None else color
        face_kwargs['lw'] = 0.0
        p_face = a_Patch(*args, **face_kwargs)
        patches.append(p_face)
        wipe_kwargs = dict(kwargs)
        wipe_kwargs['fc'] = 'none'
        wipe_kwargs['ec'] = background_color
        wipe_kwargs['alpha'] = 1.0
        p_wipe = a_Patch(*args, **wipe_kwargs)
        patches.append(p_wipe)
        edge_kwargs = dict(kwargs)
        edge_kwargs['fc'] = 'none'
        edge_kwargs['ec'] = ec if ec is not None else color
        p_edge = a_Patch(*args, **edge_kwargs)
        patches.append(p_edge)
    else:
        p_simple = a_Patch(*args, **kwargs)
        patches.append(p_simple)
    return PatchCollection(patches, match_original=True)