在圆弧补丁之间填充-Matplotlib [英] Fill between arc patches - Matplotlib

查看:62
本文介绍了在圆弧补丁之间填充-Matplotlib的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个椭圆,我想用不同部分的颜色 solid 填充.为此,我使用了 arcs 补丁.我目前正在绘制多个 arcs ,并使用 zorder 重叠相应的 arcs .

主要问题是我无法固定填充 arc 补丁,并且它们不能整齐地填充 ellipse .也不重叠,所以我可以使用透明度参数.

 将matplotlib.pyplot导入为plt将matplotlib导入为mpl导入数学无花果,ax = plt.subplots(figsize =(8,5))ax.grid(假)ax.set_xlim(-85,85)ax.set_ylim(-70,70)Arc1_xy = -68,0Arc2_xy = -48,0Arc3_xy = 15,0Arc4_xy = 68,0Arc5_xy = 48,0Arc6_xy = -15,0E_xy = 0,0角度=数学度(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)椭圆= mpl.patches.Ellipse(E_xy,160,130,lw = 1,颜色='白色',alpha = 1,填充= 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(椭圆)Arc1.set_color('绿色')Arc2.set_color('绿色')Arc3.set_color('blue')Arc4.set_color('红色')Arc5.set_color('红色')Arc6.set_color('紫色') 

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

解决方案

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

 <代码>#已编辑,请参见下文 

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

我还添加了一个有关如何使用颜色图的示例.有各种各样的

您说要固定填充椭圆.不使用色块".要进行实心填充,只需使用您所在区域的 fill color 参数(如果不需要,请删除 hatch ).但是,我看不出没有补丁"如何可以实现想要的目标.抱歉.

希望获得帮助.


编辑2

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

 导入数学导入matplotlib.pyplot作为plt将matplotlib导入为mpldef main():无花果,ax = plt.subplots(figsize =(8,5))ax.grid(假)ax.set_xlim(-85,85)ax.set_ylim(-70,70)Arc1_xy = -68,0E_xy = 0,0#使用预定义的颜色图colormap = plt.cm.get_cmap("Set1")#绘制多个具有不同颜色和样式的椭圆.一切都完美地叠加ellipse = mpl.patches.Ellipse(#基数一,黑线较大,仅供参考E_xy,160、130,lw = 2,颜色='k',填充=否,zorder = 100)#椭圆表示您的子区域.#如果需要更多区域,请添加更多#在此处应用您所在区域的样式(颜色,alpha,阴影线等)面积= [mpl.patches.Ellipse(E_xy,160、130,#非常适合您的基本椭圆color = colormap(i),fill = True,alpha = 0.5,#添加一些样式,填充,颜色,alphazorder = i)因为我的范围是(4)#在这里,我们有4个区域]#定义一些剪切路径#每个区域一个剪辑= [mpl.patches.Arc(#一个覆盖椭圆的右半部分E_xy,160、130,theta1 = -90,theta2 = 90,visible = False#我们不需要显示它,只需将其用于剪切),mpl.patches.Arc(#一个覆盖椭圆的左半部分元组([-x for E_xy中的x]]),160、130,theta1 = 90,theta2 = -90,visible = False#我们不需要显示它,只需将其用于剪切),mpl.patches.Ellipse(#左侧的一个小区域Arc1_xy,75、92,visible = False#我们不需要显示它,只需将其用于剪切),mpl.patches.Ellipse(#右边的一个小区域元组([-x for Arc1_xy中的x]],75、92,visible = False#我们不需要显示它,只需将其用于剪切)]#将所有组件添加到斧头中ax.add_patch(椭圆)对于区域,用zip夹(区域,剪辑):ax.add_patch(区域)ax.add_patch(剪辑)area.set_clip_path(clip)#使用剪切路径剪切区域plt.show()如果__name__ =='__main__':主要的() 

和生成的图像:

它是如何工作的:

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

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

顺便说一句,我看到了您更新的问题和您对使区域不重叠的要求.这将需要更多的工作.您可以使用 matplotlip.path 模块.

I have an ellipse that I want to solid fill with colors in different sections. To achieve this I'm using arcs patches. I'm currently drawing multiple arcs and using zorder to overlap the appropriate arcs.

Main issues are that I cannot solid fill arc patches and they are not neatly filling the ellipse. It would be great if the areas didn't overlap either so I could use transparency parameters.

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

The main issues are I want to solid fill the different colored sections within the ellipse. Ideally the sections would not overlap so I could use alpha. Also the arcs don't neatly fit within the ellipse.

解决方案

Your question is not very clear. Here is an updated version of your code:

# EDITED, see below

The Arc4 fills the other side of the ellipse. Is it what you expected?

I also added an example on how to use a colormap. There is wide range of colormaps, many of them ranging from 0 to 255 (up to you to normalize to 0.0-1.0).

Another solution could be to draw overlapping ellipses and use the clip_path attribute to only show the required part.


Edit after comment

To fit perfectly the ellipse you have to calculate you arcs to fit it, which is probably difficult (maybe some nice math tricks allow it, but it is out of my knowledge). So my best bet is to draw multiple ellipses of the same size and use clipping paths.

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

This will draw you:

  • A big black elliptic line (the base ellipse)
  • Two hatched (one with dots, one with circles) sub-area inside your base ellipse
  • Thin dotted lines, outlining your clipping paths

You say that you want to "solid fill the ellipse. Not use patch". To solid fill, just play with the fill and color arguments of your areas (and remove hatch if you don't want it). However, I don't see how you can achieve what you want without "patch". Sorry.

Hope this help.


Edit 2

After clarifications here is a new version:

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

And the resulting image:

How does it works is:

  • by drawing multiple ellipses perfectly superposed to the "base" one. This make sure that all your areas are perfectly fitted inside your base ellipse (none of them can outreach)
  • by defining clipping paths that will crop/clip the ellipses to just show part of them. These clipping paths have to cross (or at least follow) the base ellipse borders to make it filled (that's why I change your Arc3, using the ellipse center and dimensions, else there was a white space on the border, inside the ellipse, as you can see on the first figure).

You were not so far with your last try. To style your areas, you have to apply style to your base ellipses (listed in the areas list in my code), not to your clipping paths (listed in the clips list in my code). Both lists, areas and clips need to have the same length! Up to you to add more areas and more clipping paths if you want more sub-areas in your ellipses.

By the way, I see your updated question and your requirements to make the areas not overlapping. This will require more work. You can achieve it by building more complicated clipping path, using the matplotlip.path module.

这篇关于在圆弧补丁之间填充-Matplotlib的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆