【问题标题】:matplotlib Circle patch with alpha produces overlap of edge and facecolor带 alpha 的 matplotlib Circle 补丁产生边缘和 facecolor 的重叠
【发布时间】:2020-01-30 17:24:42
【问题描述】:

总的来说,我对 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()

这是一个插图:

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

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

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    在某种程度上,是的,就是这样。 关键是边缘实际上是在圆的边缘上绘制的。 这意味着边缘宽度的一半绘制在圆面的顶部,另一半绘制在外面。如果现在您设置alpha<1.0,您会看到,正如您正确得出的结论,facecolor 和 edgecolor 重叠。

    但是,您可以摆脱“额外边框”。以下是 2 种方法,哪一种最适合您,具体取决于您想要做什么。

    第一个建议

    恕我直言,最简单的方法是只为 facecolor 设置 alpha。这可以通过直接为facecolor 设置alpha 通道并在Circle 的调用中省略alpha 参数来完成。您可以使用 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()
    

    第二条建议

    更详细的选项是在仅绘制面部后用白色边缘“擦除”圆的边缘,然后仅绘制边缘。 通过这种方法,两种颜色都出现在 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()
    


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

    为了完整起见,这里定义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)
    

    【讨论】:

    • 哇,太快了!这已经不那么令人不安了,但现在边缘颜色与alpha=0.5 版本明显不同。有没有办法解决这个问题?
    • 杰普来了!嗯,有点。给我一点我正在写的...... :)
    • 这太完美了!但是告诉我,不是 matplotlib 向导的人怎么会知道这些事情?!
    • =) 哈,我不是 matplotlib 向导!我同意 matplotlib 不是最直接的使用方法。就个人而言,我使用一个小脚本来创建那些额外的补丁,我将把它作为一个要点放在 github 上并将链接放在这里。
    • @ImportanceOfBeingErnest 你是对的!增加了get_Patch的定义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    • 1970-01-01
    • 2017-01-06
    • 2019-07-03
    • 2021-11-25
    • 1970-01-01
    相关资源
    最近更新 更多