在圆弧补丁之间填充-Matplotlib

时间:2019-10-07 04:40:09

标签: python matplotlib fill

我有一个ellipse,我想用不同部分的颜色固定 fill。为此,我使用了arcs补丁。我目前正在绘制多个arcs,并使用zorder覆盖适当的arcs

主要问题是我无法固定填充arc补丁,并且它们不能整齐地填充ellipse如果这些区域也没有重叠,那就太好了。我可以使用透明度参数。

import matplotlib.pyplot as plt
import matplotlib as mpl
import math

fig, ax = plt.subplots(figsize = (8,5))
ax.grid(False)

ax.set_xlim(-85,85)
ax.set_ylim(-70,70)

Arc1_xy = -68, 0
Arc2_xy = -48,0
Arc3_xy = 15, 0

Arc4_xy = 68, 0
Arc5_xy = 48,0
Arc6_xy = -15, 0

E_xy = 0,0

angle = math.degrees(math.acos(2/9.15))

Arc1 = mpl.patches.Arc(Arc1_xy, 75, 92, angle = 360, theta2 = angle, theta1 = 360-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 3)
Arc2 = mpl.patches.Arc(Arc2_xy, 64, 94, angle = 180, theta2 = angle, theta1 = 360-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 3)
Arc3 = mpl.patches.Arc(Arc3_xy, 190, 132, angle = -180, theta2 = angle, theta1 = 360-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 1)

Arc4 = mpl.patches.Arc(Arc4_xy, 75, 92, angle = 180, theta2 = angle, theta1 = 360-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 3)
Arc5 = mpl.patches.Arc(Arc5_xy, 64, 94, angle = 0, theta2 = angle, theta1 = 0-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 3)
Arc6 = mpl.patches.Arc(Arc6_xy, 190, 132, angle = 360, theta2 = angle, theta1 = 360-angle, color = 'w', lw = 1, alpha = 1, hatch = 'oooooo', zorder = 1)

Ellipse = mpl.patches.Ellipse(E_xy, 160, 130, lw = 1, color = 'white', alpha = 1, fill = False)

ax.add_patch(Arc1)
ax.add_patch(Arc2)
ax.add_patch(Arc3)
ax.add_patch(Arc4)
ax.add_patch(Arc5)
ax.add_patch(Arc6)

ax.add_patch(Ellipse)

Arc1.set_color('green')
Arc2.set_color('green')
Arc3.set_color('blue')  
Arc4.set_color('red')
Arc5.set_color('red')
Arc6.set_color('purple')   

主要问题是我想固定填充ellipse中不同颜色的部分。理想情况下,这些部分不会重叠,因此我可以使用alpha。同样,arcs也不完全适合ellipse

1 个答案:

答案 0 :(得分:1)

您的问题不是很清楚。这是您代码的更新版本:

# EDITED, see below

Arc4填充椭圆的另一侧。是您所期望的吗?

我还添加了一个有关如何使用颜色图的示例。 range of colormaps范围很广, 其中许多的范围是0到255(您可以将其归一化为0.0-1.0)。

另一种解决方案是绘制重叠的椭圆,并使用clip_path属性仅显示所需的部分。


评论后编辑

要完美地拟合椭圆,您必须计算出适合其的圆弧,这可能很困难(也许有一些不错的数学技巧可以实现,但这是我所不知道的)。因此,我最好的选择是绘制相同大小的多个椭圆并使用剪切路径。

import matplotlib.pyplot as plt
import matplotlib as mpl

def main():
    fig, ax = plt.subplots(figsize = (8,5))
    ax.grid(False)
    ax.set_xlim(-80,80)
    ax.set_ylim(-70,70)

    Arc1_xy = -68, 0
    Arc3_xy = 15, 0
    E_xy = 0,0

    # Use a predefined colormap
    colormap = plt.cm.get_cmap("Set1")

    # Draw multiple ellipses with different colors and hatching style. All are perfectly superposed
    ellipse = mpl.patches.Ellipse( # Base one, with big black line for reference, in background (zorder=0)
        E_xy, 160, 130,
        lw = 2, color = 'k', fill=False, zorder=0)
    area1 = mpl.patches.Ellipse( # A second one, above the base one, using a color from colormap
        E_xy, 160, 130,
        lw=1,  # Just to highlight that we perfectly fit the base ellipse
        color = colormap(0), hatch='o', fill=False, zorder=1)
    area2 = mpl.patches.Ellipse( # Third one, above the others
        E_xy, 160, 130,
        lw=1,  # Just to highlight that we perfectly fit the base ellipse
        color = colormap(1), hatch='..', fill=False, zorder=2)
    # Add more if you want more "sub-areas" in your base ellipse

    # Define some clipping paths
    clip1 = mpl.patches.Ellipse(
        Arc1_xy, 75, 92,
        fill=False,
        ls=":"  # Just to highlight it but you should remove it
        # visible=False  # We do not need to display it, just to use it for clipping
    )
    clip2 = mpl.patches.Ellipse(
        Arc3_xy, 190, 132, angle = -180,
        fill=False,
        ls=":"  # Just to highlight it but you should remove it
        # visible=False  # We do not need to display it, just to use it for clipping
    )

    # Add all your components to your axe
    ax.add_patch(ellipse)
    ax.add_patch(area1)
    ax.add_patch(area2)
    ax.add_patch(clip1)
    ax.add_patch(clip2)

    # Clip the sub-areas with your clipping paths
    area1.set_clip_path(clip2)
    area2.set_clip_path(clip1)

    plt.show()

if __name__ == '__main__':
    main()

这将吸引您:

  • 一条大的黑色椭圆线(基本椭圆)
  • 两个椭圆形阴影区域(一个带点,一个带圆圈)内部基本椭圆
  • 细虚线,概述了剪切路径

Rendering of the above code

您说要“固定填充椭圆。不使用色块”。要实心填充,只需使用您所在区域的fillcolor参数即可(如果不需要,请删除hatch)。但是,我看不到没有“补丁”如何可以实现想要的目标。抱歉。

希望获得帮助。


编辑2

经过澄清后,这里是一个新版本:

import math

import matplotlib.pyplot as plt
import matplotlib as mpl


def main():
    fig, ax = plt.subplots(figsize=(8, 5))
    ax.grid(False)
    ax.set_xlim(-85, 85)
    ax.set_ylim(-70, 70)

    Arc1_xy = -68, 0
    E_xy = 0, 0

    # Use a predefined colormap
    colormap = plt.cm.get_cmap("Set1")

    # Draw multiple ellipses with different colors and style. All are perfectly superposed
    ellipse = mpl.patches.Ellipse(  # Base one, with big black line for reference
        E_xy, 160, 130,
        lw=2, color='k', fill=False, zorder=100)
    # Ellipses for your sub-areas.
    # Add more if you want more areas
    # Apply the style of your areas here (colors, alpha, hatch, etc.)
    areas = [
        mpl.patches.Ellipse(
            E_xy, 160, 130,  # Perfectly fit your base ellipse
            color=colormap(i), fill=True, alpha=0.5,  # Add some style, fill, color, alpha
            zorder=i)
        for i in range(4)  # Here, we have 4 areas
    ]

    # Define some clipping paths
    # One for each area
    clips = [
        mpl.patches.Arc(  # One covering right half of your ellipse
            E_xy, 160, 130, theta1=-90, theta2=90,
            visible=False  # We do not need to display it, just to use it for clipping
        ),
        mpl.patches.Arc(  # One covering left half of your ellipse
            tuple([-x for x in E_xy]), 160, 130, theta1=90, theta2=-90,
            visible=False  # We do not need to display it, just to use it for clipping
        ),
        mpl.patches.Ellipse(  # A small area on the left
            Arc1_xy, 75, 92,
            visible=False  # We do not need to display it, just to use it for clipping
        ),
        mpl.patches.Ellipse(  # A small area on the right
            tuple([-x for x in Arc1_xy]), 75, 92,
            visible=False  # We do not need to display it, just to use it for clipping
        )
    ]

    # Add all your components to your axe
    ax.add_patch(ellipse)
    for area, clip in zip(areas, clips):
        ax.add_patch(area)
        ax.add_patch(clip)
        area.set_clip_path(clip)  # Use clipping paths to clip you areas

    plt.show()


if __name__ == '__main__':
    main()

和生成的图像: Rendering of the above code

它是如何工作的:

  • 绘制多个完全与“基本”椭圆重叠的椭圆。这样可以确保您所有的区域都完全适合内部基础椭圆(没有一个可以扩展)
  • 通过定义剪切路径来裁剪/剪切椭圆以仅显示其中的一部分。这些剪切路径必须穿过(或至少遵循)基本椭圆边框以使其充满(这就是为什么我使用椭圆的中心和尺寸来更改您的Arc3的原因,否则椭圆内的边框,如第一个图所示。

您最近一次尝试并没有那么远。要为您的区域设置样式,您必须将样式应用于基本椭圆(在我的代码的areas列表中列出),而不是在剪切路径(在我的代码的clips列表中列出)中应用。 areasclips这两个列表的长度必须相同!如果您想在椭圆中添加更多子区域,则可以自行决定添加更多区域和更多剪切路径。

顺便说一句,我看到了您更新的问题和您对使区域不重叠的要求。这将需要更多的工作。您可以使用matplotlip.path模块通过构建更复杂的剪切路径来实现。