【问题标题】:How to access the properties of one specific patch from subplot in matplotlib如何从 matplotlib 的子图中访问一个特定补丁的属性
【发布时间】:2019-12-09 05:30:19
【问题描述】:

我遇到了一个关于如何从子图轴检索特定补丁对象的问题。 例如,我创建了一个包含许多补丁的子图。函数中的多边形对象(我为每个对象分配了不同的标签)。在我通过 add_subplot 将此子图添加到图形后,我似乎无法访问这些补丁。我在子图中创建的多边形对象。 我知道我可以使用 findobj() 方法获取对象,但是,它只返回对象的类型及其内存地址。我可以更改所有对象的 facecolor,但我真正需要的是通过名称或标签访问一个特定对象,例如更改一个色块的颜色。Ploygon 而不是所有色块。 如果有人知道如何实现这一点,我将不胜感激。我的脚本附在下面。

import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.gridspec as gridspec
import numpy as np


def drawEI(ax) :
    # draw Endcap
    x0 = np.array([0.5, 0.5, 0.5, 0.5])
    y0 = np.array([0.5, 0.5, 0.5, 0.5])

    step = 0.08

    xy = np.zeros((2, 4))
    print(xy)
    # theta = [for i in range(16) : ]
    theta = [345, 15, 30, 60, 75, 105, 120, 150, 165, 195, 210, 240, 255, 285, 300, 330]
    nSector = 16
    nEta = 4

    chamberPlot = {}

    for sector in range(nSector):
        for eta in range(nEta):
            # skip eta = 3
            if eta == 2 : continue
            if eta == 3 and sector%2 == 0 : continue
            #if eta == 4 :
            # print (sector, eta)
            # x1[sector][eta] = step*(1+eta)*np.cos(np.pi*theta[sector]/360.)
            # y1[sector][eta] = step*(1+eta)*np.sin(np.pi*theta[sector]/360.)
            # create polygon coordinate by numpy
            # xy = np.arange(8).reshape(4,2)
            x1 = np.array([step * (1 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.)])
            y1 = np.array([step * (1 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.)])
            # print (x1+=x0,y1+=y0)
            xy[0] = x1 + x0
            xy[1] = y1 + y0
            newxy = xy.transpose()
            print(newxy.tolist())
            # ax.add_patch(patches.Polygon(xy=list(zip(np.add(x1+x0),np.add(y1+y0))), fill=False))
            index = sector + sector * eta
            print(index)
            chamberPlot[index] = patches.Polygon(newxy.tolist(), edgecolor='black', facecolor='green')
            chamberPlot[index].set_label('EI_%s_%s'%(eta,sector))
            # ax.add_patch(patches.Polygon(newxy.tolist(), edgecolor = 'black', facecolor = 'green'))
            ax.add_patch(chamberPlot[index])

    return ax

def drawEM(ax) :
    # draw Endcap
    x0 = np.array([0.5, 0.5, 0.5, 0.5])
    y0 = np.array([0.5, 0.5, 0.5, 0.5])

    step = 0.07

    xy = np.zeros((2, 4))
    print(xy)
    # theta = [for i in range(16) : ]
    theta = [345, 15, 30, 60, 75, 105, 120, 150, 165, 195, 210, 240, 255, 285, 300, 330]
    nSector = 16
    nEta = 5

    chamberPlot = {}

    for sector in range(nSector):
        for eta in range(nEta):
            # print (sector, eta)
            # x1[sector][eta] = step*(1+eta)*np.cos(np.pi*theta[sector]/360.)
            # y1[sector][eta] = step*(1+eta)*np.sin(np.pi*theta[sector]/360.)
            # create polygon coordinate by numpy
            # xy = np.arange(8).reshape(4,2)
            x1 = np.array([step * (1 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.)])
            y1 = np.array([step * (1 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.)])
            # print (x1+=x0,y1+=y0)
            xy[0] = x1 + x0
            xy[1] = y1 + y0
            newxy = xy.transpose()
            print(newxy.tolist())
            # ax.add_patch(patches.Polygon(xy=list(zip(np.add(x1+x0),np.add(y1+y0))), fill=False))
            index = sector + sector * eta
            print(index)
            chamberPlot[index] = patches.Polygon(newxy.tolist(), edgecolor='black', facecolor='green')
            chamberPlot[index].set_label('EM_%s_%s'%(eta,sector))
            # ax.add_patch(patches.Polygon(newxy.tolist(), edgecolor = 'black', facecolor = 'green'))
            ax.add_patch(chamberPlot[index])

    return ax

def drawEO(ax) :
    # draw Endcap
    x0 = np.array([0.5, 0.5, 0.5, 0.5])
    y0 = np.array([0.5, 0.5, 0.5, 0.5])

    step = 0.07

    xy = np.zeros((2, 4))
    print(xy)
    # theta = [for i in range(16) : ]
    theta = [345, 15, 30, 60, 75, 105, 120, 150, 165, 195, 210, 240, 255, 285, 300, 330]
    nSector = 16
    nEta = 6

    chamberPlot = {}

    for sector in range(nSector):
        for eta in range(nEta):
            # print (sector, eta)
            # x1[sector][eta] = step*(1+eta)*np.cos(np.pi*theta[sector]/360.)
            # y1[sector][eta] = step*(1+eta)*np.sin(np.pi*theta[sector]/360.)
            # create polygon coordinate by numpy
            # xy = np.arange(8).reshape(4,2)
            x1 = np.array([step * (1 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.cos(np.pi * theta[(sector + 1) % 16] / 180.)])
            y1 = np.array([step * (1 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[sector] / 180.),
                           step * (2 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.),
                           step * (1 + eta) * np.sin(np.pi * theta[(sector + 1) % 16] / 180.)])
            # print (x1+=x0,y1+=y0)
            xy[0] = x1 + x0
            xy[1] = y1 + y0
            newxy = xy.transpose()
            print(newxy.tolist())
            # ax.add_patch(patches.Polygon(xy=list(zip(np.add(x1+x0),np.add(y1+y0))), fill=False))
            index = sector + sector * eta
            print(index)
            chamberPlot[index] = patches.Polygon(newxy.tolist(), edgecolor='black', facecolor='green')
            chamberPlot[index].set_label('EO_%s_%s'%(eta,sector))
            # ax.add_patch(patches.Polygon(newxy.tolist(), edgecolor = 'black', facecolor = 'green'))
            ax.add_patch(chamberPlot[index])

    return ax



fig = plt.figure(constrained_layout=False)

spec2 = gridspec.GridSpec(ncols=2, nrows=2, figure=fig)

axEM = fig.add_subplot(spec2[1,0])
axEM.set_xticklabels([])
axEM.set_yticklabels([])
axEM.axis('off')

axEM = drawEM(axEM)

axEO = fig.add_subplot(spec2[0,1])
axEO.set_xticklabels([])
axEO.set_yticklabels([])
axEO.axis('off')

axEO = drawEO(axEO)

axEI = fig.add_subplot(spec2[0,0])
axEI.set_xticklabels([])
axEI.set_yticklabels([])
axEI.axis('off')

axEI = drawEI(axEI)


objs = axEI.findobj(patches.Polygon)
print (objs)
for obj in objs :
    #print (obj.label())
    obj.set_facecolor('red')  # this is ok 

plt.subplots_adjust(wspace=0, hspace=0)
plt.show()  

我的问题是如何在 subplot axEM 中更改一个特定多边形“BM_2_5”的面颜色?

【问题讨论】:

    标签: python matplotlib patch


    【解决方案1】:

    使用你的 Patch 的轴对象和索引,你可以通过这种方式实现你想要的:

    import matplotlib.pyplot as plt
    import matplotlib.patches as ptc
    import numpy as np
    
    fig, ax = plt.subplots()
    pCol = ['red', 'blue']
    for i in range(2):
        ax.add_patch(ptc.Polygon(np.random.rand(3, 2), fc=pCol[i]))
    ax.patches[0].set_facecolor((0, 1, 0, 1))
    plt.show()
    

    注意如何没有绘制红色多边形。

    编辑:记住您的评论

    import matplotlib.pyplot as plt
    import matplotlib.patches as ptc
    import numpy as np
    
    fig, ax = plt.subplots()
    pLab = ['First', 'Second']
    pCol = ['red', 'blue']
    for i in range(2):
        ax.add_patch(ptc.Polygon(np.random.rand(3, 2), fc=pCol[i], label=pLab[i]))
    for patch in ax.patches:
        if patch.get_label() == 'First':
            patch.set_facecolor('green')
    plt.show()
    

    编辑:从函数返回轴应该没问题。

    import matplotlib.pyplot as plt
    import matplotlib.patches as ptc
    import numpy as np
    
    
    def drawPatches(ax):
        for i in range(2):
            ax.add_patch(ptc.Polygon(np.random.rand(3, 2), fc=pCol[i],
                                     label=pLab[i]))
        return ax
    
    
    fig, ax = plt.subplots()
    pLab = ['First', 'Second']
    pCol = ['red', 'blue']
    ax = drawPatches(ax)
    for patch in ax.patches:
        if patch.get_label() == 'First':
            patch.set_facecolor('green')
    plt.show()
    

    【讨论】:

    • 非常感谢@Patol75,用索引来访问就知道了。但是,我正在寻找是否有办法通过我创建补丁时自己给出的名称/标签来访问补丁。否则,必须有人提前知道这些补丁的确切顺序才能更改属性。
    • 再次感谢。事实上,我真正的问题是我无法从函数中获取补丁标签。当我将以下两行添加到我的代码中时,我得到了一个空字符串。所以这不知何故变成了一个关于变量范围的问题。我认为轴对象仍将保留有关这些补丁的所有信息。 ``` 用于 axEM.patches 中的补丁:打印 (patch.get_label()) ```
    • 这个循环确实在axEM = drawEM(axEM)之后?另外,请参阅我的第二次编辑。
    • 你是对的,我终于运行了我的代码并得到了我想看的东西。非常感谢。
    猜你喜欢
    • 2020-11-14
    • 2016-09-15
    • 2014-03-08
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2011-12-28
    相关资源
    最近更新 更多