Allocate scatter plot into specific bins

前端 未结 2 1794
隐瞒了意图╮
隐瞒了意图╮ 2021-01-23 08:49

I have a scatter plot that gets sorted into 4 Bins. These are separated by two arcs and a line in the middle (see figure belo

2条回答
  •  醉话见心
    2021-01-23 09:52

    This is a version where I sort it into ellipses. As the OP is using simple geometric shapes one can test this with a simple formula, i.e. not "asking" the patch. I generalized it for n arcs with the small disadvantage that bin numbering is not from left to right, but this can be taken care of elsewhere. Output is of type

    [ [ [x,y], [x,y],...], ... ] 
    

    i.e. a list of x,y for each bins. Numbering here is from -3 to 3 though, with 0 being outside.

    import matplotlib.pyplot as plt
    import matplotlib as mpl
    import numpy as np
    
    def in_ellipse( xy, x0y0ab):
        x, y = xy
        x0, y0 = x0y0ab[0]
        a = x0y0ab[1]/2.  ## as the list of ellipses takes width and not semi axis
        b = x0y0ab[2]/2.
        return ( x - x0 )**2 / a**2+ ( y - y0 )**2 / b**2 < 1
    
    def sort_into_bins( xy, mainE, eList ):
        binCntr = 0
        xyA = (np.abs(xy[0]),xy[1]) ## all positive
        if in_ellipse( xyA, mainE ):
            binCntr +=1
            for ell in eList:
                if in_ellipse( xyA, ell ):
                    break
                binCntr +=1
        binCntr=np.copysign( binCntr, xy[0] )
        return int( binCntr )
    
    X = 200 * np.random.random(150) - 100
    Y = 140 * np.random.random(150) - 70 + 60
    
    fig, ax = plt.subplots()
    ax.set_xlim(-100,100)
    ax.set_ylim(-40,140)
    ax.grid(False)
    
    
    BIN_23_X = 0 
    mainEllipse = [ np.array([0, 60]), 160, 130 ]
    allEllipses = [ [ np.array([60,60]), 70., 110. ], [ np.array([60,60]), 100, 160 ]  ]
    
    Halfway = mpl.lines.Line2D((BIN_23_X,BIN_23_X), (0,125), color = '#808080', lw = 1.5, alpha = 0.8, zorder = 1)
    Oval = mpl.patches.Ellipse( mainEllipse[0], mainEllipse[1], mainEllipse[2], lw = 3, edgecolor = '#808080', facecolor = '#808080', alpha = 0.2)
    ax.add_patch(Oval)
    ax.add_line(Halfway)
    
    for ell in allEllipses:
        arc =  mpl.patches.Arc( ell[0] , ell[1], ell[2], angle = 0,  color = '#808080', lw = 2, linestyle=':')
        ax.add_patch( arc )
        arc =  mpl.patches.Arc( ell[0] * np.array([ -1, 1 ]), ell[1], ell[2], angle = 0,  color = '#808080', lw = 2, linestyle=':')
        ax.add_patch( arc )
    
    binDict = dict()
    for x,y in zip(X,Y):
        binDict[( x,y)]=sort_into_bins( (x,y), mainEllipse, allEllipses )
    
    rowEval=[]
    for s in range(-3,4):
        rowEval+=[[]]
    for key, val in binDict.iteritems():
        rowEval[ val + 3 ]+=[key]
    
    for s in range(-3,4):
        plt.scatter( *zip( *rowEval[ s + 3 ] ) )
    
    plt.show()
    

    showing

    Note that I used the fact of symmetry with respect to x=0. If the ellipses are shifted with respect to x the code has to be modified a little. Also note that the order in which the ellipses are provided matters!

提交回复
热议问题