簡體   English   中英

圍繞點繪制橢圓

[英]Draw ellipses around points

我正在嘗試用 matplotlib 在圖形上的一組點周圍繪制橢圓。我想獲得這樣的東西:

在此處輸入圖像描述

一組數據集(例如紅色組)可能如下所示:

[[-23.88315146  -3.26328266]  # first point
 [-25.94906669  -1.47440904]  # second point
 [-26.52423229  -4.84947907]]  # third point

我可以輕松地在圖表上繪制點,但在繪制橢圓時遇到問題。

橢圓的直徑為2 * standard deviation ,其中心坐標為(x_mean, y_mean) 一個橢圓的寬度等於x standard deviation * 2 它的高度等於y standard deviation * 2

但是,我不知道如何計算橢圓的角度(你可以在圖片上看到橢圓不是完全垂直的)。

你知道怎么做嗎?

注:本題是LDA問題(線性判別分析)的簡化。 我試圖將問題簡化為最基本的表達方式。

這與數學有很大關系,而不是編程;)

既然你已經擁有尺寸並且只想找到角度,那么這就是我要做的事情(根據我的直覺):

嘗試找到最適合給定點集(趨勢線)的線,這也稱為線性回歸 有幾種方法可以做到這一點,但最小二乘法是一個相對簡單的方法(見下文)。

找到最佳擬合線后,可以使用斜率作為角度。

最小二乘線性回歸

最小二乘線性回歸方法用於找到趨勢線的斜率,正是我們想要的。

這是一段視頻,解釋它如何工作的

假設你有一個數據集: data = [(x1, y1), (x2, y2), ...]

使用最小二乘法,您的斜率將是:

# I see in your example that you already have x_mean and y_mean
# No need to calculate them again, skip the two following lines
# and use your values in the rest of the example
avg_x = sum(element[0] for element in data)/len(data)
avg_y = sum(element[1] for element in data)/len(data)

x_diff = [element[0] - avg_x for element in data]
y_diff = [element[1] - avg_y for element in data]

x_diff_squared = [element**2 for element in x_diff]

slope = sum(x * y for x,y in zip(x_diff, y_diff)) / sum(x_diff_squared)

一旦你擁有了,你就快完成了。 斜率等於角度slope = tan(angle)的正切值

使用python的math模塊angle = math.atan(slope)這將返回以弧度表示的角度。 如果你想要它在度數你必須使用math.degrees(angle)轉換它

將它與你已經擁有的尺寸和位置相結合,你就得到了一個橢圓;)


這就是我如何解決這個特殊問題,但是可能有一千種不同的方法也可以工作,最終可能比我建議的更好(也更復雜)。

這是一個研究得很好的問題。 首先采用您希望包含的點集的凸包 然后執行文獻中描述的計算。 我在下面提供兩個來源。

“最小的封閉橢圓 - C ++中的精確和通用實現”( 摘要鏈接 )。


橢圓


Charles F. Van Loan。 “使用橢圓來擬合和包含數據點。” PDF下載 )。

我寫了一個簡單的 function 來實現 Mathieu David 的解決方案。 我確信有很多方法可以做到這一點,但這對我的應用程序有效。

    def get_ellipse_params(self, points):
        ''' Calculate the parameters needed to graph an ellipse around a cluster of points in 2D.

            Calculate the height, width and angle of an ellipse to enclose the points in a cluster.
            Calculate the width by finding the maximum distance between the x-coordinates of points
            in the cluster, and the height by finding the maximum distance between the y-coordinates
            in the cluster. Multiple both by a scale factor to give padding around the points when
            constructing the ellipse. Calculate the angle by taking the inverse tangent of the
            gradient of the regression line. Note that tangent solutions repeat every 180 degrees,
            and so to ensure the correct solution has been found for plotting, add a correction
            factor of +/- 90 degrees if the magnitude of the angle exceeds 45 degrees.

            Args:
                points (ndarray): The points in a cluster to enclose with an ellipse, containing n
                                  ndarray elements representing each point, each with d elements
                                  representing the coordinates for the point.

            Returns:
                width (float):  The width of the ellipse.
                height (float): The height of the ellipse.
                angle (float):  The angle of the ellipse in degrees.
        '''
        if points.ndim == 1:
            width, height, angle = 0.1, 0.1, 0
            return width, height, angle

        else:
            SCALE = 2.5
            width = np.amax(points[:,0]) - np.amin(points[:,0])
            height = np.amax(points[:,1]) - np.amin(points[:,1])
            
            # Calculate angle
            x_reg, y_reg = [[p[0]] for p in points], [[p[1]] for p in points]
            grad = LinearRegression().fit(x_reg, y_reg).coef_[0][0]
            angle = np.degrees(np.arctan(grad))

            # Account for multiple solutions of arctan
            if angle < -45: angle += 90
            elif angle > 45: angle -= 90

            return width*SCALE, height*SCALE, angle

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM