Example #1
0
def create_polygon(ellipse):
    ellipse1 = Ellipse((ellipse["center_x"], ellipse["center_y"]),
                       ellipse["radius_x"] * 2, ellipse["radius_y"] * 2,
                       ellipse["theta"])
    vertices = ellipse1.get_verts()
    polygon = Polygon(vertices)
    return polygon
Example #2
0
    def error_ellipse(self, i, j, nstd=1, space_factor=5.0, clr="b", alpha=0.5, lw=1.5):
        """
        return the plot of the error ellipse from the covariance matrix
        use ideas from error_ellipse.m from
        http://www.mathworks.com/matlabcentral/fileexchange/4705-error-ellipse
        ( the version used here was taken from an earlier version, it looks to have been updated there to a new version.)

        * (i,j) specify the ith and jth parameters to be used and
        * nstd specifies the number of standard deviations to plot, the default is 1 sigma.
        * space_factor specifies the number that divides the width/height, the result of which is then added as extra space to the figure
        """

        def eigsorted(cov):
            vals, vecs = np.linalg.eigh(cov)
            order = vals.argsort()[::1]
            return vals[order], vecs[:, order]

        self.marginalize(param_list=[i, j])
        vals, vecs = eigsorted(self.marginal_covariance_matrix)
        theta = np.degrees(np.arctan2(*vecs[:, 0][::-1]))
        # print theta
        width, height = 2 * nstd * np.sqrt(vals)
        xypos = [self.parameter_values[i], self.parameter_values[j]]
        ellip = Ellipse(xy=xypos, width=width, height=height, angle=theta, color=clr, alpha=alpha)
        # ellip.set_facecolor("white")
        ellip.set_linewidth(lw)
        ellip_vertices = ellip.get_verts()
        xl = [ellip_vertices[k][0] for k in range(len(ellip_vertices))]
        yl = [ellip_vertices[k][1] for k in range(len(ellip_vertices))]
        dx = (max(xl) - min(xl)) / space_factor
        dy = (max(yl) - min(yl)) / space_factor
        xyaxes = [min(xl) - dx, max(xl) + dx, min(yl) - dy, max(yl) + dy]
        return ellip, xyaxes
Example #3
0
    def error_ellipse(self, i, j, nstd=1, space_factor=5., clr='b', alpha=0.5, lw=1.5):
        """
        return the plot of the error ellipse from the covariance matrix
        use ideas from error_ellipse.m from
        http://www.mathworks.com/matlabcentral/fileexchange/4705-error-ellipse
        ( the version used here was taken from an earlier version, it looks to have been updated there to a new version.)

        * (i,j) specify the ith and jth parameters to be used and
        * nstd specifies the number of standard deviations to plot, the default is 1 sigma.
        * space_factor specifies the number that divides the width/height, the result of which is then added as extra space to the figure
        """
        def eigsorted(cov):
            vals, vecs = np.linalg.eigh(cov)
            order = vals.argsort()[::1]
            return vals[order], vecs[:,order]

        self.marginalize(param_list=[i,j])
        vals, vecs = eigsorted(self.marginal_covariance_matrix)
        theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
        #print theta
        width, height = 2* nstd * np.sqrt(vals)
        xypos=[self.parameter_values[i], self.parameter_values[j]]
        ellip = Ellipse(xy=xypos, width=width, height=height, angle=theta, color=clr, alpha=alpha)
        #ellip.set_facecolor("white")
        ellip.set_linewidth(lw)
        ellip_vertices=ellip.get_verts()
        xl=[ellip_vertices[k][0] for k in range(len(ellip_vertices))]
        yl=[ellip_vertices[k][1] for k in range(len(ellip_vertices))]
        dx=(max(xl)-min(xl))/space_factor
        dy=(max(yl)-min(yl))/space_factor
        xyaxes=[min(xl)-dx, max(xl)+dx, min(yl)-dy, max(yl)+dy]
        return ellip, xyaxes
Example #4
0
def get_ellipse_path(params):
    cx = params[0]
    cy = params[1]
    a = params[2]
    b = params[3]
    alpha = params[4]
    ell = Ellipse((cx, cy), a * 2., b * 2., alpha)
    coord = ell.get_verts()
    xs = coord[:, 0]
    ys = coord[:, 1]
    return xs, ys
Example #5
0
def fitEllipse(cont, name):

    x = cont[:, 0]
    y = cont[:, 1]

    x = x[:, None]
    y = y[:, None]
    #create an array, D, of elliptical polynomial values from points
    #a1x**2+a2xy+a3y**2+a4x+a5y+a6=0
    D = numpy.hstack([x * x, x * y, y * y, x, y, numpy.ones(x.shape)])
    #perform a series of linear algebra steps to find lagrangian multipliers.
    S = numpy.dot(D.T, D)
    C = numpy.zeros([6, 6])
    C[0, 2] = C[2, 0] = 2
    C[1, 1] = -1
    E, V = numpy.linalg.eig(numpy.dot(numpy.linalg.inv(S), C))
    n = numpy.argmax(E)
    #Output various polynomial parameters for best fit stored in array, 'a'.
    a = V[:, n]

    #-------------------Fit ellipse-------------------
    b, c, d, f, g, a = a[1] / 2., a[2], a[3] / 2., a[4] / 2., a[5], a[0]
    #Use a number of geometric identities to convert the polynomial coefficients to major and minor axis, center point, and tilt angle values.
    num = b * b - a * c
    cx = (c * d - b * f) / num
    cy = (a * f - b * d) / num
    angle = 0.5 * numpy.arctan(2 * b / (a - c)) * 180 / numpy.pi
    up = 2 * (a * f * f + c * d * d + g * b * b - 2 * b * d * f - a * c * g)
    down1 = (b * b - a * c) * ((c - a) * numpy.sqrt(1 + 4 * b * b /
                                                    ((a - c) * (a - c))) -
                               (c + a))
    down2 = (b * b - a * c) * ((a - c) * numpy.sqrt(1 + 4 * b * b /
                                                    ((a - c) * (a - c))) -
                               (c + a))
    a = numpy.sqrt(abs(up / down1))
    b = numpy.sqrt(abs(up / down2))

    #---------------------Get path---------------------
    #returns a matplotlib patch associated with an ellipse.
    ell = Ellipse((cx, cy),
                  a * 2.,
                  b * 2.,
                  angle,
                  lw=4,
                  fill=False,
                  color=(numpy.random.randint(100) / 100,
                         numpy.random.randint(100) / 100,
                         numpy.random.randint(100) / 100),
                  label=name)
    ell_coord = ell.get_verts()
    #params values: cx=center point x value, cy=center point y value, a=major axis length, b=minor axis length, angle=tilt angle
    params = [cx, cy, a, b, angle]
    return params, ell_coord, ell
def fitEllipseCorrected(cont):
    # https://stackoverflow.com/questions/39693869/fitting-an-ellipse-to-a-set-of-data-points-in-python
    x = cont[:, 0]
    y = cont[:, 1]

    x = x[:, None]
    y = y[:, None]

    D = np.hstack([x * x, x * y, y * y, x, y, np.ones(x.shape)])
    S = np.dot(D.T, D)
    C = np.zeros([6, 6])
    C[0, 2] = C[2, 0] = 2
    C[1, 1] = -1
    E, V = np.linalg.eig(np.dot(np.linalg.inv(S), C))

    #    if method==1:
    #        n=numpy.argmax(numpy.abs(E))
    #    else:
    #
    n = np.argmax(E)
    a = V[:, n]

    #-------------------Fit ellipse-------------------
    b, c, d, f, g, a = a[1] / 2., a[2], a[3] / 2., a[4] / 2., a[5], a[0]
    num = b * b - a * c
    cx = (c * d - b * f) / num
    cy = (a * f - b * d) / num

    angle = 0.5 * np.arctan(2 * b / (a - c)) * 180 / np.pi
    up = 2 * (a * f * f + c * d * d + g * b * b - 2 * b * d * f - a * c * g)
    down1 = (b * b - a * c) * ((c - a) * np.sqrt(1 + 4 * b * b / ((a - c) *
                                                                  (a - c))) -
                               (c + a))
    down2 = (b * b - a * c) * ((a - c) * np.sqrt(1 + 4 * b * b / ((a - c) *
                                                                  (a - c))) -
                               (c + a))
    a = np.sqrt(abs(up / down1))
    b = np.sqrt(abs(up / down2))

    #---------------------Get path---------------------
    ell = Ellipse((cx, cy), a * 2., b * 2., angle)
    ell_coord = ell.get_verts()

    params = [cx, cy, a, b, angle]

    return params, ell_coord
Example #7
0
def fitEllipse(contour):

    x = contour[:,0]
    y = contour[:,1]
    x = x[:,None]
    y = y[:,None]

    D = np.hstack([x*x,x*y,y*y,x,y,np.ones(x.shape)])
    S = np.dot(D.T,D)
    C = np.zeros([6,6])
    
    C[0,2] = C[2,0] = 2
    C[1,1] = -1
    E, V   = np.linalg.eig(np.dot(np.linalg.inv(S),C))

    n = np.argmax(E)
    a = V[:,n]

	#fit ellipse
    b,c,d,f,g,a = a[1]/2., a[2], a[3]/2., a[4]/2., a[5], a[0]
    num = b*b-a*c
    cx  = (c*d-b*f)/num
    cy  = (a*f-b*d)/num

    angle = 0.5*np.arctan(2*b/(a-c))*180/np.pi
    up    = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g)
    down1 = (b*b-a*c)*( (c-a)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a))
    down2 = (b*b-a*c)*( (a-c)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a))
    a     = np.sqrt(abs(up/down1))
    b     = np.sqrt(abs(up/down2))

    ell       = Ellipse((cx,cy),a*2.,b*2.,angle)
    ell_coord = ell.get_verts()
    params    = [cx,cy,a,b,angle]

    return params,ell_coord
Example #8
0
    def update_ellipse(self, datd, dats, nodepth=False):
        """Update error ellipse plot."""
        self.figure.clear()

        x = np.ma.masked_invalid(datd['1_longitude'])
        y = np.ma.masked_invalid(datd['1_latitude'])

        xmin = x.min()-0.5
        xmax = x.max()+0.5
        ymin = y.min()-0.5
        ymax = y.max()+0.5

        self.axes = self.figure.add_subplot(111)  # , projection=ccrs.PlateCarree())
        self.axes.set_xlim(xmin, xmax)
        self.axes.set_ylim(ymin, ymax)

#        extent = [xmin, xmax, ymax, ymin]
#        request = cimgt.GoogleTiles(style='satellite')
#        self.axes.set_extent(extent, crs=ccrs.PlateCarree())

#        self.axes.add_image(request, 6)
#        self.axes.gridlines(draw_labels=True)

        for dat in dats:
            if 'E' not in dat:
                continue

            lon = dat['1'].longitude
            lat = dat['1'].latitude

            erx = dat['E'].longitude_error
            ery = dat['E'].latitude_error
            erz = dat['E'].depth_error
            cvxy = dat['E'].cov_xy
            cvxz = dat['E'].cov_xz
            cvyz = dat['E'].cov_yz

            if nodepth is True:
                cvxz = 0
                cvyz = 0
                erz = 0

            cov = np.array([[erx*erx, cvxy, cvxz],
                            [cvxy, ery*ery, cvyz],
                            [cvxz, cvyz, erz*erz]])

            if True in np.isnan(cov):
                continue

            vals, vecs = eigsorted(cov)
            abc = (2*np.sqrt(abs(vals)) *
                   np.cos(np.arctan2(vecs[2, :],
                                     np.sqrt(vecs[0, :]**2+vecs[1, :]**2))))

            if abc[0] == abc.max():
                ang = np.rad2deg(np.arctan2(vecs[1, 0], vecs[0, 0]))
            if abc[1] == abc.max():
                ang = np.rad2deg(np.arctan2(vecs[1, 1], vecs[0, 1]))
            if abc[2] == abc.max():
                ang = np.rad2deg(np.arctan2(vecs[1, 2], vecs[0, 2]))

            abc[::-1].sort()  # sort in reverse order
            emaj = abc[0]
            emin = abc[1]

            # approx conversion to degrees
            demin = emin/110.93  # lat
            demaj = emaj/(111.3*np.cos(np.deg2rad(lat+demin)))  # long from lat

            ell = Ellipse(xy=(lon, lat),
                          width=demaj, height=demin,
                          angle=ang, color='black')
            ell.set_facecolor('none')
            #    ell.set_edgecolor('black')

#            self.axes.add_artist(ell)
            self.ellipses.append(ell.get_verts())
            self.axes.add_artist(ell)

        self.figure.tight_layout()
        self.figure.canvas.draw()
Example #9
0
    def __init__(self,*args):
        '''
        A least-squares fitted ellipse.
        
        Parameters
        ----------
        *args : An arraylike of points XY (shape Nx2), 
                 or two arraylikes of ordinates, X and Y (shape N)
            The points against which to fit the ellipse.
            
        Raises
        ------
        np.linalg.LinAlgError
            Raised when there are an insufficient number of points
            to fit the ellipse, or when the resultant matrix is singular.
            
        Attributes
        -------
        centre_x: x ordinate of ellipse centre
        centree_y: y ordinate of ellipse centre
        centre:   (centre_x,centre_y)
        angle:   rotation of the ellipse from horizontal, in degrees
                   counterclockwise
        axes:    major and minor axes (order not guaranteed)
        area:    ellipse area
        points:  a series of points on the ellipse, for plotting
        '''
        if len(args)==1:
            xy = np.array(args[0])
            xy = xy.reshape(-1,2)
            x = xy[:,0:1]
            y = xy[:,1:]
        elif len(args)==2:
            x = args[0]
            y = args[1]
        #Require at least 6 points#
        if x.shape[0]<self.min_points:
            raise np.linalg.LinAlgError(f"Insufficient data for fitting ellipse, {self.min_points} required, received {x.shape[0]}")
        #The general form of a conic is Ax**2 + By**2 + Cx + Dy + E == 0
        D=np.hstack([x*x,x*y,y*y,x,y,np.ones(x.shape)])
        #But we can't just least-squares solve this matrix equation, because
        #we could end up with any conic! We need to constrain to the ellipse
        #case, ie we have a constrained minimization problem.

        #The algorithm to do this is from here: 
        #https://github.com/ndvanforeest/fit_ellipse/blob/master/fitEllipse.pdf
        #With additional adaptions from here: 
        #https://stackoverflow.com/a/48002645/12488760
        S=np.dot(D.T,D)
        C=np.zeros([6,6])
        C[0,2]=C[2,0]=2
        C[1,1]=-1
        E,V=np.linalg.eig(np.dot(np.linalg.inv(S),C))
        n=np.argmax(E)
        a=V[:,n]
        b,c,d,f,g,a=a[1]/2., a[2], a[3]/2., a[4]/2., a[5], a[0]
        num=b*b-a*c
        if num==0:
            raise np.linalg.LinAlgError("Insufficient data to fit an ellipse")
            
        #Now we know the general form coefficients, so we can convert them
        #to useful quantities
        self.centre_x = (c*d-b*f)/num
        self.centre_y = (a*f-b*d)/num
        self.centre = (self.centre_x,self.centre_y)
        self.angle = 0.5*np.arctan(2*b/(a-c))*180/np.pi #In degrees
        
        up = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g)
        down1=(b*b-a*c)*( (c-a)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a))
        down2=(b*b-a*c)*( (a-c)*np.sqrt(1+4*b*b/((a-c)*(a-c)))-(c+a))
        
        radius_horizontal=np.sqrt(abs(up/down1))
        radius_vertical  =np.sqrt(abs(up/down2))
        
        self.axes = (radius_horizontal,radius_vertical)
        self.area = np.pi*radius_horizontal*radius_vertical
        
        
        ell=Ellipse(self.centre,
                    radius_horizontal*2.,
                    radius_vertical*2.,
                    self.angle)
        self.points=ell.get_verts()
        self.sum_of_squares_error = self.get_mean_squared_error(xy)